Commit 69bcdecf authored by Tvrtko Ursulin's avatar Tvrtko Ursulin

drm/i915: Move register white-listing to the common workaround framework

Instead of having a separate list of white-listed registers we can
trivially move this to the common workarounds framework.

This brings us one step closer to the goal of driving all workaround
classes using the same code.

v2:
 * Use GEM_DEBUG_WARN_ON for the sanity check. (Chris Wilson)

v3:
 * API rename. (Chris Wilson)
Signed-off-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20181203125014.3219-6-tvrtko.ursulin@linux.intel.com
parent 28d6ccce
...@@ -725,6 +725,7 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine) ...@@ -725,6 +725,7 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
i915_timeline_fini(&engine->timeline); i915_timeline_fini(&engine->timeline);
intel_wa_list_free(&engine->wa_list); intel_wa_list_free(&engine->wa_list);
intel_wa_list_free(&engine->whitelist);
} }
u64 intel_engine_get_active_head(const struct intel_engine_cs *engine) u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
......
...@@ -1652,7 +1652,7 @@ static int gen8_init_render_ring(struct intel_engine_cs *engine) ...@@ -1652,7 +1652,7 @@ static int gen8_init_render_ring(struct intel_engine_cs *engine)
if (ret) if (ret)
return ret; return ret;
intel_whitelist_workarounds_apply(engine); intel_engine_apply_whitelist(engine);
/* We need to disable the AsyncFlip performance optimisations in order /* We need to disable the AsyncFlip performance optimisations in order
* to use MI_WAIT_FOR_EVENT within the CS. It should already be * to use MI_WAIT_FOR_EVENT within the CS. It should already be
...@@ -1675,7 +1675,7 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine) ...@@ -1675,7 +1675,7 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine)
if (ret) if (ret)
return ret; return ret;
intel_whitelist_workarounds_apply(engine); intel_engine_apply_whitelist(engine);
return 0; return 0;
} }
...@@ -2307,6 +2307,7 @@ int logical_render_ring_init(struct intel_engine_cs *engine) ...@@ -2307,6 +2307,7 @@ int logical_render_ring_init(struct intel_engine_cs *engine)
ret); ret);
} }
intel_engine_init_whitelist(engine);
intel_engine_init_workarounds(engine); intel_engine_init_workarounds(engine);
return 0; return 0;
......
...@@ -437,6 +437,7 @@ struct intel_engine_cs { ...@@ -437,6 +437,7 @@ struct intel_engine_cs {
struct intel_hw_status_page status_page; struct intel_hw_status_page status_page;
struct i915_ctx_workarounds wa_ctx; struct i915_ctx_workarounds wa_ctx;
struct i915_wa_list wa_list; struct i915_wa_list wa_list;
struct i915_wa_list whitelist;
struct i915_vma *scratch; struct i915_vma *scratch;
u32 irq_keep_mask; /* always keep these interrupts */ u32 irq_keep_mask; /* always keep these interrupts */
......
...@@ -1011,29 +1011,20 @@ bool intel_gt_verify_workarounds(struct drm_i915_private *dev_priv, ...@@ -1011,29 +1011,20 @@ bool intel_gt_verify_workarounds(struct drm_i915_private *dev_priv,
return wa_list_verify(dev_priv, &dev_priv->gt_wa_list, from); return wa_list_verify(dev_priv, &dev_priv->gt_wa_list, from);
} }
struct whitelist { static void
i915_reg_t reg[RING_MAX_NONPRIV_SLOTS]; whitelist_reg(struct i915_wa_list *wal, i915_reg_t reg)
unsigned int count;
u32 nopid;
};
static void whitelist_reg(struct whitelist *w, i915_reg_t reg)
{ {
if (GEM_DEBUG_WARN_ON(w->count >= RING_MAX_NONPRIV_SLOTS)) struct i915_wa wa = {
return; .reg = reg
};
w->reg[w->count++] = reg;
}
static void bdw_whitelist_build(struct whitelist *w) if (GEM_DEBUG_WARN_ON(wal->count >= RING_MAX_NONPRIV_SLOTS))
{ return;
}
static void chv_whitelist_build(struct whitelist *w) wal_add(wal, &wa);
{
} }
static void gen9_whitelist_build(struct whitelist *w) static void gen9_whitelist_build(struct i915_wa_list *w)
{ {
/* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */ /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */
whitelist_reg(w, GEN9_CTX_PREEMPT_REG); whitelist_reg(w, GEN9_CTX_PREEMPT_REG);
...@@ -1045,7 +1036,7 @@ static void gen9_whitelist_build(struct whitelist *w) ...@@ -1045,7 +1036,7 @@ static void gen9_whitelist_build(struct whitelist *w)
whitelist_reg(w, GEN8_HDC_CHICKEN1); whitelist_reg(w, GEN8_HDC_CHICKEN1);
} }
static void skl_whitelist_build(struct whitelist *w) static void skl_whitelist_build(struct i915_wa_list *w)
{ {
gen9_whitelist_build(w); gen9_whitelist_build(w);
...@@ -1053,12 +1044,12 @@ static void skl_whitelist_build(struct whitelist *w) ...@@ -1053,12 +1044,12 @@ static void skl_whitelist_build(struct whitelist *w)
whitelist_reg(w, GEN8_L3SQCREG4); whitelist_reg(w, GEN8_L3SQCREG4);
} }
static void bxt_whitelist_build(struct whitelist *w) static void bxt_whitelist_build(struct i915_wa_list *w)
{ {
gen9_whitelist_build(w); gen9_whitelist_build(w);
} }
static void kbl_whitelist_build(struct whitelist *w) static void kbl_whitelist_build(struct i915_wa_list *w)
{ {
gen9_whitelist_build(w); gen9_whitelist_build(w);
...@@ -1066,7 +1057,7 @@ static void kbl_whitelist_build(struct whitelist *w) ...@@ -1066,7 +1057,7 @@ static void kbl_whitelist_build(struct whitelist *w)
whitelist_reg(w, GEN8_L3SQCREG4); whitelist_reg(w, GEN8_L3SQCREG4);
} }
static void glk_whitelist_build(struct whitelist *w) static void glk_whitelist_build(struct i915_wa_list *w)
{ {
gen9_whitelist_build(w); gen9_whitelist_build(w);
...@@ -1074,18 +1065,18 @@ static void glk_whitelist_build(struct whitelist *w) ...@@ -1074,18 +1065,18 @@ static void glk_whitelist_build(struct whitelist *w)
whitelist_reg(w, GEN9_SLICE_COMMON_ECO_CHICKEN1); whitelist_reg(w, GEN9_SLICE_COMMON_ECO_CHICKEN1);
} }
static void cfl_whitelist_build(struct whitelist *w) static void cfl_whitelist_build(struct i915_wa_list *w)
{ {
gen9_whitelist_build(w); gen9_whitelist_build(w);
} }
static void cnl_whitelist_build(struct whitelist *w) static void cnl_whitelist_build(struct i915_wa_list *w)
{ {
/* WaEnablePreemptionGranularityControlByUMD:cnl */ /* WaEnablePreemptionGranularityControlByUMD:cnl */
whitelist_reg(w, GEN8_CS_CHICKEN1); whitelist_reg(w, GEN8_CS_CHICKEN1);
} }
static void icl_whitelist_build(struct whitelist *w) static void icl_whitelist_build(struct i915_wa_list *w)
{ {
/* WaAllowUMDToModifyHalfSliceChicken7:icl */ /* WaAllowUMDToModifyHalfSliceChicken7:icl */
whitelist_reg(w, GEN9_HALF_SLICE_CHICKEN7); whitelist_reg(w, GEN9_HALF_SLICE_CHICKEN7);
...@@ -1094,22 +1085,21 @@ static void icl_whitelist_build(struct whitelist *w) ...@@ -1094,22 +1085,21 @@ static void icl_whitelist_build(struct whitelist *w)
whitelist_reg(w, GEN10_SAMPLER_MODE); whitelist_reg(w, GEN10_SAMPLER_MODE);
} }
static struct whitelist *whitelist_build(struct intel_engine_cs *engine, void intel_engine_init_whitelist(struct intel_engine_cs *engine)
struct whitelist *w)
{ {
struct drm_i915_private *i915 = engine->i915; struct drm_i915_private *i915 = engine->i915;
struct i915_wa_list *w = &engine->whitelist;
GEM_BUG_ON(engine->id != RCS); GEM_BUG_ON(engine->id != RCS);
w->count = 0; wa_init_start(w, "whitelist");
w->nopid = i915_mmio_reg_offset(RING_NOPID(engine->mmio_base));
if (INTEL_GEN(i915) < 8) if (INTEL_GEN(i915) < 8)
return NULL; return;
else if (IS_BROADWELL(i915)) else if (IS_BROADWELL(i915))
bdw_whitelist_build(w); return;
else if (IS_CHERRYVIEW(i915)) else if (IS_CHERRYVIEW(i915))
chv_whitelist_build(w); return;
else if (IS_SKYLAKE(i915)) else if (IS_SKYLAKE(i915))
skl_whitelist_build(w); skl_whitelist_build(w);
else if (IS_BROXTON(i915)) else if (IS_BROXTON(i915))
...@@ -1127,37 +1117,30 @@ static struct whitelist *whitelist_build(struct intel_engine_cs *engine, ...@@ -1127,37 +1117,30 @@ static struct whitelist *whitelist_build(struct intel_engine_cs *engine,
else else
MISSING_CASE(INTEL_GEN(i915)); MISSING_CASE(INTEL_GEN(i915));
return w; wa_init_finish(w);
} }
static void whitelist_apply(struct intel_engine_cs *engine, void intel_engine_apply_whitelist(struct intel_engine_cs *engine)
const struct whitelist *w)
{ {
struct drm_i915_private *dev_priv = engine->i915; struct drm_i915_private *dev_priv = engine->i915;
const struct i915_wa_list *wal = &engine->whitelist;
const u32 base = engine->mmio_base; const u32 base = engine->mmio_base;
struct i915_wa *wa;
unsigned int i; unsigned int i;
if (!w) if (!wal->count)
return; return;
intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL); for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
I915_WRITE(RING_FORCE_TO_NONPRIV(base, i),
for (i = 0; i < w->count; i++) i915_mmio_reg_offset(wa->reg));
I915_WRITE_FW(RING_FORCE_TO_NONPRIV(base, i),
i915_mmio_reg_offset(w->reg[i]));
/* And clear the rest just in case of garbage */ /* And clear the rest just in case of garbage */
for (; i < RING_MAX_NONPRIV_SLOTS; i++) for (; i < RING_MAX_NONPRIV_SLOTS; i++)
I915_WRITE_FW(RING_FORCE_TO_NONPRIV(base, i), w->nopid); I915_WRITE(RING_FORCE_TO_NONPRIV(base, i),
i915_mmio_reg_offset(RING_NOPID(base)));
intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL);
}
void intel_whitelist_workarounds_apply(struct intel_engine_cs *engine) DRM_DEBUG_DRIVER("Applied %u %s workarounds\n", wal->count, wal->name);
{
struct whitelist w;
whitelist_apply(engine, whitelist_build(engine, &w));
} }
static void rcs_engine_wa_init(struct intel_engine_cs *engine) static void rcs_engine_wa_init(struct intel_engine_cs *engine)
......
...@@ -35,7 +35,8 @@ void intel_gt_apply_workarounds(struct drm_i915_private *dev_priv); ...@@ -35,7 +35,8 @@ void intel_gt_apply_workarounds(struct drm_i915_private *dev_priv);
bool intel_gt_verify_workarounds(struct drm_i915_private *dev_priv, bool intel_gt_verify_workarounds(struct drm_i915_private *dev_priv,
const char *from); const char *from);
void intel_whitelist_workarounds_apply(struct intel_engine_cs *engine); void intel_engine_init_whitelist(struct intel_engine_cs *engine);
void intel_engine_apply_whitelist(struct intel_engine_cs *engine);
void intel_engine_init_workarounds(struct intel_engine_cs *engine); void intel_engine_init_workarounds(struct intel_engine_cs *engine);
void intel_engine_apply_workarounds(struct intel_engine_cs *engine); void intel_engine_apply_workarounds(struct intel_engine_cs *engine);
......
...@@ -94,17 +94,23 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) ...@@ -94,17 +94,23 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine)
return ERR_PTR(err); return ERR_PTR(err);
} }
static u32 get_whitelist_reg(const struct whitelist *w, unsigned int i) static u32
get_whitelist_reg(const struct intel_engine_cs *engine, unsigned int i)
{ {
return i < w->count ? i915_mmio_reg_offset(w->reg[i]) : w->nopid; i915_reg_t reg = i < engine->whitelist.count ?
engine->whitelist.list[i].reg :
RING_NOPID(engine->mmio_base);
return i915_mmio_reg_offset(reg);
} }
static void print_results(const struct whitelist *w, const u32 *results) static void
print_results(const struct intel_engine_cs *engine, const u32 *results)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
u32 expected = get_whitelist_reg(w, i); u32 expected = get_whitelist_reg(engine, i);
u32 actual = results[i]; u32 actual = results[i];
pr_info("RING_NONPRIV[%d]: expected 0x%08x, found 0x%08x\n", pr_info("RING_NONPRIV[%d]: expected 0x%08x, found 0x%08x\n",
...@@ -112,8 +118,7 @@ static void print_results(const struct whitelist *w, const u32 *results) ...@@ -112,8 +118,7 @@ static void print_results(const struct whitelist *w, const u32 *results)
} }
} }
static int check_whitelist(const struct whitelist *w, static int check_whitelist(struct i915_gem_context *ctx,
struct i915_gem_context *ctx,
struct intel_engine_cs *engine) struct intel_engine_cs *engine)
{ {
struct drm_i915_gem_object *results; struct drm_i915_gem_object *results;
...@@ -141,11 +146,11 @@ static int check_whitelist(const struct whitelist *w, ...@@ -141,11 +146,11 @@ static int check_whitelist(const struct whitelist *w,
} }
for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) { for (i = 0; i < RING_MAX_NONPRIV_SLOTS; i++) {
u32 expected = get_whitelist_reg(w, i); u32 expected = get_whitelist_reg(engine, i);
u32 actual = vaddr[i]; u32 actual = vaddr[i];
if (expected != actual) { if (expected != actual) {
print_results(w, vaddr); print_results(engine, vaddr);
pr_err("Invalid RING_NONPRIV[%d], expected 0x%08x, found 0x%08x\n", pr_err("Invalid RING_NONPRIV[%d], expected 0x%08x, found 0x%08x\n",
i, expected, actual); i, expected, actual);
...@@ -217,7 +222,6 @@ switch_to_scratch_context(struct intel_engine_cs *engine, ...@@ -217,7 +222,6 @@ switch_to_scratch_context(struct intel_engine_cs *engine,
static int check_whitelist_across_reset(struct intel_engine_cs *engine, static int check_whitelist_across_reset(struct intel_engine_cs *engine,
int (*reset)(struct intel_engine_cs *), int (*reset)(struct intel_engine_cs *),
const struct whitelist *w,
const char *name) const char *name)
{ {
struct drm_i915_private *i915 = engine->i915; struct drm_i915_private *i915 = engine->i915;
...@@ -227,7 +231,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine, ...@@ -227,7 +231,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine,
int err; int err;
pr_info("Checking %d whitelisted registers (RING_NONPRIV) [%s]\n", pr_info("Checking %d whitelisted registers (RING_NONPRIV) [%s]\n",
w->count, name); engine->whitelist.count, name);
if (want_spin) { if (want_spin) {
err = igt_spinner_init(&spin, i915); err = igt_spinner_init(&spin, i915);
...@@ -239,7 +243,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine, ...@@ -239,7 +243,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
err = check_whitelist(w, ctx, engine); err = check_whitelist(ctx, engine);
if (err) { if (err) {
pr_err("Invalid whitelist *before* %s reset!\n", name); pr_err("Invalid whitelist *before* %s reset!\n", name);
goto out; goto out;
...@@ -263,7 +267,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine, ...@@ -263,7 +267,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine,
goto out; goto out;
} }
err = check_whitelist(w, ctx, engine); err = check_whitelist(ctx, engine);
if (err) { if (err) {
pr_err("Whitelist not preserved in context across %s reset!\n", pr_err("Whitelist not preserved in context across %s reset!\n",
name); name);
...@@ -276,7 +280,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine, ...@@ -276,7 +280,7 @@ static int check_whitelist_across_reset(struct intel_engine_cs *engine,
if (IS_ERR(ctx)) if (IS_ERR(ctx))
return PTR_ERR(ctx); return PTR_ERR(ctx);
err = check_whitelist(w, ctx, engine); err = check_whitelist(ctx, engine);
if (err) { if (err) {
pr_err("Invalid whitelist *after* %s reset in fresh context!\n", pr_err("Invalid whitelist *after* %s reset in fresh context!\n",
name); name);
...@@ -292,22 +296,18 @@ static int live_reset_whitelist(void *arg) ...@@ -292,22 +296,18 @@ static int live_reset_whitelist(void *arg)
{ {
struct drm_i915_private *i915 = arg; struct drm_i915_private *i915 = arg;
struct intel_engine_cs *engine = i915->engine[RCS]; struct intel_engine_cs *engine = i915->engine[RCS];
struct whitelist w;
int err = 0; int err = 0;
/* If we reset the gpu, we should not lose the RING_NONPRIV */ /* If we reset the gpu, we should not lose the RING_NONPRIV */
if (!engine) if (!engine || engine->whitelist.count == 0)
return 0;
if (!whitelist_build(engine, &w))
return 0; return 0;
igt_global_reset_lock(i915); igt_global_reset_lock(i915);
if (intel_has_reset_engine(i915)) { if (intel_has_reset_engine(i915)) {
err = check_whitelist_across_reset(engine, err = check_whitelist_across_reset(engine,
do_engine_reset, &w, do_engine_reset,
"engine"); "engine");
if (err) if (err)
goto out; goto out;
...@@ -315,7 +315,7 @@ static int live_reset_whitelist(void *arg) ...@@ -315,7 +315,7 @@ static int live_reset_whitelist(void *arg)
if (intel_has_gpu_reset(i915)) { if (intel_has_gpu_reset(i915)) {
err = check_whitelist_across_reset(engine, err = check_whitelist_across_reset(engine,
do_device_reset, &w, do_device_reset,
"device"); "device");
if (err) if (err)
goto out; goto out;
......
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