#include "ioctl_wrappers.h"
#include "drmtest.h"
#include "igt_debugfs.h"
-#include "intel_bufmgr.h"
#include "intel_chipset.h"
-#include "intel_batchbuffer.h"
#include "intel_io.h"
+#include "igt_aux.h"
#define RS_NO_ERROR 0
#define RS_BATCH_ACTIVE (1 << 0)
#define RS_BATCH_PENDING (1 << 1)
#define RS_UNKNOWN (1 << 2)
+static uint32_t devid;
+static bool hw_contexts;
+
struct local_drm_i915_reset_stats {
__u32 ctx_id;
__u32 flags;
static bool has_context(const struct target_ring *ring)
{
+ if (!hw_contexts)
+ return false;
+
if(ring->exec == I915_EXEC_RENDER)
return true;
return exec_valid_ring(fd, ctx, current_ring->exec);
}
-static void stop_rings(const int mask)
-{
- int fd;
- char buf[80];
-
- igt_assert((mask & ~((1 << NUM_RINGS) - 1)) == 0);
- igt_assert(snprintf(buf, sizeof(buf), "0x%02x", mask) == 4);
- fd = igt_debugfs_open("i915_ring_stop", O_WRONLY);
- igt_assert(fd >= 0);
-
- igt_assert(write(fd, buf, 4) == 4);
- close(fd);
-}
-
#define BUFSIZE (4 * 1024)
#define ITEMS (BUFSIZE >> 2)
-static int ring_to_mask(int ring)
-{
- for (unsigned i = 0; i < NUM_RINGS; i++) {
- const struct target_ring *r = &rings[i];
-
- if (r->exec == ring)
- return (1 << i);
- }
-
- igt_assert(0);
-
- return -1;
-}
-
-static int inject_hang_ring(int fd, int ctx, int ring)
+static int inject_hang_ring(int fd, int ctx, int ring, bool ignore_ban_error)
{
struct drm_i915_gem_execbuffer2 execbuf;
struct drm_i915_gem_exec_object2 exec;
uint32_t *buf;
int roff, i;
unsigned cmd_len = 2;
+ enum stop_ring_flags flags;
srandom(time(NULL));
- if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+ if (intel_gen(devid) >= 8)
cmd_len = 3;
buf = malloc(BUFSIZE);
for (i = 0; i < ITEMS; i++)
buf[i] = MI_NOOP;
- roff = random() % (ITEMS - cmd_len);
+ roff = random() % (ITEMS - cmd_len - 1);
buf[roff] = MI_BATCH_BUFFER_START | (cmd_len - 2);
buf[roff + 1] = (gtt_off & 0xfffffffc) + (roff << 2);
if (cmd_len == 3)
- buf[roff + 2] = gtt_off & 0xffffffff00000000ull;
-
-#ifdef VERBOSE
- printf("loop injected at 0x%lx (off 0x%x, bo_start 0x%lx, bo_end 0x%lx)\n",
- (long unsigned int)((roff << 2) + gtt_off),
- roff << 2, (long unsigned int)gtt_off,
- (long unsigned int)(gtt_off + BUFSIZE - 1));
-#endif
+ buf[roff + 2] = (gtt_off & 0xffffffff00000000ull) >> 32;
+
+ buf[roff + cmd_len] = MI_BATCH_BUFFER_END;
+
+ igt_debug("loop injected at 0x%lx (off 0x%x, bo_start 0x%lx, bo_end 0x%lx)\n",
+ (long unsigned int)((roff << 2) + gtt_off),
+ roff << 2, (long unsigned int)gtt_off,
+ (long unsigned int)(gtt_off + BUFSIZE - 1));
gem_write(fd, exec.handle, 0, buf, BUFSIZE);
exec.relocation_count = 0;
free(buf);
- stop_rings(ring_to_mask(ring));
+ flags = igt_to_stop_ring_flag(ring);
+
+ flags |= STOP_RING_ALLOW_BAN;
+
+ if (!ignore_ban_error)
+ flags |= STOP_RING_ALLOW_ERRORS;
+
+ igt_set_stop_rings(flags);
return exec.handle;
}
static int inject_hang(int fd, int ctx)
{
- return inject_hang_ring(fd, ctx, current_ring->exec);
+ return inject_hang_ring(fd, ctx, current_ring->exec, false);
+}
+
+static int inject_hang_no_ban_error(int fd, int ctx)
+{
+ return inject_hang_ring(fd, ctx, current_ring->exec, true);
}
static int _assert_reset_status(int fd, int ctx, int status)
rs = gem_reset_status(fd, ctx);
if (rs < 0) {
- printf("reset status for %d ctx %d returned %d\n",
- fd, ctx, rs);
+ igt_info("reset status for %d ctx %d returned %d\n",
+ fd, ctx, rs);
return rs;
}
if (rs != status) {
- printf("%d:%d reset status %d differs from assumed %d\n",
- fd, ctx, rs, status);
+ igt_info("%d:%d reset status %d differs from assumed %d\n",
+ fd, ctx, rs, status);
return 1;
}
assert_reset_status(fd_bad, 0, RS_NO_ERROR);
assert_reset_status(fd_good, 0, RS_NO_ERROR);
- h2 = inject_hang(fd_bad, 0);
+ h2 = inject_hang_no_ban_error(fd_bad, 0);
igt_assert(h2 >= 0);
active_count++;
/* Second hang will be pending for this */
h7 = exec_valid(fd_good, 0);
while (retry--) {
- h3 = inject_hang(fd_bad, 0);
+ h3 = inject_hang_no_ban_error(fd_bad, 0);
igt_assert(h3 >= 0);
gem_sync(fd_bad, h3);
active_count++;
gem_close(fd_bad, h3);
gem_close(fd_bad, h4);
- printf("retrying for ban (%d)\n", retry);
+ igt_info("retrying for ban (%d)\n", retry);
}
igt_assert(h4 == -EIO);
assert_reset_status(fd, ctx_good, RS_NO_ERROR);
assert_reset_status(fd, ctx_bad, RS_NO_ERROR);
- h2 = inject_hang(fd, ctx_bad);
+ h2 = inject_hang_no_ban_error(fd, ctx_bad);
igt_assert(h2 >= 0);
active_count++;
/* Second hang will be pending for this */
h7 = exec_valid(fd, ctx_good);
while (retry--) {
- h3 = inject_hang(fd, ctx_bad);
+ h3 = inject_hang_no_ban_error(fd, ctx_bad);
igt_assert(h3 >= 0);
gem_sync(fd, h3);
active_count++;
gem_close(fd, h3);
gem_close(fd, h4);
- printf("retrying for ban (%d)\n", retry);
+ igt_info("retrying for ban (%d)\n", retry);
}
igt_assert(h4 == -EIO);
typedef enum { root = 0, user } cap_t;
-static void test_param_ctx(const int fd, const int ctx, const cap_t cap)
+static void _check_param_ctx(const int fd, const int ctx, const cap_t cap)
{
const uint32_t bad = rand() + 1;
igt_assert(ioctl(fd, GET_RESET_STATS_IOCTL, 0) == -1);
igt_assert(_test_params(fd, 0xbadbad, 0, 0) == -ENOENT);
- test_param_ctx(fd, 0, cap);
- test_param_ctx(fd, ctx, cap);
+ _check_param_ctx(fd, ctx, cap);
}
static void _test_param(const int fd, const int ctx)
igt_waitchildren();
}
-static void test_params(void)
+static void test_params_ctx(void)
{
int fd, ctx;
close(fd);
}
-#define RING_HAS_CONTEXTS current_ring->contexts(current_ring)
-#define RUN_CTX_TEST(...) do { igt_skip_on(RING_HAS_CONTEXTS == false); __VA_ARGS__; } while (0)
+static void test_params(void)
+{
+ int fd;
-int fd;
+ fd = drm_open_any();
+ igt_assert(fd >= 0);
-igt_main
+ _test_param(fd, 0);
+
+ close(fd);
+
+}
+
+static bool gem_has_hw_contexts(int fd)
{
struct local_drm_i915_gem_context_create create;
- uint32_t devid;
int ret;
+ memset(&create, 0, sizeof(create));
+ ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
+
+ if (ret == 0) {
+ drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &create);
+ return true;
+ }
+
+ return false;
+}
+
+static bool gem_has_reset_stats(int fd)
+{
+ struct local_drm_i915_reset_stats rs;
+ int ret;
+
+ /* Carefully set flags and pad to zero, otherwise
+ we get -EINVAL
+ */
+ memset(&rs, 0, sizeof(rs));
+
+ ret = drmIoctl(fd, GET_RESET_STATS_IOCTL, &rs);
+ if (ret == 0)
+ return true;
+
+ /* If we get EPERM, we have support but did not
+ have CAP_SYSADM */
+ if (ret == -1 && errno == EPERM)
+ return true;
+
+ return false;
+}
+
+static void check_gpu_ok(void)
+{
+ int retry_count = 30;
+ enum stop_ring_flags flags;
+ int fd;
+
+ igt_debug("checking gpu state\n");
+
+ while (retry_count--) {
+ flags = igt_get_stop_rings();
+ if (flags == 0)
+ break;
+
+ igt_debug("waiting previous hang to clear\n");
+ sleep(1);
+ }
+
+ igt_assert(flags == 0);
+
+ fd = drm_open_any();
+ gem_quiescent_gpu(fd);
+ close(fd);
+}
+
+#define RING_HAS_CONTEXTS (current_ring->contexts(current_ring))
+#define RUN_TEST(...) do { check_gpu_ok(); __VA_ARGS__; check_gpu_ok(); } while (0)
+#define RUN_CTX_TEST(...) do { igt_skip_on(RING_HAS_CONTEXTS == false); RUN_TEST(__VA_ARGS__); } while (0)
+
+igt_main
+{
igt_skip_on_simulation();
igt_fixture {
+ int fd;
+
+ bool has_reset_stats;
fd = drm_open_any();
devid = intel_get_drm_devid(fd);
- igt_require_f(intel_gen(devid) >= 4,
- "Architecture %d too old\n", intel_gen(devid));
- ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
- igt_skip_on_f(ret != 0 && (errno == ENODEV || errno == EINVAL),
- "Kernel is too old, or contexts not supported: %s\n",
- strerror(errno));
+ hw_contexts = gem_has_hw_contexts(fd);
+ has_reset_stats = gem_has_reset_stats(fd);
+
+ close(fd);
+
+ igt_require_f(has_reset_stats,
+ "No reset stats ioctl support. Too old kernel?\n");
}
igt_subtest("params")
current_ring = &rings[i];
name = current_ring->name;
- igt_fixture
+ igt_fixture {
+ int fd = drm_open_any();
gem_require_ring(fd, current_ring->exec);
+ close(fd);
+ }
+
+ igt_fixture
+ igt_require_f(intel_gen(devid) >= 4,
+ "gen %d doesn't support reset\n", intel_gen(devid));
+
+ igt_subtest_f("params-ctx-%s", name)
+ RUN_CTX_TEST(test_params_ctx());
igt_subtest_f("reset-stats-%s", name)
- test_rs(4, 1, 0);
+ RUN_TEST(test_rs(4, 1, 0));
igt_subtest_f("reset-stats-ctx-%s", name)
RUN_CTX_TEST(test_rs_ctx(4, 4, 1, 2));
igt_subtest_f("ban-%s", name)
- test_ban();
+ RUN_TEST(test_ban());
igt_subtest_f("ban-ctx-%s", name)
RUN_CTX_TEST(test_ban_ctx());
igt_subtest_f("reset-count-%s", name)
- test_reset_count(false);
+ RUN_TEST(test_reset_count(false));
igt_subtest_f("reset-count-ctx-%s", name)
RUN_CTX_TEST(test_reset_count(true));
igt_subtest_f("unrelated-ctx-%s", name)
RUN_CTX_TEST(test_unrelated_ctx());
- igt_subtest_f("close-pending-%s", name) {
- test_close_pending();
- gem_quiescent_gpu(fd);
- }
+ igt_subtest_f("close-pending-%s", name)
+ RUN_TEST(test_close_pending());
- igt_subtest_f("close-pending-ctx-%s", name) {
+ igt_subtest_f("close-pending-ctx-%s", name)
RUN_CTX_TEST(test_close_pending_ctx());
- gem_quiescent_gpu(fd);
- }
- igt_subtest_f("close-pending-fork-%s", name) {
- test_close_pending_fork(true);
- test_close_pending_fork(false);
- }
- }
+ igt_subtest_f("close-pending-fork-%s", name)
+ RUN_TEST(test_close_pending_fork(false));
- igt_fixture
- close(fd);
+ igt_subtest_f("close-pending-fork-reverse-%s", name)
+ RUN_TEST(test_close_pending_fork(true));
+ }
}