|
@@ -567,204 +567,6 @@ void i915_gem_context_close(struct drm_file *file)
|
|
idr_destroy(&file_priv->context_idr);
|
|
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)
|
|
static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
|
|
{
|
|
{
|
|
struct i915_gem_timeline *timeline;
|
|
struct i915_gem_timeline *timeline;
|