Reads of multicast registers give the value for slice/subslice 0 by default unless we manually steer them to a specific slice/subslice. If slice/subslice 0 are fused off in hardware, we'll always read back a value of 0 rather than the value we wrote into the multicast register. Although wa_init_mcr() sets up some initial steering to a valid slice/subslice at startup, we appear to later lose that steering setting in some cases. Let's handle this more explicitly and have wa_verify use intel_read_subslice_reg() to directly steer the readback of workaround registers in an MCR range to a valid slice/subslice.
Signed-off-by: Matt Roper <matthew.d.ro...@intel.com> --- drivers/gpu/drm/i915/gt/intel_engine.h | 3 + drivers/gpu/drm/i915/gt/intel_engine_cs.c | 17 ++-- drivers/gpu/drm/i915/gt/intel_workarounds.c | 98 ++++++++++++------- .../gpu/drm/i915/gt/intel_workarounds_types.h | 2 + 4 files changed, 73 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index d10e52ff059f..54d1fa233a8a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -214,6 +214,9 @@ int intel_ring_submission_setup(struct intel_engine_cs *engine); int intel_engine_stop_cs(struct intel_engine_cs *engine); void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine); +u32 intel_read_subslice_reg(struct intel_uncore *uncore, + int slice, int subslice, i915_reg_t reg); + void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask); u64 intel_engine_get_active_head(const struct intel_engine_cs *engine); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index c9e46c5ced43..3ee17aa9928e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -951,12 +951,11 @@ const char *i915_cache_level_str(struct drm_i915_private *i915, int type) } } -static u32 -read_subslice_reg(const struct intel_engine_cs *engine, - int slice, int subslice, i915_reg_t reg) +u32 +intel_read_subslice_reg(struct intel_uncore *uncore, + int slice, int subslice, i915_reg_t reg) { - struct drm_i915_private *i915 = engine->i915; - struct intel_uncore *uncore = engine->uncore; + struct drm_i915_private *i915 = uncore->i915; u32 mcr_mask, mcr_ss, mcr, old_mcr, val; enum forcewake_domains fw_domains; @@ -1027,11 +1026,11 @@ void intel_engine_get_instdone(const struct intel_engine_cs *engine, } for_each_instdone_slice_subslice(i915, sseu, slice, subslice) { instdone->sampler[slice][subslice] = - read_subslice_reg(engine, slice, subslice, - GEN7_SAMPLER_INSTDONE); + intel_read_subslice_reg(uncore, slice, subslice, + GEN7_SAMPLER_INSTDONE); instdone->row[slice][subslice] = - read_subslice_reg(engine, slice, subslice, - GEN7_ROW_INSTDONE); + intel_read_subslice_reg(uncore, slice, subslice, + GEN7_ROW_INSTDONE); } break; case 7: diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 4a255de13394..73a3937c689b 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -56,6 +56,7 @@ static void wa_init_start(struct i915_wa_list *wal, const char *name, const char { wal->name = name; wal->engine_name = engine_name; + wal->mcrslice = wal->mcrss = 0; } #define WA_LIST_CHUNK (1 << 4) @@ -863,6 +864,8 @@ wa_init_mcr(struct drm_i915_private *i915, struct i915_wa_list *wal) } drm_dbg(&i915->drm, "MCR slice/subslice = %x\n", mcr); + wal->mcrslice = slice; + wal->mcrss = subslice; wa_write_masked_or(wal, GEN8_MCR_SELECTOR, mcr_mask, mcr); } @@ -1006,7 +1009,8 @@ wal_get_fw_for_rmw(struct intel_uncore *uncore, const struct i915_wa_list *wal) } static bool -wa_verify(const struct i915_wa *wa, u32 cur, const char *name, const char *from) +wa_verify(struct drm_i915_private *i915, const struct i915_wa *wa, u32 cur, + const char *name, const char *from) { if ((cur ^ wa->set) & wa->read) { DRM_ERROR("%s workaround lost on %s! (%x=%x/%x, expected %x)\n", @@ -1019,6 +1023,38 @@ wa_verify(const struct i915_wa *wa, u32 cur, const char *name, const char *from) return true; } +static const struct { + u32 start; + u32 end; +} mcr_ranges_gen8[] = { + { .start = 0x5500, .end = 0x55ff }, + { .start = 0x7000, .end = 0x7fff }, + { .start = 0x9400, .end = 0x97ff }, + { .start = 0xb000, .end = 0xb3ff }, + { .start = 0xe000, .end = 0xe7ff }, + {}, +}; + +static bool mcr_range(struct drm_i915_private *i915, u32 offset) +{ + int i; + + if (INTEL_GEN(i915) < 8) + return false; + + /* + * Registers in these ranges are affected by the MCR selector + * which only controls CPU initiated MMIO. Routing does not + * work for CS access so we cannot verify them on this path. + */ + for (i = 0; mcr_ranges_gen8[i].start; i++) + if (offset >= mcr_ranges_gen8[i].start && + offset <= mcr_ranges_gen8[i].end) + return true; + + return false; +} + static void wa_list_apply(struct intel_uncore *uncore, const struct i915_wa_list *wal) { @@ -1040,10 +1076,28 @@ wa_list_apply(struct intel_uncore *uncore, const struct i915_wa_list *wal) intel_uncore_rmw_fw(uncore, wa->reg, wa->clr, wa->set); else intel_uncore_write_fw(uncore, wa->reg, wa->set); - if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) - wa_verify(wa, - intel_uncore_read_fw(uncore, wa->reg), + if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { + u32 readout; + + /* + * Reads of multicast registers default to slice 0, + * subslice 0 unless we steer them to a specific + * slice/subslice instance. If the first slice/subslice + * is fused off, regular reads will come back as 0's + * rather than the value we applied. + */ + if (mcr_range(uncore->i915, + i915_mmio_reg_offset(wa->reg))) + readout = intel_read_subslice_reg(uncore, + wal->mcrslice, + wal->mcrss, + wa->reg); + else + readout = intel_uncore_read_fw(uncore, wa->reg); + + wa_verify(uncore->i915, wa, readout, wal->name, "application"); + } } intel_uncore_forcewake_put__locked(uncore, fw); @@ -1064,7 +1118,7 @@ static bool wa_list_verify(struct intel_uncore *uncore, bool ok = true; for (i = 0, wa = wal->list; i < wal->count; i++, wa++) - ok &= wa_verify(wa, + ok &= wa_verify(uncore->i915, wa, intel_uncore_read(uncore, wa->reg), wal->name, from); @@ -1665,38 +1719,6 @@ create_scratch(struct i915_address_space *vm, int count) return ERR_PTR(err); } -static const struct { - u32 start; - u32 end; -} mcr_ranges_gen8[] = { - { .start = 0x5500, .end = 0x55ff }, - { .start = 0x7000, .end = 0x7fff }, - { .start = 0x9400, .end = 0x97ff }, - { .start = 0xb000, .end = 0xb3ff }, - { .start = 0xe000, .end = 0xe7ff }, - {}, -}; - -static bool mcr_range(struct drm_i915_private *i915, u32 offset) -{ - int i; - - if (INTEL_GEN(i915) < 8) - return false; - - /* - * Registers in these ranges are affected by the MCR selector - * which only controls CPU initiated MMIO. Routing does not - * work for CS access so we cannot verify them on this path. - */ - for (i = 0; mcr_ranges_gen8[i].start; i++) - if (offset >= mcr_ranges_gen8[i].start && - offset <= mcr_ranges_gen8[i].end) - return true; - - return false; -} - static int wa_list_srm(struct i915_request *rq, const struct i915_wa_list *wal, @@ -1794,7 +1816,7 @@ static int engine_wa_list_verify(struct intel_context *ce, if (mcr_range(rq->i915, i915_mmio_reg_offset(wa->reg))) continue; - if (!wa_verify(wa, results[i], wal->name, from)) + if (!wa_verify(rq->i915, wa, results[i], wal->name, from)) err = -ENXIO; } diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h index d166a7145720..a881ea470aa4 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds_types.h +++ b/drivers/gpu/drm/i915/gt/intel_workarounds_types.h @@ -24,6 +24,8 @@ struct i915_wa_list { struct i915_wa *list; unsigned int count; unsigned int wa_count; + u32 mcrslice; + u32 mcrss; }; #endif /* __INTEL_WORKAROUNDS_TYPES_H__ */ -- 2.24.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx