drm/i915: Hold reference to intel_frontbuffer as we track activity
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 18 Dec 2019 10:40:43 +0000 (10:40 +0000)
committerJani Nikula <jani.nikula@intel.com>
Mon, 23 Dec 2019 12:27:23 +0000 (14:27 +0200)
Since obj->frontbuffer is no longer protected by the struct_mutex, as we
are processing the execbuf, it may be removed. Mark the
intel_frontbuffer as rcu protected, and so acquire a reference to
the struct as we track activity upon it.

Closes: https://gitlab.freedesktop.org/drm/intel/issues/827
Fixes: 8e7cb1799b4f ("drm/i915: Extract intel_frontbuffer active tracking")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: <stable@vger.kernel.org> # v5.4+
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191218104043.3539458-1-chris@chris-wilson.co.uk
(cherry picked from commit da42104f589d979bbe402703fd836cec60befae1)
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/i915/display/intel_frontbuffer.c
drivers/gpu/drm/i915/display/intel_frontbuffer.h
drivers/gpu/drm/i915/display/intel_overlay.c
drivers/gpu/drm/i915/gem/i915_gem_clflush.c
drivers/gpu/drm/i915/gem/i915_gem_domain.c
drivers/gpu/drm/i915/gem/i915_gem_object.c
drivers/gpu/drm/i915/gem/i915_gem_object.h
drivers/gpu/drm/i915/gem/i915_gem_object_types.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_vma.c

index 6f5e3bd..effc425 100644 (file)
@@ -15112,7 +15112,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
                return ret;
 
        fb_obj_bump_render_priority(obj);
-       intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_DIRTYFB);
+       i915_gem_object_flush_frontbuffer(obj, ORIGIN_DIRTYFB);
 
        if (!new_plane_state->base.fence) { /* implicit fencing */
                struct dma_fence *fence;
index 84b164f..6cb02c9 100644 (file)
@@ -229,11 +229,11 @@ static void frontbuffer_release(struct kref *ref)
                vma->display_alignment = I915_GTT_MIN_ALIGNMENT;
        spin_unlock(&obj->vma.lock);
 
-       obj->frontbuffer = NULL;
+       RCU_INIT_POINTER(obj->frontbuffer, NULL);
        spin_unlock(&to_i915(obj->base.dev)->fb_tracking.lock);
 
        i915_gem_object_put(obj);
-       kfree(front);
+       kfree_rcu(front, rcu);
 }
 
 struct intel_frontbuffer *
@@ -242,11 +242,7 @@ intel_frontbuffer_get(struct drm_i915_gem_object *obj)
        struct drm_i915_private *i915 = to_i915(obj->base.dev);
        struct intel_frontbuffer *front;
 
-       spin_lock(&i915->fb_tracking.lock);
-       front = obj->frontbuffer;
-       if (front)
-               kref_get(&front->ref);
-       spin_unlock(&i915->fb_tracking.lock);
+       front = __intel_frontbuffer_get(obj);
        if (front)
                return front;
 
@@ -262,13 +258,13 @@ intel_frontbuffer_get(struct drm_i915_gem_object *obj)
                         i915_active_may_sleep(frontbuffer_retire));
 
        spin_lock(&i915->fb_tracking.lock);
