[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