drm/i915: Re-arm the idle timers if the device is still busy
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 8 Dec 2010 09:43:41 +0000 (09:43 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 9 Dec 2010 19:13:52 +0000 (19:13 +0000)
Don't post a downclocking task if the device is still active when the
idle timer fires. A pathological process could queue up several seconds
worth of processing and then go to sleep, during which time the idle
timer would kick in and downclock the GPU.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/intel_display.c

index 1ccf2ad7cd888f3e93782f35bae37dfe163aa9b7..6d4faff8121b8c5d2aad2d69a2b711ab03d5475c 100644 (file)
@@ -4758,8 +4758,14 @@ static void intel_gpu_idle_timer(unsigned long arg)
        struct drm_device *dev = (struct drm_device *)arg;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       dev_priv->busy = false;
+       if (!list_empty(&dev_priv->mm.active_list)) {
+               /* Still processing requests, so just re-arm the timer. */
+               mod_timer(&dev_priv->idle_timer, jiffies +
+                         msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+               return;
+       }
 
+       dev_priv->busy = false;
        queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
@@ -4770,9 +4776,17 @@ static void intel_crtc_idle_timer(unsigned long arg)
        struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
        struct drm_crtc *crtc = &intel_crtc->base;
        drm_i915_private_t *dev_priv = crtc->dev->dev_private;
+       struct intel_framebuffer *intel_fb;
 
-       intel_crtc->busy = false;
+       intel_fb = to_intel_framebuffer(crtc->fb);
+       if (intel_fb && intel_fb->obj->active) {
+               /* The framebuffer is still being accessed by the GPU. */
+               mod_timer(&intel_crtc->idle_timer, jiffies +
+                         msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+               return;
+       }
 
+       intel_crtc->busy = false;
        queue_work(dev_priv->wq, &dev_priv->idle_work);
 }