Commit 1acfc104 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Enable rcu-only context lookups

Whilst the contents of the context is still protected by the big
struct_mutex, this is not much of an improvement. It is just one tiny
step towards reducing our BKL.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170620110547.15947-3-chris@chris-wilson.co.uk
parent 5f09a9c8
...@@ -3533,16 +3533,22 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj, ...@@ -3533,16 +3533,22 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj,
void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj, void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj,
struct sg_table *pages); struct sg_table *pages);
static inline struct i915_gem_context *
__i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
{
return idr_find(&file_priv->context_idr, id);
}
static inline struct i915_gem_context * static inline struct i915_gem_context *
i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id) i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
{ {
struct i915_gem_context *ctx; struct i915_gem_context *ctx;
lockdep_assert_held(&file_priv->dev_priv->drm.struct_mutex); rcu_read_lock();
ctx = __i915_gem_context_lookup_rcu(file_priv, id);
ctx = idr_find(&file_priv->context_idr, id); if (ctx && !kref_get_unless_zero(&ctx->ref))
if (!ctx) ctx = NULL;
return ERR_PTR(-ENOENT); rcu_read_unlock();
return ctx; return ctx;
} }
......
...@@ -187,7 +187,7 @@ static void i915_gem_context_free(struct i915_gem_context *ctx) ...@@ -187,7 +187,7 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
list_del(&ctx->link); list_del(&ctx->link);
ida_simple_remove(&ctx->i915->contexts.hw_ida, ctx->hw_id); ida_simple_remove(&ctx->i915->contexts.hw_ida, ctx->hw_id);
kfree(ctx); kfree_rcu(ctx, rcu);
} }
static void contexts_free(struct drm_i915_private *i915) static void contexts_free(struct drm_i915_private *i915)
...@@ -1021,20 +1021,19 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, ...@@ -1021,20 +1021,19 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
if (args->ctx_id == DEFAULT_CONTEXT_HANDLE) if (args->ctx_id == DEFAULT_CONTEXT_HANDLE)
return -ENOENT; return -ENOENT;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
ctx = i915_gem_context_lookup(file_priv, args->ctx_id); ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
if (IS_ERR(ctx)) { if (!ctx)
mutex_unlock(&dev->struct_mutex); return -ENOENT;
return PTR_ERR(ctx);
} ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
goto out;
__destroy_hw_context(ctx, file_priv); __destroy_hw_context(ctx, file_priv);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("HW context %d destroyed\n", args->ctx_id); out:
i915_gem_context_put(ctx);
return 0; return 0;
} }
...@@ -1044,17 +1043,11 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, ...@@ -1044,17 +1043,11 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
struct drm_i915_file_private *file_priv = file->driver_priv; struct drm_i915_file_private *file_priv = file->driver_priv;
struct drm_i915_gem_context_param *args = data; struct drm_i915_gem_context_param *args = data;
struct i915_gem_context *ctx; struct i915_gem_context *ctx;
int ret; int ret = 0;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
ctx = i915_gem_context_lookup(file_priv, args->ctx_id); ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
if (IS_ERR(ctx)) { if (!ctx)
mutex_unlock(&dev->struct_mutex); return -ENOENT;
return PTR_ERR(ctx);
}
args->size = 0; args->size = 0;
switch (args->param) { switch (args->param) {
...@@ -1082,8 +1075,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, ...@@ -1082,8 +1075,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
mutex_unlock(&dev->struct_mutex);
i915_gem_context_put(ctx);
return ret; return ret;
} }
...@@ -1095,15 +1088,13 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, ...@@ -1095,15 +1088,13 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
struct i915_gem_context *ctx; struct i915_gem_context *ctx;
int ret; int ret;
ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
if (!ctx)
return -ENOENT;
ret = i915_mutex_lock_interruptible(dev); ret = i915_mutex_lock_interruptible(dev);
if (ret) if (ret)
return ret; goto out;
ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
if (IS_ERR(ctx)) {
mutex_unlock(&dev->struct_mutex);
return PTR_ERR(ctx);
}
switch (args->param) { switch (args->param) {
case I915_CONTEXT_PARAM_BAN_PERIOD: case I915_CONTEXT_PARAM_BAN_PERIOD:
...@@ -1141,6 +1132,8 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, ...@@ -1141,6 +1132,8 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
} }
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
out:
i915_gem_context_put(ctx);
return ret; return ret;
} }
...@@ -1155,27 +1148,31 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, ...@@ -1155,27 +1148,31 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
if (args->flags || args->pad) if (args->flags || args->pad)
return -EINVAL; return -EINVAL;
ret = i915_mutex_lock_interruptible(dev); ret = -ENOENT;
if (ret) rcu_read_lock();
return ret; ctx = __i915_gem_context_lookup_rcu(file->driver_priv, args->ctx_id);
if (!ctx)
goto out;
ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id); /*
if (IS_ERR(ctx)) { * We opt for unserialised reads here. This may result in tearing
mutex_unlock(&dev->struct_mutex); * in the extremely unlikely event of a GPU hang on this context
return PTR_ERR(ctx); * as we are querying them. If we need that extra layer of protection,
} * we should wrap the hangstats with a seqlock.
*/
if (capable(CAP_SYS_ADMIN)) if (capable(CAP_SYS_ADMIN))
args->reset_count = i915_reset_count(&dev_priv->gpu_error); args->reset_count = i915_reset_count(&dev_priv->gpu_error);
else else
args->reset_count = 0; args->reset_count = 0;
args->batch_active = ctx->guilty_count; args->batch_active = READ_ONCE(ctx->guilty_count);
args->batch_pending = ctx->active_count; args->batch_pending = READ_ONCE(ctx->active_count);
mutex_unlock(&dev->struct_mutex);
return 0; ret = 0;
out:
rcu_read_unlock();
return ret;
} }
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
......
...@@ -99,6 +99,11 @@ struct i915_gem_context { ...@@ -99,6 +99,11 @@ struct i915_gem_context {
*/ */
struct kref ref; struct kref ref;
/**
* @rcu: rcu_head for deferred freeing.
*/
struct rcu_head rcu;
/** /**
* @flags: small set of booleans * @flags: small set of booleans
*/ */
......
...@@ -669,16 +669,17 @@ static int eb_select_context(struct i915_execbuffer *eb) ...@@ -669,16 +669,17 @@ static int eb_select_context(struct i915_execbuffer *eb)
struct i915_gem_context *ctx; struct i915_gem_context *ctx;
ctx = i915_gem_context_lookup(eb->file->driver_priv, eb->args->rsvd1); ctx = i915_gem_context_lookup(eb->file->driver_priv, eb->args->rsvd1);
if (unlikely(IS_ERR(ctx))) if (unlikely(!ctx))
return PTR_ERR(ctx); return -ENOENT;
if (unlikely(i915_gem_context_is_banned(ctx))) { if (unlikely(i915_gem_context_is_banned(ctx))) {
DRM_DEBUG("Context %u tried to submit while banned\n", DRM_DEBUG("Context %u tried to submit while banned\n",
ctx->user_handle); ctx->user_handle);
i915_gem_context_put(ctx);
return -EIO; return -EIO;
} }
eb->ctx = i915_gem_context_get(ctx); eb->ctx = ctx;
eb->vm = ctx->ppgtt ? &ctx->ppgtt->base : &eb->i915->ggtt.base; eb->vm = ctx->ppgtt ? &ctx->ppgtt->base : &eb->i915->ggtt.base;
eb->context_flags = 0; eb->context_flags = 0;
...@@ -2127,7 +2128,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2127,7 +2128,6 @@ i915_gem_do_execbuffer(struct drm_device *dev,
if (DBG_FORCE_RELOC || !(args->flags & I915_EXEC_NO_RELOC)) if (DBG_FORCE_RELOC || !(args->flags & I915_EXEC_NO_RELOC))
args->flags |= __EXEC_HAS_RELOC; args->flags |= __EXEC_HAS_RELOC;
eb.exec = exec; eb.exec = exec;
eb.ctx = NULL;
eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS;
if (USES_FULL_PPGTT(eb.i915)) if (USES_FULL_PPGTT(eb.i915))
eb.invalid_flags |= EXEC_OBJECT_NEEDS_GTT; eb.invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
...@@ -2182,6 +2182,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2182,6 +2182,10 @@ i915_gem_do_execbuffer(struct drm_device *dev,
if (eb_create(&eb)) if (eb_create(&eb))
return -ENOMEM; return -ENOMEM;
err = eb_select_context(&eb);
if (unlikely(err))
goto err_destroy;
/* /*
* Take a local wakeref for preparing to dispatch the execbuf as * Take a local wakeref for preparing to dispatch the execbuf as
* we expect to access the hardware fairly frequently in the * we expect to access the hardware fairly frequently in the
...@@ -2190,14 +2194,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2190,14 +2194,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
* 100ms. * 100ms.
*/ */
intel_runtime_pm_get(eb.i915); intel_runtime_pm_get(eb.i915);
err = i915_mutex_lock_interruptible(dev); err = i915_mutex_lock_interruptible(dev);
if (err) if (err)
goto err_rpm; goto err_rpm;
err = eb_select_context(&eb);
if (unlikely(err))
goto err_unlock;
err = eb_relocate(&eb); err = eb_relocate(&eb);
if (err) if (err)
/* /*
...@@ -2333,11 +2334,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2333,11 +2334,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
err_vma: err_vma:
if (eb.exec) if (eb.exec)
eb_release_vmas(&eb); eb_release_vmas(&eb);
i915_gem_context_put(eb.ctx);
err_unlock:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
err_rpm: err_rpm:
intel_runtime_pm_put(eb.i915); intel_runtime_pm_put(eb.i915);
i915_gem_context_put(eb.ctx);
err_destroy:
eb_destroy(&eb); eb_destroy(&eb);
if (out_fence_fd != -1) if (out_fence_fd != -1)
put_unused_fd(out_fence_fd); put_unused_fd(out_fence_fd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment