drm/i915: Hold reference to intel_frontbuffer as we track activity
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: 8e7cb1799b
("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
This commit is contained in:
parent
edb1ecad77
commit
da42104f58
11 changed files with 116 additions and 31 deletions
|
@ -15186,7 +15186,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fb_obj_bump_render_priority(obj);
|
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->uapi.fence) { /* implicit fencing */
|
if (!new_plane_state->uapi.fence) { /* implicit fencing */
|
||||||
struct dma_fence *fence;
|
struct dma_fence *fence;
|
||||||
|
|
|
@ -229,11 +229,11 @@ static void frontbuffer_release(struct kref *ref)
|
||||||
vma->display_alignment = I915_GTT_MIN_ALIGNMENT;
|
vma->display_alignment = I915_GTT_MIN_ALIGNMENT;
|
||||||
spin_unlock(&obj->vma.lock);
|
spin_unlock(&obj->vma.lock);
|
||||||
|
|
||||||
obj->frontbuffer = NULL;
|
RCU_INIT_POINTER(obj->frontbuffer, NULL);
|
||||||
spin_unlock(&to_i915(obj->base.dev)->fb_tracking.lock);
|
spin_unlock(&to_i915(obj->base.dev)->fb_tracking.lock);
|
||||||
|
|
||||||
i915_gem_object_put(obj);
|
i915_gem_object_put(obj);
|
||||||
kfree(front);
|
kfree_rcu(front, rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct intel_frontbuffer *
|
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 drm_i915_private *i915 = to_i915(obj->base.dev);
|
||||||
struct intel_frontbuffer *front;
|
struct intel_frontbuffer *front;
|
||||||
|
|
||||||
spin_lock(&i915->fb_tracking.lock);
|
front = __intel_frontbuffer_get(obj);
|
||||||
front = obj->frontbuffer;
|
|
||||||
if (front)
|
|
||||||
kref_get(&front->ref);
|
|
||||||
spin_unlock(&i915->fb_tracking.lock);
|
|
||||||
if (front)
|
if (front)
|
||||||
return front;
|
return front;
|
||||||
|
|
||||||
|
@ -262,13 +258,13 @@ intel_frontbuffer_get(struct drm_i915_gem_object *obj)
|
||||||
i915_active_may_sleep(frontbuffer_retire));
|
i915_active_may_sleep(frontbuffer_retire));
|
||||||
|
|
||||||
spin_lock(&i915->fb_tracking.lock);
|
spin_lock(&i915->fb_tracking.lock);
|
||||||
if (obj->frontbuffer) {
|
if (rcu_access_pointer(obj->frontbuffer)) {
|
||||||
kfree(front);
|
kfree(front);
|
||||||
front = obj->frontbuffer;
|
front = rcu_dereference_protected(obj->frontbuffer, true);
|
||||||
kref_get(&front->ref);
|
kref_get(&front->ref);
|
||||||
} else {
|
} else {
|
||||||
i915_gem_object_get(obj);
|
i915_gem_object_get(obj);
|
||||||
obj->frontbuffer = front;
|
rcu_assign_pointer(obj->frontbuffer, front);
|
||||||
}
|
}
|
||||||
spin_unlock(&i915->fb_tracking.lock);
|
spin_unlock(&i915->fb_tracking.lock);
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,10 @@
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
|
|
||||||
|
#include "gem/i915_gem_object_types.h"
|
||||||
#include "i915_active.h"
|
#include "i915_active.h"
|
||||||
|
|
||||||
struct drm_i915_private;
|
struct drm_i915_private;
|
||||||
struct drm_i915_gem_object;
|
|
||||||
|
|
||||||
enum fb_op_origin {
|
enum fb_op_origin {
|
||||||
ORIGIN_GTT,
|
ORIGIN_GTT,
|
||||||
|
@ -45,6 +45,7 @@ struct intel_frontbuffer {
|
||||||
atomic_t bits;
|
atomic_t bits;
|
||||||
struct i915_active write;
|
struct i915_active write;
|
||||||
struct drm_i915_gem_object *obj;
|
struct drm_i915_gem_object *obj;
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
void intel_frontbuffer_flip_prepare(struct drm_i915_private *i915,
|
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,
|
void intel_frontbuffer_flip(struct drm_i915_private *i915,
|
||||||
unsigned frontbuffer_bits);
|
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 *
|
struct intel_frontbuffer *
|
||||||
intel_frontbuffer_get(struct drm_i915_gem_object *obj);
|
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,
|
struct intel_frontbuffer *new,
|
||||||
unsigned int frontbuffer_bits);
|
unsigned int frontbuffer_bits);
|
||||||
|
|
||||||
void intel_frontbuffer_put(struct intel_frontbuffer *front);
|
|
||||||
|
|
||||||
#endif /* __INTEL_FRONTBUFFER_H__ */
|
#endif /* __INTEL_FRONTBUFFER_H__ */
|
||||||
|
|
|
@ -279,12 +279,21 @@ static void intel_overlay_flip_prepare(struct intel_overlay *overlay,
|
||||||
struct i915_vma *vma)
|
struct i915_vma *vma)
|
||||||
{
|
{
|
||||||
enum pipe pipe = overlay->crtc->pipe;
|
enum pipe pipe = overlay->crtc->pipe;
|
||||||
|
struct intel_frontbuffer *from, *to;
|
||||||
|
|
||||||
WARN_ON(overlay->old_vma);
|
WARN_ON(overlay->old_vma);
|
||||||
|
|
||||||
intel_frontbuffer_track(overlay->vma ? overlay->vma->obj->frontbuffer : NULL,
|
if (overlay->vma)
|
||||||
vma ? vma->obj->frontbuffer : NULL,
|
from = intel_frontbuffer_get(overlay->vma->obj);
|
||||||
INTEL_FRONTBUFFER_OVERLAY(pipe));
|
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_flip_prepare(overlay->i915,
|
||||||
INTEL_FRONTBUFFER_OVERLAY(pipe));
|
INTEL_FRONTBUFFER_OVERLAY(pipe));
|
||||||
|
@ -764,7 +773,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
||||||
ret = PTR_ERR(vma);
|
ret = PTR_ERR(vma);
|
||||||
goto out_pin_section;
|
goto out_pin_section;
|
||||||
}
|
}
|
||||||
intel_frontbuffer_flush(new_bo->frontbuffer, ORIGIN_DIRTYFB);
|
i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB);
|
||||||
|
|
||||||
if (!overlay->active) {
|
if (!overlay->active) {
|
||||||
u32 oconfig;
|
u32 oconfig;
|
||||||
|
|
|
@ -20,7 +20,8 @@ static void __do_clflush(struct drm_i915_gem_object *obj)
|
||||||
{
|
{
|
||||||
GEM_BUG_ON(!i915_gem_object_has_pages(obj));
|
GEM_BUG_ON(!i915_gem_object_has_pages(obj));
|
||||||
drm_clflush_sg(obj->mm.pages);
|
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)
|
static int clflush_work(struct dma_fence_work *base)
|
||||||
|
|
|
@ -558,7 +558,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
||||||
i915_gem_object_unlock(obj);
|
i915_gem_object_unlock(obj);
|
||||||
|
|
||||||
if (write_domain)
|
if (write_domain)
|
||||||
intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
|
i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
|
||||||
|
|
||||||
out_unpin:
|
out_unpin:
|
||||||
i915_gem_object_unpin_pages(obj);
|
i915_gem_object_unpin_pages(obj);
|
||||||
|
@ -678,7 +678,7 @@ int i915_gem_object_prepare_write(struct drm_i915_gem_object *obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CPU);
|
i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU);
|
||||||
obj->mm.dirty = true;
|
obj->mm.dirty = true;
|
||||||
/* return with the pages pinned */
|
/* return with the pages pinned */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -313,7 +313,7 @@ i915_gem_object_flush_write_domain(struct drm_i915_gem_object *obj,
|
||||||
}
|
}
|
||||||
spin_unlock(&obj->vma.lock);
|
spin_unlock(&obj->vma.lock);
|
||||||
|
|
||||||
intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
|
i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case I915_GEM_DOMAIN_WC:
|
case I915_GEM_DOMAIN_WC:
|
||||||
|
@ -333,6 +333,30 @@ i915_gem_object_flush_write_domain(struct drm_i915_gem_object *obj,
|
||||||
obj->write_domain = 0;
|
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)
|
void i915_gem_init__objects(struct drm_i915_private *i915)
|
||||||
{
|
{
|
||||||
INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
|
INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
#include <drm/i915_drm.h>
|
#include <drm/i915_drm.h>
|
||||||
|
|
||||||
|
#include "display/intel_frontbuffer.h"
|
||||||
#include "i915_gem_object_types.h"
|
#include "i915_gem_object_types.h"
|
||||||
|
|
||||||
#include "i915_gem_gtt.h"
|
#include "i915_gem_gtt.h"
|
||||||
|
|
||||||
void i915_gem_init__objects(struct drm_i915_private *i915);
|
void i915_gem_init__objects(struct drm_i915_private *i915);
|
||||||
|
@ -471,4 +471,25 @@ int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const struct i915_sched_attr *attr);
|
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
|
#endif
|
||||||
|
|
|
@ -173,7 +173,7 @@ struct drm_i915_gem_object {
|
||||||
*/
|
*/
|
||||||
u16 write_domain;
|
u16 write_domain;
|
||||||
|
|
||||||
struct intel_frontbuffer *frontbuffer;
|
struct intel_frontbuffer __rcu *frontbuffer;
|
||||||
|
|
||||||
/** Current tiling stride for the object, if it's tiled. */
|
/** Current tiling stride for the object, if it's tiled. */
|
||||||
unsigned int tiling_and_stride;
|
unsigned int tiling_and_stride;
|
||||||
|
|
|
@ -200,7 +200,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
|
||||||
* We manually control the domain here and pretend that it
|
* We manually control the domain here and pretend that it
|
||||||
* remains coherent i.e. in the GTT domain, like shmem_pwrite.
|
* 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))
|
if (copy_from_user(vaddr, user_data, args->size))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -208,7 +208,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
|
||||||
drm_clflush_virt_range(vaddr, args->size);
|
drm_clflush_virt_range(vaddr, args->size);
|
||||||
intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,7 +628,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj,
|
||||||
goto out_unpin;
|
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);
|
user_data = u64_to_user_ptr(args->data_ptr);
|
||||||
offset = args->offset;
|
offset = args->offset;
|
||||||
|
@ -672,7 +672,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_gt_flush_ggtt_writes(ggtt->vm.gt);
|
intel_gt_flush_ggtt_writes(ggtt->vm.gt);
|
||||||
intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
|
i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
|
||||||
|
|
||||||
i915_gem_object_unlock_fence(obj, fence);
|
i915_gem_object_unlock_fence(obj, fence);
|
||||||
out_unpin:
|
out_unpin:
|
||||||
|
@ -761,7 +761,7 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj,
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
intel_frontbuffer_flush(obj->frontbuffer, ORIGIN_CPU);
|
i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU);
|
||||||
i915_gem_object_unlock_fence(obj, fence);
|
i915_gem_object_unlock_fence(obj, fence);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1148,8 +1148,14 @@ int i915_vma_move_to_active(struct i915_vma *vma,
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (flags & EXEC_OBJECT_WRITE) {
|
if (flags & EXEC_OBJECT_WRITE) {
|
||||||
if (intel_frontbuffer_invalidate(obj->frontbuffer, ORIGIN_CS))
|
struct intel_frontbuffer *front;
|
||||||
i915_active_add_request(&obj->frontbuffer->write, rq);
|
|
||||||
|
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);
|
dma_resv_add_excl_fence(vma->resv, &rq->fence);
|
||||||
obj->write_domain = I915_GEM_DOMAIN_RENDER;
|
obj->write_domain = I915_GEM_DOMAIN_RENDER;
|
||||||
|
|
Loading…
Add table
Reference in a new issue