From 172975aa746e155533cb386c7159c2d6510e2bc8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 14 Dec 2011 13:57:25 +0100 Subject: [PATCH] drm/i915: Handle unmappable buffers during error state capture As the buffer is not necessarily accessible through the GTT at the time of a GPU hang, and capturing some of its contents is far more valuable than skipping it, provide a clflushed fallback read path. We still prefer to read through the GTT as that is more consistent with the GPU access of the same buffer. So example it will demonstrate any errorneous tiling or swizzling of the command buffer as seen by the GPU. This becomes necessary with use of CPU relocations and lazy GTT binding, but could potentially happen anyway as a result of a pathological error. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Reviewed-by: Eugeni Dodonov Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 64bb212..8ea1ca4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -720,7 +720,6 @@ i915_error_object_create(struct drm_i915_private *dev_priv, reloc_offset = src->gtt_offset; for (page = 0; page < page_count; page++) { unsigned long flags; - void __iomem *s; void *d; d = kmalloc(PAGE_SIZE, GFP_ATOMIC); @@ -728,10 +727,29 @@ i915_error_object_create(struct drm_i915_private *dev_priv, goto unwind; local_irq_save(flags); - s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, - reloc_offset); - memcpy_fromio(d, s, PAGE_SIZE); - io_mapping_unmap_atomic(s); + if (reloc_offset < dev_priv->mm.gtt_mappable_end) { + void __iomem *s; + + /* Simply ignore tiling or any overlapping fence. + * It's part of the error state, and this hopefully + * captures what the GPU read. + */ + + s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + reloc_offset); + memcpy_fromio(d, s, PAGE_SIZE); + io_mapping_unmap_atomic(s); + } else { + void *s; + + drm_clflush_pages(&src->pages[page], 1); + + s = kmap_atomic(src->pages[page]); + memcpy(d, s, PAGE_SIZE); + kunmap_atomic(s); + + drm_clflush_pages(&src->pages[page], 1); + } local_irq_restore(flags); dst->pages[page] = d; -- 2.7.4