aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Widawsky <ben@bwidawsk.net>2011-04-25 14:25:20 -0400
committerKeith Packard <keithp@keithp.com>2011-05-10 16:56:47 -0400
commit4912d04193733a825216b926ffd290fada88ab07 (patch)
tree28f299240c04955f9cca7a7fad794ece744da4bb /drivers/gpu/drm
parentd1ebd816e6d7967c764f0cfa7d718f7c5cc7a8e4 (diff)
drm/i915: move gen6 rps handling to workqueue
The render P-state handling code requires reading from a GT register. This means that FORCEWAKE must be written to, a resource which is shared and should be protected by struct_mutex. Hence we can not manipulate that register from within the interrupt handling and so must delegate the task to a workqueue. Signed-off-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c49
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h5
-rw-r--r--drivers/gpu/drm/i915/intel_display.c8
5 files changed, 58 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 01ca0e97beb..b1ddcdc0748 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -2038,6 +2038,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
2038 2038
2039 spin_lock_init(&dev_priv->irq_lock); 2039 spin_lock_init(&dev_priv->irq_lock);
2040 spin_lock_init(&dev_priv->error_lock); 2040 spin_lock_init(&dev_priv->error_lock);
2041 spin_lock_init(&dev_priv->rps_lock);
2041 2042
2042 if (IS_MOBILE(dev) || !IS_GEN2(dev)) 2043 if (IS_MOBILE(dev) || !IS_GEN2(dev))
2043 dev_priv->num_pipe = 2; 2044 dev_priv->num_pipe = 2;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index bafb387dd41..e9d824326a0 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -682,6 +682,10 @@ typedef struct drm_i915_private {
682 682
683 bool mchbar_need_disable; 683 bool mchbar_need_disable;
684 684
685 struct work_struct rps_work;
686 spinlock_t rps_lock;
687 u32 pm_iir;
688
685 u8 cur_delay; 689 u8 cur_delay;
686 u8 min_delay; 690 u8 min_delay;
687 u8 max_delay; 691 u8 max_delay;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index edd208e4730..5be2aa0f54a 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev,
367 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); 367 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
368} 368}
369 369
370static void gen6_pm_irq_handler(struct drm_device *dev) 370static void gen6_pm_rps_work(struct work_struct *work)
371{ 371{
372 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 372 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
373 rps_work);
373 u8 new_delay = dev_priv->cur_delay; 374 u8 new_delay = dev_priv->cur_delay;
374 u32 pm_iir; 375 u32 pm_iir, pm_imr;
376
377 spin_lock_irq(&dev_priv->rps_lock);
378 pm_iir = dev_priv->pm_iir;
379 dev_priv->pm_iir = 0;
380 pm_imr = I915_READ(GEN6_PMIMR);
381 spin_unlock_irq(&dev_priv->rps_lock);
375 382
376 pm_iir = I915_READ(GEN6_PMIIR);
377 if (!pm_iir) 383 if (!pm_iir)
378 return; 384 return;
379 385
386 mutex_lock(&dev_priv->dev->struct_mutex);
380 if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { 387 if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
381 if (dev_priv->cur_delay != dev_priv->max_delay) 388 if (dev_priv->cur_delay != dev_priv->max_delay)
382 new_delay = dev_priv->cur_delay + 1; 389 new_delay = dev_priv->cur_delay + 1;
383 if (new_delay > dev_priv->max_delay) 390 if (new_delay > dev_priv->max_delay)
384 new_delay = dev_priv->max_delay; 391 new_delay = dev_priv->max_delay;
385 } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) { 392 } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
393 gen6_gt_force_wake_get(dev_priv);
386 if (dev_priv->cur_delay != dev_priv->min_delay) 394 if (dev_priv->cur_delay != dev_priv->min_delay)
387 new_delay = dev_priv->cur_delay - 1; 395 new_delay = dev_priv->cur_delay - 1;
388 if (new_delay < dev_priv->min_delay) { 396 if (new_delay < dev_priv->min_delay) {
@@ -396,12 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
396 I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, 404 I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
397 I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000); 405 I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
398 } 406 }
407 gen6_gt_force_wake_put(dev_priv);
399 } 408 }
400 409
401 gen6_set_rps(dev, new_delay); 410 gen6_set_rps(dev_priv->dev, new_delay);
402 dev_priv->cur_delay = new_delay; 411 dev_priv->cur_delay = new_delay;
403 412
404 I915_WRITE(GEN6_PMIIR, pm_iir); 413 /*
414 * rps_lock not held here because clearing is non-destructive. There is
415 * an *extremely* unlikely race with gen6_rps_enable() that is prevented
416 * by holding struct_mutex for the duration of the write.
417 */
418 I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir);
419 mutex_unlock(&dev_priv->dev->struct_mutex);
405} 420}
406 421
407static void pch_irq_handler(struct drm_device *dev) 422static void pch_irq_handler(struct drm_device *dev)
@@ -525,13 +540,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
525 i915_handle_rps_change(dev); 540 i915_handle_rps_change(dev);
526 } 541 }
527 542
528 if (IS_GEN6(dev)) 543 if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
529 gen6_pm_irq_handler(dev); 544 /*
545 * IIR bits should never already be set because IMR should
546 * prevent an interrupt from being shown in IIR. The warning
547 * displays a case where we've unsafely cleared
548 * dev_priv->pm_iir. Although missing an interrupt of the same
549 * type is not a problem, it displays a problem in the logic.
550 *
551 * The mask bit in IMR is cleared by rps_work.
552 */
553 unsigned long flags;
554 spin_lock_irqsave(&dev_priv->rps_lock, flags);
555 WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
556 I915_WRITE(GEN6_PMIMR, pm_iir);
557 dev_priv->pm_iir |= pm_iir;
558 spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
559 queue_work(dev_priv->wq, &dev_priv->rps_work);
560 }
530 561
531 /* should clear PCH hotplug event before clear CPU irq */ 562 /* should clear PCH hotplug event before clear CPU irq */
532 I915_WRITE(SDEIIR, pch_iir); 563 I915_WRITE(SDEIIR, pch_iir);
533 I915_WRITE(GTIIR, gt_iir); 564 I915_WRITE(GTIIR, gt_iir);
534 I915_WRITE(DEIIR, de_iir); 565 I915_WRITE(DEIIR, de_iir);
566 I915_WRITE(GEN6_PMIIR, pm_iir);
535 567
536done: 568done:
537 I915_WRITE(DEIER, de_ier); 569 I915_WRITE(DEIER, de_ier);
@@ -1658,6 +1690,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
1658 1690
1659 INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); 1691 INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
1660 INIT_WORK(&dev_priv->error_work, i915_error_work_func); 1692 INIT_WORK(&dev_priv->error_work, i915_error_work_func);
1693 INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
1661 1694
1662 if (HAS_PCH_SPLIT(dev)) { 1695 if (HAS_PCH_SPLIT(dev)) {
1663 ironlake_irq_preinstall(dev); 1696 ironlake_irq_preinstall(dev);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f39ac3a0fa9..289adaa9c92 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3386,7 +3386,7 @@
3386#define GEN6_PMINTRMSK 0xA168 3386#define GEN6_PMINTRMSK 0xA168
3387 3387
3388#define GEN6_PMISR 0x44020 3388#define GEN6_PMISR 0x44020
3389#define GEN6_PMIMR 0x44024 3389#define GEN6_PMIMR 0x44024 /* rps_lock */
3390#define GEN6_PMIIR 0x44028 3390#define GEN6_PMIIR 0x44028
3391#define GEN6_PMIER 0x4402C 3391#define GEN6_PMIER 0x4402C
3392#define GEN6_PM_MBOX_EVENT (1<<25) 3392#define GEN6_PM_MBOX_EVENT (1<<25)
@@ -3396,6 +3396,9 @@
3396#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4) 3396#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4)
3397#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2) 3397#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2)
3398#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1) 3398#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1)
3399#define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \
3400 GEN6_PM_RP_DOWN_THRESHOLD | \
3401 GEN6_PM_RP_DOWN_TIMEOUT)
3399 3402
3400#define GEN6_PCODE_MAILBOX 0x138124 3403#define GEN6_PCODE_MAILBOX 0x138124
3401#define GEN6_PCODE_READY (1<<31) 3404#define GEN6_PCODE_READY (1<<31)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 5504ff2a109..784e52c6e19 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6876,6 +6876,11 @@ void gen6_disable_rps(struct drm_device *dev)
6876 I915_WRITE(GEN6_RPNSWREQ, 1 << 31); 6876 I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
6877 I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); 6877 I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
6878 I915_WRITE(GEN6_PMIER, 0); 6878 I915_WRITE(GEN6_PMIER, 0);
6879
6880 spin_lock_irq(&dev_priv->rps_lock);
6881 dev_priv->pm_iir = 0;
6882 spin_unlock_irq(&dev_priv->rps_lock);
6883
6879 I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); 6884 I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
6880} 6885}
6881 6886
@@ -7078,7 +7083,10 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
7078 GEN6_PM_RP_DOWN_THRESHOLD | 7083 GEN6_PM_RP_DOWN_THRESHOLD |
7079 GEN6_PM_RP_UP_EI_EXPIRED | 7084 GEN6_PM_RP_UP_EI_EXPIRED |
7080 GEN6_PM_RP_DOWN_EI_EXPIRED); 7085 GEN6_PM_RP_DOWN_EI_EXPIRED);
7086 spin_lock_irq(&dev_priv->rps_lock);
7087 WARN_ON(dev_priv->pm_iir != 0);
7081 I915_WRITE(GEN6_PMIMR, 0); 7088 I915_WRITE(GEN6_PMIMR, 0);
7089 spin_unlock_irq(&dev_priv->rps_lock);
7082 /* enable all PM interrupts */ 7090 /* enable all PM interrupts */
7083 I915_WRITE(GEN6_PMINTRMSK, 0); 7091 I915_WRITE(GEN6_PMINTRMSK, 0);
7084 7092