[Intel-gfx] [PATCH] drm/i915: Serialize the reset worker and any waiters

Chris Wilson chris at chris-wilson.co.uk
Mon Nov 12 11:27:45 CET 2012


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




More information about the Intel-gfx mailing list