Commit 5b26d57f authored by Aditya Swarup's avatar Aditya Swarup Committed by Matt Roper

drm/i915: Add Wa_14010733141

The WA requires the following procedure for VDBox SFC reset:

If (MFX-SFC usage is 1) {
	1.Issue a MFX-SFC forced lock
	2.Wait for MFX-SFC forced lock ack
	3.Check the MFX-SFC usage bit
	If (MFX-SFC usage bit is 1)
		Reset VDBOX and SFC
	else
		Reset VDBOX
	Release the force lock MFX-SFC
}
else if(HCP+SFC usage is 1) {
	1.Issue a VE-SFC forced lock
	2.Wait for SFC forced lock ack
	3.Check the VE-SFC usage bit
	If (VE-SFC usage bit is 1)
		Reset VDBOX
	else
		Reset VDBOX and SFC
	Release the force lock VE-SFC.
}
else
	Reset VDBOX

- Restructure: the changes to the original code flow should stay
  relatively minimal; we only need to do an extra HCP check after the
  usual VD-MFX check and, if true, switch the register/bit we're
  performing the lock on.(MattR)

v2:
- Assign unlock mask using paired_engine->mask instead of using
  BIT(paired_vecs->id). (Daniele)

Bspec: 52890, 53509

Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Matt Roper <matthew.d.roper@intel.com>
Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: default avatarAditya Swarup <aditya.swarup@intel.com>
Co-developed-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Signed-off-by: default avatarMatt Roper <matthew.d.roper@intel.com>
Reviewed-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210526094852.286424-2-aditya.swarup@intel.com
parent 61516033
...@@ -338,15 +338,69 @@ static int gen6_reset_engines(struct intel_gt *gt, ...@@ -338,15 +338,69 @@ static int gen6_reset_engines(struct intel_gt *gt,
return gen6_hw_domain_reset(gt, hw_mask); return gen6_hw_domain_reset(gt, hw_mask);
} }
static int gen11_lock_sfc(struct intel_engine_cs *engine, u32 *hw_mask) static struct intel_engine_cs *find_sfc_paired_vecs_engine(struct intel_engine_cs *engine)
{
int vecs_id;
GEM_BUG_ON(engine->class != VIDEO_DECODE_CLASS);
vecs_id = _VECS((engine->instance) / 2);
return engine->gt->engine[vecs_id];
}
struct sfc_lock_data {
i915_reg_t lock_reg;
i915_reg_t ack_reg;
i915_reg_t usage_reg;
u32 lock_bit;
u32 ack_bit;
u32 usage_bit;
u32 reset_bit;
};
static void get_sfc_forced_lock_data(struct intel_engine_cs *engine,
struct sfc_lock_data *sfc_lock)
{
switch (engine->class) {
default:
MISSING_CASE(engine->class);
fallthrough;
case VIDEO_DECODE_CLASS:
sfc_lock->lock_reg = GEN11_VCS_SFC_FORCED_LOCK(engine);
sfc_lock->lock_bit = GEN11_VCS_SFC_FORCED_LOCK_BIT;
sfc_lock->ack_reg = GEN11_VCS_SFC_LOCK_STATUS(engine);
sfc_lock->ack_bit = GEN11_VCS_SFC_LOCK_ACK_BIT;
sfc_lock->usage_reg = GEN11_VCS_SFC_LOCK_STATUS(engine);
sfc_lock->usage_bit = GEN11_VCS_SFC_USAGE_BIT;
sfc_lock->reset_bit = GEN11_VCS_SFC_RESET_BIT(engine->instance);
break;
case VIDEO_ENHANCEMENT_CLASS:
sfc_lock->lock_reg = GEN11_VECS_SFC_FORCED_LOCK(engine);
sfc_lock->lock_bit = GEN11_VECS_SFC_FORCED_LOCK_BIT;
sfc_lock->ack_reg = GEN11_VECS_SFC_LOCK_ACK(engine);
sfc_lock->ack_bit = GEN11_VECS_SFC_LOCK_ACK_BIT;
sfc_lock->usage_reg = GEN11_VECS_SFC_USAGE(engine);
sfc_lock->usage_bit = GEN11_VECS_SFC_USAGE_BIT;
sfc_lock->reset_bit = GEN11_VECS_SFC_RESET_BIT(engine->instance);
break;
}
}
static int gen11_lock_sfc(struct intel_engine_cs *engine,
u32 *reset_mask,
u32 *unlock_mask)
{ {
struct intel_uncore *uncore = engine->uncore; struct intel_uncore *uncore = engine->uncore;
u8 vdbox_sfc_access = engine->gt->info.vdbox_sfc_access; u8 vdbox_sfc_access = engine->gt->info.vdbox_sfc_access;
i915_reg_t sfc_forced_lock, sfc_forced_lock_ack; struct sfc_lock_data sfc_lock;
u32 sfc_forced_lock_bit, sfc_forced_lock_ack_bit; bool lock_obtained, lock_to_other = false;
i915_reg_t sfc_usage;
u32 sfc_usage_bit;
u32 sfc_reset_bit;
int ret; int ret;
switch (engine->class) { switch (engine->class) {
...@@ -354,53 +408,72 @@ static int gen11_lock_sfc(struct intel_engine_cs *engine, u32 *hw_mask) ...@@ -354,53 +408,72 @@ static int gen11_lock_sfc(struct intel_engine_cs *engine, u32 *hw_mask)
if ((BIT(engine->instance) & vdbox_sfc_access) == 0) if ((BIT(engine->instance) & vdbox_sfc_access) == 0)
return 0; return 0;
sfc_forced_lock = GEN11_VCS_SFC_FORCED_LOCK(engine); fallthrough;
sfc_forced_lock_bit = GEN11_VCS_SFC_FORCED_LOCK_BIT; case VIDEO_ENHANCEMENT_CLASS:
get_sfc_forced_lock_data(engine, &sfc_lock);
sfc_forced_lock_ack = GEN11_VCS_SFC_LOCK_STATUS(engine);
sfc_forced_lock_ack_bit = GEN11_VCS_SFC_LOCK_ACK_BIT;
sfc_usage = GEN11_VCS_SFC_LOCK_STATUS(engine);
sfc_usage_bit = GEN11_VCS_SFC_USAGE_BIT;
sfc_reset_bit = GEN11_VCS_SFC_RESET_BIT(engine->instance);
break; break;
default:
return 0;
}
case VIDEO_ENHANCEMENT_CLASS: if (!(intel_uncore_read_fw(uncore, sfc_lock.usage_reg) & sfc_lock.usage_bit)) {
sfc_forced_lock = GEN11_VECS_SFC_FORCED_LOCK(engine); struct intel_engine_cs *paired_vecs;
sfc_forced_lock_bit = GEN11_VECS_SFC_FORCED_LOCK_BIT;
sfc_forced_lock_ack = GEN11_VECS_SFC_LOCK_ACK(engine); if (engine->class != VIDEO_DECODE_CLASS ||
sfc_forced_lock_ack_bit = GEN11_VECS_SFC_LOCK_ACK_BIT; !IS_GEN(engine->i915, 12))
return 0;
sfc_usage = GEN11_VECS_SFC_USAGE(engine); /*
sfc_usage_bit = GEN11_VECS_SFC_USAGE_BIT; * Wa_14010733141
sfc_reset_bit = GEN11_VECS_SFC_RESET_BIT(engine->instance); *
break; * If the VCS-MFX isn't using the SFC, we also need to check
* whether VCS-HCP is using it. If so, we need to issue a *VE*
* forced lock on the VE engine that shares the same SFC.
*/
if (!(intel_uncore_read_fw(uncore,
GEN12_HCP_SFC_LOCK_STATUS(engine)) &
GEN12_HCP_SFC_USAGE_BIT))
return 0;
default: paired_vecs = find_sfc_paired_vecs_engine(engine);
return 0; get_sfc_forced_lock_data(paired_vecs, &sfc_lock);
lock_to_other = true;
*unlock_mask |= paired_vecs->mask;
} else {
*unlock_mask |= engine->mask;
} }
/* /*
* If the engine is using a SFC, tell the engine that a software reset * If the engine is using an SFC, tell the engine that a software reset
* is going to happen. The engine will then try to force lock the SFC. * is going to happen. The engine will then try to force lock the SFC.
* If SFC ends up being locked to the engine we want to reset, we have * If SFC ends up being locked to the engine we want to reset, we have
* to reset it as well (we will unlock it once the reset sequence is * to reset it as well (we will unlock it once the reset sequence is
* completed). * completed).
*/ */
if (!(intel_uncore_read_fw(uncore, sfc_usage) & sfc_usage_bit)) rmw_set_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
return 0;
rmw_set_fw(uncore, sfc_forced_lock, sfc_forced_lock_bit);
ret = __intel_wait_for_register_fw(uncore, ret = __intel_wait_for_register_fw(uncore,
sfc_forced_lock_ack, sfc_lock.ack_reg,
sfc_forced_lock_ack_bit, sfc_lock.ack_bit,
sfc_forced_lock_ack_bit, sfc_lock.ack_bit,
1000, 0, NULL); 1000, 0, NULL);
/* Was the SFC released while we were trying to lock it? */ /*
if (!(intel_uncore_read_fw(uncore, sfc_usage) & sfc_usage_bit)) * Was the SFC released while we were trying to lock it?
*
* We should reset both the engine and the SFC if:
* - We were locking the SFC to this engine and the lock succeeded
* OR
* - We were locking the SFC to a different engine (Wa_14010733141)
* but the SFC was released before the lock was obtained.
*
* Otherwise we need only reset the engine by itself and we can
* leave the SFC alone.
*/
lock_obtained = (intel_uncore_read_fw(uncore, sfc_lock.usage_reg) &
sfc_lock.usage_bit) != 0;
if (lock_obtained == lock_to_other)
return 0; return 0;
if (ret) { if (ret) {
...@@ -408,7 +481,7 @@ static int gen11_lock_sfc(struct intel_engine_cs *engine, u32 *hw_mask) ...@@ -408,7 +481,7 @@ static int gen11_lock_sfc(struct intel_engine_cs *engine, u32 *hw_mask)
return ret; return ret;
} }
*hw_mask |= sfc_reset_bit; *reset_mask |= sfc_lock.reset_bit;
return 0; return 0;
} }
...@@ -416,28 +489,19 @@ static void gen11_unlock_sfc(struct intel_engine_cs *engine) ...@@ -416,28 +489,19 @@ static void gen11_unlock_sfc(struct intel_engine_cs *engine)
{ {
struct intel_uncore *uncore = engine->uncore; struct intel_uncore *uncore = engine->uncore;
u8 vdbox_sfc_access = engine->gt->info.vdbox_sfc_access; u8 vdbox_sfc_access = engine->gt->info.vdbox_sfc_access;
i915_reg_t sfc_forced_lock; struct sfc_lock_data sfc_lock = {};
u32 sfc_forced_lock_bit;
switch (engine->class) {
case VIDEO_DECODE_CLASS:
if ((BIT(engine->instance) & vdbox_sfc_access) == 0)
return;
sfc_forced_lock = GEN11_VCS_SFC_FORCED_LOCK(engine);
sfc_forced_lock_bit = GEN11_VCS_SFC_FORCED_LOCK_BIT;
break;
case VIDEO_ENHANCEMENT_CLASS: if (engine->class != VIDEO_DECODE_CLASS &&
sfc_forced_lock = GEN11_VECS_SFC_FORCED_LOCK(engine); engine->class != VIDEO_ENHANCEMENT_CLASS)
sfc_forced_lock_bit = GEN11_VECS_SFC_FORCED_LOCK_BIT; return;
break;
default: if (engine->class == VIDEO_DECODE_CLASS &&
(BIT(engine->instance) & vdbox_sfc_access) == 0)
return; return;
}
rmw_clear_fw(uncore, sfc_forced_lock, sfc_forced_lock_bit); get_sfc_forced_lock_data(engine, &sfc_lock);
rmw_clear_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
} }
static int gen11_reset_engines(struct intel_gt *gt, static int gen11_reset_engines(struct intel_gt *gt,
...@@ -456,23 +520,23 @@ static int gen11_reset_engines(struct intel_gt *gt, ...@@ -456,23 +520,23 @@ static int gen11_reset_engines(struct intel_gt *gt,
}; };
struct intel_engine_cs *engine; struct intel_engine_cs *engine;
intel_engine_mask_t tmp; intel_engine_mask_t tmp;
u32 hw_mask; u32 reset_mask, unlock_mask = 0;
int ret; int ret;
if (engine_mask == ALL_ENGINES) { if (engine_mask == ALL_ENGINES) {
hw_mask = GEN11_GRDOM_FULL; reset_mask = GEN11_GRDOM_FULL;
} else { } else {
hw_mask = 0; reset_mask = 0;
for_each_engine_masked(engine, gt, engine_mask, tmp) { for_each_engine_masked(engine, gt, engine_mask, tmp) {
GEM_BUG_ON(engine->id >= ARRAY_SIZE(hw_engine_mask)); GEM_BUG_ON(engine->id >= ARRAY_SIZE(hw_engine_mask));
hw_mask |= hw_engine_mask[engine->id]; reset_mask |= hw_engine_mask[engine->id];
ret = gen11_lock_sfc(engine, &hw_mask); ret = gen11_lock_sfc(engine, &reset_mask, &unlock_mask);
if (ret) if (ret)
goto sfc_unlock; goto sfc_unlock;
} }
} }
ret = gen6_hw_domain_reset(gt, hw_mask); ret = gen6_hw_domain_reset(gt, reset_mask);
sfc_unlock: sfc_unlock:
/* /*
...@@ -480,10 +544,14 @@ static int gen11_reset_engines(struct intel_gt *gt, ...@@ -480,10 +544,14 @@ static int gen11_reset_engines(struct intel_gt *gt,
* gen11_lock_sfc to make sure that we clean properly if something * gen11_lock_sfc to make sure that we clean properly if something
* wrong happened during the lock (e.g. lock acquired after timeout * wrong happened during the lock (e.g. lock acquired after timeout
* expiration). * expiration).
*
* Due to Wa_14010733141, we may have locked an SFC to an engine that
* wasn't being reset. So instead of calling gen11_unlock_sfc()
* on engine_mask, we instead call it on the mask of engines that our
* gen11_lock_sfc() calls told us actually had locks attempted.
*/ */
if (engine_mask != ALL_ENGINES) for_each_engine_masked(engine, gt, unlock_mask, tmp)
for_each_engine_masked(engine, gt, engine_mask, tmp) gen11_unlock_sfc(engine);
gen11_unlock_sfc(engine);
return ret; return ret;
} }
......
...@@ -416,6 +416,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) ...@@ -416,6 +416,12 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define GEN11_VECS_SFC_USAGE(engine) _MMIO((engine)->mmio_base + 0x2014) #define GEN11_VECS_SFC_USAGE(engine) _MMIO((engine)->mmio_base + 0x2014)
#define GEN11_VECS_SFC_USAGE_BIT (1 << 0) #define GEN11_VECS_SFC_USAGE_BIT (1 << 0)
#define GEN12_HCP_SFC_FORCED_LOCK(engine) _MMIO((engine)->mmio_base + 0x2910)
#define GEN12_HCP_SFC_FORCED_LOCK_BIT REG_BIT(0)
#define GEN12_HCP_SFC_LOCK_STATUS(engine) _MMIO((engine)->mmio_base + 0x2914)
#define GEN12_HCP_SFC_LOCK_ACK_BIT REG_BIT(1)
#define GEN12_HCP_SFC_USAGE_BIT REG_BIT(0)
#define GEN12_SFC_DONE(n) _MMIO(0x1cc00 + (n) * 0x100) #define GEN12_SFC_DONE(n) _MMIO(0x1cc00 + (n) * 0x100)
#define GEN12_SFC_DONE_MAX 4 #define GEN12_SFC_DONE_MAX 4
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment