drm/i915: Make dev_priv->mm.wedged an atomic_t
authorBen Gamari <bgamari.foss@gmail.com>
Mon, 14 Sep 2009 21:48:47 +0000 (17:48 -0400)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Thu, 17 Sep 2009 21:36:46 +0000 (14:36 -0700)
There is a very real possibility that multiple CPUs will notice that the
GPU is wedged. This introduces all sorts of potential race conditions.
Make the wedged flag atomic to mitigate this risk.

Signed-off-by: Ben Gamari <bgamari.foss@gmail.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c

index 42142f26976527ce6578db509d3a0c1ef9df0cf7..bcc1be281de617927f9cebbd08cbb11e1de0d198 100644 (file)
@@ -450,7 +450,7 @@ typedef struct drm_i915_private {
                 * It prevents command submission from occuring and makes
                 * every pending request fail
                 */
-               int wedged;
+               atomic_t wedged;
 
                /** Bit 6 swizzling required for X tiling */
                uint32_t bit_6_swizzle_x;
index 579b3b04ff1237643ce3b94dcbebde5e3d95b5b7..f0f6f668a61e4e783a6e756e69d16265bb1fc0c1 100644 (file)
@@ -1712,7 +1712,7 @@ i915_gem_retire_requests(struct drm_device *dev)
                retiring_seqno = request->seqno;
 
                if (i915_seqno_passed(seqno, retiring_seqno) ||
-                   dev_priv->mm.wedged) {
+                   atomic_read(&dev_priv->mm.wedged)) {
                        i915_gem_retire_request(dev, request);
 
                        list_del(&request->list);
@@ -1754,7 +1754,7 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno)
 
        BUG_ON(seqno == 0);
 
-       if (dev_priv->mm.wedged)
+       if (atomic_read(&dev_priv->mm.wedged))
                return -EIO;
 
        if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
@@ -1774,11 +1774,11 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno)
                ret = wait_event_interruptible(dev_priv->irq_queue,
                                               i915_seqno_passed(i915_get_gem_seqno(dev),
                                                                 seqno) ||
-                                              dev_priv->mm.wedged);
+                                              atomic_read(&dev_priv->mm.wedged));
                i915_user_irq_put(dev);
                dev_priv->mm.waiting_gem_seqno = 0;
        }
-       if (dev_priv->mm.wedged)
+       if (atomic_read(&dev_priv->mm.wedged))
                ret = -EIO;
 
        if (ret && ret != -ERESTARTSYS)
@@ -3359,7 +3359,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 
        i915_verify_inactive(dev, __FILE__, __LINE__);
 
-       if (dev_priv->mm.wedged) {
+       if (atomic_read(&dev_priv->mm.wedged)) {
                DRM_ERROR("Execbuf while wedged\n");
                mutex_unlock(&dev->struct_mutex);
                ret = -EIO;
@@ -3929,7 +3929,7 @@ i915_gem_idle(struct drm_device *dev)
                if (last_seqno == cur_seqno) {
                        if (stuck++ > 100) {
                                DRM_ERROR("hardware wedged\n");
-                               dev_priv->mm.wedged = 1;
+                               atomic_set(&dev_priv->mm.wedged, 1);
                                DRM_WAKEUP(&dev_priv->irq_queue);
                                break;
                        }
@@ -3942,7 +3942,7 @@ i915_gem_idle(struct drm_device *dev)
        i915_gem_retire_requests(dev);
 
        spin_lock(&dev_priv->mm.active_list_lock);
-       if (!dev_priv->mm.wedged) {
+       if (!atomic_read(&dev_priv->mm.wedged)) {
                /* Active and flushing should now be empty as we've
                 * waited for a sequence higher than any pending execbuffer
                 */
@@ -4204,9 +4204,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return 0;
 
-       if (dev_priv->mm.wedged) {
+       if (atomic_read(&dev_priv->mm.wedged)) {
                DRM_ERROR("Reenabling wedged hardware, good luck\n");
-               dev_priv->mm.wedged = 0;
+               atomic_set(&dev_priv->mm.wedged, 0);
        }
 
        mutex_lock(&dev->struct_mutex);
index 8f5276614ce2c2e65b727b3bbf79f8cf0033b783..13e664ddb61106111fd31703671a7582aa23f276 100644 (file)
@@ -309,12 +309,12 @@ static void i915_error_work_func(struct work_struct *work)
        DRM_DEBUG("generating error event\n");
        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
-       if (dev_priv->mm.wedged) {
+       if (atomic_read(&dev_priv->mm.wedged)) {
                if (IS_I965G(dev)) {
                        DRM_DEBUG("resetting chip\n");
                        kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
                        if (!i965_reset(dev, GDRST_RENDER)) {
-                               dev_priv->mm.wedged = 0;
+                               atomic_set(&dev_priv->mm.wedged, 0);
                                kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
                        }
                } else {
@@ -385,7 +385,7 @@ out:
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
  */
-static void i915_handle_error(struct drm_device *dev)
+static void i915_handle_error(struct drm_device *dev, bool wedged)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 eir = I915_READ(EIR);
@@ -495,7 +495,9 @@ static void i915_handle_error(struct drm_device *dev)
                I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
        }
 
-       if (dev_priv->mm.wedged) {
+       if (wedged) {
+               atomic_set(&dev_priv->mm.wedged, 1);
+
                /*
                 * Wakeup waiting processes so they don't hang
                 */
@@ -548,7 +550,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                pipeb_stats = I915_READ(PIPEBSTAT);
 
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev);
+                       i915_handle_error(dev, false);
 
                /*
                 * Clear the PIPE(A|B)STAT regs before the IIR
@@ -934,8 +936,7 @@ void i915_hangcheck_elapsed(unsigned long data)
 
        if (dev_priv->last_acthd == acthd && dev_priv->hangcheck_count > 0) {
                DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
-               dev_priv->mm.wedged = true; /* Hopefully this is atomic */
-               i915_handle_error(dev);
+               i915_handle_error(dev, true);
                return;
        }