Re: [Intel-gfx] [PATCH 1/2] lib: add igt_get_stop_rings and igt_set_stop_rings

2014-03-25 Thread Daniel Vetter
On Tue, Mar 25, 2014 at 07:02:21PM +0200, Mika Kuoppala wrote:
> Multiple tests are introducing hangs by fidding with i915_ring_stop
> debugfs entry.
> 
> Signed-off-by: Mika Kuoppala 

Both patches look good to me. One thing we could do is add an exit handler
to reset stop_rings to 0, just in case the test died and somehow the
stop_rings value leaked.

With or w/o that change both patches lgtm, so feel free to push.
-Daniel

> ---
>  lib/igt_debugfs.c |  107 
> +
>  lib/igt_debugfs.h |   28 ++
>  2 files changed, 135 insertions(+)
> 
> diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> index e04f8c5..c4cf50d 100644
> --- a/lib/igt_debugfs.c
> +++ b/lib/igt_debugfs.c
> @@ -28,9 +28,11 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include "drmtest.h"
>  #include "igt_display.h"
> @@ -615,3 +617,108 @@ int igt_open_forcewake_handle(void)
>  {
>   return igt_debugfs_open("i915_forcewake_user", O_WRONLY);
>  }
> +
> +/**
> + * igt_to_stop_ring_flag:
> + * @ring: ring to get flag for, in drm I915_EXEC_* namespace
> + *
> + * This converts ring specified (drm namespace) to a ring flag
> + * to be used with igt_get_stop_rings() and igt_set_stop_rings().
> + *
> + * Returns:
> + * Ring flag for the give 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 cpu from writing tail pointer for ring @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 to give a log
> + * notification that this was simulated hang, as the batch would have
> + * caused hang in any case. Or if you use valid or noop batch and want
> + * to hang the ring (gpu), you must set this flag before submitting the
> + * batch.
> + *
> + * Driver checks periodically if ring is making any progress, and if
> + * 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 tunes down gpu 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) == 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..72f4999 100644
> --- a/lib/igt_debugfs.h
> +++ b/lib/igt_debugfs.h
> @@ -143,4 +143,32 @@ 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

[Intel-gfx] [PATCH 1/2] lib: add igt_get_stop_rings and igt_set_stop_rings

2014-03-25 Thread Mika Kuoppala
Multiple tests are introducing hangs by fidding with i915_ring_stop
debugfs entry.

Signed-off-by: Mika Kuoppala 
---
 lib/igt_debugfs.c |  107 +
 lib/igt_debugfs.h |   28 ++
 2 files changed, 135 insertions(+)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index e04f8c5..c4cf50d 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -28,9 +28,11 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
+#include 
 
 #include "drmtest.h"
 #include "igt_display.h"
@@ -615,3 +617,108 @@ int igt_open_forcewake_handle(void)
 {
return igt_debugfs_open("i915_forcewake_user", O_WRONLY);
 }
+
+/**
+ * igt_to_stop_ring_flag:
+ * @ring: ring to get flag for, in drm I915_EXEC_* namespace
+ *
+ * This converts ring specified (drm namespace) to a ring flag
+ * to be used with igt_get_stop_rings() and igt_set_stop_rings().
+ *
+ * Returns:
+ * Ring flag for the give 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 cpu from writing tail pointer for ring @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 to give a log
+ * notification that this was simulated hang, as the batch would have
+ * caused hang in any case. Or if you use valid or noop batch and want
+ * to hang the ring (gpu), you must set this flag before submitting the
+ * batch.
+ *
+ * Driver checks periodically if ring is making any progress, and if
+ * 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 tunes down gpu 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) == 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..72f4999 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -143,4 +143,32 @@ 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
+ *
+ * Enumeration of all supported flags for igt_set_stop_rings().
+ *
+ */
+enum stop_ring_flags {
+   STOP_RING_NONE = 0,
+   STOP_RING_RENDER = (1 << 0),
+   STOP_RING_BSD = (1 << 1),
+   STOP_RING_BLT = (1 << 2),
+   STOP_RING_VEBOX = (1 << 3),
+   STOP_RING_ALL = 0xff,
+};
+
+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_ge