[Intel-gfx] [PATCH 21/27] drm/i915: Move context management under GEM

Tvrtko Ursulin tvrtko.ursulin at linux.intel.com
Wed Oct 2 16:09:26 UTC 2019


Ping on some comments from the previous round:

On 26/09/2019 14:57, Tvrtko Ursulin wrote:
> 
> On 25/09/2019 11:01, Chris Wilson wrote:
>> Keep track of the GEM contexts underneath i915->gem.contexts and assign
>> them their own lock for the purposes of list management.
>>
>> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
>> Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
>> ---
>>   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 155 +++++++-----------
>>   drivers/gpu/drm/i915/gem/i915_gem_context.h   |   4 +-
>>   .../gpu/drm/i915/gem/i915_gem_context_types.h |   2 +-
>>   .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |   2 +-
>>   drivers/gpu/drm/i915/gem/i915_gem_userptr.c   |   2 +-
>>   .../gpu/drm/i915/gem/selftests/huge_pages.c   |  12 +-
>>   .../drm/i915/gem/selftests/i915_gem_context.c | 122 ++++++--------
>>   .../gpu/drm/i915/gem/selftests/mock_context.c |   4 +-
>>   drivers/gpu/drm/i915/gt/intel_context.c       |   8 +-
>>   drivers/gpu/drm/i915/gt/selftest_context.c    |  24 +--
>>   drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |  19 +--
>>   drivers/gpu/drm/i915/gt/selftest_lrc.c        |   4 +-
>>   .../gpu/drm/i915/gt/selftest_workarounds.c    |  10 +-
>>   drivers/gpu/drm/i915/gvt/scheduler.c          |  20 +--
>>   drivers/gpu/drm/i915/i915_debugfs.c           |  50 +++---
>>   drivers/gpu/drm/i915/i915_drv.c               |   2 -
>>   drivers/gpu/drm/i915/i915_drv.h               |  27 +--
>>   drivers/gpu/drm/i915/i915_gem.c               |  10 +-
>>   drivers/gpu/drm/i915/i915_gem_gtt.c           |   4 +-
>>   drivers/gpu/drm/i915/i915_perf.c              |  24 ++-
>>   drivers/gpu/drm/i915/i915_sysfs.c             |  77 ++++-----
>>   drivers/gpu/drm/i915/i915_trace.h             |   2 +-
>>   drivers/gpu/drm/i915/selftests/i915_gem.c     |   8 -
>>   .../gpu/drm/i915/selftests/i915_gem_evict.c   |   3 -
>>   drivers/gpu/drm/i915/selftests/i915_gem_gtt.c |   4 +-
>>   drivers/gpu/drm/i915/selftests/i915_request.c |  11 +-
>>   drivers/gpu/drm/i915/selftests/i915_vma.c     |   5 +-
>>   .../gpu/drm/i915/selftests/mock_gem_device.c  |   6 +-
>>   28 files changed, 272 insertions(+), 349 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c 
>> b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> index 4e59b809d901..a77f439358d7 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> @@ -219,9 +219,12 @@ static struct i915_gem_engines 
>> *default_engines(struct i915_gem_context *ctx)
>>   static void i915_gem_context_free(struct i915_gem_context *ctx)
>>   {
>> -    lockdep_assert_held(&ctx->i915->drm.struct_mutex);
>>       GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
>> +    spin_lock(&ctx->i915->gem.contexts.lock);
>> +    list_del(&ctx->link);
>> +    spin_unlock(&ctx->i915->gem.contexts.lock);
>> +
>>       free_engines(rcu_access_pointer(ctx->engines));
>>       mutex_destroy(&ctx->engines_mutex);
>> @@ -231,56 +234,40 @@ static void i915_gem_context_free(struct 
>> i915_gem_context *ctx)
>>       kfree(ctx->name);
>>       put_pid(ctx->pid);
>> -    list_del(&ctx->link);
>>       mutex_destroy(&ctx->mutex);
>>       kfree_rcu(ctx, rcu);
>>   }
>> -static void contexts_free(struct drm_i915_private *i915)
>> +static void contexts_free_all(struct llist_node *list)
>>   {
>> -    struct llist_node *freed = llist_del_all(&i915->contexts.free_list);
>>       struct i915_gem_context *ctx, *cn;
>> -    lockdep_assert_held(&i915->drm.struct_mutex);
>> -
>> -    llist_for_each_entry_safe(ctx, cn, freed, free_link)
>> +    llist_for_each_entry_safe(ctx, cn, list, free_link)
>>           i915_gem_context_free(ctx);
>>   }
>> -static void contexts_free_first(struct drm_i915_private *i915)
>> +static void contexts_flush_free(struct i915_gem_contexts *gc)
>>   {
>> -    struct i915_gem_context *ctx;
>> -    struct llist_node *freed;
>> -
>> -    lockdep_assert_held(&i915->drm.struct_mutex);
>> -
>> -    freed = llist_del_first(&i915->contexts.free_list);
>> -    if (!freed)
>> -        return;
>> -
>> -    ctx = container_of(freed, typeof(*ctx), free_link);
>> -    i915_gem_context_free(ctx);
>> +    contexts_free_all(llist_del_all(&gc->free_list));
>>   }
>>   static void contexts_free_worker(struct work_struct *work)
>>   {
>> -    struct drm_i915_private *i915 =
>> -        container_of(work, typeof(*i915), contexts.free_work);
>> +    struct i915_gem_contexts *gc =
>> +        container_of(work, typeof(*gc), free_work);
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -    contexts_free(i915);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>> +    contexts_flush_free(gc);
>>   }
>>   void i915_gem_context_release(struct kref *ref)
>>   {
>>       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), 
>> ref);
>> -    struct drm_i915_private *i915 = ctx->i915;
>> +    struct i915_gem_contexts *gc = &ctx->i915->gem.contexts;
>>       trace_i915_context_free(ctx);
>> -    if (llist_add(&ctx->free_link, &i915->contexts.free_list))
>> -        queue_work(i915->wq, &i915->contexts.free_work);
>> +    if (llist_add(&ctx->free_link, &gc->free_list))
>> +        queue_work(ctx->i915->wq, &gc->free_work);
> 
> At first I thought gc was some sort of garbage collection list. But it 
> is a GEM contexts list. :) This hunk looks completely avoidable, I don't 
> see it brings much benefit on balance since in turn it adds ctx->i915 
> twice . But as you wish..
> 
>>   }
>>   static inline struct i915_gem_engines *
>> @@ -359,8 +346,8 @@ static void context_close(struct i915_gem_context 
>> *ctx)
>>   {
>>       i915_gem_context_set_closed(ctx);
>> -    if (ctx->vm)
>> -        i915_vm_close(ctx->vm);
>> +    if (rcu_access_pointer(ctx->vm))
>> +        i915_vm_close(rcu_dereference_protected(ctx->vm, true));
>>       mutex_lock(&ctx->mutex);
>> @@ -394,7 +381,6 @@ __create_context(struct drm_i915_private *i915)
>>           return ERR_PTR(-ENOMEM);
>>       kref_init(&ctx->ref);
>> -    list_add_tail(&ctx->link, &i915->contexts.list);
>>       ctx->i915 = i915;
>>       ctx->sched.priority = I915_USER_PRIORITY(I915_PRIORITY_NORMAL);
>>       mutex_init(&ctx->mutex);
>> @@ -435,6 +421,10 @@ __create_context(struct drm_i915_private *i915)
>>       for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
>>           ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
>> +    spin_lock(&i915->gem.contexts.lock);
>> +    list_add_tail(&ctx->link, &i915->gem.contexts.list);
>> +    spin_unlock(&i915->gem.contexts.lock);
>> +
>>       return ctx;
>>   err_free:
>> @@ -464,11 +454,11 @@ static void __apply_ppgtt(struct intel_context 
>> *ce, void *vm)
>>   static struct i915_address_space *
>>   __set_ppgtt(struct i915_gem_context *ctx, struct i915_address_space 
>> *vm)
>>   {
>> -    struct i915_address_space *old = ctx->vm;
>> +    struct i915_address_space *old = 
>> rcu_dereference_protected(ctx->vm, 1);
>>       GEM_BUG_ON(old && i915_vm_is_4lvl(vm) != i915_vm_is_4lvl(old));
>> -    ctx->vm = i915_vm_open(vm);
>> +    rcu_assign_pointer(ctx->vm, i915_vm_open(vm));
> 
> Are updaters here serialized? Lost track if struct mutex is still held 
> in set_ppgtt at this point in the series or not.. Thinking of "old = 
> rcu_dereference_protected.." and here.
> 
>>       context_apply_all(ctx, __apply_ppgtt, vm);
>>       return old;
>> @@ -477,7 +467,7 @@ __set_ppgtt(struct i915_gem_context *ctx, struct 
>> i915_address_space *vm)
>>   static void __assign_ppgtt(struct i915_gem_context *ctx,
>>                  struct i915_address_space *vm)
>>   {
>> -    if (vm == ctx->vm)
>> +    if (vm == rcu_access_pointer(ctx->vm))
>>           return;
>>       vm = __set_ppgtt(ctx, vm);
>> @@ -509,27 +499,25 @@ static void __assign_timeline(struct 
>> i915_gem_context *ctx,
>>   }
>>   static struct i915_gem_context *
>> -i915_gem_create_context(struct drm_i915_private *dev_priv, unsigned 
>> int flags)
>> +i915_gem_create_context(struct drm_i915_private *i915, unsigned int 
>> flags)
>>   {
>>       struct i915_gem_context *ctx;
>> -    lockdep_assert_held(&dev_priv->drm.struct_mutex);
>> -
>>       if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
>> -        !HAS_EXECLISTS(dev_priv))
>> +        !HAS_EXECLISTS(i915))
>>           return ERR_PTR(-EINVAL);
>> -    /* Reap the most stale context */
>> -    contexts_free_first(dev_priv);
>> +    /* Reap the stale contexts */
>> +    contexts_flush_free(&i915->gem.contexts);
>> -    ctx = __create_context(dev_priv);
>> +    ctx = __create_context(i915);
>>       if (IS_ERR(ctx))
>>           return ctx;
>> -    if (HAS_FULL_PPGTT(dev_priv)) {
>> +    if (HAS_FULL_PPGTT(i915)) {
>>           struct i915_ppgtt *ppgtt;
>> -        ppgtt = i915_ppgtt_create(dev_priv);
>> +        ppgtt = i915_ppgtt_create(i915);
>>           if (IS_ERR(ppgtt)) {
>>               DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
>>                        PTR_ERR(ppgtt));
>> @@ -544,7 +532,7 @@ i915_gem_create_context(struct drm_i915_private 
>> *dev_priv, unsigned int flags)
>>       if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
>>           struct intel_timeline *timeline;
>> -        timeline = intel_timeline_create(&dev_priv->gt, NULL);
>> +        timeline = intel_timeline_create(&i915->gt, NULL);
>>           if (IS_ERR(timeline)) {
>>               context_close(ctx);
>>               return ERR_CAST(timeline);
>> @@ -590,48 +578,40 @@ i915_gem_context_create_kernel(struct 
>> drm_i915_private *i915, int prio)
>>       return ctx;
>>   }
>> -static void init_contexts(struct drm_i915_private *i915)
>> +static void init_contexts(struct i915_gem_contexts *gc)
>>   {
>> -    mutex_init(&i915->contexts.mutex);
>> -    INIT_LIST_HEAD(&i915->contexts.list);
>> -
>> -    /* Using the simple ida interface, the max is limited by 
>> sizeof(int) */
>> -    BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX);
>> -    BUILD_BUG_ON(GEN11_MAX_CONTEXT_HW_ID > INT_MAX);
>> -    ida_init(&i915->contexts.hw_ida);
>> -    INIT_LIST_HEAD(&i915->contexts.hw_id_list);
> 
> This (and some more bits) belong to the hw_id removal patch.
> 
>> +    spin_lock_init(&gc->lock);
>> +    INIT_LIST_HEAD(&gc->list);
>> -    INIT_WORK(&i915->contexts.free_work, contexts_free_worker);
>> -    init_llist_head(&i915->contexts.free_list);
>> +    INIT_WORK(&gc->free_work, contexts_free_worker);
>> +    init_llist_head(&gc->free_list);
>>   }
>> -int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
>> +int i915_gem_init_contexts(struct drm_i915_private *i915)
>>   {
>>       struct i915_gem_context *ctx;
>>       /* Reassure ourselves we are only called once */
>> -    GEM_BUG_ON(dev_priv->kernel_context);
>> +    GEM_BUG_ON(i915->kernel_context);
>> -    init_contexts(dev_priv);
>> +    init_contexts(&i915->gem.contexts);
>>       /* lowest priority; idle task */
>> -    ctx = i915_gem_context_create_kernel(dev_priv, I915_PRIORITY_MIN);
>> +    ctx = i915_gem_context_create_kernel(i915, I915_PRIORITY_MIN);
>>       if (IS_ERR(ctx)) {
>>           DRM_ERROR("Failed to create default global context\n");
>>           return PTR_ERR(ctx);
>>       }
>> -    dev_priv->kernel_context = ctx;
>> +    i915->kernel_context = ctx;
>>       DRM_DEBUG_DRIVER("%s context support initialized\n",
>> -             DRIVER_CAPS(dev_priv)->has_logical_contexts ?
>> +             DRIVER_CAPS(i915)->has_logical_contexts ?
>>                "logical" : "fake");
>>       return 0;
>>   }
>> -void i915_gem_contexts_fini(struct drm_i915_private *i915)
>> +void i915_gem_driver_release__contexts(struct drm_i915_private *i915)
>>   {
>> -    lockdep_assert_held(&i915->drm.struct_mutex);
>> -
>>       destroy_kernel_context(&i915->kernel_context);
>>   }
>> @@ -653,8 +633,8 @@ static int gem_context_register(struct 
>> i915_gem_context *ctx,
>>       int ret;
>>       ctx->file_priv = fpriv;
>> -    if (ctx->vm)
>> -        ctx->vm->file = fpriv;
>> +    if (rcu_access_pointer(ctx->vm))
>> +        rcu_dereference_protected(ctx->vm, true)->file = fpriv;
> 
> Here rcu accesses are just to satisfy sparse?
> 
>>       ctx->pid = get_task_pid(current, PIDTYPE_PID);
>>       ctx->name = kasprintf(GFP_KERNEL, "%s[%d]",
>> @@ -691,9 +671,7 @@ int i915_gem_context_open(struct drm_i915_private 
>> *i915,
>>       idr_init(&file_priv->context_idr);
>>       idr_init_base(&file_priv->vm_idr, 1);
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       ctx = i915_gem_create_context(i915, 0);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       if (IS_ERR(ctx)) {
>>           err = PTR_ERR(ctx);
>>           goto err;
>> @@ -721,6 +699,7 @@ int i915_gem_context_open(struct drm_i915_private 
>> *i915,
>>   void i915_gem_context_close(struct drm_file *file)
>>   {
>>       struct drm_i915_file_private *file_priv = file->driver_priv;
>> +    struct drm_i915_private *i915 = file_priv->dev_priv;
>>       idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL);
>>       idr_destroy(&file_priv->context_idr);
>> @@ -729,6 +708,8 @@ void i915_gem_context_close(struct drm_file *file)
>>       idr_for_each(&file_priv->vm_idr, vm_idr_cleanup, NULL);
>>       idr_destroy(&file_priv->vm_idr);
>>       mutex_destroy(&file_priv->vm_idr_lock);
>> +
>> +    contexts_flush_free(&i915->gem.contexts);
>>   }
>>   int i915_gem_vm_create_ioctl(struct drm_device *dev, void *data,
>> @@ -907,16 +888,12 @@ static int get_ppgtt(struct 
>> drm_i915_file_private *file_priv,
>>       struct i915_address_space *vm;
>>       int ret;
>> -    if (!ctx->vm)
>> +    if (!rcu_access_pointer(ctx->vm))
>>           return -ENODEV;
>> -    /* XXX rcu acquire? */
>> -    ret = mutex_lock_interruptible(&ctx->i915->drm.struct_mutex);
>> -    if (ret)
>> -        return ret;
>> -
>> +    rcu_read_lock();
>>       vm = i915_vm_get(ctx->vm);
>> -    mutex_unlock(&ctx->i915->drm.struct_mutex);
>> +    rcu_read_unlock();
>>       ret = mutex_lock_interruptible(&file_priv->vm_idr_lock);
>>       if (ret)
>> @@ -1025,7 +1002,7 @@ static int set_ppgtt(struct 
>> drm_i915_file_private *file_priv,
>>       if (args->size)
>>           return -EINVAL;
>> -    if (!ctx->vm)
>> +    if (!rcu_access_pointer(ctx->vm))
>>           return -ENODEV;
>>       if (upper_32_bits(args->value))
>> @@ -1039,17 +1016,15 @@ static int set_ppgtt(struct 
>> drm_i915_file_private *file_priv,
>>       if (!vm)
>>           return -ENOENT;
>> -    err = mutex_lock_interruptible(&ctx->i915->drm.struct_mutex);
>> +    err = mutex_lock_interruptible(&ctx->mutex);
>>       if (err)
>>           goto out;
>> -    if (vm == ctx->vm)
>> +    if (vm == rcu_access_pointer(ctx->vm))
>>           goto unlock;
>>       /* Teardown the existing obj:vma cache, it will have to be 
>> rebuilt. */
>> -    mutex_lock(&ctx->mutex);
>>       lut_close(ctx);
>> -    mutex_unlock(&ctx->mutex);
>>       old = __set_ppgtt(ctx, vm);
>> @@ -1069,8 +1044,7 @@ static int set_ppgtt(struct 
>> drm_i915_file_private *file_priv,
>>       }
>>   unlock:
>> -    mutex_unlock(&ctx->i915->drm.struct_mutex);
>> -
>> +    mutex_unlock(&ctx->mutex);
>>   out:
>>       i915_vm_put(vm);
>>       return err;
>> @@ -1953,7 +1927,7 @@ static int clone_vm(struct i915_gem_context *dst,
>>       rcu_read_lock();
>>       do {
>> -        vm = READ_ONCE(src->vm);
>> +        vm = rcu_dereference(src->vm);
>>           if (!vm)
>>               break;
>> @@ -1975,7 +1949,7 @@ static int clone_vm(struct i915_gem_context *dst,
>>            * it cannot be reallocated elsewhere.
>>            */
>> -        if (vm == READ_ONCE(src->vm))
>> +        if (vm == rcu_access_pointer(src->vm))
>>               break;
>>           i915_vm_put(vm);
>> @@ -2077,12 +2051,7 @@ int i915_gem_context_create_ioctl(struct 
>> drm_device *dev, void *data,
>>           return -EIO;
>>       }
>> -    ret = i915_mutex_lock_interruptible(dev);
>> -    if (ret)
>> -        return ret;
>> -
>>       ext_data.ctx = i915_gem_create_context(i915, args->flags);
>> -    mutex_unlock(&dev->struct_mutex);
>>       if (IS_ERR(ext_data.ctx))
>>           return PTR_ERR(ext_data.ctx);
>> @@ -2209,10 +2178,12 @@ int i915_gem_context_getparam_ioctl(struct 
>> drm_device *dev, void *data,
>>       case I915_CONTEXT_PARAM_GTT_SIZE:
>>           args->size = 0;
>> -        if (ctx->vm)
>> -            args->value = ctx->vm->total;
>> +        rcu_read_lock();
>> +        if (rcu_access_pointer(ctx->vm))
>> +            args->value = rcu_dereference(ctx->vm)->total;
>>           else
>>               args->value = to_i915(dev)->ggtt.vm.total;
>> +        rcu_read_unlock();
>>           break;
>>       case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
>> @@ -2283,7 +2254,7 @@ int i915_gem_context_setparam_ioctl(struct 
>> drm_device *dev, void *data,
>>   int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
>>                          void *data, struct drm_file *file)
>>   {
>> -    struct drm_i915_private *dev_priv = to_i915(dev);
>> +    struct drm_i915_private *i915 = to_i915(dev);
>>       struct drm_i915_reset_stats *args = data;
>>       struct i915_gem_context *ctx;
>>       int ret;
>> @@ -2305,7 +2276,7 @@ int i915_gem_context_reset_stats_ioctl(struct 
>> drm_device *dev,
>>        */
>>       if (capable(CAP_SYS_ADMIN))
>> -        args->reset_count = i915_reset_count(&dev_priv->gpu_error);
>> +        args->reset_count = i915_reset_count(&i915->gpu_error);
>>       else
>>           args->reset_count = 0;
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h 
>> b/drivers/gpu/drm/i915/gem/i915_gem_context.h
>> index 1b0df53436cf..4ee5dfc5794e 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.h
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h
>> @@ -133,8 +133,8 @@ static inline bool 
>> i915_gem_context_is_kernel(struct i915_gem_context *ctx)
>>   }
>>   /* i915_gem_context.c */
>> -int __must_check i915_gem_contexts_init(struct drm_i915_private 
>> *dev_priv);
>> -void i915_gem_contexts_fini(struct drm_i915_private *dev_priv);
>> +int __must_check i915_gem_init_contexts(struct drm_i915_private *i915);
>> +void i915_gem_driver_release__contexts(struct drm_i915_private *i915);
>>   int i915_gem_context_open(struct drm_i915_private *i915,
>>                 struct drm_file *file);
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h 
>> b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
>> index 6419da7c9f90..a3ecd19f2303 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
>> @@ -88,7 +88,7 @@ struct i915_gem_context {
>>        * In other modes, this is a NULL pointer with the expectation that
>>        * the caller uses the shared global GTT.
>>        */
>> -    struct i915_address_space *vm;
>> +    struct i915_address_space __rcu *vm;
>>       /**
>>        * @pid: process id of creator
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c 
>> b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>> index 88a881be12ec..98816c35ffc3 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>> @@ -728,7 +728,7 @@ static int eb_select_context(struct 
>> i915_execbuffer *eb)
>>           return -ENOENT;
>>       eb->gem_context = ctx;
>> -    if (ctx->vm)
>> +    if (rcu_access_pointer(ctx->vm))
>>           eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
>>       eb->context_flags = 0;
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c 
>> b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
>> index 27573ef903b4..7c225e1d2a11 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
>> @@ -757,7 +757,7 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
>>            * On almost all of the older hw, we cannot tell the GPU that
>>            * a page is readonly.
>>            */
>> -        vm = dev_priv->kernel_context->vm;
>> +        vm = rcu_dereference_protected(dev_priv->kernel_context->vm, 
>> true);
> 
> Hm, should it not be rcu_dereference here?
> 
>>           if (!vm || !vm->has_read_only)
>>               return -ENODEV;
>>       }
>> diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c 
>> b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
>> index 98b2a6ccfcc1..e204e653b459 100644
>> --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
>> +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c
>> @@ -1322,7 +1322,7 @@ static int igt_ppgtt_pin_update(void *arg)
>>       struct i915_gem_context *ctx = arg;
>>       struct drm_i915_private *dev_priv = ctx->i915;
>>       unsigned long supported = INTEL_INFO(dev_priv)->page_sizes;
>> -    struct i915_address_space *vm = ctx->vm;
>> +    struct i915_address_space *vm = 
>> rcu_dereference_protected(ctx->vm, 1);
>>       struct drm_i915_gem_object *obj;
>>       struct i915_gem_engines_iter it;
>>       struct intel_context *ce;
>> @@ -1460,7 +1460,8 @@ static int igt_tmpfs_fallback(void *arg)
>>       struct i915_gem_context *ctx = arg;
>>       struct drm_i915_private *i915 = ctx->i915;
>>       struct vfsmount *gemfs = i915->mm.gemfs;
>> -    struct i915_address_space *vm = ctx->vm ?: &i915->ggtt.vm;
>> +    struct i915_address_space *vm =
>> +        rcu_dereference_protected(ctx->vm, true) ?: &i915->ggtt.vm;
>>       struct drm_i915_gem_object *obj;
>>       struct i915_vma *vma;
>>       u32 *vaddr;
>> @@ -1517,7 +1518,8 @@ static int igt_shrink_thp(void *arg)
>>   {
>>       struct i915_gem_context *ctx = arg;
>>       struct drm_i915_private *i915 = ctx->i915;
>> -    struct i915_address_space *vm = ctx->vm ?: &i915->ggtt.vm;
>> +    struct i915_address_space *vm =
>> +        rcu_dereference_protected(ctx->vm, true) ?: &i915->ggtt.vm;
>>       struct drm_i915_gem_object *obj;
>>       struct i915_gem_engines_iter it;
>>       struct intel_context *ce;
>> @@ -1699,8 +1701,8 @@ int i915_gem_huge_page_live_selftests(struct 
>> drm_i915_private *i915)
>>           goto out_unlock;
>>       }
>> -    if (ctx->vm)
>> -        ctx->vm->scrub_64K = true;
>> +    if (rcu_access_pointer(ctx->vm))
>> +        rcu_dereference_protected(ctx->vm, true)->scrub_64K = true;
>>       err = i915_subtests(tests, ctx);
>> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c 
>> b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
>> index a8a9293f4ac6..7de1c0078d6f 100644
>> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
>> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
>> @@ -53,19 +53,17 @@ static int live_nop_switch(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       ctx = kcalloc(nctx, sizeof(*ctx), GFP_KERNEL);
>>       if (!ctx) {
>>           err = -ENOMEM;
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>>       for (n = 0; n < nctx; n++) {
>>           ctx[n] = live_context(i915, file);
>>           if (IS_ERR(ctx[n])) {
>>               err = PTR_ERR(ctx[n]);
>> -            goto out_unlock;
>> +            goto out_file;
>>           }
>>       }
>> @@ -79,7 +77,7 @@ static int live_nop_switch(void *arg)
>>               rq = igt_request_alloc(ctx[n], engine);
>>               if (IS_ERR(rq)) {
>>                   err = PTR_ERR(rq);
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               i915_request_add(rq);
>>           }
>> @@ -87,7 +85,7 @@ static int live_nop_switch(void *arg)
>>               pr_err("Failed to populated %d contexts\n", nctx);
>>               intel_gt_set_wedged(&i915->gt);
>>               err = -EIO;
>> -            goto out_unlock;
>> +            goto out_file;
>>           }
>>           times[1] = ktime_get_raw();
>> @@ -97,7 +95,7 @@ static int live_nop_switch(void *arg)
>>           err = igt_live_test_begin(&t, i915, __func__, engine->name);
>>           if (err)
>> -            goto out_unlock;
>> +            goto out_file;
>>           end_time = jiffies + i915_selftest.timeout_jiffies;
>>           for_each_prime_number_from(prime, 2, 8192) {
>> @@ -107,7 +105,7 @@ static int live_nop_switch(void *arg)
>>                   rq = igt_request_alloc(ctx[n % nctx], engine);
>>                   if (IS_ERR(rq)) {
>>                       err = PTR_ERR(rq);
>> -                    goto out_unlock;
>> +                    goto out_file;
>>                   }
>>                   /*
>> @@ -143,7 +141,7 @@ static int live_nop_switch(void *arg)
>>           err = igt_live_test_end(&t);
>>           if (err)
>> -            goto out_unlock;
>> +            goto out_file;
>>           pr_info("Switch latencies on %s: 1 = %lluns, %lu = %lluns\n",
>>               engine->name,
>> @@ -151,8 +149,7 @@ static int live_nop_switch(void *arg)
>>               prime - 1, div64_u64(ktime_to_ns(times[1]), prime - 1));
>>       }
>> -out_unlock:
>> -    mutex_unlock(&i915->drm.struct_mutex);
>> +out_file:
>>       mock_file_free(i915, file);
>>       return err;
>>   }
>> @@ -412,11 +409,9 @@ static int igt_ctx_exec(void *arg)
>>           if (IS_ERR(file))
>>               return PTR_ERR(file);
>> -        mutex_lock(&i915->drm.struct_mutex);
>> -
>>           err = igt_live_test_begin(&t, i915, __func__, engine->name);
>>           if (err)
>> -            goto out_unlock;
>> +            goto out_file;
>>           ncontexts = 0;
>>           ndwords = 0;
>> @@ -428,7 +423,7 @@ static int igt_ctx_exec(void *arg)
>>               ctx = kernel_context(i915);
>>               if (IS_ERR(ctx)) {
>>                   err = PTR_ERR(ctx);
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
>> @@ -440,7 +435,7 @@ static int igt_ctx_exec(void *arg)
>>                       err = PTR_ERR(obj);
>>                       intel_context_put(ce);
>>                       kernel_context_close(ctx);
>> -                    goto out_unlock;
>> +                    goto out_file;
>>                   }
>>               }
>> @@ -449,17 +444,18 @@ static int igt_ctx_exec(void *arg)
>>                   pr_err("Failed to fill dword %lu [%lu/%lu] with gpu 
>> (%s) [full-ppgtt? %s], err=%d\n",
>>                          ndwords, dw, max_dwords(obj),
>>                          engine->name,
>> -                       yesno(!!ctx->vm), err);
>> +                       yesno(!!rcu_access_pointer(ctx->vm)),
>> +                       err);
>>                   intel_context_put(ce);
>>                   kernel_context_close(ctx);
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               err = throttle(ce, tq, ARRAY_SIZE(tq));
>>               if (err) {
>>                   intel_context_put(ce);
>>                   kernel_context_close(ctx);
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               if (++dw == max_dwords(obj)) {
>> @@ -489,11 +485,10 @@ static int igt_ctx_exec(void *arg)
>>               dw += rem;
>>           }
>> -out_unlock:
>> +out_file:
>>           throttle_release(tq, ARRAY_SIZE(tq));
>>           if (igt_live_test_end(&t))
>>               err = -EIO;
>> -        mutex_unlock(&i915->drm.struct_mutex);
>>           mock_file_free(i915, file);
>>           if (err)
>> @@ -528,22 +523,20 @@ static int igt_shared_ctx_exec(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       parent = live_context(i915, file);
>>       if (IS_ERR(parent)) {
>>           err = PTR_ERR(parent);
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>>       if (!parent->vm) { /* not full-ppgtt; nothing to share */
>>           err = 0;
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>>       err = igt_live_test_begin(&t, i915, __func__, "");
>>       if (err)
>> -        goto out_unlock;
>> +        goto out_file;
>>       for_each_engine(engine, i915, id) {
>>           unsigned long ncontexts, ndwords, dw;
>> @@ -587,7 +580,8 @@ static int igt_shared_ctx_exec(void *arg)
>>                   pr_err("Failed to fill dword %lu [%lu/%lu] with gpu 
>> (%s) [full-ppgtt? %s], err=%d\n",
>>                          ndwords, dw, max_dwords(obj),
>>                          engine->name,
>> -                       yesno(!!ctx->vm), err);
>> +                       yesno(!!rcu_access_pointer(ctx->vm)),
>> +                       err);
>>                   intel_context_put(ce);
>>                   kernel_context_close(ctx);
>>                   goto out_test;
>> @@ -626,17 +620,13 @@ static int igt_shared_ctx_exec(void *arg)
>>               dw += rem;
>>           }
>> -        mutex_unlock(&i915->drm.struct_mutex);
>>           i915_gem_drain_freed_objects(i915);
>> -        mutex_lock(&i915->drm.struct_mutex);
>>       }
>>   out_test:
>>       throttle_release(tq, ARRAY_SIZE(tq));
>>       if (igt_live_test_end(&t))
>>           err = -EIO;
>> -out_unlock:
>> -    mutex_unlock(&i915->drm.struct_mutex);
>> -
>> +out_file:
>>       mock_file_free(i915, file);
>>       return err;
>>   }
>> @@ -1008,8 +998,6 @@ __igt_ctx_sseu(struct drm_i915_private *i915,
>>       if (flags & TEST_RESET)
>>           igt_global_reset_lock(&i915->gt);
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       ctx = live_context(i915, file);
>>       if (IS_ERR(ctx)) {
>>           ret = PTR_ERR(ctx);
>> @@ -1064,8 +1052,6 @@ __igt_ctx_sseu(struct drm_i915_private *i915,
>>       i915_gem_object_put(obj);
>>   out_unlock:
>> -    mutex_unlock(&i915->drm.struct_mutex);
>> -
>>       if (flags & TEST_RESET)
>>           igt_global_reset_unlock(&i915->gt);
>> @@ -1125,23 +1111,24 @@ static int igt_ctx_readonly(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       err = igt_live_test_begin(&t, i915, __func__, "");
>>       if (err)
>> -        goto out_unlock;
>> +        goto out_file;
>>       ctx = live_context(i915, file);
>>       if (IS_ERR(ctx)) {
>>           err = PTR_ERR(ctx);
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>> -    vm = ctx->vm ?: &i915->ggtt.alias->vm;
>> +    rcu_read_lock();
>> +    vm = rcu_dereference(ctx->vm) ?: &i915->ggtt.alias->vm;
>>       if (!vm || !vm->has_read_only) {
>> +        rcu_read_unlock();
>>           err = 0;
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>> +    rcu_read_unlock();
>>       ndwords = 0;
>>       dw = 0;
>> @@ -1159,7 +1146,7 @@ static int igt_ctx_readonly(void *arg)
>>                   if (IS_ERR(obj)) {
>>                       err = PTR_ERR(obj);
>>                       i915_gem_context_unlock_engines(ctx);
>> -                    goto out_unlock;
>> +                    goto out_file;
>>                   }
>>                   if (prandom_u32_state(&prng) & 1)
>> @@ -1170,15 +1157,17 @@ static int igt_ctx_readonly(void *arg)
>>               if (err) {
>>                   pr_err("Failed to fill dword %lu [%lu/%lu] with gpu 
>> (%s) [full-ppgtt? %s], err=%d\n",
>>                          ndwords, dw, max_dwords(obj),
>> -                       ce->engine->name, yesno(!!ctx->vm), err);
>> +                       ce->engine->name,
>> +                       yesno(!!rcu_access_pointer(ctx->vm)),
>> +                       err);
>>                   i915_gem_context_unlock_engines(ctx);
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               err = throttle(ce, tq, ARRAY_SIZE(tq));
>>               if (err) {
>>                   i915_gem_context_unlock_engines(ctx);
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               if (++dw == max_dwords(obj)) {
>> @@ -1210,11 +1199,10 @@ static int igt_ctx_readonly(void *arg)
>>           dw += rem;
>>       }
>> -out_unlock:
>> +out_file:
>>       throttle_release(tq, ARRAY_SIZE(tq));
>>       if (igt_live_test_end(&t))
>>           err = -EIO;
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       mock_file_free(i915, file);
>>       return err;
>> @@ -1223,7 +1211,7 @@ static int igt_ctx_readonly(void *arg)
>>   static int check_scratch(struct i915_gem_context *ctx, u64 offset)
>>   {
>>       struct drm_mm_node *node =
>> -        __drm_mm_interval_first(&ctx->vm->mm,
>> +        __drm_mm_interval_first(&rcu_dereference_protected(ctx->vm, 
>> true)->mm,
>>                       offset, offset + sizeof(u32) - 1);
>>       if (!node || node->start > offset)
>>           return 0;
>> @@ -1273,7 +1261,9 @@ static int write_to_scratch(struct 
>> i915_gem_context *ctx,
>>       intel_gt_chipset_flush(engine->gt);
>> -    vma = i915_vma_instance(obj, ctx->vm, NULL);
>> +    vma = i915_vma_instance(obj,
>> +                rcu_dereference_protected(ctx->vm, true),
>> +                NULL);
>>       if (IS_ERR(vma)) {
>>           err = PTR_ERR(vma);
>>           goto err;
>> @@ -1372,7 +1362,9 @@ static int read_from_scratch(struct 
>> i915_gem_context *ctx,
>>       intel_gt_chipset_flush(engine->gt);
>> -    vma = i915_vma_instance(obj, ctx->vm, NULL);
>> +    vma = i915_vma_instance(obj,
>> +                rcu_dereference_protected(ctx->vm, true),
>> +                NULL);
>>       if (IS_ERR(vma)) {
>>           err = PTR_ERR(vma);
>>           goto err;
>> @@ -1463,27 +1455,25 @@ static int igt_vm_isolation(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       err = igt_live_test_begin(&t, i915, __func__, "");
>>       if (err)
>> -        goto out_unlock;
>> +        goto out_file;
>>       ctx_a = live_context(i915, file);
>>       if (IS_ERR(ctx_a)) {
>>           err = PTR_ERR(ctx_a);
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>>       ctx_b = live_context(i915, file);
>>       if (IS_ERR(ctx_b)) {
>>           err = PTR_ERR(ctx_b);
>> -        goto out_unlock;
>> +        goto out_file;
>>       }
>>       /* We can only test vm isolation, if the vm are distinct */
>>       if (ctx_a->vm == ctx_b->vm)
>> -        goto out_unlock;
>> +        goto out_file;
>>       vm_total = ctx_a->vm->total;
>>       GEM_BUG_ON(ctx_b->vm->total != vm_total);
>> @@ -1512,7 +1502,7 @@ static int igt_vm_isolation(void *arg)
>>                   err = read_from_scratch(ctx_b, engine,
>>                               offset, &value);
>>               if (err)
>> -                goto out_unlock;
>> +                goto out_file;
>>               if (value) {
>>                   pr_err("%s: Read %08x from scratch (offset 
>> 0x%08x_%08x), after %lu reads!\n",
>> @@ -1521,7 +1511,7 @@ static int igt_vm_isolation(void *arg)
>>                          lower_32_bits(offset),
>>                          this);
>>                   err = -EINVAL;
>> -                goto out_unlock;
>> +                goto out_file;
>>               }
>>               this++;
>> @@ -1531,11 +1521,9 @@ static int igt_vm_isolation(void *arg)
>>       pr_info("Checked %lu scratch offsets across %d engines\n",
>>           count, RUNTIME_INFO(i915)->num_engines);
>> -out_unlock:
>> +out_file:
>>       if (igt_live_test_end(&t))
>>           err = -EIO;
>> -    mutex_unlock(&i915->drm.struct_mutex);
>> -
>>       mock_file_free(i915, file);
>>       return err;
>>   }
>> @@ -1567,13 +1555,9 @@ static int mock_context_barrier(void *arg)
>>        * a request; useful for retiring old state after loading new.
>>        */
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       ctx = mock_context(i915, "mock");
>> -    if (!ctx) {
>> -        err = -ENOMEM;
>> -        goto unlock;
>> -    }
>> +    if (!ctx)
>> +        return -ENOMEM;
>>       counter = 0;
>>       err = context_barrier_task(ctx, 0,
>> @@ -1646,8 +1630,6 @@ static int mock_context_barrier(void *arg)
>>   out:
>>       mock_context_close(ctx);
>> -unlock:
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       return err;
>>   #undef pr_fmt
>>   #define pr_fmt(x) x
>> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c 
>> b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> index ebc46f098561..6ef86e7923a7 100644
>> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> @@ -67,7 +67,7 @@ void mock_context_close(struct i915_gem_context *ctx)
>>   void mock_init_contexts(struct drm_i915_private *i915)
>>   {
>> -    init_contexts(i915);
>> +    init_contexts(&i915->gem.contexts);
>>   }
>>   struct i915_gem_context *
>> @@ -76,8 +76,6 @@ live_context(struct drm_i915_private *i915, struct 
>> drm_file *file)
>>       struct i915_gem_context *ctx;
>>       int err;
>> -    lockdep_assert_held(&i915->drm.struct_mutex);
>> -
>>       ctx = i915_gem_create_context(i915, 0);
>>       if (IS_ERR(ctx))
>>           return ctx;
>> diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
>> b/drivers/gpu/drm/i915/gt/intel_context.c
>> index 35a40c2820a2..107eb03d6dd4 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_context.c
>> +++ b/drivers/gpu/drm/i915/gt/intel_context.c
>> @@ -226,7 +226,13 @@ intel_context_init(struct intel_context *ce,
>>       kref_init(&ce->ref);
>>       ce->gem_context = ctx;
>> -    ce->vm = i915_vm_get(ctx->vm ?: &engine->gt->ggtt->vm);
>> +    rcu_read_lock();
>> +    ce->vm = rcu_dereference(ctx->vm);
>> +    if (ce->vm && !kref_get_unless_zero(&ce->vm->ref))
>> +        ce->vm = NULL;
>> +    if (!ce->vm)
>> +        ce->vm = i915_vm_get(&engine->gt->ggtt->vm);
>> +    rcu_read_unlock();
>>       if (ctx->timeline)
>>           ce->timeline = intel_timeline_get(ctx->timeline);
>> diff --git a/drivers/gpu/drm/i915/gt/selftest_context.c 
>> b/drivers/gpu/drm/i915/gt/selftest_context.c
>> index 86cffbb0a9cb..7c838a57e174 100644
>> --- a/drivers/gpu/drm/i915/gt/selftest_context.c
>> +++ b/drivers/gpu/drm/i915/gt/selftest_context.c
>> @@ -155,13 +155,9 @@ static int live_context_size(void *arg)
>>        * HW tries to write past the end of one.
>>        */
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>> -
>>       fixme = kernel_context(gt->i915);
>> -    if (IS_ERR(fixme)) {
>> -        err = PTR_ERR(fixme);
>> -        goto unlock;
>> -    }
>> +    if (IS_ERR(fixme))
>> +        return PTR_ERR(fixme);
>>       for_each_engine(engine, gt->i915, id) {
>>           struct {
>> @@ -201,8 +197,6 @@ static int live_context_size(void *arg)
>>       }
>>       kernel_context_close(fixme);
>> -unlock:
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>>       return err;
>>   }
>> @@ -305,12 +299,10 @@ static int live_active_context(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>> -
>>       fixme = live_context(gt->i915, file);
>>       if (IS_ERR(fixme)) {
>>           err = PTR_ERR(fixme);
>> -        goto unlock;
>> +        goto out_file;
>>       }
>>       for_each_engine(engine, gt->i915, id) {
>> @@ -323,8 +315,7 @@ static int live_active_context(void *arg)
>>               break;
>>       }
>> -unlock:
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>> +out_file:
>>       mock_file_free(gt->i915, file);
>>       return err;
>>   }
>> @@ -418,12 +409,10 @@ static int live_remote_context(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>> -
>>       fixme = live_context(gt->i915, file);
>>       if (IS_ERR(fixme)) {
>>           err = PTR_ERR(fixme);
>> -        goto unlock;
>> +        goto out_file;
>>       }
>>       for_each_engine(engine, gt->i915, id) {
>> @@ -436,8 +425,7 @@ static int live_remote_context(void *arg)
>>               break;
>>       }
>> -unlock:
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>> +out_file:
>>       mock_file_free(gt->i915, file);
>>       return err;
>>   }
>> diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c 
>> b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
>> index f2b5ab1e5a2e..1b836ff0a756 100644
>> --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
>> +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
>> @@ -58,9 +58,7 @@ static int hang_init(struct hang *h, struct intel_gt 
>> *gt)
>>       memset(h, 0, sizeof(*h));
>>       h->gt = gt;
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>>       h->ctx = kernel_context(gt->i915);
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>>       if (IS_ERR(h->ctx))
>>           return PTR_ERR(h->ctx);
>> @@ -133,7 +131,8 @@ static struct i915_request *
>>   hang_create_request(struct hang *h, struct intel_engine_cs *engine)
>>   {
>>       struct intel_gt *gt = h->gt;
>> -    struct i915_address_space *vm = h->ctx->vm ?: &engine->gt->ggtt->vm;
>> +    struct i915_address_space *vm =
>> +        rcu_dereference_protected(h->ctx->vm, true) ?: 
>> &engine->gt->ggtt->vm;
>>       struct drm_i915_gem_object *obj;
>>       struct i915_request *rq = NULL;
>>       struct i915_vma *hws, *vma;
>> @@ -382,9 +381,7 @@ static int igt_reset_nop(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>>       ctx = live_context(gt->i915, file);
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>>       if (IS_ERR(ctx)) {
>>           err = PTR_ERR(ctx);
>>           goto out;
>> @@ -458,9 +455,7 @@ static int igt_reset_nop_engine(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>>       ctx = live_context(gt->i915, file);
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>>       if (IS_ERR(ctx)) {
>>           err = PTR_ERR(ctx);
>>           goto out;
>> @@ -705,9 +700,7 @@ static int active_engine(void *data)
>>           return PTR_ERR(file);
>>       for (count = 0; count < ARRAY_SIZE(ctx); count++) {
>> -        mutex_lock(&engine->i915->drm.struct_mutex);
>>           ctx[count] = live_context(engine->i915, file);
>> -        mutex_unlock(&engine->i915->drm.struct_mutex);
>>           if (IS_ERR(ctx[count])) {
>>               err = PTR_ERR(ctx[count]);
>>               while (--count)
>> @@ -1298,18 +1291,18 @@ static int igt_reset_evict_ppgtt(void *arg)
>>       if (IS_ERR(file))
>>           return PTR_ERR(file);
>> -    mutex_lock(&gt->i915->drm.struct_mutex);
>>       ctx = live_context(gt->i915, file);
>> -    mutex_unlock(&gt->i915->drm.struct_mutex);
>>       if (IS_ERR(ctx)) {
>>           err = PTR_ERR(ctx);
>>           goto out;
>>       }
>>       err = 0;
>> -    if (ctx->vm) /* aliasing == global gtt locking, covered above */
>> -        err = __igt_reset_evict_vma(gt, ctx->vm,
>> +    if (rcu_access_pointer(ctx->vm)) {
>> +        /* aliasing == global gtt locking, covered above */
>> +        err = __igt_reset_evict_vma(gt, 
>> rcu_dereference_protected(ctx->vm, true),
>>                           evict_vma, EXEC_OBJECT_WRITE);
>> +    }
>>   out:
>>       mock_file_free(gt->i915, file);
>> diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c 
>> b/drivers/gpu/drm/i915/gt/selftest_lrc.c
>> index 3300acd9199d..e33c2f66c683 100644
>> --- a/drivers/gpu/drm/i915/gt/selftest_lrc.c
>> +++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c
>> @@ -1453,7 +1453,9 @@ static int smoke_submit(struct preempt_smoke 
>> *smoke,
>>       int err = 0;
>>       if (batch) {
>> -        vma = i915_vma_instance(batch, ctx->vm, NULL);
>> +        vma = i915_vma_instance(batch,
>> +                    rcu_dereference_protected(ctx->vm, true),
>> +                    NULL);
>>           if (IS_ERR(vma))
>>               return PTR_ERR(vma);
>> diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c 
>> b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
>> index 06351fefbbf3..ed44333d9e20 100644
>> --- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c
>> +++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
>> @@ -33,6 +33,8 @@ struct wa_lists {
>>       } engine[I915_NUM_ENGINES];
>>   };
>> +#define ctx_vm(ctx) rcu_dereference_protected((ctx)->vm, true)
>> +
>>   static void
>>   reference_lists_init(struct drm_i915_private *i915, struct wa_lists 
>> *lists)
>>   {
>> @@ -362,7 +364,7 @@ static struct i915_vma *create_batch(struct 
>> i915_gem_context *ctx)
>>       if (IS_ERR(obj))
>>           return ERR_CAST(obj);
>> -    vma = i915_vma_instance(obj, ctx->vm, NULL);
>> +    vma = i915_vma_instance(obj, ctx_vm(ctx), NULL);
>>       if (IS_ERR(vma)) {
>>           err = PTR_ERR(vma);
>>           goto err_obj;
>> @@ -468,7 +470,7 @@ static int check_dirty_whitelist(struct 
>> i915_gem_context *ctx,
>>       int err = 0, i, v;
>>       u32 *cs, *results;
>> -    scratch = create_scratch(ctx->vm, 2 * ARRAY_SIZE(values) + 1);
>> +    scratch = create_scratch(ctx_vm(ctx), 2 * ARRAY_SIZE(values) + 1);
>>       if (IS_ERR(scratch))
>>           return PTR_ERR(scratch);
>> @@ -1018,14 +1020,14 @@ static int live_isolated_whitelist(void *arg)
>>               goto err;
>>           }
>> -        client[i].scratch[0] = create_scratch(c->vm, 1024);
>> +        client[i].scratch[0] = create_scratch(ctx_vm(c), 1024);
>>           if (IS_ERR(client[i].scratch[0])) {
>>               err = PTR_ERR(client[i].scratch[0]);
>>               kernel_context_close(c);
>>               goto err;
>>           }
>> -        client[i].scratch[1] = create_scratch(c->vm, 1024);
>> +        client[i].scratch[1] = create_scratch(ctx_vm(c), 1024);
>>           if (IS_ERR(client[i].scratch[1])) {
>>               err = PTR_ERR(client[i].scratch[1]);
>>               i915_vma_unpin_and_release(&client[i].scratch[0], 0);
>> diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c 
>> b/drivers/gpu/drm/i915/gvt/scheduler.c
>> index 03f567084548..ce5cff01f44c 100644
>> --- a/drivers/gpu/drm/i915/gvt/scheduler.c
>> +++ b/drivers/gpu/drm/i915/gvt/scheduler.c
>> @@ -365,7 +365,8 @@ static void set_context_ppgtt_from_shadow(struct 
>> intel_vgpu_workload *workload,
>>                         struct i915_gem_context *ctx)
>>   {
>>       struct intel_vgpu_mm *mm = workload->shadow_mm;
>> -    struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(ctx->vm);
>> +    struct i915_ppgtt *ppgtt =
>> +        i915_vm_to_ppgtt(rcu_dereference_protected(ctx->vm, true));
>>       int i = 0;
>>       if (mm->ppgtt_mm.root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
>> @@ -1230,20 +1231,18 @@ int intel_vgpu_setup_submission(struct 
>> intel_vgpu *vgpu)
>>       struct intel_vgpu_submission *s = &vgpu->submission;
>>       struct intel_engine_cs *engine;
>>       struct i915_gem_context *ctx;
>> +    struct i915_ppgtt *ppgtt;
>>       enum intel_engine_id i;
>>       int ret;
>> -    mutex_lock(&i915->drm.struct_mutex);
>> -
>>       ctx = i915_gem_context_create_kernel(i915, I915_PRIORITY_MAX);
>> -    if (IS_ERR(ctx)) {
>> -        ret = PTR_ERR(ctx);
>> -        goto out_unlock;
>> -    }
>> +    if (IS_ERR(ctx))
>> +        return PTR_ERR(ctx);
>>       i915_gem_context_set_force_single_submission(ctx);
>> -    i915_context_ppgtt_root_save(s, i915_vm_to_ppgtt(ctx->vm));
>> +    ppgtt = i915_vm_to_ppgtt(rcu_dereference_protected(ctx->vm, true));
>> +    i915_context_ppgtt_root_save(s, ppgtt);
>>       for_each_engine(engine, i915, i) {
>>           struct intel_context *ce;
>> @@ -1289,11 +1288,10 @@ int intel_vgpu_setup_submission(struct 
>> intel_vgpu *vgpu)
>>       bitmap_zero(s->tlb_handle_pending, I915_NUM_ENGINES);
>>       i915_gem_context_put(ctx);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       return 0;
>>   out_shadow_ctx:
>> -    i915_context_ppgtt_root_restore(s, i915_vm_to_ppgtt(ctx->vm));
>> +    i915_context_ppgtt_root_restore(s, ppgtt);
>>       for_each_engine(engine, i915, i) {
>>           if (IS_ERR(s->shadow[i]))
>>               break;
>> @@ -1302,8 +1300,6 @@ int intel_vgpu_setup_submission(struct 
>> intel_vgpu *vgpu)
>>           intel_context_put(s->shadow[i]);
>>       }
>>       i915_gem_context_put(ctx);
>> -out_unlock:
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       return ret;
>>   }
>> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
>> b/drivers/gpu/drm/i915/i915_debugfs.c
>> index 8caaa446490f..d4a7cda60679 100644
>> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> @@ -315,12 +315,18 @@ static void print_context_stats(struct seq_file *m,
>>                   struct drm_i915_private *i915)
>>   {
>>       struct file_stats kstats = {};
>> -    struct i915_gem_context *ctx;
>> +    struct i915_gem_context *ctx, *cn;
>> -    list_for_each_entry(ctx, &i915->contexts.list, link) {
>> +    spin_lock(&i915->gem.contexts.lock);
>> +    list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) {
>>           struct i915_gem_engines_iter it;
>>           struct intel_context *ce;
>> +        if (!kref_get_unless_zero(&ctx->ref))
>> +            continue;
>> +
>> +        spin_unlock(&i915->gem.contexts.lock);
>> +
>>           for_each_gem_engine(ce,
>>                       i915_gem_context_lock_engines(ctx), it) {
>>               intel_context_lock_pinned(ce);
>> @@ -337,7 +343,9 @@ static void print_context_stats(struct seq_file *m,
>>           i915_gem_context_unlock_engines(ctx);
>>           if (!IS_ERR_OR_NULL(ctx->file_priv)) {
>> -            struct file_stats stats = { .vm = ctx->vm, };
>> +            struct file_stats stats = {
>> +                .vm = rcu_access_pointer(ctx->vm),
>> +            };
>>               struct drm_file *file = ctx->file_priv->file;
>>               struct task_struct *task;
>>               char name[80];
>> @@ -354,7 +362,12 @@ static void print_context_stats(struct seq_file *m,
>>               print_file_stats(m, name, stats);
>>           }
>> +
>> +        spin_lock(&i915->gem.contexts.lock);
>> +        list_safe_reset_next(ctx, cn, link);
>> +        i915_gem_context_put(ctx);
>>       }
>> +    spin_unlock(&i915->gem.contexts.lock);
>>       print_file_stats(m, "[k]contexts", kstats);
>>   }
>> @@ -362,7 +375,6 @@ static void print_context_stats(struct seq_file *m,
>>   static int i915_gem_object_info(struct seq_file *m, void *data)
>>   {
>>       struct drm_i915_private *i915 = node_to_i915(m->private);
>> -    int ret;
>>       seq_printf(m, "%u shrinkable [%u free] objects, %llu bytes\n",
>>              i915->mm.shrink_count,
>> @@ -371,12 +383,7 @@ static int i915_gem_object_info(struct seq_file 
>> *m, void *data)
>>       seq_putc(m, '\n');
>> -    ret = mutex_lock_interruptible(&i915->drm.struct_mutex);
>> -    if (ret)
>> -        return ret;
>> -
>>       print_context_stats(m, i915);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       return 0;
>>   }
>> @@ -1490,19 +1497,19 @@ static void describe_ctx_ring(struct seq_file 
>> *m, struct intel_ring *ring)
>>   static int i915_context_status(struct seq_file *m, void *unused)
>>   {
>> -    struct drm_i915_private *dev_priv = node_to_i915(m->private);
>> -    struct drm_device *dev = &dev_priv->drm;
>> -    struct i915_gem_context *ctx;
>> -    int ret;
>> -
>> -    ret = mutex_lock_interruptible(&dev->struct_mutex);
>> -    if (ret)
>> -        return ret;
>> +    struct drm_i915_private *i915 = node_to_i915(m->private);
>> +    struct i915_gem_context *ctx, *cn;
>> -    list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
>> +    spin_lock(&i915->gem.contexts.lock);
>> +    list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) {
>>           struct i915_gem_engines_iter it;
>>           struct intel_context *ce;
>> +        if (!kref_get_unless_zero(&ctx->ref))
>> +            continue;
>> +
>> +        spin_unlock(&i915->gem.contexts.lock);
>> +
>>           seq_puts(m, "HW context ");
>>           if (ctx->pid) {
>>               struct task_struct *task;
>> @@ -1537,9 +1544,12 @@ static int i915_context_status(struct seq_file 
>> *m, void *unused)
>>           i915_gem_context_unlock_engines(ctx);
>>           seq_putc(m, '\n');
>> -    }
>> -    mutex_unlock(&dev->struct_mutex);
>> +        spin_lock(&i915->gem.contexts.lock);
>> +        list_safe_reset_next(ctx, cn, link);
>> +        i915_gem_context_put(ctx);
>> +    }
>> +    spin_unlock(&i915->gem.contexts.lock);
>>       return 0;
>>   }
>> diff --git a/drivers/gpu/drm/i915/i915_drv.c 
>> b/drivers/gpu/drm/i915/i915_drv.c
>> index 8cac6124d16a..a8ddac22d633 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.c
>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>> @@ -1685,10 +1685,8 @@ static void i915_driver_postclose(struct 
>> drm_device *dev, struct drm_file *file)
>>   {
>>       struct drm_i915_file_private *file_priv = file->driver_priv;
>> -    mutex_lock(&dev->struct_mutex);
>>       i915_gem_context_close(file);
>>       i915_gem_release(dev, file);
>> -    mutex_unlock(&dev->struct_mutex);
>>       kfree_rcu(file_priv, rcu);
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h 
>> b/drivers/gpu/drm/i915/i915_drv.h
>> index ad7ed7f72da8..23f311172e75 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -1543,25 +1543,6 @@ struct drm_i915_private {
>>       int audio_power_refcount;
>>       u32 audio_freq_cntrl;
>> -    struct {
>> -        struct mutex mutex;
>> -        struct list_head list;
>> -        struct llist_head free_list;
>> -        struct work_struct free_work;
>> -
>> -        /* The hw wants to have a stable context identifier for the
>> -         * lifetime of the context (for OA, PASID, faults, etc).
>> -         * This is limited in execlists to 21 bits.
>> -         */
>> -        struct ida hw_ida;
>> -#define MAX_CONTEXT_HW_ID (1<<21) /* exclusive */
>> -#define MAX_GUC_CONTEXT_HW_ID (1 << 20) /* exclusive */
>> -#define GEN11_MAX_CONTEXT_HW_ID (1<<11) /* exclusive */
>> -/* in Gen12 ID 0x7FF is reserved to indicate idle */
>> -#define GEN12_MAX_CONTEXT_HW_ID    (GEN11_MAX_CONTEXT_HW_ID - 1)
>> -        struct list_head hw_id_list;
> 
> These bits.
> 
>> -    } contexts;
>> -
>>       u32 fdi_rx_config;
>>       /* Shadow for DISPLAY_PHY_CONTROL which can't be safely read */
>> @@ -1717,6 +1698,14 @@ struct drm_i915_private {
>>       struct {
>>           struct notifier_block pm_notifier;
>> +
>> +        struct i915_gem_contexts {
>> +            spinlock_t lock; /* locks list */
>> +            struct list_head list;
>> +
>> +            struct llist_head free_list;
>> +            struct work_struct free_work;
>> +        } contexts;
>>       } gem;
>>       /* For i945gm vblank irq vs. C3 workaround */
>> diff --git a/drivers/gpu/drm/i915/i915_gem.c 
>> b/drivers/gpu/drm/i915/i915_gem.c
>> index 9c2877441540..8814db7023db 100644
>> --- a/drivers/gpu/drm/i915/i915_gem.c
>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> @@ -1263,7 +1263,7 @@ int i915_gem_init(struct drm_i915_private 
>> *dev_priv)
>>           goto err_unlock;
>>       }
>> -    ret = i915_gem_contexts_init(dev_priv);
>> +    ret = i915_gem_init_contexts(dev_priv);
>>       if (ret) {
>>           GEM_BUG_ON(ret == -EIO);
>>           goto err_scratch;
>> @@ -1345,7 +1345,7 @@ int i915_gem_init(struct drm_i915_private 
>> *dev_priv)
>>       }
>>   err_context:
>>       if (ret != -EIO)
>> -        i915_gem_contexts_fini(dev_priv);
>> +        i915_gem_driver_release__contexts(dev_priv);
>>   err_scratch:
>>       intel_gt_driver_release(&dev_priv->gt);
>>   err_unlock:
>> @@ -1413,11 +1413,9 @@ void i915_gem_driver_remove(struct 
>> drm_i915_private *dev_priv)
>>   void i915_gem_driver_release(struct drm_i915_private *dev_priv)
>>   {
>> -    mutex_lock(&dev_priv->drm.struct_mutex);
>>       intel_engines_cleanup(dev_priv);
>> -    i915_gem_contexts_fini(dev_priv);
>> +    i915_gem_driver_release__contexts(dev_priv);
>>       intel_gt_driver_release(&dev_priv->gt);
>> -    mutex_unlock(&dev_priv->drm.struct_mutex);
>>       intel_wa_list_free(&dev_priv->gt_wa_list);
>> @@ -1427,7 +1425,7 @@ void i915_gem_driver_release(struct 
>> drm_i915_private *dev_priv)
>>       i915_gem_drain_freed_objects(dev_priv);
>> -    WARN_ON(!list_empty(&dev_priv->contexts.list));
>> +    WARN_ON(!list_empty(&dev_priv->gem.contexts.list));
>>   }
>>   void i915_gem_init_mmio(struct drm_i915_private *i915)
>> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c 
>> b/drivers/gpu/drm/i915/i915_gem_gtt.c
>> index 0d040517787b..db32e0fe78b1 100644
>> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
>> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
>> @@ -1366,7 +1366,9 @@ static int gen8_init_scratch(struct 
>> i915_address_space *vm)
>>       if (vm->has_read_only &&
>>           vm->i915->kernel_context &&
>>           vm->i915->kernel_context->vm) {
>> -        struct i915_address_space *clone = vm->i915->kernel_context->vm;
>> +        struct i915_address_space *clone =
>> +            rcu_dereference_protected(vm->i915->kernel_context->vm,
>> +                          true);
> 
> What is the protection here?
> 
>>           GEM_BUG_ON(!clone->has_read_only);
>> diff --git a/drivers/gpu/drm/i915/i915_perf.c 
>> b/drivers/gpu/drm/i915/i915_perf.c
>> index d36ba248d438..bfe6e9b6d71d 100644
>> --- a/drivers/gpu/drm/i915/i915_perf.c
>> +++ b/drivers/gpu/drm/i915/i915_perf.c
>> @@ -1853,8 +1853,8 @@ static int gen8_configure_all_contexts(struct 
>> i915_perf_stream *stream,
>>       };
>>   #undef ctx_flexeuN
>>       struct intel_engine_cs *engine;
>> -    struct i915_gem_context *ctx;
>> -    int i;
>> +    struct i915_gem_context *ctx, *cn;
>> +    int i, err;
>>       for (i = 2; i < ARRAY_SIZE(regs); i++)
>>           regs[i].value = oa_config_flex_reg(oa_config, regs[i].reg);
>> @@ -1877,16 +1877,27 @@ static int gen8_configure_all_contexts(struct 
>> i915_perf_stream *stream,
>>        * context. Contexts idle at the time of reconfiguration are not
>>        * trapped behind the barrier.
>>        */
>> -    list_for_each_entry(ctx, &i915->contexts.list, link) {
>> -        int err;
>> -
>> +    spin_lock(&i915->gem.contexts.lock);
>> +    list_for_each_entry_safe(ctx, cn, &i915->gem.contexts.list, link) {
>>           if (ctx == i915->kernel_context)
>>               continue;
>> +        if (!kref_get_unless_zero(&ctx->ref))
>> +            continue;
>> +
>> +        spin_unlock(&i915->gem.contexts.lock);
>> +
>>           err = gen8_configure_context(ctx, regs, ARRAY_SIZE(regs));
>> -        if (err)
>> +        if (err) {
>> +            i915_gem_context_put(ctx);
>>               return err;
>> +        }
>> +
>> +        spin_lock(&i915->gem.contexts.lock);
>> +        list_safe_reset_next(ctx, cn, link);
>> +        i915_gem_context_put(ctx);
>>       }
>> +    spin_unlock(&i915->gem.contexts.lock);
>>       /*
>>        * After updating all other contexts, we need to modify ourselves.
>> @@ -1895,7 +1906,6 @@ static int gen8_configure_all_contexts(struct 
>> i915_perf_stream *stream,
>>        */
>>       for_each_uabi_engine(engine, i915) {
>>           struct intel_context *ce = engine->kernel_context;
>> -        int err;
>>           if (engine->class != RENDER_CLASS)
>>               continue;
>> diff --git a/drivers/gpu/drm/i915/i915_sysfs.c 
>> b/drivers/gpu/drm/i915/i915_sysfs.c
>> index 6b88d934927a..585808c2ee84 100644
>> --- a/drivers/gpu/drm/i915/i915_sysfs.c
>> +++ b/drivers/gpu/drm/i915/i915_sysfs.c
>> @@ -144,9 +144,9 @@ static const struct attribute_group 
>> media_rc6_attr_group = {
>>   };
>>   #endif
>> -static int l3_access_valid(struct drm_i915_private *dev_priv, loff_t 
>> offset)
>> +static int l3_access_valid(struct drm_i915_private *i915, loff_t offset)
>>   {
>> -    if (!HAS_L3_DPF(dev_priv))
>> +    if (!HAS_L3_DPF(i915))
>>           return -EPERM;
>>       if (offset % 4 != 0)
>> @@ -164,31 +164,24 @@ i915_l3_read(struct file *filp, struct kobject 
>> *kobj,
>>            loff_t offset, size_t count)
>>   {
>>       struct device *kdev = kobj_to_dev(kobj);
>> -    struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
>> -    struct drm_device *dev = &dev_priv->drm;
>> +    struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
>>       int slice = (int)(uintptr_t)attr->private;
>>       int ret;
>> -    count = round_down(count, 4);
>> -
>> -    ret = l3_access_valid(dev_priv, offset);
>> +    ret = l3_access_valid(i915, offset);
>>       if (ret)
>>           return ret;
>> +    count = round_down(count, 4);
>>       count = min_t(size_t, GEN7_L3LOG_SIZE - offset, count);
>> +    memset(buf, 0, count);
>> -    ret = i915_mutex_lock_interruptible(dev);
>> -    if (ret)
>> -        return ret;
>> -
>> -    if (dev_priv->l3_parity.remap_info[slice])
>> +    spin_lock(&i915->gem.contexts.lock);
>> +    if (i915->l3_parity.remap_info[slice])
>>           memcpy(buf,
>> -               dev_priv->l3_parity.remap_info[slice] + (offset/4),
>> +               i915->l3_parity.remap_info[slice] + offset / 4,
>>                  count);
>> -    else
>> -        memset(buf, 0, count);
>> -
>> -    mutex_unlock(&dev->struct_mutex);
>> +    spin_unlock(&i915->gem.contexts.lock);
>>       return count;
>>   }
>> @@ -199,46 +192,46 @@ i915_l3_write(struct file *filp, struct kobject 
>> *kobj,
>>             loff_t offset, size_t count)
>>   {
>>       struct device *kdev = kobj_to_dev(kobj);
>> -    struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
>> -    struct drm_device *dev = &dev_priv->drm;
>> +    struct drm_i915_private *i915 = kdev_minor_to_i915(kdev);
>>       struct i915_gem_context *ctx;
>>       int slice = (int)(uintptr_t)attr->private;
>> -    u32 **remap_info;
>> +    u32 *remap_info, *freeme = NULL;
>>       int ret;
>> -    ret = l3_access_valid(dev_priv, offset);
>> +    ret = l3_access_valid(i915, offset);
>>       if (ret)
>>           return ret;
>> -    ret = i915_mutex_lock_interruptible(dev);
>> -    if (ret)
>> -        return ret;
>> +    remap_info = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
>> +    if (!remap_info)
>> +        return -ENOMEM;
>> -    remap_info = &dev_priv->l3_parity.remap_info[slice];
>> -    if (!*remap_info) {
>> -        *remap_info = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
>> -        if (!*remap_info) {
>> -            ret = -ENOMEM;
>> -            goto out;
>> -        }
>> +    spin_lock(&i915->gem.contexts.lock);
>> +
>> +    if (i915->l3_parity.remap_info[slice]) {
>> +        freeme = remap_info;
>> +        remap_info = i915->l3_parity.remap_info[slice];
>> +    } else {
>> +        i915->l3_parity.remap_info[slice] = remap_info;
>>       }
>> -    /* TODO: Ideally we really want a GPU reset here to make sure errors
>> -     * aren't propagated. Since I cannot find a stable way to reset 
>> the GPU
>> -     * at this point it is left as a TODO.
>> -    */
>> -    memcpy(*remap_info + (offset/4), buf, count);
>> +    count = round_down(count, 4);
> 
> Where was this round_down before, can't see it!
> 
>> +    memcpy(remap_info + offset / 4, buf, count);
>>       /* NB: We defer the remapping until we switch to the context */
>> -    list_for_each_entry(ctx, &dev_priv->contexts.list, link)
>> -        ctx->remap_slice |= (1<<slice);
>> +    list_for_each_entry(ctx, &i915->gem.contexts.list, link)
>> +        ctx->remap_slice |= BIT(slice);
>> -    ret = count;
>> +    spin_unlock(&i915->gem.contexts.lock);
>> +    kfree(freeme);
>> -out:
>> -    mutex_unlock(&dev->struct_mutex);
>> +    /*
>> +     * TODO: Ideally we really want a GPU reset here to make sure errors
>> +     * aren't propagated. Since I cannot find a stable way to reset 
>> the GPU
>> +     * at this point it is left as a TODO.
>> +     */
>> -    return ret;
>> +    return count;
>>   }
>>   static const struct bin_attribute dpf_attrs = {
>> diff --git a/drivers/gpu/drm/i915/i915_trace.h 
>> b/drivers/gpu/drm/i915/i915_trace.h
>> index 1f2cf6cfafb5..7ef7a1e1664c 100644
>> --- a/drivers/gpu/drm/i915/i915_trace.h
>> +++ b/drivers/gpu/drm/i915/i915_trace.h
>> @@ -952,7 +952,7 @@ DECLARE_EVENT_CLASS(i915_context,
>>       TP_fast_assign(
>>               __entry->dev = ctx->i915->drm.primary->index;
>>               __entry->ctx = ctx;
>> -            __entry->vm = ctx->vm;
>> +            __entry->vm = rcu_access_pointer(ctx->vm);
>>       ),
>>       TP_printk("dev=%u, ctx=%p, ctx_vm=%p",
>> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem.c 
>> b/drivers/gpu/drm/i915/selftests/i915_gem.c
>> index 0346c3e5b6b6..bfa40a5b6d98 100644
>> --- a/drivers/gpu/drm/i915/selftests/i915_gem.c
>> +++ b/drivers/gpu/drm/i915/selftests/i915_gem.c
>> @@ -138,11 +138,9 @@ static int igt_gem_suspend(void *arg)
>>           return PTR_ERR(file);
>>       err = -ENOMEM;
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       ctx = live_context(i915, file);
>>       if (!IS_ERR(ctx))
>>           err = switch_to_context(i915, ctx);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       if (err)
>>           goto out;
>> @@ -157,9 +155,7 @@ static int igt_gem_suspend(void *arg)
>>       pm_resume(i915);
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       err = switch_to_context(i915, ctx);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>   out:
>>       mock_file_free(i915, file);
>>       return err;
>> @@ -177,11 +173,9 @@ static int igt_gem_hibernate(void *arg)
>>           return PTR_ERR(file);
>>       err = -ENOMEM;
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       ctx = live_context(i915, file);
>>       if (!IS_ERR(ctx))
>>           err = switch_to_context(i915, ctx);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       if (err)
>>           goto out;
>> @@ -196,9 +190,7 @@ static int igt_gem_hibernate(void *arg)
>>       pm_resume(i915);
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       err = switch_to_context(i915, ctx);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>   out:
>>       mock_file_free(i915, file);
>>       return err;
>> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c 
>> b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c
>> index f39f0282e78c..0af9a58d011d 100644
>> --- a/drivers/gpu/drm/i915/selftests/i915_gem_evict.c
>> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_evict.c
>> @@ -473,7 +473,6 @@ static int igt_evict_contexts(void *arg)
>>           }
>>           count = 0;
>> -        mutex_lock(&i915->drm.struct_mutex);
>>           onstack_fence_init(&fence);
>>           do {
>>               struct i915_request *rq;
>> @@ -510,8 +509,6 @@ static int igt_evict_contexts(void *arg)
>>               count++;
>>               err = 0;
>>           } while(1);
>> -        mutex_unlock(&i915->drm.struct_mutex);
>> -
>>           onstack_fence_fini(&fence);
>>           pr_info("Submitted %lu contexts/requests on %s\n",
>>               count, engine->name);
>> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c 
>> b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>> index 9939dd40c6a8..6777a335bd44 100644
>> --- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>> +++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
>> @@ -1246,6 +1246,7 @@ static int exercise_mock(struct drm_i915_private 
>> *i915,
>>                        unsigned long end_time))
>>   {
>>       const u64 limit = totalram_pages() << PAGE_SHIFT;
>> +    struct i915_address_space *vm;
>>       struct i915_gem_context *ctx;
>>       IGT_TIMEOUT(end_time);
>>       int err;
>> @@ -1254,7 +1255,8 @@ static int exercise_mock(struct drm_i915_private 
>> *i915,
>>       if (!ctx)
>>           return -ENOMEM;
>> -    err = func(i915, ctx->vm, 0, min(ctx->vm->total, limit), end_time);
>> +    vm = rcu_dereference_protected(ctx->vm, true);
>> +    err = func(i915, vm, 0, min(vm->total, limit), end_time);
>>       mock_context_close(ctx);
>>       return err;
>> diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c 
>> b/drivers/gpu/drm/i915/selftests/i915_request.c
>> index d1ee384a3260..4abf52733520 100644
>> --- a/drivers/gpu/drm/i915/selftests/i915_request.c
>> +++ b/drivers/gpu/drm/i915/selftests/i915_request.c
>> @@ -181,9 +181,7 @@ static int igt_request_rewind(void *arg)
>>       struct intel_context *ce;
>>       int err = -EINVAL;
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       ctx[0] = mock_context(i915, "A");
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       ce = i915_gem_context_get_engine(ctx[0], RCS0);
>>       GEM_BUG_ON(IS_ERR(ce));
>> @@ -197,9 +195,7 @@ static int igt_request_rewind(void *arg)
>>       i915_request_get(request);
>>       i915_request_add(request);
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       ctx[1] = mock_context(i915, "B");
>> -    mutex_unlock(&i915->drm.struct_mutex);
>>       ce = i915_gem_context_get_engine(ctx[1], RCS0);
>>       GEM_BUG_ON(IS_ERR(ce));
>> @@ -438,9 +434,7 @@ static int mock_breadcrumbs_smoketest(void *arg)
>>       }
>>       for (n = 0; n < t.ncontexts; n++) {
>> -        mutex_lock(&t.engine->i915->drm.struct_mutex);
>>           t.contexts[n] = mock_context(t.engine->i915, "mock");
>> -        mutex_unlock(&t.engine->i915->drm.struct_mutex);
>>           if (!t.contexts[n]) {
>>               ret = -ENOMEM;
>>               goto out_contexts;
>> @@ -734,7 +728,8 @@ static int live_empty_request(void *arg)
>>   static struct i915_vma *recursive_batch(struct drm_i915_private *i915)
>>   {
>>       struct i915_gem_context *ctx = i915->kernel_context;
>> -    struct i915_address_space *vm = ctx->vm ?: &i915->ggtt.vm;
>> +    struct i915_address_space *vm =
>> +        rcu_dereference_protected(ctx->vm, true) ?: &i915->ggtt.vm;
>>       struct drm_i915_gem_object *obj;
>>       const int gen = INTEL_GEN(i915);
>>       struct i915_vma *vma;
>> @@ -1109,9 +1104,7 @@ static int live_breadcrumbs_smoketest(void *arg)
>>       }
>>       for (n = 0; n < t[0].ncontexts; n++) {
>> -        mutex_lock(&i915->drm.struct_mutex);
>>           t[0].contexts[n] = live_context(i915, file);
>> -        mutex_unlock(&i915->drm.struct_mutex);
>>           if (!t[0].contexts[n]) {
>>               ret = -ENOMEM;
>>               goto out_contexts;
>> diff --git a/drivers/gpu/drm/i915/selftests/i915_vma.c 
>> b/drivers/gpu/drm/i915/selftests/i915_vma.c
>> index ac1ff558eb90..f6e6b0aae38c 100644
>> --- a/drivers/gpu/drm/i915/selftests/i915_vma.c
>> +++ b/drivers/gpu/drm/i915/selftests/i915_vma.c
>> @@ -38,7 +38,7 @@ static bool assert_vma(struct i915_vma *vma,
>>   {
>>       bool ok = true;
>> -    if (vma->vm != ctx->vm) {
>> +    if (vma->vm != rcu_access_pointer(ctx->vm)) {
>>           pr_err("VMA created with wrong VM\n");
>>           ok = false;
>>       }
>> @@ -113,7 +113,8 @@ static int create_vmas(struct drm_i915_private *i915,
>>       list_for_each_entry(obj, objects, st_link) {
>>           for (pinned = 0; pinned <= 1; pinned++) {
>>               list_for_each_entry(ctx, contexts, link) {
>> -                struct i915_address_space *vm = ctx->vm;
>> +                struct i915_address_space *vm =
>> +                    rcu_dereference_protected(ctx->vm, true);
>>                   struct i915_vma *vma;
>>                   int err;
>> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c 
>> b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
>> index efe40c29fcf2..0ed21a7b8682 100644
>> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
>> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
>> @@ -59,11 +59,9 @@ static void mock_device_release(struct drm_device 
>> *dev)
>>       i915_gem_drain_workqueue(i915);
>> -    mutex_lock(&i915->drm.struct_mutex);
>>       for_each_engine(engine, i915, id)
>>           mock_engine_free(engine);
>> -    i915_gem_contexts_fini(i915);
>> -    mutex_unlock(&i915->drm.struct_mutex);
>> +    i915_gem_driver_release__contexts(i915);
>>       intel_timelines_fini(i915);
>> @@ -207,7 +205,7 @@ struct drm_i915_private *mock_gem_device(void)
>>       return i915;
>>   err_context:
>> -    i915_gem_contexts_fini(i915);
>> +    i915_gem_driver_release__contexts(i915);
>>   err_engine:
>>       mock_engine_free(i915->engine[RCS0]);
>>   err_unlock:
>>
> 
> Regards,
> 
> Tvrtko


More information about the Intel-gfx mailing list