-       if (obj->frontbuffer) {
+       if (rcu_access_pointer(obj->frontbuffer)) {
                kfree(front);
-               front = obj->frontbuffer;
+               front = rcu_dereference_protected(obj->frontbuffer, true);
                kref_get(&front->ref);
        } else {
                i915_gem_object_get(obj);
-               obj->frontbuffer = front;
+               rcu_assign_pointer(obj->frontbuffer, front);
        }
        spin_unlock(&i915->fb_tracking.lock);
 
index adc64d6..6d41f53 100644 (file)
 #include <linux/atomic.h>
 #include <linux/kref.h>
 
+#include "gem/i915_gem_object_types.h"
 #include "i915_active.h"
 
 struct drm_i915_private;
-struct drm_i915_gem_object;
 
 enum fb_op_origin {
        ORIGIN_GTT,
@@ -45,6 +45,7 @@ struct intel_frontbuffer {
        atomic_t bits;
        struct i915_active write;
        struct drm_i915_gem_object *obj;
+       struct rcu_head rcu;
 };
 
 void intel_frontbuffer_flip_prepare(struct drm_i915_private *i915,
@@ -54,6 +55,35 @@ void intel_frontbuffer_flip_complete(struct drm_i915_private *i915,
 void intel_frontbuffer_flip(struct drm_i915_private *i915,
                            unsigned frontbuffer_bits);
 
+void intel_frontbuffer_put(struct intel_frontbuffer *front);
+
+static inline struct intel_frontbuffer *
+__intel_frontbuffer_get(const struct drm_i915_gem_object *obj)
+{
+       struct intel_frontbuffer *front;
+
+       if (likely(!rcu_access_pointer(obj->frontbuffer)))
+               return NULL;
+
+       rcu_read_lock();
+       do {
+               front = rcu_dereference(obj->frontbuffer);
+               if (!front)
+                       break;
+
+               if (unlikely(!kref_get_unless_zero(&front->ref)))
+                       continue;
+
+               if (likely(front == rcu_access_pointer(obj->frontbuffer)))
+                       break;
+
+               intel_frontbuffer_put(front);
+       } while (1);
+       rcu_read_unlock();
+
+       return front;
+}
+
 struct intel_frontbuffer *
 intel_frontbuffer_get(struct drm_i915_gem_object *obj);
 
@@ -119,6 +149,4 @@ void intel_frontbuffer_track(struct intel_frontbuffer *old,
                             struct intel_frontbuffer *new,
                             unsigned int frontbuffer_bits);
 
-void intel_frontbuffer_put(struct intel_frontbuffer *front);
-
 #endif /* __INTEL_FRONTBUFFER_H__ */
index 848ce07..8a98a1a 100644 (file)
@@ -279,12 +279,21 @@ static void intel_overlay_flip_prepare(struct intel_overlay *overlay,
                                       struct i915_vma *vma)
 {
        enum pipe pipe = overlay->crtc->pipe;
+       struct intel_frontbuffer *from = NULL, *to = NULL;
 
        WARN_ON(overlay->old_vma);
 
-       intel_frontbuffer_track(overlay->vma ? overlay->vma->obj->frontbuffer : NULL,
-                               vma ? vma->obj->frontbuffer : NULL,
-                               INTEL_FRONTBUFFER_OVERLAY(pipe));
+       if (overlay->vma)
+               from = intel_frontbuffer_get(overlay->vma->obj);
+       if (vma)
+               to = intel_frontbuffer_get(vma->obj);
+
+       intel_frontbuffer_track(from, to, INTEL_FRONTBUFFER_OVERLAY(pipe));
+
+       if (to)
+               intel_frontbuffer_put(to);
+       if (from)
+               intel_frontbuffer_put(from);
 
        intel_frontbuffer_flip_prepare(overlay->i915,
                                       INTEL_FRONTBUFFER_OVERLAY(pipe));
@@ -766,7 +775,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
                ret = PTR_ERR(vma);
                goto out_pin_section;
        }
-       intel_frontbuffer_flush(new_bo->frontbuffer, ORIGIN_DIRTYFB);
+       i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB);
 
        if (!overlay->active) {
                u32 oconfig;
index b9f504b..18ee708 100644 (file)
@@ -20,7 +20,8 @@ static void __do_clflush(struct drm_i915_gem_object *obj)
 {
        GEM_BUG_ON(!i915_gem_object_has_pages(obj));
        drm_clflush_sg(obj->mm.pages);
-       intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+
+       i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 }
 
 static int clflush_work(struct dma_fence_work *base)
index 9937b4c..f86400a 100644 (file)
@@ -664,7 +664,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        i915_gem_object_unlock(obj);
 
        if (write_domain)
-               intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+               i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 
 out_unpin:
        i915_gem_object_unpin_pages(obj);
@@ -784,7 +784,7 @@ int i915_gem_object_prepare_write(struct drm_i915_gem_object *obj,
        }
 
 out:
-       intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+       i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
        obj->mm.dirty = true;
        /* return with the pages pinned */
        return 0;
index a50296c..a596548 100644 (file)
@@ -280,7 +280,7 @@ i915_gem_object_flush_write_domain(struct drm_i915_gem_object *obj,
                for_each_ggtt_vma(vma, obj)
                        intel_gt_flush_ggtt_writes(vma->vm->gt);
 
-               intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+               i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 
                for_each_ggtt_vma(vma, obj) {
                        if (vma->iomap)
@@ -308,6 +308,30 @@ i915_gem_object_flush_write_domain(struct drm_i915_gem_object *obj,
        obj->write_domain = 0;
 }
 
+void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
+                                        enum fb_op_origin origin)
+{
+       struct intel_frontbuffer *front;
+
+       front = __intel_frontbuffer_get(obj);
+       if (front) {
+               intel_frontbuffer_flush(front, origin);
+               intel_frontbuffer_put(front);
+       }
+}
+
+void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
+                                             enum fb_op_origin origin)
+{
+       struct intel_frontbuffer *front;
+
+       front = __intel_frontbuffer_get(obj);
+       if (front) {
+               intel_frontbuffer_invalidate(front, origin);
+               intel_frontbuffer_put(front);
+       }
+}
+
 void i915_gem_init__objects(struct drm_i915_private *i915)
 {
        INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
index 458cd51..4b93591 100644 (file)
@@ -13,8 +13,8 @@
 
 #include <drm/i915_drm.h>
 
+#include "display/intel_frontbuffer.h"
 #include "i915_gem_object_types.h"
-
 #include "i915_gem_gtt.h"
 
 void i915_gem_init__objects(struct drm_i915_private *i915);
@@ -463,4 +463,25 @@ int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
                                  unsigned int flags,
                                  const struct i915_sched_attr *attr);
 
+void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
+                                        enum fb_op_origin origin);
+void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
+                                             enum fb_op_origin origin);
+
+static inline void
+i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
+                                 enum fb_op_origin origin)
+{
+       if (unlikely(rcu_access_pointer(obj->frontbuffer)))
+               __i915_gem_object_flush_frontbuffer(obj, origin);
+}
+
+static inline void
+i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj,
+                                      enum fb_op_origin origin)
+{
+       if (unlikely(rcu_access_pointer(obj->frontbuffer)))
+               __i915_gem_object_invalidate_frontbuffer(obj, origin);
+}
+
 #endif
