diff mbox

[1/4] lib: add igt_get_stop_rings and igt_set_stop_rings

Message ID 1396024730-9514-1-git-send-email-mika.kuoppala@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mika Kuoppala March 28, 2014, 4:38 p.m. UTC
Multiple tests are introducing hangs by fidding with i915_ring_stop
debugfs entry.

Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
---
 lib/drmtest.c     |   16 ++++++++
 lib/igt_debugfs.c |  108 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_debugfs.h |   33 ++++++++++++++++
 3 files changed, 157 insertions(+)
diff mbox

Patch

diff --git a/lib/drmtest.c b/lib/drmtest.c
index b1bf589..2c9cf62 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -88,6 +88,18 @@  is_intel(int fd)
 	return IS_INTEL(devid);
 }
 
+static void check_stop_rings(void)
+{
+	enum stop_ring_flags flags;
+	flags = igt_get_stop_rings();
+	igt_warn_on_f(flags != 0,
+		      "i915_ring_stop flags on exit 0x%x, can't quiescent gpu cleanly\n",
+		      flags);
+
+	if (flags)
+		igt_set_stop_rings(STOP_RING_NONE);
+}
+
 #define LOCAL_I915_EXEC_VEBOX	(4 << 0)
 /**
  * gem_quiescent_gpu:
@@ -108,6 +120,8 @@  void gem_quiescent_gpu(int fd)
 	struct drm_i915_gem_execbuffer2 execbuf;
 	struct drm_i915_gem_exec_object2 gem_exec[1];
 
+	check_stop_rings();
+
 	handle = gem_create(fd, 4096);
 	gem_write(fd, handle, 0, batch, sizeof(batch));
 
@@ -252,6 +266,7 @@  static void quiescent_gpu_at_exit(int sig)
 	if (at_exit_drm_fd < 0)
 		return;
 
+	check_stop_rings();
 	gem_quiescent_gpu(at_exit_drm_fd);
 	close(at_exit_drm_fd);
 	at_exit_drm_fd = -1;
@@ -262,6 +277,7 @@  static void quiescent_gpu_at_exit_render(int sig)
 	if (at_exit_drm_render_fd < 0)
 		return;
 
+	check_stop_rings();
 	gem_quiescent_gpu(at_exit_drm_render_fd);
 	close(at_exit_drm_render_fd);
 	at_exit_drm_render_fd = -1;
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 81a06ff..0996666 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -28,9 +28,11 @@ 
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <i915_drm.h>
 
 #include "drmtest.h"
 #include "igt_kms.h"
@@ -615,3 +617,109 @@  int igt_open_forcewake_handle(void)
 {
 	return igt_debugfs_open("i915_forcewake_user", O_WRONLY);
 }
+
+/**
+ * igt_to_stop_ring_flag:
+ * @ring: the specified ring flag from execbuf ioctl (I915_EXEC_*)
+ *
+ * This converts the specified ring to a ring flag to be used
+ * with igt_get_stop_rings() and igt_set_stop_rings().
+ *
+ * Returns:
+ * Ring flag for the given ring.
+ */
+enum stop_ring_flags igt_to_stop_ring_flag(int ring) {
+	if (ring == I915_EXEC_DEFAULT)
+		return STOP_RING_RENDER;
+
+	igt_assert(ring && ((ring & ~I915_EXEC_RING_MASK) == 0));
+	return 1 << (ring - 1);
+}
+
+static void stop_rings_write(uint32_t mask)
+{
+	int fd;
+	char buf[80];
+
+	igt_assert(snprintf(buf, sizeof(buf), "0x%08x", mask) == 10);
+	fd = igt_debugfs_open("i915_ring_stop", O_WRONLY);
+	igt_assert(fd >= 0);
+
+	igt_assert(write(fd, buf, strlen(buf)) == strlen(buf));
+	close(fd);
+}
+
+/**
+ * igt_get_stop_rings:
+ *
+ * Read current ring flags from 'i915_ring_stop' debugfs entry.
+ *
+ * Returns:
+ * Current ring flags.
+ */
+enum stop_ring_flags igt_get_stop_rings(void)
+{
+	int fd;
+	char buf[80];
+	int l;
+	unsigned long long ring_mask;
+
+	fd = igt_debugfs_open("i915_ring_stop", O_RDONLY);
+	igt_assert(fd >= 0);
+	l =  read(fd, buf, sizeof(buf));
+	igt_assert(l > 0);
+	igt_assert(l < sizeof(buf));
+
+	buf[l] = '\0';
+
+	close(fd);
+
+	errno = 0;
+	ring_mask = strtoull(buf, NULL, 0);
+	igt_assert(errno == 0);
+	return ring_mask;
+}
+
+/**
+ * igt_set_stop_rings:
+ * @flags: Ring flags to write
+ *
+ * This writes @flags to 'i915_ring_stop' debugfs entry. Driver will
+ * prevent the CPU from writing tail pointer for the ring that @flags
+ * specify. Note that the ring is not stopped right away. Instead any
+ * further command emissions won't be executed after the flag is set.
+ *
+ * This is the least invasive way to make the GPU stuck. Hence you must
+ * set this after a batch submission with it's own invalid or endless
+ * looping instructions. In this case it is merely for giving notification
+ * for the driver that this was simulated hang, as the batch would have
+ * caused hang in any case. On the other hand if you use a valid or noop
+ * batch and want to hang the ring (GPU), you must set corresponding flag
+ * before submitting the batch.
+ *
+ * Driver checks periodically if a ring is making any progress, and if
+ * it is not, it will declare the ring to be hung and will reset the GPU.
+ * After reset, the driver will clear flags in 'i915_ring_stop'
+ *
+ * Note: Always when hanging the GPU, use igt_set_stop_rings() to
+ * notify the driver. Driver controls hang log messaging based on
+ * these flags and thus prevents false positives on logs.
+ */
+void igt_set_stop_rings(enum stop_ring_flags flags)
+{
+	enum stop_ring_flags current;
+
+	igt_assert((flags & ~(STOP_RING_ALL |
+			      STOP_RING_ALLOW_BAN |
+			      STOP_RING_ALLOW_ERRORS)) == 0);
+
+	current = igt_get_stop_rings();
+	igt_assert_f(current == 0,
+		     "previous i915_ring_stop is still 0x%x\n", current);
+
+	stop_rings_write(flags);
+	current = igt_get_stop_rings();
+	if (current != flags)
+		igt_warn("i915_ring_stop readback mismatch 0x%x vs 0x%x\n",
+			 flags, current);
+}
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 3312a8b..bcd7f76 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -143,4 +143,37 @@  void igt_enable_prefault(void);
 
 int igt_open_forcewake_handle(void);
 
