@@ -1385,7 +1385,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
cleanup_gem:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ring(dev);
- i915_gem_context_fini(dev);
+ i915_gem_context_fini(dev, dev_priv->lrc_enabled);
mutex_unlock(&dev->struct_mutex);
WARN_ON(dev_priv->mm.aliasing_ppgtt);
drm_mm_takedown(&dev_priv->gtt.base.mm);
@@ -1841,7 +1841,7 @@ int i915_driver_unload(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
i915_gem_free_all_phys_object(dev);
i915_gem_cleanup_ring(dev);
- i915_gem_context_fini(dev);
+ i915_gem_context_fini(dev, dev_priv->lrc_enabled);
WARN_ON(dev_priv->mm.aliasing_ppgtt);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_stolen(dev);
@@ -2390,7 +2390,7 @@ void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
/* i915_gem_context.c */
#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
int __must_check i915_gem_context_init(struct drm_device *dev);
-void i915_gem_context_fini(struct drm_device *dev);
+void i915_gem_context_fini(struct drm_device *dev, bool is_lrc);
struct drm_i915_gem_object *intel_allocate_ctx_backing_obj(struct drm_device *dev,
size_t size);
struct i915_hw_context *i915_gem_create_context(struct drm_device *dev,
@@ -2427,6 +2427,9 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
/* intel_lrc.c */
int gen8_gem_context_init(struct drm_device *dev);
+int gen8_create_lr_context(struct i915_hw_context *ctx,
+ struct intel_engine *ring,
+ struct drm_i915_file_private *file_priv);
/* i915_gem_evict.c */
int __must_check i915_gem_evict_something(struct drm_device *dev,
@@ -181,16 +181,22 @@ void i915_gem_context_free(struct kref *ctx_ref)
struct i915_hw_context *ctx = container_of(ctx_ref,
typeof(*ctx), ref);
struct i915_hw_ppgtt *ppgtt = NULL;
- struct drm_i915_gem_object *ctx_obj = ctx->engine[RCS].obj;
+ int i;
- if (ctx_obj) {
- /* We refcount even the aliasing PPGTT to keep the code symmetric */
- if (USES_PPGTT(ctx_obj->base.dev))
- ppgtt = ctx_to_ppgtt(ctx);
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ struct drm_i915_gem_object *ctx_obj = ctx->engine[i].obj;
+ if (ctx_obj) {
+ if (i == RCS) {
+ /* We refcount even the aliasing PPGTT to keep the
+ * code symmetric */
+ if (USES_PPGTT(ctx_obj->base.dev))
+ ppgtt = ctx_to_ppgtt(ctx);
+ }
- /* XXX: Free up the object before tearing down the address space, in
- * case we're bound in the PPGTT */
- drm_gem_object_unreference(&ctx_obj->base);
+ /* XXX: Free up the object before tearing down the address
+ * space, in case we're bound in the PPGTT */
+ drm_gem_object_unreference(&ctx_obj->base);
+ }
}
if (ppgtt)
@@ -447,15 +453,15 @@ int i915_gem_context_init(struct drm_device *dev)
return 0;
}
-void i915_gem_context_fini(struct drm_device *dev)
+void i915_gem_context_fini(struct drm_device *dev, bool is_lrc)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
struct drm_i915_gem_object *dctx_obj = dctx->engine[RCS].obj;
struct intel_engine *ring;
- int unused;
+ int ring_id;
- if (dctx_obj) {
+ if (dctx_obj && !is_lrc) {
/* The only known way to stop the gpu from accessing the hw context is
* to reset it. Do this as the very last operation to avoid confusing
* other code, leading to spurious errors. */
@@ -477,15 +483,20 @@ void i915_gem_context_fini(struct drm_device *dev)
}
}
- for_each_ring(ring, dev_priv, unused) {
+ for_each_ring(ring, dev_priv, ring_id) {
if (ring->last_context)
i915_gem_context_unreference(ring->last_context);
ring->default_context = NULL;
ring->last_context = NULL;
+
+ dctx_obj = dctx->engine[ring_id].obj;
+ if (dctx_obj) {
+ BUG_ON(ring_id != RCS && !is_lrc);
+ i915_gem_object_ggtt_unpin(dctx_obj);
+ }
}
- i915_gem_object_ggtt_unpin(dctx_obj);
i915_gem_context_unreference(dctx);
}
@@ -41,7 +41,90 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
+#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
+#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)
+
+#define GEN8_LR_CONTEXT_ALIGN 4096
+
+static uint32_t get_lr_context_size(struct intel_engine *ring)
+{
+ int ret = 0;
+
+ BUG_ON(INTEL_INFO(ring->dev)->gen != 8);
+
+ switch (ring->id) {
+ case RCS:
+ ret = GEN8_LR_CONTEXT_RENDER_SIZE;
+ break;
+ case VCS:
+ case BCS:
+ case VECS:
+ case VCS2:
+ ret = GEN8_LR_CONTEXT_OTHER_SIZE;
+ break;
+ }
+
+ return ret;
+}
+
+int gen8_create_lr_context(struct i915_hw_context *ctx,
+ struct intel_engine *ring,
+ struct drm_i915_file_private *file_priv)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_gem_object *ctx_obj;
+ uint32_t context_size;
+ int ret;
+
+ if (ctx->engine[ring->id].obj)
+ return 0;
+
+ context_size = round_up(get_lr_context_size(ring), 4096);
+
+ ctx_obj = intel_allocate_ctx_backing_obj(dev, context_size);
+ if (IS_ERR_OR_NULL(ctx_obj)) {
+ ret = PTR_ERR(ctx_obj);
+ DRM_DEBUG_DRIVER("Alloc LRC backing obj failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n", ret);
+ drm_gem_object_unreference(&ctx_obj->base);
+ return ret;
+ }
+
+ ctx->engine[ring->id].obj = ctx_obj;
+
+ return 0;
+}
+
int gen8_gem_context_init(struct drm_device *dev)
{
- return -ENOSYS;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct i915_hw_context *ctx;
+ struct intel_engine *ring;
+ int ring_id;
+ int ret;
+
+ /* Any value != 0 works here */
+ dev_priv->hw_context_size = GEN8_LR_CONTEXT_RENDER_SIZE;
+
+ ctx = i915_gem_create_context(dev, NULL, true, false);
+ if (IS_ERR_OR_NULL(ctx)) {
+ ret = PTR_ERR(ctx);
+ DRM_ERROR("Init LR context failed: %d\n", ret);
+ goto err_out;
+ }
+
+ for_each_ring(ring, dev_priv, ring_id)
+ ring->default_context = ctx;
+
+ DRM_DEBUG_DRIVER("LR context support initialized\n");
+ return 0;
+
+err_out:
+ i915_gem_context_fini(dev, true);
+ return ret;
}
@@ -1443,6 +1443,7 @@ err_unref:
static int intel_init_ring(struct drm_device *dev,
struct intel_engine *ring)
{
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_ringbuffer *ringbuf = &ring->default_ringbuf;
int ret;
@@ -1453,6 +1454,15 @@ static int intel_init_ring(struct drm_device *dev,
init_waitqueue_head(&ring->irq_queue);
+ if (dev_priv->lrc_enabled) {
+ ret = gen8_create_lr_context(ring->default_context, ring, NULL);
+ if (ret) {
+ DRM_ERROR("Create LR context for %s failed: %d\n",
+ ring->name, ret);
+ return ret;
+ }
+ }
+
if (I915_NEED_GFX_HWS(dev)) {
ret = init_status_page(ring);
if (ret)