index 9600837..e3f3944 100644 (file)
@@ -150,7 +150,7 @@ struct drm_i915_gem_object {
         */
        u16 write_domain;
 
-       struct intel_frontbuffer *frontbuffer;
+       struct intel_frontbuffer __rcu *frontbuffer;
 
        /** Current tiling stride for the object, if it's tiled. */
        unsigned int tiling_and_stride;
index d034fa4..905890e 100644 (file)
@@ -161,7 +161,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
         * We manually control the domain here and pretend that it
         * remains coherent i.e. in the GTT domain, like shmem_pwrite.
         */
-       intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+       i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 
        if (copy_from_user(vaddr, user_data, args->size))
                return -EFAULT;
@@ -169,7 +169,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
        drm_clflush_virt_range(vaddr, args->size);
        intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt);
 
-       intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+       i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
        return 0;
 }
 
@@ -589,7 +589,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj,
                goto out_unpin;
        }
 
-       intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
+       i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
 
        user_data = u64_to_user_ptr(args->data_ptr);
        offset = args->offset;
@@ -631,7 +631,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj,
                user_data += page_length;
                offset += page_length;
        }
-       intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+       i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
 
        i915_gem_object_unlock_fence(obj, fence);
 out_unpin:
@@ -721,7 +721,7 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj,
                offset = 0;
        }
 
-       intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
+       i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
        i915_gem_object_unlock_fence(obj, fence);
 
        return ret;
index e5512f2..01c8222 100644 (file)
@@ -1104,8 +1104,14 @@ int i915_vma_move_to_active(struct i915_vma *vma,
                return err;
 
        if (flags & EXEC_OBJECT_WRITE) {
-               if (intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CS))
-                       i915_active_add_request(&obj->frontbuffer->write, rq);
+               struct intel_frontbuffer *front;
+
+               front = __intel_frontbuffer_get(obj);
+               if (unlikely(front)) {
+                       if (intel_frontbuffer_invalidate(front, ORIGIN_CS))
+                               i915_active_add_request(&front->write, rq);
+                       intel_frontbuffer_put(front);
+               }
 
                dma_resv_add_excl_fence(vma->resv, &rq->fence);
                obj->write_domain = I915_GEM_DOMAIN_RENDER;