+/**
+ * stop_ring_flags:
+ *
+ * @STOP_RING_NONE: Can be used to clear the pending stop (warning: hang might
+ * be declared already). Returned by igt_get_stop_rings() if there is
+ * no currently stopped rings.
+ * @STOP_RING_RENDER: Render ring
+ * @STOP_RING_BSD: Video encoding/decoding ring
+ * @STOP_RING_BLT: Blitter ring
+ * @STOP_RING_VEBOX: Video enchanment ring
+ * @STOP_RING_ALL: All rings
+ * @STOP_RING_ALLOW_ERRORS: Driver will not omit expected DRM_ERRORS
+ * @STOP_RING_ALLOW_BAN: Driver will use context ban policy
+ * @STOP_RING_DEFAULT: STOP_RING_ALL | STOP_RING_ALLOW_ERRORS
+ * Enumeration of all supported flags for igt_set_stop_rings().
+ *
+ */
+enum stop_ring_flags {
+	STOP_RING_NONE = 0x00,
+	STOP_RING_RENDER = (1 << 0),
+	STOP_RING_BSD = (1 << 1),
+	STOP_RING_BLT = (1 << 2),
+	STOP_RING_VEBOX = (1 << 3),
+	STOP_RING_ALL = 0xff,
+	STOP_RING_ALLOW_ERRORS = (1 << 30),
+	STOP_RING_ALLOW_BAN = (1 << 31),
+	STOP_RING_DEFAULTS = STOP_RING_ALL | STOP_RING_ALLOW_ERRORS,
+};
+
+enum stop_ring_flags igt_to_stop_ring_flag(int ring);
+void igt_set_stop_rings(enum stop_ring_flags flags);
+enum stop_ring_flags igt_get_stop_rings(void);
+
 #endif /* __IGT_DEBUGFS_H__ */