Unverified Commit a7ddcea1 authored by Himal Prasad Ghimiray's avatar Himal Prasad Ghimiray Committed by Rodrigo Vivi
Browse files

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: default avatarBadal Nilawar <badal.nilawar@intel.com>
Reviewed-by: default avatarMichal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: default avatarHimal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Reviewed-by: default avatarNirmoy Das <nirmoy.das@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241014075601.2324382-5-himal.prasad.ghimiray@intel.com


Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 9d62b070
Loading
Loading
Loading
Loading
+42 −10
Original line number Diff line number Diff line
@@ -154,29 +154,61 @@ static int domain_sleep_wait(struct xe_gt *gt,
					 (ffs(tmp__) - 1))) && \
					 domain__->reg_ctl.addr)

int xe_force_wake_get(struct xe_force_wake *fw,
/**
 * xe_force_wake_get() : Increase the domain refcount
 * @fw: struct xe_force_wake
 * @domains: forcewake domains to get refcount on
 *
 * This function wakes up @domains if they are asleep and takes references.
 * If requested domain is XE_FORCEWAKE_ALL then only applicable/initialized
 * domains will be considered for refcount and it is a caller responsibility
 * to check returned ref if it includes any specific domain by using
 * xe_force_wake_ref_has_domain() function. Caller must call
 * xe_force_wake_put() function to decrease incremented refcounts.
 *
 * Return: opaque reference to woken domains or zero if none of requested
 * domains were awake.
 */
unsigned int xe_force_wake_get(struct xe_force_wake *fw,
			       enum xe_force_wake_domains domains)
{
	struct xe_gt *gt = fw->gt;
	struct xe_force_wake_domain *domain;
	enum xe_force_wake_domains tmp, woken = 0;
	unsigned int ref_incr = 0, awake_rqst = 0, awake_failed = 0;
	unsigned int tmp, ref_rqst;
	unsigned long flags;
	int ret = 0;

	xe_gt_assert(gt, is_power_of_2(domains));
	xe_gt_assert(gt, domains <= XE_FORCEWAKE_ALL);
	xe_gt_assert(gt, domains == XE_FORCEWAKE_ALL || fw->initialized_domains & domains);

	ref_rqst = (domains == XE_FORCEWAKE_ALL) ? fw->initialized_domains : domains;
	spin_lock_irqsave(&fw->lock, flags);
	for_each_fw_domain_masked(domain, domains, fw, tmp) {
	for_each_fw_domain_masked(domain, ref_rqst, fw, tmp) {
		if (!domain->ref++) {
			woken |= BIT(domain->id);
			awake_rqst |= BIT(domain->id);
			domain_wake(gt, domain);
		}
		ref_incr |= BIT(domain->id);
	}
	for_each_fw_domain_masked(domain, woken, fw, tmp) {
		ret |= domain_wake_wait(gt, domain);
	for_each_fw_domain_masked(domain, awake_rqst, fw, tmp) {
		if (domain_wake_wait(gt, domain) == 0) {
			fw->awake_domains |= BIT(domain->id);
		} else {
			awake_failed |= BIT(domain->id);
			--domain->ref;
		}
	fw->awake_domains |= woken;
	}
	ref_incr &= ~awake_failed;
	spin_unlock_irqrestore(&fw->lock, flags);

	return ret;
	xe_gt_WARN(gt, awake_failed, "Forcewake domain%s %#x failed to acknowledge awake request\n",
		   str_plural(hweight_long(awake_failed)), awake_failed);

	if (domains == XE_FORCEWAKE_ALL && ref_incr == fw->initialized_domains)
		ref_incr |= XE_FORCEWAKE_ALL;

	return ref_incr;
}

int xe_force_wake_put(struct xe_force_wake *fw,
+2 −2
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ void xe_force_wake_init_gt(struct xe_gt *gt,
			   struct xe_force_wake *fw);
void xe_force_wake_init_engines(struct xe_gt *gt,
				struct xe_force_wake *fw);
int xe_force_wake_get(struct xe_force_wake *fw,
unsigned int xe_force_wake_get(struct xe_force_wake *fw,
			       enum xe_force_wake_domains domains);
int xe_force_wake_put(struct xe_force_wake *fw,
		      enum xe_force_wake_domains domains);
+1 −1
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ enum xe_force_wake_domains {
	XE_FW_MEDIA_VEBOX2	= BIT(XE_FW_DOMAIN_ID_MEDIA_VEBOX2),
	XE_FW_MEDIA_VEBOX3	= BIT(XE_FW_DOMAIN_ID_MEDIA_VEBOX3),
	XE_FW_GSC		= BIT(XE_FW_DOMAIN_ID_GSC),
	XE_FORCEWAKE_ALL	= BIT(XE_FW_DOMAIN_ID_COUNT) - 1
	XE_FORCEWAKE_ALL	= BIT(XE_FW_DOMAIN_ID_COUNT)
};

/**