Skip to content

Commit 1acfc10

Browse files
committed
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: Chris Wilson <[email protected]> Reviewed-by: Joonas Lahtinen <[email protected]> Link: http://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 5f09a9c commit 1acfc10

File tree

4 files changed

+64
-55
lines changed

4 files changed

+64
-55
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3533,16 +3533,22 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj,
35333533
void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj,
35343534
struct sg_table *pages);
35353535

3536+
static inline struct i915_gem_context *
3537+
__i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
3538+
{
3539+
return idr_find(&file_priv->context_idr, id);
3540+
}
3541+
35363542
static inline struct i915_gem_context *
35373543
i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
35383544
{
35393545
struct i915_gem_context *ctx;
35403546

3541-
lockdep_assert_held(&file_priv->dev_priv->drm.struct_mutex);
3542-
3543-
ctx = idr_find(&file_priv->context_idr, id);
3544-
if (!ctx)
3545-
return ERR_PTR(-ENOENT);
3547+
rcu_read_lock();
3548+
ctx = __i915_gem_context_lookup_rcu(file_priv, id);
3549+
if (ctx && !kref_get_unless_zero(&ctx->ref))
3550+
ctx = NULL;
3551+
rcu_read_unlock();
35463552

35473553
return ctx;
35483554
}

drivers/gpu/drm/i915/i915_gem_context.c

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
187187
list_del(&ctx->link);
188188

189189
ida_simple_remove(&ctx->i915->contexts.hw_ida, ctx->hw_id);
190-
kfree(ctx);
190+
kfree_rcu(ctx, rcu);
191191
}
192192

193193
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,
10211021
if (args->ctx_id == DEFAULT_CONTEXT_HANDLE)
10221022
return -ENOENT;
10231023

1024-
ret = i915_mutex_lock_interruptible(dev);
1025-
if (ret)
1026-
return ret;
1027-
10281024
ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1029-
if (IS_ERR(ctx)) {
1030-
mutex_unlock(&dev->struct_mutex);
1031-
return PTR_ERR(ctx);
1032-
}
1025+
if (!ctx)
1026+
return -ENOENT;
1027+
1028+
ret = mutex_lock_interruptible(&dev->struct_mutex);
1029+
if (ret)
1030+
goto out;
10331031

10341032
__destroy_hw_context(ctx, file_priv);
10351033
mutex_unlock(&dev->struct_mutex);
10361034

1037-
DRM_DEBUG("HW context %d destroyed\n", args->ctx_id);
1035+
out:
1036+
i915_gem_context_put(ctx);
10381037
return 0;
10391038
}
10401039

@@ -1044,17 +1043,11 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
10441043
struct drm_i915_file_private *file_priv = file->driver_priv;
10451044
struct drm_i915_gem_context_param *args = data;
10461045
struct i915_gem_context *ctx;
1047-
int ret;
1048-
1049-
ret = i915_mutex_lock_interruptible(dev);
1050-
if (ret)
1051-
return ret;
1046+
int ret = 0;
10521047

10531048
ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1054-
if (IS_ERR(ctx)) {
1055-
mutex_unlock(&dev->struct_mutex);
1056-
return PTR_ERR(ctx);
1057-
}
1049+
if (!ctx)
1050+
return -ENOENT;
10581051

10591052
args->size = 0;
10601053
switch (args->param) {
@@ -1082,8 +1075,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
10821075
ret = -EINVAL;
10831076
break;
10841077
}
1085-
mutex_unlock(&dev->struct_mutex);
10861078

1079+
i915_gem_context_put(ctx);
10871080
return ret;
10881081
}
10891082

@@ -1095,15 +1088,13 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
10951088
struct i915_gem_context *ctx;
10961089
int ret;
10971090

1091+
ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1092+
if (!ctx)
1093+
return -ENOENT;
1094+
10981095
ret = i915_mutex_lock_interruptible(dev);
10991096
if (ret)
1100-
return ret;
1101-
1102-
ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
1103-
if (IS_ERR(ctx)) {
1104-
mutex_unlock(&dev->struct_mutex);
1105-
return PTR_ERR(ctx);
1106-
}
1097+
goto out;
11071098

11081099
switch (args->param) {
11091100
case I915_CONTEXT_PARAM_BAN_PERIOD:
@@ -1141,6 +1132,8 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
11411132
}
11421133
mutex_unlock(&dev->struct_mutex);
11431134

1135+
out:
1136+
i915_gem_context_put(ctx);
11441137
return ret;
11451138
}
11461139

@@ -1155,27 +1148,31 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
11551148
if (args->flags || args->pad)
11561149
return -EINVAL;
11571150

1158-
ret = i915_mutex_lock_interruptible(dev);
1159-
if (ret)
1160-
return ret;
1151+
ret = -ENOENT;
1152+
rcu_read_lock();
1153+
ctx = __i915_gem_context_lookup_rcu(file->driver_priv, args->ctx_id);
1154+
if (!ctx)
1155+
goto out;
11611156

