|
@@ -263,65 +263,92 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+logical_ring_init_platform_invariants(struct intel_engine_cs *ring)
|
|
|
+{
|
|
|
+ struct drm_device *dev = ring->dev;
|
|
|
+
|
|
|
+ ring->disable_lite_restore_wa = (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
|
|
|
+ IS_BXT_REVID(dev, 0, BXT_REVID_A1)) &&
|
|
|
+ (ring->id == VCS || ring->id == VCS2);
|
|
|
+
|
|
|
+ ring->ctx_desc_template = GEN8_CTX_VALID;
|
|
|
+ ring->ctx_desc_template |= GEN8_CTX_ADDRESSING_MODE(dev) <<
|
|
|
+ GEN8_CTX_ADDRESSING_MODE_SHIFT;
|
|
|
+ if (IS_GEN8(dev))
|
|
|
+ ring->ctx_desc_template |= GEN8_CTX_L3LLC_COHERENT;
|
|
|
+ ring->ctx_desc_template |= GEN8_CTX_PRIVILEGE;
|
|
|
+
|
|
|
+ /* TODO: WaDisableLiteRestore when we start using semaphore
|
|
|
+ * signalling between Command Streamers */
|
|
|
+ /* ring->ctx_desc_template |= GEN8_CTX_FORCE_RESTORE; */
|
|
|
+
|
|
|
+ /* WaEnableForceRestoreInCtxtDescForVCS:skl */
|
|
|
+ /* WaEnableForceRestoreInCtxtDescForVCS:bxt */
|
|
|
+ if (ring->disable_lite_restore_wa)
|
|
|
+ ring->ctx_desc_template |= GEN8_CTX_FORCE_RESTORE;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
- * intel_execlists_ctx_id() - get the Execlists Context ID
|
|
|
- * @ctx_obj: Logical Ring Context backing object.
|
|
|
+ * intel_lr_context_descriptor_update() - calculate & cache the descriptor
|
|
|
+ * descriptor for a pinned context
|
|
|
*
|
|
|
- * Do not confuse with ctx->id! Unfortunately we have a name overload
|
|
|
- * here: the old context ID we pass to userspace as a handler so that
|
|
|
- * they can refer to a context, and the new context ID we pass to the
|
|
|
- * ELSP so that the GPU can inform us of the context status via
|
|
|
- * interrupts.
|
|
|
+ * @ctx: Context to work on
|
|
|
+ * @ring: Engine the descriptor will be used with
|
|
|
*
|
|
|
- * Return: 20-bits globally unique context ID.
|
|
|
+ * The context descriptor encodes various attributes of a context,
|
|
|
+ * including its GTT address and some flags. Because it's fairly
|
|
|
+ * expensive to calculate, we'll just do it once and cache the result,
|
|
|
+ * which remains valid until the context is unpinned.
|
|
|
+ *
|
|
|
+ * This is what a descriptor looks like, from LSB to MSB:
|
|
|
+ * bits 0-11: flags, GEN8_CTX_* (cached in ctx_desc_template)
|
|
|
+ * bits 12-31: LRCA, GTT address of (the HWSP of) this context
|
|
|
+ * bits 32-51: ctx ID, a globally unique tag (the LRCA again!)
|
|
|
+ * bits 52-63: reserved, may encode the engine ID (for GuC)
|
|
|
*/
|
|
|
-u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
|
|
|
+static void
|
|
|
+intel_lr_context_descriptor_update(struct intel_context *ctx,
|
|
|
+ struct intel_engine_cs *ring)
|
|
|
{
|
|
|
- u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj) +
|
|
|
- LRC_PPHWSP_PN * PAGE_SIZE;
|
|
|
+ uint64_t lrca, desc;
|
|
|
|
|
|
- /* LRCA is required to be 4K aligned so the more significant 20 bits
|
|
|
- * are globally unique */
|
|
|
- return lrca >> 12;
|
|
|
-}
|
|
|
+ lrca = ctx->engine[ring->id].lrc_vma->node.start +
|
|
|
+ LRC_PPHWSP_PN * PAGE_SIZE;
|
|
|
|
|
|
-static bool disable_lite_restore_wa(struct intel_engine_cs *ring)
|
|
|
-{
|
|
|
- struct drm_device *dev = ring->dev;
|
|
|
+ desc = ring->ctx_desc_template; /* bits 0-11 */
|
|
|
+ desc |= lrca; /* bits 12-31 */
|
|
|
+ desc |= (lrca >> PAGE_SHIFT) << GEN8_CTX_ID_SHIFT; /* bits 32-51 */
|
|
|
|
|
|
- return (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
|
|
|
- IS_BXT_REVID(dev, 0, BXT_REVID_A1)) &&
|
|
|
- (ring->id == VCS || ring->id == VCS2);
|
|
|
+ ctx->engine[ring->id].lrc_desc = desc;
|
|
|
}
|
|
|
|
|
|
uint64_t intel_lr_context_descriptor(struct intel_context *ctx,
|
|
|
struct intel_engine_cs *ring)
|
|
|
{
|
|
|
- struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;
|
|
|
- uint64_t desc;
|
|
|
- uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj) +
|
|
|
- LRC_PPHWSP_PN * PAGE_SIZE;
|
|
|
-
|
|
|
- WARN_ON(lrca & 0xFFFFFFFF00000FFFULL);
|
|
|
-
|
|
|
- desc = GEN8_CTX_VALID;
|
|
|
- desc |= GEN8_CTX_ADDRESSING_MODE(dev) << GEN8_CTX_ADDRESSING_MODE_SHIFT;
|
|
|
- if (IS_GEN8(ctx_obj->base.dev))
|
|
|
- desc |= GEN8_CTX_L3LLC_COHERENT;
|
|
|
- desc |= GEN8_CTX_PRIVILEGE;
|
|
|
- desc |= lrca;
|
|
|
- desc |= (u64)intel_execlists_ctx_id(ctx_obj) << GEN8_CTX_ID_SHIFT;
|
|
|
-
|
|
|
- /* TODO: WaDisableLiteRestore when we start using semaphore
|
|
|
- * signalling between Command Streamers */
|
|
|
- /* desc |= GEN8_CTX_FORCE_RESTORE; */
|
|
|
-
|
|
|
- /* WaEnableForceRestoreInCtxtDescForVCS:skl */
|
|
|
- /* WaEnableForceRestoreInCtxtDescForVCS:bxt */
|
|
|
- if (disable_lite_restore_wa(ring))
|
|
|
- desc |= GEN8_CTX_FORCE_RESTORE;
|
|
|
+ return ctx->engine[ring->id].lrc_desc;
|
|
|
+}
|
|
|
|
|
|
- return desc;
|
|
|
+/**
|
|
|
+ * intel_execlists_ctx_id() - get the Execlists Context ID
|
|
|
+ * @ctx: Context to get the ID for
|
|
|
+ * @ring: Engine to get the ID for
|
|
|
+ *
|
|
|
+ * Do not confuse with ctx->id! Unfortunately we have a name overload
|
|
|
+ * here: the old context ID we pass to userspace as a handler so that
|
|
|
+ * they can refer to a context, and the new context ID we pass to the
|
|
|
+ * ELSP so that the GPU can inform us of the context status via
|
|
|
+ * interrupts.
|
|
|
+ *
|
|
|
+ * The context ID is a portion of the context descriptor, so we can
|
|
|
+ * just extract the required part from the cached descriptor.
|
|
|
+ *
|
|
|
+ * Return: 20-bits globally unique context ID.
|
|
|
+ */
|
|
|
+u32 intel_execlists_ctx_id(struct intel_context *ctx,
|
|
|
+ struct intel_engine_cs *ring)
|
|
|
+{
|
|
|
+ return intel_lr_context_descriptor(ctx, ring) >> GEN8_CTX_ID_SHIFT;
|
|
|
}
|
|
|
|
|
|
static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
|
|
@@ -369,8 +396,6 @@ static int execlists_update_context(struct drm_i915_gem_request *rq)
|
|
|
uint32_t *reg_state;
|
|
|
|
|
|
BUG_ON(!ctx_obj);
|
|
|
- WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
|
|
|
- WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
|
|
|
|
|
|
page = i915_gem_object_get_dirty_page(ctx_obj, LRC_STATE_PN);
|
|
|
reg_state = kmap_atomic(page);
|
|
@@ -477,9 +502,7 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
|
|
|
execlist_link);
|
|
|
|
|
|
if (head_req != NULL) {
|
|
|
- struct drm_i915_gem_object *ctx_obj =
|
|
|
- head_req->ctx->engine[ring->id].state;
|
|
|
- if (intel_execlists_ctx_id(ctx_obj) == request_id) {
|
|
|
+ if (intel_execlists_ctx_id(head_req->ctx, ring) == request_id) {
|
|
|
WARN(head_req->elsp_submitted == 0,
|
|
|
"Never submitted head request\n");
|
|
|
|
|
@@ -556,7 +579,7 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (disable_lite_restore_wa(ring)) {
|
|
|
+ if (ring->disable_lite_restore_wa) {
|
|
|
/* Prevent a ctx to preempt itself */
|
|
|
if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) &&
|
|
|
(submit_contexts != 0))
|
|
@@ -1039,14 +1062,16 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req)
|
|
|
}
|
|
|
|
|
|
static int intel_lr_context_do_pin(struct intel_engine_cs *ring,
|
|
|
- struct drm_i915_gem_object *ctx_obj,
|
|
|
- struct intel_ringbuffer *ringbuf)
|
|
|
+ struct intel_context *ctx)
|
|
|
{
|
|
|
struct drm_device *dev = ring->dev;
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- int ret = 0;
|
|
|
+ struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;
|
|
|
+ struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
|
|
|
+ int ret;
|
|
|
|
|
|
WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
|
|
|
+
|
|
|
ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN,
|
|
|
PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
|
|
|
if (ret)
|
|
@@ -1056,6 +1081,8 @@ static int intel_lr_context_do_pin(struct intel_engine_cs *ring,
|
|
|
if (ret)
|
|
|
goto unpin_ctx_obj;
|
|
|
|
|
|
+ ctx->engine[ring->id].lrc_vma = i915_gem_obj_to_ggtt(ctx_obj);
|
|
|
+ intel_lr_context_descriptor_update(ctx, ring);
|
|
|
ctx_obj->dirty = true;
|
|
|
|
|
|
/* Invalidate GuC TLB. */
|
|
@@ -1074,11 +1101,9 @@ static int intel_lr_context_pin(struct drm_i915_gem_request *rq)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
struct intel_engine_cs *ring = rq->ring;
|
|
|
- struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state;
|
|
|
- struct intel_ringbuffer *ringbuf = rq->ringbuf;
|
|
|
|
|
|
if (rq->ctx->engine[ring->id].pin_count++ == 0) {
|
|
|
- ret = intel_lr_context_do_pin(ring, ctx_obj, ringbuf);
|
|
|
+ ret = intel_lr_context_do_pin(ring, rq->ctx);
|
|
|
if (ret)
|
|
|
goto reset_pin_count;
|
|
|
}
|
|
@@ -1100,6 +1125,8 @@ void intel_lr_context_unpin(struct drm_i915_gem_request *rq)
|
|
|
if (--rq->ctx->engine[ring->id].pin_count == 0) {
|
|
|
intel_unpin_ringbuffer_obj(ringbuf);
|
|
|
i915_gem_object_ggtt_unpin(ctx_obj);
|
|
|
+ rq->ctx->engine[ring->id].lrc_vma = NULL;
|
|
|
+ rq->ctx->engine[ring->id].lrc_desc = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1939,6 +1966,9 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
|
|
|
ring->status_page.obj = NULL;
|
|
|
}
|
|
|
|
|
|
+ ring->disable_lite_restore_wa = false;
|
|
|
+ ring->ctx_desc_template = 0;
|
|
|
+
|
|
|
lrc_destroy_wa_ctx_obj(ring);
|
|
|
ring->dev = NULL;
|
|
|
}
|
|
@@ -1989,6 +2019,8 @@ logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
|
|
|
INIT_LIST_HEAD(&ring->execlist_retired_req_list);
|
|
|
spin_lock_init(&ring->execlist_lock);
|
|
|
|
|
|
+ logical_ring_init_platform_invariants(ring);
|
|
|
+
|
|
|
ret = i915_cmd_parser_init_ring(ring);
|
|
|
if (ret)
|
|
|
goto error;
|
|
@@ -1998,10 +2030,7 @@ logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
|
|
|
goto error;
|
|
|
|
|
|
/* As this is the default context, always pin it */
|
|
|
- ret = intel_lr_context_do_pin(
|
|
|
- ring,
|
|
|
- ring->default_context->engine[ring->id].state,
|
|
|
- ring->default_context->engine[ring->id].ringbuf);
|
|
|
+ ret = intel_lr_context_do_pin(ring, ring->default_context);
|
|
|
if (ret) {
|
|
|
DRM_ERROR(
|
|
|
"Failed to pin and map ringbuffer %s: %d\n",
|