[Intel-gfx] [PATCH] RFC drm/i915: Deflate error objects upon capture

Chris Wilson chris at chris-wilson.co.uk
Thu Oct 30 19:25:35 CET 2014


When we capture the GPU error state, we allocate large amounts of memory
to preserve copies of the active objects on the GPU. We can compress the
copy in memory, and use an asci85 encoding when printing them out (to
avoid presenting binary data to unsuspecting catting of debugfs/procfs).

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala at intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h       |   1 +
 drivers/gpu/drm/i915/i915_gpu_error.c | 133 +++++++++++++++++++++++++---------
 2 files changed, 98 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 12c4b918fa3d..669a066cbd50 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -391,6 +391,7 @@ struct drm_i915_error_state {
 
 		struct drm_i915_error_object {
 			int page_count;
+			int unused;
 			u32 gtt_offset;
 			u32 *pages[0];
 		} *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 3e97db2c9fe8..a2243be753af 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -28,6 +28,7 @@
  */
 
 #include <generated/utsrelease.h>
+#include <linux/zlib.h>
 #include "i915_drv.h"
 
 static const char *yesno(int v)
@@ -328,16 +329,40 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
 	va_end(args);
 }
 
+static bool
+asci85_encode(uint32_t in, char *out)
+{
+	int i;
+
+	if (in == 0)
+		return false;
+
+	out[5] = '\0';
+	for (i = 5; i--; ) {
+		int digit = in % 85;
+		out[i] = digit + 33;
+		in /= 85;
+	}
+
+	return true;
+}
+
 static void print_error_obj(struct drm_i915_error_state_buf *m,
 			    struct drm_i915_error_object *obj)
 {
-	int page, offset, elt;
+	char out[6];
+	int page;
 
-	for (page = offset = 0; page < obj->page_count; page++) {
-		for (elt = 0; elt < PAGE_SIZE/4; elt++) {
-			err_printf(m, "%08x :  %08x\n", offset,
-				   obj->pages[page][elt]);
-			offset += 4;
+	for (page = 0; page < obj->page_count; page++) {
+		int i, len = PAGE_SIZE;
+		if (page == obj->page_count - 1)
+			len -= obj->unused;
+		len = (len + 3) / 4;
+		for (i = 0; i < len; i++) {
+			if (asci85_encode(obj->pages[page][i], out))
+				err_puts(m, out);
+			else
+				err_puts(m, "z");
 		}
 	}
 }
@@ -559,7 +584,7 @@ static void i915_error_object_free(struct drm_i915_error_object *obj)
 		return;
 
 	for (page = 0; page < obj->page_count; page++)
-		kfree(obj->pages[page]);
+		free_page((unsigned long)obj->pages[page]);
 
 	kfree(obj);
 }
@@ -585,6 +610,35 @@ static void i915_error_state_free(struct kref *error_ref)
 	kfree(error);
 }
 
+static int compress_page(struct z_stream_s *zstream,
+			 void *src,
+			 struct drm_i915_error_object *dst)
+{
+	zstream->next_in = src;
+	zstream->avail_in = PAGE_SIZE;
+
+	do {
+		if (zstream->avail_out == 0) {
+			zstream->next_out = (void *)__get_free_page(GFP_ATOMIC);
+			if (zstream->next_out == NULL)
+				return -ENOMEM;
+
+			dst->pages[dst->page_count++] = (void *)zstream->next_out;
+			zstream->avail_out = PAGE_SIZE;
+		}
+
+		if (zlib_deflate(zstream, Z_SYNC_FLUSH) != Z_OK)
+			return -EIO;
+
+#if 0
+		if (zstream->total_out > zstream->total_in)
+			return -E2BIG;
+#endif
+	} while (zstream->avail_in);
+
+	return 0;
+}
+
 static struct drm_i915_error_object *
 i915_error_object_create(struct drm_i915_private *dev_priv,
 			 struct i915_vma *vma)
@@ -593,8 +647,8 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
 	struct drm_i915_error_object *dst;
 	int num_pages;
 	bool use_ggtt;
-	int i = 0;
 	u32 reloc_offset;
+	struct z_stream_s zstream;
 
 	if (vma == NULL)
 		return NULL;
@@ -605,11 +659,23 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
 
 	num_pages = src->base.size >> PAGE_SHIFT;
 
-	dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
+	dst = kmalloc(sizeof(*dst) + (10 * num_pages * sizeof(u32 *) >> 3), GFP_ATOMIC);
 	if (dst == NULL)
 		return NULL;
 
 	dst->gtt_offset = vma->node.start;
+	dst->page_count = 0;
+	dst->unused = 0;
+
+	memset(&zstream, 0, sizeof(zstream));
+	zstream.workspace = kmalloc(max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL),
+					zlib_inflate_workspacesize()),
+					GFP_ATOMIC);
+	if (zstream.workspace == NULL ||
+	    zlib_deflateInit(&zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
+		kfree(dst);
+		return NULL;
+	}
 
 	reloc_offset = dst->gtt_offset;
 	use_ggtt = (src->cache_level == I915_CACHE_NONE &&
@@ -632,53 +698,48 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
 	if (use_ggtt && src->cache_level != I915_CACHE_NONE && !HAS_LLC(dev_priv->dev))
 		goto unwind;
 
-	dst->page_count = num_pages;
+	if (!use_ggtt)
+		reloc_offset = 0;
+
 	while (num_pages--) {
 		unsigned long flags;
-		void *d;
-
-		d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
-		if (d == NULL)
-			goto unwind;
+		void *s;
+		int ret;
 
 		local_irq_save(flags);
 		if (use_ggtt) {
-			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->gtt.mappable,
-						     reloc_offset);
-			memcpy_fromio(d, s, PAGE_SIZE);
+			s = (void *__force)
+				io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
+							 reloc_offset);
+			ret = compress_page(&zstream, s, dst);
 			io_mapping_unmap_atomic(s);
 		} else {
-			struct page *page;
-			void *s;
-
-			page = i915_gem_object_get_page(src, i);
-
-			drm_clflush_pages(&page, 1);
-
-			s = kmap_atomic(page);
-			memcpy(d, s, PAGE_SIZE);
+			s = kmap_atomic(i915_gem_object_get_page(src, reloc_offset >> PAGE_SHIFT));
+			drm_clflush_virt_range(s, PAGE_SIZE);
+			ret = compress_page(&zstream, s, dst);
 			kunmap_atomic(s);
-
-			drm_clflush_pages(&page, 1);
 		}
 		local_irq_restore(flags);
-
-		dst->pages[i++] = d;
+		if (ret)
+			goto unwind;
 		reloc_offset += PAGE_SIZE;
 	}
+	zlib_deflate(&zstream, Z_FINISH);
+	dst->unused = zstream.avail_out;
+	zlib_deflateEnd(&zstream);
+	kfree(zstream.workspace);
 
 	return dst;
 
 unwind:
-	while (i--)
-		kfree(dst->pages[i]);
+	while (dst->page_count--)
+		kfree(dst->pages[dst->page_count]);
+	zlib_deflateEnd(&zstream);
+	kfree(zstream.workspace);
 	kfree(dst);
 	return NULL;
 }
-- 
2.1.1




More information about the Intel-gfx mailing list