1 // SPDX-License-Identifier: MIT
3 * Copyright © 2022 Intel Corporation
6 #include "xe_force_wake.h"
8 #include <drm/drm_util.h>
10 #include "regs/xe_gt_regs.h"
11 #include "regs/xe_reg_defs.h"
15 #define XE_FORCE_WAKE_ACK_TIMEOUT_MS 50
18 fw_to_gt(struct xe_force_wake *fw)
23 static struct xe_device *
24 fw_to_xe(struct xe_force_wake *fw)
26 return gt_to_xe(fw_to_gt(fw));
29 static void domain_init(struct xe_force_wake_domain *domain,
30 enum xe_force_wake_domain_id id,
31 struct xe_reg reg, struct xe_reg ack, u32 val, u32 mask)
34 domain->reg_ctl = reg;
35 domain->reg_ack = ack;
40 void xe_force_wake_init_gt(struct xe_gt *gt, struct xe_force_wake *fw)
42 struct xe_device *xe = gt_to_xe(gt);
45 spin_lock_init(&fw->lock);
47 /* Assuming gen11+ so assert this assumption is correct */
48 xe_gt_assert(gt, GRAPHICS_VER(gt_to_xe(gt)) >= 11);
50 if (xe->info.graphics_verx100 >= 1270) {
51 domain_init(&fw->domains[XE_FW_DOMAIN_ID_GT],
57 domain_init(&fw->domains[XE_FW_DOMAIN_ID_GT],
65 void xe_force_wake_init_engines(struct xe_gt *gt, struct xe_force_wake *fw)
69 /* Assuming gen11+ so assert this assumption is correct */
70 xe_gt_assert(gt, GRAPHICS_VER(gt_to_xe(gt)) >= 11);
72 if (!xe_gt_is_media_type(gt))
73 domain_init(&fw->domains[XE_FW_DOMAIN_ID_RENDER],
74 XE_FW_DOMAIN_ID_RENDER,
79 for (i = XE_HW_ENGINE_VCS0, j = 0; i <= XE_HW_ENGINE_VCS7; ++i, ++j) {
80 if (!(gt->info.engine_mask & BIT(i)))
83 domain_init(&fw->domains[XE_FW_DOMAIN_ID_MEDIA_VDBOX0 + j],
84 XE_FW_DOMAIN_ID_MEDIA_VDBOX0 + j,
85 FORCEWAKE_MEDIA_VDBOX(j),
86 FORCEWAKE_ACK_MEDIA_VDBOX(j),
90 for (i = XE_HW_ENGINE_VECS0, j = 0; i <= XE_HW_ENGINE_VECS3; ++i, ++j) {
91 if (!(gt->info.engine_mask & BIT(i)))
94 domain_init(&fw->domains[XE_FW_DOMAIN_ID_MEDIA_VEBOX0 + j],
95 XE_FW_DOMAIN_ID_MEDIA_VEBOX0 + j,
96 FORCEWAKE_MEDIA_VEBOX(j),
97 FORCEWAKE_ACK_MEDIA_VEBOX(j),
101 if (gt->info.engine_mask & BIT(XE_HW_ENGINE_GSCCS0))
102 domain_init(&fw->domains[XE_FW_DOMAIN_ID_GSC],
109 static void domain_wake(struct xe_gt *gt, struct xe_force_wake_domain *domain)
111 xe_mmio_write32(gt, domain->reg_ctl, domain->mask | domain->val);
114 static int domain_wake_wait(struct xe_gt *gt,
115 struct xe_force_wake_domain *domain)
117 return xe_mmio_wait32(gt, domain->reg_ack, domain->val, domain->val,
118 XE_FORCE_WAKE_ACK_TIMEOUT_MS * USEC_PER_MSEC,
122 static void domain_sleep(struct xe_gt *gt, struct xe_force_wake_domain *domain)
124 xe_mmio_write32(gt, domain->reg_ctl, domain->mask);
127 static int domain_sleep_wait(struct xe_gt *gt,
128 struct xe_force_wake_domain *domain)
130 return xe_mmio_wait32(gt, domain->reg_ack, domain->val, 0,
131 XE_FORCE_WAKE_ACK_TIMEOUT_MS * USEC_PER_MSEC,
135 #define for_each_fw_domain_masked(domain__, mask__, fw__, tmp__) \
136 for (tmp__ = (mask__); tmp__; tmp__ &= ~BIT(ffs(tmp__) - 1)) \
137 for_each_if((domain__ = ((fw__)->domains + \
138 (ffs(tmp__) - 1))) && \
139 domain__->reg_ctl.addr)
141 int xe_force_wake_get(struct xe_force_wake *fw,
142 enum xe_force_wake_domains domains)
144 struct xe_device *xe = fw_to_xe(fw);
145 struct xe_gt *gt = fw_to_gt(fw);
146 struct xe_force_wake_domain *domain;
147 enum xe_force_wake_domains tmp, woken = 0;
151 spin_lock_irqsave(&fw->lock, flags);
152 for_each_fw_domain_masked(domain, domains, fw, tmp) {
153 if (!domain->ref++) {
154 woken |= BIT(domain->id);
155 domain_wake(gt, domain);
158 for_each_fw_domain_masked(domain, woken, fw, tmp) {
159 ret = domain_wake_wait(gt, domain);
162 drm_notice(&xe->drm, "Force wake domain (%d) failed to ack wake, ret=%d\n",
165 fw->awake_domains |= woken;
166 spin_unlock_irqrestore(&fw->lock, flags);
171 int xe_force_wake_put(struct xe_force_wake *fw,
172 enum xe_force_wake_domains domains)
174 struct xe_device *xe = fw_to_xe(fw);
175 struct xe_gt *gt = fw_to_gt(fw);
176 struct xe_force_wake_domain *domain;
177 enum xe_force_wake_domains tmp, sleep = 0;
181 spin_lock_irqsave(&fw->lock, flags);
182 for_each_fw_domain_masked(domain, domains, fw, tmp) {
183 if (!--domain->ref) {
184 sleep |= BIT(domain->id);
185 domain_sleep(gt, domain);
188 for_each_fw_domain_masked(domain, sleep, fw, tmp) {
189 ret = domain_sleep_wait(gt, domain);
192 drm_notice(&xe->drm, "Force wake domain (%d) failed to ack sleep, ret=%d\n",
195 fw->awake_domains &= ~sleep;
196 spin_unlock_irqrestore(&fw->lock, flags);