diff options
| author | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
| commit | 1ac731c529cd4d6adbce134754b51ff7d822b145 (patch) | |
| tree | 143ab3f35ca5f3b69f583c84e6964b17139c2ec1 /drivers/gpu/drm/i915/gt/intel_reset.c | |
| parent | 07b4c950f27bef0362dc6ad7ee713aab61d58149 (diff) | |
| parent | 54116d442e001e1b6bd482122043b1870998a1f3 (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.6 merge window.
Diffstat (limited to 'drivers/gpu/drm/i915/gt/intel_reset.c')
| -rw-r--r-- | drivers/gpu/drm/i915/gt/intel_reset.c | 119 | 
1 files changed, 99 insertions, 20 deletions
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 0bb9094fdacd..797ea8340467 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -14,6 +14,8 @@  #include "gt/intel_gt_regs.h" +#include "gt/uc/intel_gsc_fw.h" +  #include "i915_drv.h"  #include "i915_file_private.h"  #include "i915_gpu_error.h" @@ -268,10 +270,28 @@ out:  static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)  {  	struct intel_uncore *uncore = gt->uncore; -	int loops = 2; +	int loops;  	int err;  	/* +	 * On some platforms, e.g. Jasperlake, we see that the engine register +	 * state is not cleared until shortly after GDRST reports completion, +	 * causing a failure as we try to immediately resume while the internal +	 * state is still in flux. If we immediately repeat the reset, the +	 * second reset appears to serialise with the first, and since it is a +	 * no-op, the registers should retain their reset value. However, there +	 * is still a concern that upon leaving the second reset, the internal +	 * engine state is still in flux and not ready for resuming. +	 * +	 * Starting on MTL, there are some prep steps that we need to do when +	 * resetting some engines that need to be applied every time we write to +	 * GEN6_GDRST. As those are time consuming (tens of ms), we don't want +	 * to perform that twice, so, since the Jasperlake issue hasn't been +	 * observed on MTL, we avoid repeating the reset on newer platforms. +	 */ +	loops = GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 70) ? 2 : 1; + +	/*  	 * GEN6_GDRST is not in the gt power well, no need to check  	 * for fifo space for the write or forcewake the chip for  	 * the read @@ -279,20 +299,7 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)  	do {  		intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask); -		/* -		 * Wait for the device to ack the reset requests. -		 * -		 * On some platforms, e.g. Jasperlake, we see that the -		 * engine register state is not cleared until shortly after -		 * GDRST reports completion, causing a failure as we try -		 * to immediately resume while the internal state is still -		 * in flux. If we immediately repeat the reset, the second -		 * reset appears to serialise with the first, and since -		 * it is a no-op, the registers should retain their reset -		 * value. However, there is still a concern that upon -		 * leaving the second reset, the internal engine state -		 * is still in flux and not ready for resuming. -		 */ +		/* Wait for the device to ack the reset requests. */  		err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,  						   hw_domain_mask, 0,  						   2000, 0, @@ -690,6 +697,74 @@ static reset_func intel_get_gpu_reset(const struct intel_gt *gt)  		return NULL;  } +static int __reset_guc(struct intel_gt *gt) +{ +	u32 guc_domain = +		GRAPHICS_VER(gt->i915) >= 11 ? GEN11_GRDOM_GUC : GEN9_GRDOM_GUC; + +	return gen6_hw_domain_reset(gt, guc_domain); +} + +static bool needs_wa_14015076503(struct intel_gt *gt, intel_engine_mask_t engine_mask) +{ +	if (!IS_METEORLAKE(gt->i915) || !HAS_ENGINE(gt, GSC0)) +		return false; + +	if (!__HAS_ENGINE(engine_mask, GSC0)) +		return false; + +	return intel_gsc_uc_fw_init_done(>->uc.gsc); +} + +static intel_engine_mask_t +wa_14015076503_start(struct intel_gt *gt, intel_engine_mask_t engine_mask, bool first) +{ +	if (!needs_wa_14015076503(gt, engine_mask)) +		return engine_mask; + +	/* +	 * wa_14015076503: if the GSC FW is loaded, we need to alert it that +	 * we're going to do a GSC engine reset and then wait for 200ms for the +	 * FW to get ready for it. However, if this is the first ALL_ENGINES +	 * reset attempt and the GSC is not busy, we can try to instead reset +	 * the GuC and all the other engines individually to avoid the 200ms +	 * wait. +	 * Skipping the GSC engine is safe because, differently from other +	 * engines, the GSCCS only role is to forward the commands to the GSC +	 * FW, so it doesn't have any HW outside of the CS itself and therefore +	 * it has no state that we don't explicitly re-init on resume or on +	 * context switch LRC or power context). The HW for the GSC uC is +	 * managed by the GSC FW so we don't need to care about that. +	 */ +	if (engine_mask == ALL_ENGINES && first && intel_engine_is_idle(gt->engine[GSC0])) { +		__reset_guc(gt); +		engine_mask = gt->info.engine_mask & ~BIT(GSC0); +	} else { +		intel_uncore_rmw(gt->uncore, +				 HECI_H_GS1(MTL_GSC_HECI2_BASE), +				 0, HECI_H_GS1_ER_PREP); + +		/* make sure the reset bit is clear when writing the CSR reg */ +		intel_uncore_rmw(gt->uncore, +				 HECI_H_CSR(MTL_GSC_HECI2_BASE), +				 HECI_H_CSR_RST, HECI_H_CSR_IG); +		msleep(200); +	} + +	return engine_mask; +} + +static void +wa_14015076503_end(struct intel_gt *gt, intel_engine_mask_t engine_mask) +{ +	if (!needs_wa_14015076503(gt, engine_mask)) +		return; + +	intel_uncore_rmw(gt->uncore, +			 HECI_H_GS1(MTL_GSC_HECI2_BASE), +			 HECI_H_GS1_ER_PREP, 0); +} +  int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask)  {  	const int retries = engine_mask == ALL_ENGINES ? RESET_MAX_RETRIES : 1; @@ -707,10 +782,16 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask)  	 */  	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL);  	for (retry = 0; ret == -ETIMEDOUT && retry < retries; retry++) { -		GT_TRACE(gt, "engine_mask=%x\n", engine_mask); +		intel_engine_mask_t reset_mask; + +		reset_mask = wa_14015076503_start(gt, engine_mask, !retry); + +		GT_TRACE(gt, "engine_mask=%x\n", reset_mask);  		preempt_disable(); -		ret = reset(gt, engine_mask, retry); +		ret = reset(gt, reset_mask, retry);  		preempt_enable(); + +		wa_14015076503_end(gt, reset_mask);  	}  	intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); @@ -735,14 +816,12 @@ bool intel_has_reset_engine(const struct intel_gt *gt)  int intel_reset_guc(struct intel_gt *gt)  { -	u32 guc_domain = -		GRAPHICS_VER(gt->i915) >= 11 ? GEN11_GRDOM_GUC : GEN9_GRDOM_GUC;  	int ret;  	GEM_BUG_ON(!HAS_GT_UC(gt->i915));  	intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); -	ret = gen6_hw_domain_reset(gt, guc_domain); +	ret = __reset_guc(gt);  	intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL);  	return ret;  |