summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-01-09 12:04:40 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2011-01-19 12:38:26 +0000
commitb0b544cd37c060e261afb2cf486296983fcb56da (patch)
tree90a57f398e2fdc9b1caacaecdd43d7607dbb4a59 /drivers/gpu/drm/i915/i915_irq.c
parentf67a559daaa0e2ba616bfe9438f202bc57bc8c72 (diff)
drm/i915: Use PM QoS to prevent C-State starvation of gen3 GPU
945 class hardware has an interesting quirk in which the vblank interrupt is not raised if the CPU is in a low power state. (We also suspect that the memory bus is clocked to the CPU/c-state and not the GPU so there are secondary starvation issues.) In order to prevent the most obvious issue of the low of the vblank interrupt (stuttering compositing that only updates when the mouse is moving) is to install a PM QoS request to prevent low c-states whilst the GPU is active. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b8e509ae065..46d649bdce0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1337,6 +1337,22 @@ int i915_irq_wait(struct drm_device *dev, void *data,
return i915_wait_irq(dev, irqwait->irq_seq);
}
+static void i915_vblank_work_func(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv =
+ container_of(work, drm_i915_private_t, vblank_work);
+
+ if (atomic_read(&dev_priv->vblank_enabled)) {
+ if (!dev_priv->vblank_pm_qos.pm_qos_class)
+ pm_qos_add_request(&dev_priv->vblank_pm_qos,
+ PM_QOS_CPU_DMA_LATENCY,
+ 15); //>=20 won't work
+ } else {
+ if (dev_priv->vblank_pm_qos.pm_qos_class)
+ pm_qos_remove_request(&dev_priv->vblank_pm_qos);
+ }
+}
+
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
@@ -1359,6 +1375,16 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
i915_enable_pipestat(dev_priv, pipe,
PIPE_VBLANK_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ /* gen3 platforms have an issue with vsync interrupts not reaching
+ * cpu during deep c-state sleep (>C1), so we need to install a
+ * PM QoS handle to prevent C-state starvation of the GPU.
+ */
+ if (dev_priv->info->gen == 3 && !dev_priv->info->is_g33) {
+ atomic_inc(&dev_priv->vblank_enabled);
+ queue_work(dev_priv->wq, &dev_priv->vblank_work);
+ }
+
return 0;
}
@@ -1370,6 +1396,11 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
+ if (dev_priv->info->gen == 3 && !dev_priv->info->is_g33) {
+ atomic_dec(&dev_priv->vblank_enabled);
+ queue_work(dev_priv->wq, &dev_priv->vblank_work);
+ }
+
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev))
ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
@@ -1659,9 +1690,11 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
atomic_set(&dev_priv->irq_received, 0);
+ atomic_set(&dev_priv->vblank_enabled, 0);
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+ INIT_WORK(&dev_priv->vblank_work, i915_vblank_work_func);
if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_preinstall(dev);