From 7f809d184b4f9512efd28b8d01323568866e2ec6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 27 Mar 2014 09:55:23 +0000 Subject: [PATCH] pnv-fake-ctx --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 180 +++++++++++------------------ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 4 files changed, 70 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9563a23402ce..b8c76a1d70bf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2326,7 +2326,7 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); int i915_gem_context_enable(struct drm_i915_private *dev_priv); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, - struct drm_file *file, struct i915_hw_context *to); + struct i915_hw_context *to); struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 31cc192c6ca8..7183caa3b312 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2983,7 +2983,7 @@ int i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ for_each_ring(ring, dev_priv, i) { - ret = i915_switch_context(ring, NULL, ring->default_context); + ret = i915_switch_context(ring, ring->default_context); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 021e21223c9c..486cd01f55cf 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -96,9 +96,6 @@ #define GEN6_CONTEXT_ALIGN (64<<10) #define GEN7_CONTEXT_ALIGN 4096 -static int do_switch(struct intel_ring_buffer *ring, - struct i915_hw_context *to); - static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) { struct drm_device *dev = ppgtt->base.dev; @@ -225,9 +222,12 @@ create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx) } static struct i915_hw_context * -__ctx_alloc(void) +__create_hw_context(struct drm_device *dev, + struct drm_i915_file_private *file_priv) { + struct drm_i915_private *dev_priv = dev->dev_private; struct i915_hw_context *ctx; + int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) @@ -236,48 +236,34 @@ __ctx_alloc(void) kref_init(&ctx->ref); INIT_LIST_HEAD(&ctx->link); - return ctx; -} - -static struct i915_hw_context * -__create_hw_context(struct drm_device *dev, - struct drm_i915_file_private *file_priv) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_context *ctx; - int ret; - - ctx = __ctx_alloc(); - if (IS_ERR(ctx)) - return ctx; - - ctx->obj = i915_gem_object_create_stolen(dev, dev_priv->hw_context_size); - if (ctx->obj == NULL) - ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); - if (ctx->obj == NULL) { - kfree(ctx); - DRM_DEBUG_DRIVER("Context object allocated failed\n"); - return ERR_PTR(-ENOMEM); - } - - if (INTEL_INFO(dev)->gen >= 7) { - ret = i915_gem_object_set_cache_level(ctx->obj, - I915_CACHE_L3_LLC); - /* Failure shouldn't ever happen this early */ - if (WARN_ON(ret)) + if (dev_priv->hw_context_size) { + ctx->obj = i915_gem_object_create_stolen(dev, dev_priv->hw_context_size); + if (ctx->obj == NULL) + ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); + if (ctx->obj == NULL) { + ret = -ENOMEM; goto err_out; + } + + if (INTEL_INFO(dev)->gen >= 7) { + ret = i915_gem_object_set_cache_level(ctx->obj, + I915_CACHE_L3_LLC); + /* Failure shouldn't ever happen this early */ + if (WARN_ON(ret)) + goto err_out; + } } list_add_tail(&ctx->link, &dev_priv->context_list); /* Default context will never have a file_priv */ - if (file_priv == NULL) - return ctx; - - ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0, - GFP_KERNEL); - if (ret < 0) - goto err_out; + if (file_priv != NULL) { + ret = idr_alloc(&file_priv->context_idr, ctx, + DEFAULT_CONTEXT_ID, 0, GFP_KERNEL); + if (ret < 0) + goto err_out; + } else + ret = 0; ctx->file_priv = file_priv; ctx->id = ret; @@ -314,7 +300,7 @@ i915_gem_create_context(struct drm_device *dev, if (IS_ERR(ctx)) return ctx; - if (is_global_default_ctx) { + if (is_global_default_ctx && ctx->obj) { /* We may need to do things with the shrinker which * require us to immediately switch back to the default * context. This can cause a problem as pinning the @@ -362,7 +348,7 @@ i915_gem_create_context(struct drm_device *dev, return ctx; err_unpin: - if (is_global_default_ctx) + if (is_global_default_ctx && ctx->obj) i915_gem_object_ggtt_unpin(ctx->obj); err_destroy: i915_gem_context_unreference(ctx); @@ -372,16 +358,14 @@ err_destroy: void i915_gem_context_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; int i; - if (!HAS_HW_CONTEXTS(dev)) - return; - /* Prevent the hardware from restoring the last context (which hung) on * the next switch */ for (i = 0; i < I915_NUM_RINGS; i++) { struct i915_hw_context *dctx; + struct intel_ring_buffer *ring; + if (!(INTEL_INFO(dev)->ring_mask & (1<last_context == dctx) continue; - if (i == RCS) { + if (dctx->obj && i == RCS) { WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj, get_context_alignment(dev), 0)); /* Fake a finish/inactive */ @@ -414,44 +398,35 @@ void i915_gem_context_reset(struct drm_device *dev) int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; + struct i915_hw_context *ctx; int i; - if (!HAS_HW_CONTEXTS(dev)) - return 0; - /* Init should only be called once per module load. Eventually the * restriction on the context_disabled check can be loosened. */ if (WARN_ON(dev_priv->ring[RCS].default_context)) return 0; - dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); - - if (dev_priv->hw_context_size > (1<<20)) { - DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n"); - return -E2BIG; + if (HAS_HW_CONTEXTS(dev)) { + dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); + if (dev_priv->hw_context_size > (1<<20)) { + DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n", + dev_priv->hw_context_size); + dev_priv->hw_context_size = 0; + } } - dev_priv->ring[RCS].default_context = - i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); - - if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { - DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", - PTR_ERR(dev_priv->ring[RCS].default_context)); - return PTR_ERR(dev_priv->ring[RCS].default_context); + ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); + if (IS_ERR(ctx)) { + DRM_ERROR("Failed to create default global context (error %ld)\n", + PTR_ERR(ctx)); + return PTR_ERR(ctx); } - for (i = RCS + 1; i < I915_NUM_RINGS; i++) { - if (!(INTEL_INFO(dev)->ring_mask & (1<ring[i]; - - /* NB: RCS will hold a ref for all rings */ - ring->default_context = dev_priv->ring[RCS].default_context; - } + /* NB: RCS will hold a ref for all rings */ + for (i = 0; i < I915_NUM_RINGS; i++) + dev_priv->ring[i].default_context = ctx; - DRM_DEBUG_DRIVER("HW context support initialized\n"); + DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake"); return 0; } @@ -461,13 +436,11 @@ void i915_gem_context_fini(struct drm_device *dev) struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context; int i; - if (!HAS_HW_CONTEXTS(dev)) - return; - - /* 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. */ - intel_gpu_reset(dev); + if (dev_priv->hw_context_size) + /* 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. */ + intel_gpu_reset(dev); /* When default context is created and switched to, base object refcount * will be 2 (+1 from object creation and +1 from do_switch()). @@ -476,7 +449,7 @@ void i915_gem_context_fini(struct drm_device *dev) * to offset the do_switch part, so that i915_gem_context_unreference() * can then free the base object correctly. */ WARN_ON(!dev_priv->ring[RCS].last_context); - if (dev_priv->ring[RCS].last_context == dctx) { + if (dctx->obj && dev_priv->ring[RCS].last_context == dctx) { /* Fake switch to NULL context */ WARN_ON(dctx->obj->active); i915_gem_object_ggtt_unpin(dctx->obj); @@ -486,6 +459,7 @@ void i915_gem_context_fini(struct drm_device *dev) for (i = 0; i < I915_NUM_RINGS; i++) { struct intel_ring_buffer *ring = &dev_priv->ring[i]; + if (!(INTEL_INFO(dev)->ring_mask & (1<obj); i915_gem_context_unreference(dctx); - dev_priv->mm.aliasing_ppgtt = NULL; } int i915_gem_context_enable(struct drm_i915_private *dev_priv) @@ -506,9 +479,6 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) struct intel_ring_buffer *ring; int ret, i; - if (!HAS_HW_CONTEXTS(dev_priv->dev)) - return 0; - /* This is the only place the aliasing PPGTT gets enabled, which means * it has to happen before we bail on reset */ if (dev_priv->mm.aliasing_ppgtt) { @@ -523,7 +493,7 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) BUG_ON(!dev_priv->ring[RCS].default_context); for_each_ring(ring, dev_priv, i) { - ret = do_switch(ring, ring->default_context); + ret = i915_switch_context(ring, ring->default_context); if (ret) return ret; } @@ -546,17 +516,6 @@ static int context_idr_cleanup(int id, void *p, void *data) int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!HAS_HW_CONTEXTS(dev)) { - /* Cheat for hang stats */ - file_priv->private_default_ctx = __ctx_alloc(); - if (IS_ERR(file_priv->private_default_ctx)) - return PTR_ERR(file_priv->private_default_ctx); - - file_priv->private_default_ctx->vm = &dev_priv->gtt.base; - return 0; - } idr_init(&file_priv->context_idr); @@ -580,10 +539,8 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) if (IS_ERR_OR_NULL(file_priv->private_default_ctx)) return; - if (HAS_HW_CONTEXTS(dev)) { - idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); - idr_destroy(&file_priv->context_idr); - } + idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); + idr_destroy(&file_priv->context_idr); i915_gem_context_unreference(file_priv->private_default_ctx); } @@ -593,9 +550,6 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) { struct i915_hw_context *ctx; - if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev)) - return file_priv->private_default_ctx; - ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id); if (!ctx) return ERR_PTR(-ENOENT); @@ -687,7 +641,6 @@ mi_set_context(struct intel_ring_buffer *ring, intel_ring_advance(ring); return ret; - } static int do_switch(struct intel_ring_buffer *ring, @@ -813,7 +766,6 @@ unpin_out: /** * i915_switch_context() - perform a GPU context switch. * @ring: ring for which we'll execute the context switch - * @file_priv: file_priv associated with the context, may be NULL * @to: the context to switch to * * The context life cycle is simple. The context refcount is incremented and @@ -822,18 +774,20 @@ unpin_out: * object while letting the normal object tracking destroy the backing BO. */ int i915_switch_context(struct intel_ring_buffer *ring, - struct drm_file *file, struct i915_hw_context *to) { struct drm_i915_private *dev_priv = ring->dev->dev_private; WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - BUG_ON(file && to == NULL); - - /* We have the fake context */ - if (!HAS_HW_CONTEXTS(ring->dev)) { - ring->last_context = to; + if (to->obj == NULL) { /* We have the fake context */ + if (to != ring->last_context) { + if (to) + i915_gem_context_reference(to); + if (ring->last_context) + i915_gem_context_unreference(ring->last_context); + ring->last_context = to; + } return 0; } @@ -848,7 +802,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct i915_hw_context *ctx; int ret; - if (!HAS_HW_CONTEXTS(dev)) + if (to_i915(dev)->hw_context_size == 0) return -ENODEV; ret = i915_mutex_lock_interruptible(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1b45163e19f3..8100a1e17db6 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1208,7 +1208,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err_batch; - ret = i915_switch_context(ring, file, ctx); + ret = i915_switch_context(ring, ctx); if (ret) goto err_batch; -- 1.9.1