Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe: Error handling in xe_force_wake_get()

If an acknowledgment timeout occurs for a forcewake domain awake
request, do not increment the reference count for the domain. This
ensures that subsequent _get calls do not incorrectly assume the domain
is awake. The return value is a mask of domains that got refcounted,
and these domains need to be provided for subsequent xe_force_wake_put
call.

While at it, add simple kernel-doc for xe_force_wake_get()

v3
- Use explicit type for mask (Michal/Badal)
- Improve kernel-doc (Michal)
- Use unsigned int instead of abusing enum (Michal)

v5
- Use unsigned int for return (MattB/Badal/Rodrigo)
- use xe_gt_WARN for domain awake ack failure (Badal/Rodrigo)

v6
- Change XE_FORCEWAKE_ALL to single bit, this helps accommodate
actually refcounted domains in return. (Michal)
- Modify commit message and warn message (Badal)
- Remove unnecessary information in kernel-doc (Michal)

v7
- Add assert condition for valid input domains (Badal)

v9
- Update kernel-doc and simplify conditions (Michal)

Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: Badal Nilawar <badal.nilawar@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Cc: Nirmoy Das <nirmoy.das@intel.com>
Reviewed-by: Badal Nilawar <badal.nilawar@intel.com>
Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Reviewed-by: Nirmoy Das <nirmoy.das@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241014075601.2324382-5-himal.prasad.ghimiray@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Himal Prasad Ghimiray and committed by
Rodrigo Vivi
a7ddcea1 9d62b070

+45 -13
+42 -10
drivers/gpu/drm/xe/xe_force_wake.c
··· 154 154 (ffs(tmp__) - 1))) && \ 155 155 domain__->reg_ctl.addr) 156 156 157 - int xe_force_wake_get(struct xe_force_wake *fw, 158 - enum xe_force_wake_domains domains) 157 + /** 158 + * xe_force_wake_get() : Increase the domain refcount 159 + * @fw: struct xe_force_wake 160 + * @domains: forcewake domains to get refcount on 161 + * 162 + * This function wakes up @domains if they are asleep and takes references. 163 + * If requested domain is XE_FORCEWAKE_ALL then only applicable/initialized 164 + * domains will be considered for refcount and it is a caller responsibility 165 + * to check returned ref if it includes any specific domain by using 166 + * xe_force_wake_ref_has_domain() function. Caller must call 167 + * xe_force_wake_put() function to decrease incremented refcounts. 168 + * 169 + * Return: opaque reference to woken domains or zero if none of requested 170 + * domains were awake. 171 + */ 172 + unsigned int xe_force_wake_get(struct xe_force_wake *fw, 173 + enum xe_force_wake_domains domains) 159 174 { 160 175 struct xe_gt *gt = fw->gt; 161 176 struct xe_force_wake_domain *domain; 162 - enum xe_force_wake_domains tmp, woken = 0; 177 + unsigned int ref_incr = 0, awake_rqst = 0, awake_failed = 0; 178 + unsigned int tmp, ref_rqst; 163 179 unsigned long flags; 164 - int ret = 0; 165 180 181 + xe_gt_assert(gt, is_power_of_2(domains)); 182 + xe_gt_assert(gt, domains <= XE_FORCEWAKE_ALL); 183 + xe_gt_assert(gt, domains == XE_FORCEWAKE_ALL || fw->initialized_domains & domains); 184 + 185 + ref_rqst = (domains == XE_FORCEWAKE_ALL) ? fw->initialized_domains : domains; 166 186 spin_lock_irqsave(&fw->lock, flags); 167 - for_each_fw_domain_masked(domain, domains, fw, tmp) { 187 + for_each_fw_domain_masked(domain, ref_rqst, fw, tmp) { 168 188 if (!domain->ref++) { 169 - woken |= BIT(domain->id); 189 + awake_rqst |= BIT(domain->id); 170 190 domain_wake(gt, domain); 171 191 } 192 + ref_incr |= BIT(domain->id); 172 193 } 173 - for_each_fw_domain_masked(domain, woken, fw, tmp) { 174 - ret |= domain_wake_wait(gt, domain); 194 + for_each_fw_domain_masked(domain, awake_rqst, fw, tmp) { 195 + if (domain_wake_wait(gt, domain) == 0) { 196 + fw->awake_domains |= BIT(domain->id); 197 + } else { 198 + awake_failed |= BIT(domain->id); 199 + --domain->ref; 200 + } 175 201 } 176 - fw->awake_domains |= woken; 202 + ref_incr &= ~awake_failed; 177 203 spin_unlock_irqrestore(&fw->lock, flags); 178 204 179 - return ret; 205 + xe_gt_WARN(gt, awake_failed, "Forcewake domain%s %#x failed to acknowledge awake request\n", 206 + str_plural(hweight_long(awake_failed)), awake_failed); 207 + 208 + if (domains == XE_FORCEWAKE_ALL && ref_incr == fw->initialized_domains) 209 + ref_incr |= XE_FORCEWAKE_ALL; 210 + 211 + return ref_incr; 180 212 } 181 213 182 214 int xe_force_wake_put(struct xe_force_wake *fw,
+2 -2
drivers/gpu/drm/xe/xe_force_wake.h
··· 15 15 struct xe_force_wake *fw); 16 16 void xe_force_wake_init_engines(struct xe_gt *gt, 17 17 struct xe_force_wake *fw); 18 - int xe_force_wake_get(struct xe_force_wake *fw, 19 - enum xe_force_wake_domains domains); 18 + unsigned int xe_force_wake_get(struct xe_force_wake *fw, 19 + enum xe_force_wake_domains domains); 20 20 int xe_force_wake_put(struct xe_force_wake *fw, 21 21 enum xe_force_wake_domains domains); 22 22
+1 -1
drivers/gpu/drm/xe/xe_force_wake_types.h
··· 48 48 XE_FW_MEDIA_VEBOX2 = BIT(XE_FW_DOMAIN_ID_MEDIA_VEBOX2), 49 49 XE_FW_MEDIA_VEBOX3 = BIT(XE_FW_DOMAIN_ID_MEDIA_VEBOX3), 50 50 XE_FW_GSC = BIT(XE_FW_DOMAIN_ID_GSC), 51 - XE_FORCEWAKE_ALL = BIT(XE_FW_DOMAIN_ID_COUNT) - 1 51 + XE_FORCEWAKE_ALL = BIT(XE_FW_DOMAIN_ID_COUNT) 52 52 }; 53 53 54 54 /**