mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-28 03:40:04 +00:00
drm/i915: Move mi_set_context() into the legacy ringbuffer submission
The legacy i915_switch_context() is only applicable to the legacy ringbuffer submission method, so move it from the general i915_gem_context.c to intel_ringbuffer.c (rename pending!). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20171123152631.31385-2-chris@chris-wilson.co.uk
This commit is contained in:
parent
b1c24a6137
commit
8911a31c81
2 changed files with 185 additions and 199 deletions
|
@ -567,204 +567,6 @@ void i915_gem_context_close(struct drm_file *file)
|
|||
idr_destroy(&file_priv->context_idr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
mi_set_context(struct drm_i915_gem_request *req, u32 flags)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = req->i915;
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
enum intel_engine_id id;
|
||||
const int num_rings =
|
||||
/* Use an extended w/a on gen7 if signalling from other rings */
|
||||
(HAS_LEGACY_SEMAPHORES(dev_priv) && IS_GEN7(dev_priv)) ?
|
||||
INTEL_INFO(dev_priv)->num_rings - 1 :
|
||||
0;
|
||||
int len;
|
||||
u32 *cs;
|
||||
|
||||
flags |= MI_MM_SPACE_GTT;
|
||||
if (IS_HASWELL(dev_priv))
|
||||
/* These flags are for resource streamer on HSW+ */
|
||||
flags |= HSW_MI_RS_SAVE_STATE_EN | HSW_MI_RS_RESTORE_STATE_EN;
|
||||
else
|
||||
flags |= MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN;
|
||||
|
||||
len = 4;
|
||||
if (IS_GEN7(dev_priv))
|
||||
len += 2 + (num_rings ? 4*num_rings + 6 : 0);
|
||||
|
||||
cs = intel_ring_begin(req, len);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
/* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
|
||||
if (IS_GEN7(dev_priv)) {
|
||||
*cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
|
||||
if (num_rings) {
|
||||
struct intel_engine_cs *signaller;
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(num_rings);
|
||||
for_each_engine(signaller, dev_priv, id) {
|
||||
if (signaller == engine)
|
||||
continue;
|
||||
|
||||
*cs++ = i915_mmio_reg_offset(
|
||||
RING_PSMI_CTL(signaller->mmio_base));
|
||||
*cs++ = _MASKED_BIT_ENABLE(
|
||||
GEN6_PSMI_SLEEP_MSG_DISABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
*cs++ = MI_SET_CONTEXT;
|
||||
*cs++ = i915_ggtt_offset(req->ctx->engine[RCS].state) | flags;
|
||||
/*
|
||||
* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
|
||||
* WaMiSetContext_Hang:snb,ivb,vlv
|
||||
*/
|
||||
*cs++ = MI_NOOP;
|
||||
|
||||
if (IS_GEN7(dev_priv)) {
|
||||
if (num_rings) {
|
||||
struct intel_engine_cs *signaller;
|
||||
i915_reg_t last_reg = {}; /* keep gcc quiet */
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(num_rings);
|
||||
for_each_engine(signaller, dev_priv, id) {
|
||||
if (signaller == engine)
|
||||
continue;
|
||||
|
||||
last_reg = RING_PSMI_CTL(signaller->mmio_base);
|
||||
*cs++ = i915_mmio_reg_offset(last_reg);
|
||||
*cs++ = _MASKED_BIT_DISABLE(
|
||||
GEN6_PSMI_SLEEP_MSG_DISABLE);
|
||||
}
|
||||
|
||||
/* Insert a delay before the next switch! */
|
||||
*cs++ = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT;
|
||||
*cs++ = i915_mmio_reg_offset(last_reg);
|
||||
*cs++ = i915_ggtt_offset(engine->scratch);
|
||||
*cs++ = MI_NOOP;
|
||||
}
|
||||
*cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
|
||||
}
|
||||
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remap_l3(struct drm_i915_gem_request *req, int slice)
|
||||
{
|
||||
u32 *cs, *remap_info = req->i915->l3_parity.remap_info[slice];
|
||||
int i;
|
||||
|
||||
if (!remap_info)
|
||||
return 0;
|
||||
|
||||
cs = intel_ring_begin(req, GEN7_L3LOG_SIZE/4 * 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
/*
|
||||
* Note: We do not worry about the concurrent register cacheline hang
|
||||
* here because no other code should access these registers other than
|
||||
* at initialization time.
|
||||
*/
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(GEN7_L3LOG_SIZE/4);
|
||||
for (i = 0; i < GEN7_L3LOG_SIZE/4; i++) {
|
||||
*cs++ = i915_mmio_reg_offset(GEN7_L3LOG(slice, i));
|
||||
*cs++ = remap_info[i];
|
||||
}
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(req, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_switch_context() - perform a GPU context switch.
|
||||
* @rq: request for which we'll execute the context switch
|
||||
*
|
||||
* The context life cycle is simple. The context refcount is incremented and
|
||||
* decremented by 1 on create and destroy. If the context is in use by the GPU,
|
||||
* it will have a refcount > 1. This allows us to destroy the context abstract
|
||||
* object while letting the normal object tracking destroy the backing BO.
|
||||
*
|
||||
* This function should not be used in execlists mode. Instead the context is
|
||||
* switched by writing to the ELSP and requests keep a reference to their
|
||||
* context.
|
||||
*/
|
||||
int i915_switch_context(struct drm_i915_gem_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct i915_gem_context *to_ctx = rq->ctx;
|
||||
struct i915_hw_ppgtt *to_mm =
|
||||
to_ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
|
||||
struct i915_gem_context *from_ctx = engine->legacy_active_context;
|
||||
struct i915_hw_ppgtt *from_mm = engine->legacy_active_ppgtt;
|
||||
u32 hw_flags = 0;
|
||||
int ret, i;
|
||||
|
||||
lockdep_assert_held(&rq->i915->drm.struct_mutex);
|
||||
GEM_BUG_ON(HAS_EXECLISTS(rq->i915));
|
||||
|
||||
if (to_mm != from_mm ||
|
||||
(to_mm && intel_engine_flag(engine) & to_mm->pd_dirty_rings)) {
|
||||
trace_switch_mm(engine, to_ctx);
|
||||
ret = to_mm->switch_mm(to_mm, rq);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
to_mm->pd_dirty_rings &= ~intel_engine_flag(engine);
|
||||
engine->legacy_active_ppgtt = to_mm;
|
||||
hw_flags = MI_FORCE_RESTORE;
|
||||
}
|
||||
|
||||
if (to_ctx->engine[engine->id].state &&
|
||||
(to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) {
|
||||
GEM_BUG_ON(engine->id != RCS);
|
||||
|
||||
/*
|
||||
* The kernel context(s) is treated as pure scratch and is not
|
||||
* expected to retain any state (as we sacrifice it during
|
||||
* suspend and on resume it may be corrupted). This is ok,
|
||||
* as nothing actually executes using the kernel context; it
|
||||
* is purely used for flushing user contexts.
|
||||
*/
|
||||
if (i915_gem_context_is_kernel(to_ctx))
|
||||
hw_flags = MI_RESTORE_INHIBIT;
|
||||
|
||||
ret = mi_set_context(rq, hw_flags);
|
||||
if (ret)
|
||||
goto err_mm;
|
||||
|
||||
engine->legacy_active_context = to_ctx;
|
||||
}
|
||||
|
||||
if (to_ctx->remap_slice) {
|
||||
for (i = 0; i < MAX_L3_SLICES; i++) {
|
||||
if (!(to_ctx->remap_slice & BIT(i)))
|
||||
continue;
|
||||
|
||||
ret = remap_l3(rq, i);
|
||||
if (ret)
|
||||
goto err_ctx;
|
||||
}
|
||||
|
||||
to_ctx->remap_slice = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctx:
|
||||
engine->legacy_active_context = from_ctx;
|
||||
err_mm:
|
||||
engine->legacy_active_ppgtt = from_mm;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct i915_gem_timeline *timeline;
|
||||
|
|
|
@ -1385,6 +1385,190 @@ void intel_legacy_submission_resume(struct drm_i915_private *dev_priv)
|
|||
intel_ring_reset(engine->buffer, 0);
|
||||
}
|
||||
|
||||
static inline int mi_set_context(struct drm_i915_gem_request *rq, u32 flags)
|
||||
{
|
||||
struct drm_i915_private *i915 = rq->i915;
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
enum intel_engine_id id;
|
||||
const int num_rings =
|
||||
/* Use an extended w/a on gen7 if signalling from other rings */
|
||||
(HAS_LEGACY_SEMAPHORES(i915) && IS_GEN7(i915)) ?
|
||||
INTEL_INFO(i915)->num_rings - 1 :
|
||||
0;
|
||||
int len;
|
||||
u32 *cs;
|
||||
|
||||
flags |= MI_MM_SPACE_GTT;
|
||||
if (IS_HASWELL(i915))
|
||||
/* These flags are for resource streamer on HSW+ */
|
||||
flags |= HSW_MI_RS_SAVE_STATE_EN | HSW_MI_RS_RESTORE_STATE_EN;
|
||||
else
|
||||
flags |= MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN;
|
||||
|
||||
len = 4;
|
||||
if (IS_GEN7(i915))
|
||||
len += 2 + (num_rings ? 4*num_rings + 6 : 0);
|
||||
|
||||
cs = intel_ring_begin(rq, len);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
/* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
|
||||
if (IS_GEN7(i915)) {
|
||||
*cs++ = MI_ARB_ON_OFF | MI_ARB_DISABLE;
|
||||
if (num_rings) {
|
||||
struct intel_engine_cs *signaller;
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(num_rings);
|
||||
for_each_engine(signaller, i915, id) {
|
||||
if (signaller == engine)
|
||||
continue;
|
||||
|
||||
*cs++ = i915_mmio_reg_offset(
|
||||
RING_PSMI_CTL(signaller->mmio_base));
|
||||
*cs++ = _MASKED_BIT_ENABLE(
|
||||
GEN6_PSMI_SLEEP_MSG_DISABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*cs++ = MI_NOOP;
|
||||
*cs++ = MI_SET_CONTEXT;
|
||||
*cs++ = i915_ggtt_offset(rq->ctx->engine[RCS].state) | flags;
|
||||
/*
|
||||
* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
|
||||
* WaMiSetContext_Hang:snb,ivb,vlv
|
||||
*/
|
||||
*cs++ = MI_NOOP;
|
||||
|
||||
if (IS_GEN7(i915)) {
|
||||
if (num_rings) {
|
||||
struct intel_engine_cs *signaller;
|
||||
i915_reg_t last_reg = {}; /* keep gcc quiet */
|
||||
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(num_rings);
|
||||
for_each_engine(signaller, i915, id) {
|
||||
if (signaller == engine)
|
||||
continue;
|
||||
|
||||
last_reg = RING_PSMI_CTL(signaller->mmio_base);
|
||||
*cs++ = i915_mmio_reg_offset(last_reg);
|
||||
*cs++ = _MASKED_BIT_DISABLE(
|
||||
GEN6_PSMI_SLEEP_MSG_DISABLE);
|
||||
}
|
||||
|
||||
/* Insert a delay before the next switch! */
|
||||
*cs++ = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT;
|
||||
*cs++ = i915_mmio_reg_offset(last_reg);
|
||||
*cs++ = i915_ggtt_offset(engine->scratch);
|
||||
*cs++ = MI_NOOP;
|
||||
}
|
||||
*cs++ = MI_ARB_ON_OFF | MI_ARB_ENABLE;
|
||||
}
|
||||
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remap_l3(struct drm_i915_gem_request *rq, int slice)
|
||||
{
|
||||
u32 *cs, *remap_info = rq->i915->l3_parity.remap_info[slice];
|
||||
int i;
|
||||
|
||||
if (!remap_info)
|
||||
return 0;
|
||||
|
||||
cs = intel_ring_begin(rq, GEN7_L3LOG_SIZE/4 * 2 + 2);
|
||||
if (IS_ERR(cs))
|
||||
return PTR_ERR(cs);
|
||||
|
||||
/*
|
||||
* Note: We do not worry about the concurrent register cacheline hang
|
||||
* here because no other code should access these registers other than
|
||||
* at initialization time.
|
||||
*/
|
||||
*cs++ = MI_LOAD_REGISTER_IMM(GEN7_L3LOG_SIZE/4);
|
||||
for (i = 0; i < GEN7_L3LOG_SIZE/4; i++) {
|
||||
*cs++ = i915_mmio_reg_offset(GEN7_L3LOG(slice, i));
|
||||
*cs++ = remap_info[i];
|
||||
}
|
||||
*cs++ = MI_NOOP;
|
||||
intel_ring_advance(rq, cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int switch_context(struct drm_i915_gem_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct i915_gem_context *to_ctx = rq->ctx;
|
||||
struct i915_hw_ppgtt *to_mm =
|
||||
to_ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
|
||||
struct i915_gem_context *from_ctx = engine->legacy_active_context;
|
||||
struct i915_hw_ppgtt *from_mm = engine->legacy_active_ppgtt;
|
||||
u32 hw_flags = 0;
|
||||
int ret, i;
|
||||
|
||||
lockdep_assert_held(&rq->i915->drm.struct_mutex);
|
||||
GEM_BUG_ON(HAS_EXECLISTS(rq->i915));
|
||||
|
||||
if (to_mm != from_mm ||
|
||||
(to_mm && intel_engine_flag(engine) & to_mm->pd_dirty_rings)) {
|
||||
trace_switch_mm(engine, to_ctx);
|
||||
ret = to_mm->switch_mm(to_mm, rq);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
to_mm->pd_dirty_rings &= ~intel_engine_flag(engine);
|
||||
engine->legacy_active_ppgtt = to_mm;
|
||||
hw_flags = MI_FORCE_RESTORE;
|
||||
}
|
||||
|
||||
if (to_ctx->engine[engine->id].state &&
|
||||
(to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) {
|
||||
GEM_BUG_ON(engine->id != RCS);
|
||||
|
||||
/*
|
||||
* The kernel context(s) is treated as pure scratch and is not
|
||||
* expected to retain any state (as we sacrifice it during
|
||||
* suspend and on resume it may be corrupted). This is ok,
|
||||
* as nothing actually executes using the kernel context; it
|
||||
* is purely used for flushing user contexts.
|
||||
*/
|
||||
if (i915_gem_context_is_kernel(to_ctx))
|
||||
hw_flags = MI_RESTORE_INHIBIT;
|
||||
|
||||
ret = mi_set_context(rq, hw_flags);
|
||||
if (ret)
|
||||
goto err_mm;
|
||||
|
||||
engine->legacy_active_context = to_ctx;
|
||||
}
|
||||
|
||||
if (to_ctx->remap_slice) {
|
||||
for (i = 0; i < MAX_L3_SLICES; i++) {
|
||||
if (!(to_ctx->remap_slice & BIT(i)))
|
||||
continue;
|
||||
|
||||
ret = remap_l3(rq, i);
|
||||
if (ret)
|
||||
goto err_ctx;
|
||||
}
|
||||
|
||||
to_ctx->remap_slice = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctx:
|
||||
engine->legacy_active_context = from_ctx;
|
||||
err_mm:
|
||||
engine->legacy_active_ppgtt = from_mm;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ring_request_alloc(struct drm_i915_gem_request *request)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1401,7 +1585,7 @@ static int ring_request_alloc(struct drm_i915_gem_request *request)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_switch_context(request);
|
||||
ret = switch_context(request);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
Loading…
Reference in a new issue