diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 8f7187915b0d..308f81913562 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -368,11 +368,12 @@ void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) | |||
368 | */ | 368 | */ |
369 | void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) | 369 | void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) |
370 | { | 370 | { |
371 | WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); | 371 | unsigned long irqflags; |
372 | 372 | ||
373 | /* Forcewake is atomic in case we get in here without the lock */ | 373 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); |
374 | if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) | 374 | if (dev_priv->forcewake_count++ == 0) |
375 | dev_priv->display.force_wake_get(dev_priv); | 375 | dev_priv->display.force_wake_get(dev_priv); |
376 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); | ||
376 | } | 377 | } |
377 | 378 | ||
378 | void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) | 379 | void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) |
@@ -392,10 +393,12 @@ void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) | |||
392 | */ | 393 | */ |
393 | void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) | 394 | void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) |
394 | { | 395 | { |
395 | WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); | 396 | unsigned long irqflags; |
396 | 397 | ||
397 | if (atomic_dec_and_test(&dev_priv->forcewake_count)) | 398 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); |
399 | if (--dev_priv->forcewake_count == 0) | ||
398 | dev_priv->display.force_wake_put(dev_priv); | 400 | dev_priv->display.force_wake_put(dev_priv); |
401 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); | ||
399 | } | 402 | } |
400 | 403 | ||
401 | void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) | 404 | void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) |
@@ -597,9 +600,36 @@ static int ironlake_do_reset(struct drm_device *dev, u8 flags) | |||
597 | static int gen6_do_reset(struct drm_device *dev, u8 flags) | 600 | static int gen6_do_reset(struct drm_device *dev, u8 flags) |
598 | { | 601 | { |
599 | struct drm_i915_private *dev_priv = dev->dev_private; | 602 | struct drm_i915_private *dev_priv = dev->dev_private; |
603 | int ret; | ||
604 | unsigned long irqflags; | ||
600 | 605 | ||
601 | I915_WRITE(GEN6_GDRST, GEN6_GRDOM_FULL); | 606 | /* Hold gt_lock across reset to prevent any register access |
602 | return wait_for((I915_READ(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); | 607 | * with forcewake not set correctly |
608 | */ | ||
609 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); | ||
610 | |||
611 | /* Reset the chip */ | ||
612 | |||
613 | /* GEN6_GDRST is not in the gt power well, no need to check | ||
614 | * for fifo space for the write or forcewake the chip for | ||
615 | * the read | ||
616 | */ | ||
617 | I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL); | ||
618 | |||
619 | /* Spin waiting for the device to ack the reset request */ | ||
620 | ret = wait_for((I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); | ||
621 | |||
622 | /* If reset with a user forcewake, try to restore, otherwise turn it off */ | ||
623 | if (dev_priv->forcewake_count) | ||
624 | dev_priv->display.force_wake_get(dev_priv); | ||
625 | else | ||
626 | dev_priv->display.force_wake_put(dev_priv); | ||
627 | |||
628 | /* Restore fifo count */ | ||
629 | dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); | ||
630 | |||
631 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); | ||
632 | return ret; | ||
603 | } | 633 | } |
604 | 634 | ||
605 | /** | 635 | /** |
@@ -643,9 +673,6 @@ int i915_reset(struct drm_device *dev, u8 flags) | |||
643 | case 7: | 673 | case 7: |
644 | case 6: | 674 | case 6: |
645 | ret = gen6_do_reset(dev, flags); | 675 | ret = gen6_do_reset(dev, flags); |
646 | /* If reset with a user forcewake, try to restore */ | ||
647 | if (atomic_read(&dev_priv->forcewake_count)) | ||
648 | __gen6_gt_force_wake_get(dev_priv); | ||
649 | break; | 676 | break; |
650 | case 5: | 677 | case 5: |
651 | ret = ironlake_do_reset(dev, flags); | 678 | ret = ironlake_do_reset(dev, flags); |
@@ -927,9 +954,14 @@ MODULE_LICENSE("GPL and additional rights"); | |||
927 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ | 954 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ |
928 | u##x val = 0; \ | 955 | u##x val = 0; \ |
929 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ | 956 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ |
930 | gen6_gt_force_wake_get(dev_priv); \ | 957 | unsigned long irqflags; \ |
958 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ | ||
959 | if (dev_priv->forcewake_count == 0) \ | ||
960 | dev_priv->display.force_wake_get(dev_priv); \ | ||
931 | val = read##y(dev_priv->regs + reg); \ | 961 | val = read##y(dev_priv->regs + reg); \ |
932 | gen6_gt_force_wake_put(dev_priv); \ | 962 | if (dev_priv->forcewake_count == 0) \ |
963 | dev_priv->display.force_wake_put(dev_priv); \ | ||
964 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ | ||
933 | } else { \ | 965 | } else { \ |
934 | val = read##y(dev_priv->regs + reg); \ | 966 | val = read##y(dev_priv->regs + reg); \ |
935 | } \ | 967 | } \ |