1162-
ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id);
1163-
if (IS_ERR(ctx)) {
1164-
mutex_unlock(&dev->struct_mutex);
1165-
return PTR_ERR(ctx);
1166-
}
1157+
/*
1158+
* We opt for unserialised reads here. This may result in tearing
1159+
* in the extremely unlikely event of a GPU hang on this context
1160+
* as we are querying them. If we need that extra layer of protection,
1161+
* we should wrap the hangstats with a seqlock.
1162+
*/
11671163

11681164
if (capable(CAP_SYS_ADMIN))
11691165
args->reset_count = i915_reset_count(&dev_priv->gpu_error);
11701166
else
11711167
args->reset_count = 0;
11721168

1173-
args->batch_active = ctx->guilty_count;
1174-
args->batch_pending = ctx->active_count;
1175-
1176-
mutex_unlock(&dev->struct_mutex);
1169+
args->batch_active = READ_ONCE(ctx->guilty_count);
1170+
args->batch_pending = READ_ONCE(ctx->active_count);
11771171

1178-
return 0;
1172+
ret = 0;
1173+
out:
1174+
rcu_read_unlock();
1175+
return ret;
11791176
}
11801177

11811178
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)

drivers/gpu/drm/i915/i915_gem_context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ struct i915_gem_context {
9999
*/
100100
struct kref ref;
101101

102+
/**
103+
* @rcu: rcu_head for deferred freeing.
104+
*/
105+
struct rcu_head rcu;
106+
102107
/**
103108
* @flags: small set of booleans
104109
*/

drivers/gpu/drm/i915/i915_gem_execbuffer.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -669,16 +669,17 @@ static int eb_select_context(struct i915_execbuffer *eb)
669669
struct i915_gem_context *ctx;
670670

671671
ctx = i915_gem_context_lookup(eb->file->driver_priv, eb->args->rsvd1);
672-
if (unlikely(IS_ERR(ctx)))
673-
return PTR_ERR(ctx);
672+
if (unlikely(!ctx))
673+
return -ENOENT;
674674

675675
if (unlikely(i915_gem_context_is_banned(ctx))) {
676676
DRM_DEBUG("Context %u tried to submit while banned\n",
677677
ctx->user_handle);
678+
i915_gem_context_put(ctx);
678679
return -EIO;
679680
}
680681

681-
eb->ctx = i915_gem_context_get(ctx);
682+
eb->ctx = ctx;
682683
eb->vm = ctx->ppgtt ? &ctx->ppgtt->base : &eb->i915->ggtt.base;
683684

684685
eb->context_flags = 0;
@@ -2127,7 +2128,6 @@ i915_gem_do_execbuffer(struct drm_device *dev,
21272128
if (DBG_FORCE_RELOC || !(args->flags & I915_EXEC_NO_RELOC))
21282129
args->flags |= __EXEC_HAS_RELOC;
21292130
eb.exec = exec;
2130-
eb.ctx = NULL;
21312131
eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS;
21322132
if (USES_FULL_PPGTT(eb.i915))
21332133
eb.invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
@@ -2182,6 +2182,10 @@ i915_gem_do_execbuffer(struct drm_device *dev,
21822182
if (eb_create(&eb))
21832183
return -ENOMEM;
21842184

2185+
err = eb_select_context(&eb);
2186+
if (unlikely(err))
2187+
goto err_destroy;
2188+
21852189
/*
21862190
* Take a local wakeref for preparing to dispatch the execbuf as
21872191
* we expect to access the hardware fairly frequently in the
@@ -2190,14 +2194,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
21902194
* 100ms.
21912195
*/
21922196
intel_runtime_pm_get(eb.i915);
2197+
21932198
err = i915_mutex_lock_interruptible(dev);
21942199
if (err)
21952200
goto err_rpm;
21962201

2197-
err = eb_select_context(&eb);
2198-
if (unlikely(err))
2199-
goto err_unlock;
2200-
22012202
err = eb_relocate(&eb);
22022203
if (err)
22032204
/*
@@ -2333,11 +2334,11 @@ i915_gem_do_execbuffer(struct drm_device *dev,
23332334
err_vma:
23342335
if (eb.exec)
23352336
eb_release_vmas(&eb);
2336-
i915_gem_context_put(eb.ctx);
2337-
err_unlock:
23382337
mutex_unlock(&dev->struct_mutex);
23392338
err_rpm:
23402339
intel_runtime_pm_put(eb.i915);
2340+
i915_gem_context_put(eb.ctx);
2341+
err_destroy:
23412342
eb_destroy(&eb);
23422343
if (out_fence_fd != -1)
23432344
put_unused_fd(out_fence_fd);

0 commit comments

Comments
 (0)