diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 49 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 8 |
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 01ca0e97bebf..b1ddcdc0748e 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 bafb387dd416..e9d824326a03 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 edd208e47308..5be2aa0f54af 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 | ||
370 | static void gen6_pm_irq_handler(struct drm_device *dev) | 370 | static 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 | ||
407 | static void pch_irq_handler(struct drm_device *dev) | 422 | static 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 | ||
536 | done: | 568 | done: |
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 f39ac3a0fa93..289adaa9c928 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 5504ff2a109d..784e52c6e198 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 | ||