aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-01-09 07:04:40 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2011-01-19 07:38:26 -0500
commitb0b544cd37c060e261afb2cf486296983fcb56da (patch)
tree90a57f398e2fdc9b1caacaecdd43d7607dbb4a59 /drivers/gpu
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')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c33
2 files changed, 38 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 536368a43412..9b9a771110a4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -35,6 +35,7 @@
35#include "intel_ringbuffer.h" 35#include "intel_ringbuffer.h"
36#include <linux/io-mapping.h> 36#include <linux/io-mapping.h>
37#include <linux/i2c.h> 37#include <linux/i2c.h>
38#include <linux/pm_qos_params.h>
38#include <drm/intel-gtt.h> 39#include <drm/intel-gtt.h>
39 40
40/* General customization: 41/* General customization:
@@ -310,6 +311,10 @@ typedef struct drm_i915_private {
310 int vblank_pipe; 311 int vblank_pipe;
311 int num_pipe; 312 int num_pipe;
312 313
314 atomic_t vblank_enabled;
315 struct pm_qos_request_list vblank_pm_qos;
316 struct work_struct vblank_work;
317
313 /* For hangcheck timer */ 318 /* For hangcheck timer */
314#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ 319#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
315 struct timer_list hangcheck_timer; 320 struct timer_list hangcheck_timer;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b8e509ae065e..46d649bdce06 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,
1337 return i915_wait_irq(dev, irqwait->irq_seq); 1337 return i915_wait_irq(dev, irqwait->irq_seq);
1338} 1338}
1339 1339
1340static void i915_vblank_work_func(struct work_struct *work)
1341{
1342 drm_i915_private_t *dev_priv =
1343 container_of(work, drm_i915_private_t, vblank_work);
1344
1345 if (atomic_read(&dev_priv->vblank_enabled)) {
1346 if (!dev_priv->vblank_pm_qos.pm_qos_class)
1347 pm_qos_add_request(&dev_priv->vblank_pm_qos,
1348 PM_QOS_CPU_DMA_LATENCY,
1349 15); //>=20 won't work
1350 } else {
1351 if (dev_priv->vblank_pm_qos.pm_qos_class)
1352 pm_qos_remove_request(&dev_priv->vblank_pm_qos);
1353 }
1354}
1355
1340/* Called from drm generic code, passed 'crtc' which 1356/* Called from drm generic code, passed 'crtc' which
1341 * we use as a pipe index 1357 * we use as a pipe index
1342 */ 1358 */
@@ -1359,6 +1375,16 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
1359 i915_enable_pipestat(dev_priv, pipe, 1375 i915_enable_pipestat(dev_priv, pipe,
1360 PIPE_VBLANK_INTERRUPT_ENABLE); 1376 PIPE_VBLANK_INTERRUPT_ENABLE);
1361 spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); 1377 spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
1378
1379 /* gen3 platforms have an issue with vsync interrupts not reaching
1380 * cpu during deep c-state sleep (>C1), so we need to install a
1381 * PM QoS handle to prevent C-state starvation of the GPU.
1382 */
1383 if (dev_priv->info->gen == 3 && !dev_priv->info->is_g33) {
1384 atomic_inc(&dev_priv->vblank_enabled);
1385 queue_work(dev_priv->wq, &dev_priv->vblank_work);
1386 }
1387
1362 return 0; 1388 return 0;
1363} 1389}
1364 1390
@@ -1370,6 +1396,11 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
1370 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1396 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1371 unsigned long irqflags; 1397 unsigned long irqflags;
1372 1398
1399 if (dev_priv->info->gen == 3 && !dev_priv->info->is_g33) {
1400 atomic_dec(&dev_priv->vblank_enabled);
1401 queue_work(dev_priv->wq, &dev_priv->vblank_work);
1402 }
1403
1373 spin_lock_irqsave(&dev_priv->irq_lock, irqflags); 1404 spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
1374 if (HAS_PCH_SPLIT(dev)) 1405 if (HAS_PCH_SPLIT(dev))
1375 ironlake_disable_display_irq(dev_priv, (pipe == 0) ? 1406 ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
@@ -1659,9 +1690,11 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
1659 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 1690 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
1660 1691
1661 atomic_set(&dev_priv->irq_received, 0); 1692 atomic_set(&dev_priv->irq_received, 0);
1693 atomic_set(&dev_priv->vblank_enabled, 0);
1662 1694
1663 INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); 1695 INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
1664 INIT_WORK(&dev_priv->error_work, i915_error_work_func); 1696 INIT_WORK(&dev_priv->error_work, i915_error_work_func);
1697 INIT_WORK(&dev_priv->vblank_work, i915_vblank_work_func);
1665 1698
1666 if (HAS_PCH_SPLIT(dev)) { 1699 if (HAS_PCH_SPLIT(dev)) {
1667 ironlake_irq_preinstall(dev); 1700 ironlake_irq_preinstall(dev);