aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Widawsky <benjamin.widawsky@intel.com>2013-10-16 12:21:30 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-10-18 09:44:47 -0400
commit828c79087cec61eaf4c76bb32c222fbe35ac3930 (patch)
treecc75223a6c43e606f2e836fe306b9adad721c0ca /drivers/gpu/drm
parentb35b380ed46bb01726bec1795e6443e625306757 (diff)
drm/i915: Disable GGTT PTEs on GEN6+ suspend
Once the machine gets to a certain point in the suspend process, we expect the GPU to be idle. If it is not, we might corrupt memory. Empirically (with an early version of this patch) we have seen this is not the case. We cannot currently explain why the latent GPU writes occur. In the technical sense, this patch is a workaround in that we have an issue we can't explain, and the patch indirectly solves the issue. However, it's really better than a workaround because we understand why it works, and it really should be a safe thing to do in all cases. The noticeable effect other than the debug messages would be an increase in the suspend time. I have not measure how expensive it actually is. I think it would be good to spend further time to root cause why we're seeing these latent writes, but it shouldn't preclude preventing the fallout. NOTE: It should be safe (and makes some sense IMO) to also keep the VALID bit unset on resume when we clear_range(). I've opted not to do this as properly clearing those bits at some later point would be extra work. v2: Fix bugzilla link Bugzilla: http://bugs.freedesktop.org/show_bug.cgi?id=65496 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=59321 Tested-by: Takashi Iwai <tiwai@suse.de> Tested-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Ben Widawsky <ben@bwidawsk.net> Tested-By: Todd Previte <tprevite@gmail.com> Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c76
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h4
4 files changed, 78 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 69d8ed5416c3..2ad27880cd04 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -505,6 +505,8 @@ static int i915_drm_freeze(struct drm_device *dev)
505 intel_modeset_suspend_hw(dev); 505 intel_modeset_suspend_hw(dev);
506 } 506 }
507 507
508 i915_gem_suspend_gtt_mappings(dev);
509
508 i915_save_state(dev); 510 i915_save_state(dev);
509 511
510 intel_opregion_fini(dev); 512 intel_opregion_fini(dev);
@@ -648,7 +650,8 @@ static int i915_drm_thaw(struct drm_device *dev)
648 mutex_lock(&dev->struct_mutex); 650 mutex_lock(&dev->struct_mutex);
649 i915_gem_restore_gtt_mappings(dev); 651 i915_gem_restore_gtt_mappings(dev);
650 mutex_unlock(&dev->struct_mutex); 652 mutex_unlock(&dev->struct_mutex);
651 } 653 } else if (drm_core_check_feature(dev, DRIVER_MODESET))
654 i915_check_and_clear_faults(dev);
652 655
653 __i915_drm_thaw(dev); 656 __i915_drm_thaw(dev);
654 657
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3979a81dd6ee..ab0f2c0a440c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -501,7 +501,8 @@ struct i915_address_space {
501 bool valid); /* Create a valid PTE */ 501 bool valid); /* Create a valid PTE */
502 void (*clear_range)(struct i915_address_space *vm, 502 void (*clear_range)(struct i915_address_space *vm,
503 unsigned int first_entry, 503 unsigned int first_entry,
504 unsigned int num_entries); 504 unsigned int num_entries,
505 bool use_scratch);
505 void (*insert_entries)(struct i915_address_space *vm, 506 void (*insert_entries)(struct i915_address_space *vm,
506 struct sg_table *st, 507 struct sg_table *st,
507 unsigned int first_entry, 508 unsigned int first_entry,
@@ -2066,6 +2067,8 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
2066void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, 2067void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
2067 struct drm_i915_gem_object *obj); 2068 struct drm_i915_gem_object *obj);
2068 2069
2070void i915_check_and_clear_faults(struct drm_device *dev);
2071void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
2069void i915_gem_restore_gtt_mappings(struct drm_device *dev); 2072void i915_gem_restore_gtt_mappings(struct drm_device *dev);
2070int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj); 2073int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
2071void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, 2074void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 32aa69d7ef20..1f7b4caefb6e 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -241,7 +241,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
241/* PPGTT support for Sandybdrige/Gen6 and later */ 241/* PPGTT support for Sandybdrige/Gen6 and later */
242static void gen6_ppgtt_clear_range(struct i915_address_space *vm, 242static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
243 unsigned first_entry, 243 unsigned first_entry,
244 unsigned num_entries) 244 unsigned num_entries,
245 bool use_scratch)
245{ 246{
246 struct i915_hw_ppgtt *ppgtt = 247 struct i915_hw_ppgtt *ppgtt =
247 container_of(vm, struct i915_hw_ppgtt, base); 248 container_of(vm, struct i915_hw_ppgtt, base);
@@ -372,7 +373,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
372 } 373 }
373 374
374 ppgtt->base.clear_range(&ppgtt->base, 0, 375 ppgtt->base.clear_range(&ppgtt->base, 0,
375 ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES); 376 ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true);
376 377
377 ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); 378 ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
378 379
@@ -449,7 +450,8 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
449{ 450{
450 ppgtt->base.clear_range(&ppgtt->base, 451 ppgtt->base.clear_range(&ppgtt->base,
451 i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, 452 i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
452 obj->base.size >> PAGE_SHIFT); 453 obj->base.size >> PAGE_SHIFT,
454 true);
453} 455}
454 456
455extern int intel_iommu_gfx_mapped; 457extern int intel_iommu_gfx_mapped;
@@ -490,15 +492,65 @@ static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
490 dev_priv->mm.interruptible = interruptible; 492 dev_priv->mm.interruptible = interruptible;
491} 493}
492 494
495void i915_check_and_clear_faults(struct drm_device *dev)
496{
497 struct drm_i915_private *dev_priv = dev->dev_private;
498 struct intel_ring_buffer *ring;
499 int i;
500
501 if (INTEL_INFO(dev)->gen < 6)
502 return;
503
504 for_each_ring(ring, dev_priv, i) {
505 u32 fault_reg;
506 fault_reg = I915_READ(RING_FAULT_REG(ring));
507 if (fault_reg & RING_FAULT_VALID) {
508 DRM_DEBUG_DRIVER("Unexpected fault\n"
509 "\tAddr: 0x%08lx\\n"
510 "\tAddress space: %s\n"
511 "\tSource ID: %d\n"
512 "\tType: %d\n",
513 fault_reg & PAGE_MASK,
514 fault_reg & RING_FAULT_GTTSEL_MASK ? "GGTT" : "PPGTT",
515 RING_FAULT_SRCID(fault_reg),
516 RING_FAULT_FAULT_TYPE(fault_reg));
517 I915_WRITE(RING_FAULT_REG(ring),
518 fault_reg & ~RING_FAULT_VALID);
519 }
520 }
521 POSTING_READ(RING_FAULT_REG(&dev_priv->ring[RCS]));
522}
523
524void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
525{
526 struct drm_i915_private *dev_priv = dev->dev_private;
527
528 /* Don't bother messing with faults pre GEN6 as we have little
529 * documentation supporting that it's a good idea.
530 */
531 if (INTEL_INFO(dev)->gen < 6)
532 return;
533
534 i915_check_and_clear_faults(dev);
535
536 dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
537 dev_priv->gtt.base.start / PAGE_SIZE,
538 dev_priv->gtt.base.total / PAGE_SIZE,
539 false);
540}
541
493void i915_gem_restore_gtt_mappings(struct drm_device *dev) 542void i915_gem_restore_gtt_mappings(struct drm_device *dev)
494{ 543{
495 struct drm_i915_private *dev_priv = dev->dev_private; 544 struct drm_i915_private *dev_priv = dev->dev_private;
496 struct drm_i915_gem_object *obj; 545 struct drm_i915_gem_object *obj;
497 546
547 i915_check_and_clear_faults(dev);
548
498 /* First fill our portion of the GTT with scratch pages */ 549 /* First fill our portion of the GTT with scratch pages */
499 dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, 550 dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
500 dev_priv->gtt.base.start / PAGE_SIZE, 551 dev_priv->gtt.base.start / PAGE_SIZE,
501 dev_priv->gtt.base.total / PAGE_SIZE); 552 dev_priv->gtt.base.total / PAGE_SIZE,
553 true);
502 554
503 list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { 555 list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
504 i915_gem_clflush_object(obj, obj->pin_display); 556 i915_gem_clflush_object(obj, obj->pin_display);
@@ -565,7 +617,8 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
565 617
566static void gen6_ggtt_clear_range(struct i915_address_space *vm, 618static void gen6_ggtt_clear_range(struct i915_address_space *vm,
567 unsigned int first_entry, 619 unsigned int first_entry,
568 unsigned int num_entries) 620 unsigned int num_entries,
621 bool use_scratch)
569{ 622{
570 struct drm_i915_private *dev_priv = vm->dev->dev_private; 623 struct drm_i915_private *dev_priv = vm->dev->dev_private;
571 gen6_gtt_pte_t scratch_pte, __iomem *gtt_base = 624 gen6_gtt_pte_t scratch_pte, __iomem *gtt_base =
@@ -578,7 +631,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
578 first_entry, num_entries, max_entries)) 631 first_entry, num_entries, max_entries))
579 num_entries = max_entries; 632 num_entries = max_entries;
580 633
581 scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); 634 scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch);
635
582 for (i = 0; i < num_entries; i++) 636 for (i = 0; i < num_entries; i++)
583 iowrite32(scratch_pte, &gtt_base[i]); 637 iowrite32(scratch_pte, &gtt_base[i]);
584 readl(gtt_base); 638 readl(gtt_base);
@@ -599,7 +653,8 @@ static void i915_ggtt_insert_entries(struct i915_address_space *vm,
599 653
600static void i915_ggtt_clear_range(struct i915_address_space *vm, 654static void i915_ggtt_clear_range(struct i915_address_space *vm,
601 unsigned int first_entry, 655 unsigned int first_entry,
602 unsigned int num_entries) 656 unsigned int num_entries,
657 bool unused)
603{ 658{
604 intel_gtt_clear_range(first_entry, num_entries); 659 intel_gtt_clear_range(first_entry, num_entries);
605} 660}
@@ -627,7 +682,8 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
627 682
628 dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, 683 dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
629 entry, 684 entry,
630 obj->base.size >> PAGE_SHIFT); 685 obj->base.size >> PAGE_SHIFT,
686 true);
631 687
632 obj->has_global_gtt_mapping = 0; 688 obj->has_global_gtt_mapping = 0;
633} 689}
@@ -714,11 +770,11 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
714 const unsigned long count = (hole_end - hole_start) / PAGE_SIZE; 770 const unsigned long count = (hole_end - hole_start) / PAGE_SIZE;
715 DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n", 771 DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n",
716 hole_start, hole_end); 772 hole_start, hole_end);
717 ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count); 773 ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count, true);
718 } 774 }
719 775
720 /* And finally clear the reserved guard page */ 776 /* And finally clear the reserved guard page */
721 ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1); 777 ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true);
722} 778}
723 779
724static bool 780static bool
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index fd721ea8728e..ef9b35479f01 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -604,6 +604,10 @@
604#define ARB_MODE_SWIZZLE_IVB (1<<5) 604#define ARB_MODE_SWIZZLE_IVB (1<<5)
605#define RENDER_HWS_PGA_GEN7 (0x04080) 605#define RENDER_HWS_PGA_GEN7 (0x04080)
606#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id) 606#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id)
607#define RING_FAULT_GTTSEL_MASK (1<<11)
608#define RING_FAULT_SRCID(x) ((x >> 3) & 0xff)
609#define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3)
610#define RING_FAULT_VALID (1<<0)
607#define DONE_REG 0x40b0 611#define DONE_REG 0x40b0
608#define BSD_HWS_PGA_GEN7 (0x04180) 612#define BSD_HWS_PGA_GEN7 (0x04180)
609#define BLT_HWS_PGA_GEN7 (0x04280) 613#define BLT_HWS_PGA_GEN7 (0x04280)