Since the advent of trying to perform lockless-waits, commit 3236f57a0162391f84b93f39fc1882c49a8998c7 Author: Chris Wilson <chris at chris-wilson.co.uk> Date: Fri Aug 24 09:35:09 2012 +0100 drm/i915: Use a non-blocking wait for set-to-domain ioctl we exposed ourselves to a race between the reset-worker and those waiters. Previously the reset would have been serialized by the acquisition of the struct_mutex, but now we need to perform an explicit serialisation between the two. Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter at ffwll.ch> --- drivers/gpu/drm/i915/i915_dma.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ 5 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a35217d..50f5535 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1626,6 +1626,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->rps.lock); spin_lock_init(&dev_priv->dpio_lock); + init_rwsem(&dev_priv->reset_lock); + mutex_init(&dev_priv->rps.hw_lock); if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cf407b1..fc5c152 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -42,6 +42,7 @@ #include <linux/kref.h> #include <linux/mmu_notifier.h> #include <linux/pm_qos.h> +#include <linux/rwsem.h> /* General customization: */ @@ -736,6 +737,7 @@ typedef struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; + struct rw_semaphore reset_lock; spinlock_t error_lock; /* Protected by dev->error_lock. */ struct drm_i915_error_state *first_error; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 30501d3..4ef5ba6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1140,6 +1140,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, /* Record current time in case interrupted by signal, or wedged * */ getrawmonotonic(&before); + down_read(&dev_priv->reset_lock); #define EXIT_COND \ (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ @@ -1161,6 +1162,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, end = ret; } while (end == 0 && wait_forever); + up_read(&dev_priv->reset_lock); getrawmonotonic(&now); ring->irq_put(ring); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bfb6c51..54f2d92 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -875,6 +875,7 @@ static void i915_error_work_func(struct work_struct *work) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); + down_write(&dev_priv->reset_lock); if (atomic_read(&dev_priv->mm.wedged)) { DRM_DEBUG_DRIVER("resetting chip\n"); kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); @@ -884,6 +885,7 @@ static void i915_error_work_func(struct work_struct *work) } complete_all(&dev_priv->error_completion); } + up_write(&dev_priv->reset_lock); } /* NB: please notice the memset */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8a9df7d..816ea41 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2313,9 +2313,11 @@ intel_finish_fb(struct drm_framebuffer *old_fb) bool was_interruptible = dev_priv->mm.interruptible; int ret; + down_read(&dev_priv->reset_lock); wait_event(dev_priv->pending_flip_queue, atomic_read(&dev_priv->mm.wedged) || atomic_read(&obj->pending_flip) == 0); + up_read(&dev_priv->reset_lock); /* Big Hammer, we also need to ensure that any pending * MI_WAIT_FOR_EVENT inside a user batch buffer on the @@ -3075,8 +3077,10 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) if (crtc->fb == NULL) return; + down_read(&dev_priv->reset_lock); wait_event(dev_priv->pending_flip_queue, !intel_crtc_has_pending_flip(crtc)); + up_read(&dev_priv->reset_lock); mutex_lock(&dev->struct_mutex); intel_finish_fb(crtc->fb); -- 1.7.10.4