diff mbox

[1/2] intel_gpu_top: Skip head/tail reads on HSW

Message ID 1456107838-2265-1-git-send-email-ben@bwidawsk.net (mailing list archive)
State New, archived
Headers show

Commit Message

Ben Widawsky Feb. 22, 2016, 2:23 a.m. UTC
Haswell has a known issue when doing concurrent reads of MMIO (see reference for
details). This issue results in a system wide unrecoverable hang. As this tool
is shipped by default in the IGT package, this is a very mean behavior to
accidentally impose on the user.

This patch shuts this behavior down by default on HSW, and prints a warning. An
upcoming patch will provide an override for the insane.

References: https://lists.freedesktop.org/archives/mesa-dev/2013-July/041692.html
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
 man/intel_gpu_top.man |  2 ++
 tools/intel_gpu_top.c | 28 +++++++++++++++++++++++-----
 2 files changed, 25 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/man/intel_gpu_top.man b/man/intel_gpu_top.man
index b307a23..d90a7ee 100644
--- a/man/intel_gpu_top.man
+++ b/man/intel_gpu_top.man
@@ -39,3 +39,5 @@  header.
 .SH BUGS
 Some GPUs report some units as busy when they aren't, such that even when
 idle and not hung, it will show up as 100% busy.
+.TP
+Haswell GPU may hang when trying to determine ring busyness, and so it is disabled by default.
diff --git a/tools/intel_gpu_top.c b/tools/intel_gpu_top.c
index 4f327c6..33a8e0c 100644
--- a/tools/intel_gpu_top.c
+++ b/tools/intel_gpu_top.c
@@ -316,6 +316,7 @@  struct ring {
 	int head, tail, size;
 	uint64_t full;
 	int idle;
+	bool skip_ring_reads;
 };
 
 static uint32_t ring_read(struct ring *ring, uint32_t reg)
@@ -323,9 +324,14 @@  static uint32_t ring_read(struct ring *ring, uint32_t reg)
 	return INREG(ring->mmio + reg);
 }
 
-static void ring_init(struct ring *ring)
+static void ring_init(struct ring *ring, uint32_t devid)
 {
 	ring->size = (((ring_read(ring, RING_LEN) & RING_NR_PAGES) >> 12) + 1) * 4096;
+
+	if (IS_HASWELL(devid)) {
+		fprintf(stderr, "Skipping reads of head, and tail registers to avoid hangs\n");
+		ring->skip_ring_reads = true;
+	}
 }
 
 static void ring_reset(struct ring *ring)
@@ -340,6 +346,9 @@  static void ring_sample(struct ring *ring)
 	if (!ring->size)
 		return;
 
+	if (ring->skip_ring_reads)
+		return;
+
 	ring->head = ring_read(ring, RING_HEAD) & HEAD_ADDR;
 	ring->tail = ring_read(ring, RING_TAIL) & TAIL_ADDR;
 
@@ -366,6 +375,15 @@  static void ring_print(struct ring *ring, unsigned long samples_per_sec)
 	if (!ring->size)
 		return;
 
+	if (ring->skip_ring_reads) {
+		len = printf("%25s busy: ??%%: ", ring->name);
+		print_percentage_bar(0, len);
+		printf("%24s space: ??\?/%d\n",
+		       ring->name,
+		       ring->size);
+		return;
+	}
+
 	percent_busy = 100 - 100 * ring->idle / samples_per_sec;
 
 	len = printf("%25s busy: %3d%%: ", ring->name, percent_busy);
@@ -513,12 +531,12 @@  int main(int argc, char **argv)
 	/* Grab access to the registers */
 	intel_register_access_init(pci_dev, 0);
 
-	ring_init(&render_ring);
+	ring_init(&render_ring, devid);
 	if (IS_GEN4(devid) || IS_GEN5(devid))
-		ring_init(&bsd_ring);
+		ring_init(&bsd_ring, devid);
 	if (IS_GEN6(devid) || IS_GEN7(devid)) {
-		ring_init(&bsd6_ring);
-		ring_init(&blt_ring);
+		ring_init(&bsd6_ring, devid);
+		ring_init(&blt_ring, devid);
 	}
 
 	/* Initialize GPU stats */