lib: add igt_get_stop_rings and igt_set_stop_rings

Multiple tests are introducing hangs by fidding with i915_ring_stop
debugfs entry.

Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com>
This commit is contained in:
Mika Kuoppala 2014-03-25 12:21:44 +02:00
parent 1c7ca57e53
commit bfa6fa9a4b
3 changed files with 157 additions and 0 deletions

View File

@ -88,6 +88,18 @@ is_intel(int fd)
return IS_INTEL(devid); 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) #define LOCAL_I915_EXEC_VEBOX (4 << 0)
/** /**
* gem_quiescent_gpu: * gem_quiescent_gpu:
@ -108,6 +120,8 @@ void gem_quiescent_gpu(int fd)
struct drm_i915_gem_execbuffer2 execbuf; struct drm_i915_gem_execbuffer2 execbuf;
struct drm_i915_gem_exec_object2 gem_exec[1]; struct drm_i915_gem_exec_object2 gem_exec[1];
check_stop_rings();
handle = gem_create(fd, 4096); handle = gem_create(fd, 4096);
gem_write(fd, handle, 0, batch, sizeof(batch)); 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) if (at_exit_drm_fd < 0)
return; return;
check_stop_rings();
gem_quiescent_gpu(at_exit_drm_fd); gem_quiescent_gpu(at_exit_drm_fd);
close(at_exit_drm_fd); close(at_exit_drm_fd);
at_exit_drm_fd = -1; 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) if (at_exit_drm_render_fd < 0)
return; return;
check_stop_rings();
gem_quiescent_gpu(at_exit_drm_render_fd); gem_quiescent_gpu(at_exit_drm_render_fd);
close(at_exit_drm_render_fd); close(at_exit_drm_render_fd);
at_exit_drm_render_fd = -1; at_exit_drm_render_fd = -1;

View File

@ -28,9 +28,11 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <i915_drm.h>
#include "drmtest.h" #include "drmtest.h"
#include "igt_kms.h" #include "igt_kms.h"
@ -615,3 +617,109 @@ int igt_open_forcewake_handle(void)
{ {
return igt_debugfs_open("i915_forcewake_user", O_WRONLY); 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);
}

View File

@ -143,4 +143,37 @@ void igt_enable_prefault(void);
int igt_open_forcewake_handle(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__ */ #endif /* __IGT_DEBUGFS_H__ */