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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxxxxxxx>
Cc: Mika Kuoppala <mika.kuoppala@xxxxxxxxx>
---
 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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx





[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux