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 d92c92dea4ec..189041984aba 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -377,11 +377,12 @@ void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) | |||
377 | */ | 377 | */ |
378 | void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) | 378 | void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) |
379 | { | 379 | { |
380 | WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); | 380 | unsigned long irqflags; |
381 | 381 | ||
382 | /* Forcewake is atomic in case we get in here without the lock */ | 382 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); |
383 | if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) | 383 | if (dev_priv->forcewake_count++ == 0) |
384 | dev_priv->display.force_wake_get(dev_priv); | 384 | dev_priv->display.force_wake_get(dev_priv); |
385 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); | ||
385 | } | 386 | } |
386 | 387 | ||
387 | void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) | 388 | void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) |
@@ -401,10 +402,12 @@ void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) | |||
401 | */ | 402 | */ |
402 | void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) | 403 | void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) |
403 | { | 404 | { |
404 | WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); | 405 | unsigned long irqflags; |
405 | 406 | ||
406 | if (atomic_dec_and_test(&dev_priv->forcewake_count)) | 407 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); |
408 | if (--dev_priv->forcewake_count == 0) | ||
407 | dev_priv->display.force_wake_put(dev_priv); | 409 | dev_priv->display.force_wake_put(dev_priv); |
410 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); | ||
408 | } | 411 | } |
409 | 412 | ||
410 | void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) | 413 | void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) |
@@ -606,9 +609,36 @@ static int ironlake_do_reset(struct drm_device *dev, u8 flags) | |||
606 | static int gen6_do_reset(struct drm_device *dev, u8 flags) | 609 | static int gen6_do_reset(struct drm_device *dev, u8 flags) |
607 | { | 610 | { |
608 | struct drm_i915_private *dev_priv = dev->dev_private; | 611 | struct drm_i915_private *dev_priv = dev->dev_private; |
612 | int ret; | ||
613 | unsigned long irqflags; | ||
609 | 614 | ||
610 | I915_WRITE(GEN6_GDRST, GEN6_GRDOM_FULL); | 615 | /* Hold gt_lock across reset to prevent any register access |
611 | return wait_for((I915_READ(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); | 616 | * with forcewake not set correctly |
617 | */ | ||
618 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); | ||
619 | |||
620 | /* Reset the chip */ | ||
621 | |||
622 | /* GEN6_GDRST is not in the gt power well, no need to check | ||
623 | * for fifo space for the write or forcewake the chip for | ||
624 | * the read | ||
625 | */ | ||
626 | I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL); | ||
627 | |||
628 | /* Spin waiting for the device to ack the reset request */ | ||
629 | ret = wait_for((I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); | ||
630 | |||
631 | /* If reset with a user forcewake, try to restore, otherwise turn it off */ | ||
632 | if (dev_priv->forcewake_count) | ||
633 | dev_priv->display.force_wake_get(dev_priv); | ||
634 | else | ||
635 | dev_priv->display.force_wake_put(dev_priv); | ||
636 | |||
637 | /* Restore fifo count */ | ||
638 | dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); | ||
639 | |||
640 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); | ||
641 | return ret; | ||
612 | } | 642 | } |
613 | 643 | ||
614 | /** | 644 | /** |
@@ -652,9 +682,6 @@ int i915_reset(struct drm_device *dev, u8 flags) | |||
652 | case 7: | 682 | case 7: |
653 | case 6: | 683 | case 6: |
654 | ret = gen6_do_reset(dev, flags); | 684 | ret = gen6_do_reset(dev, flags); |
655 | /* If reset with a user forcewake, try to restore */ | ||
656 | if (atomic_read(&dev_priv->forcewake_count)) | ||
657 | __gen6_gt_force_wake_get(dev_priv); | ||
658 | break; | 685 | break; |
659 | case 5: | 686 | case 5: |
660 | ret = ironlake_do_reset(dev, flags); | 687 | ret = ironlake_do_reset(dev, flags); |
@@ -940,9 +967,14 @@ MODULE_LICENSE("GPL and additional rights"); | |||
940 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ | 967 | u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ |
941 | u##x val = 0; \ | 968 | u##x val = 0; \ |
942 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ | 969 | if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ |
943 | gen6_gt_force_wake_get(dev_priv); \ | 970 | unsigned long irqflags; \ |
971 | spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ | ||
972 | if (dev_priv->forcewake_count == 0) \ | ||
973 | dev_priv->display.force_wake_get(dev_priv); \ | ||
944 | val = read##y(dev_priv->regs + reg); \ | 974 | val = read##y(dev_priv->regs + reg); \ |
945 | gen6_gt_force_wake_put(dev_priv); \ | 975 | if (dev_priv->forcewake_count == 0) \ |
976 | dev_priv->display.force_wake_put(dev_priv); \ | ||
977 | spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ | ||
946 | } else { \ | 978 | } else { \ |
947 | val = read##y(dev_priv->regs + reg); \ | 979 | val = read##y(dev_priv->regs + reg); \ |
948 | } \ | 980 | } \ |