diff options
-rw-r--r-- | lib/Makefile.sources | 2 | ||||
-rw-r--r-- | lib/igt_gt.c | 109 | ||||
-rw-r--r-- | lib/igt_gt.h | 35 | ||||
-rw-r--r-- | lib/ioctl_wrappers.c | 33 | ||||
-rw-r--r-- | lib/ioctl_wrappers.h | 12 | ||||
-rw-r--r-- | tests/gem_concurrent_blit.c | 245 |
6 files changed, 371 insertions, 65 deletions
diff --git a/lib/Makefile.sources b/lib/Makefile.sources index 34a3d31c..76f353aa 100644 --- a/lib/Makefile.sources +++ b/lib/Makefile.sources @@ -10,6 +10,8 @@ libintel_tools_la_SOURCES = \ igt_debugfs.h \ igt_aux.c \ igt_aux.h \ + igt_gt.c \ + igt_gt.h \ instdone.c \ instdone.h \ intel_batchbuffer.c \ diff --git a/lib/igt_gt.c b/lib/igt_gt.c new file mode 100644 index 00000000..526cbee0 --- /dev/null +++ b/lib/igt_gt.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <string.h> +#include <errno.h> + +#include "igt_core.h" +#include "igt_gt.h" +#include "igt_debugfs.h" +#include "ioctl_wrappers.h" +#include "intel_reg.h" + +int igt_can_hang_ring(int fd, int gen, int ring) +{ + if (!gem_context_has_param(fd, LOCAL_CONTEXT_PARAM_BAN_PERIOD)) + return 0; + + if (gen < 5) /* safe resets */ + return 0; + + return 1; +} + +struct igt_hang_ring igt_hang_ring(int fd, int gen, int ring) +{ + struct drm_i915_gem_relocation_entry reloc; + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 exec; + struct local_i915_gem_context_param param; + uint32_t b[8]; + unsigned ban; + unsigned len; + + param.context = 0; + param.size = 0; + param.param = LOCAL_CONTEXT_PARAM_BAN_PERIOD; + param.value = 0; + gem_context_get_param(fd, ¶m); + ban = param.value; + + param.value = 0; + igt_require(gem_context_set_param(fd, ¶m) == 0); + + memset(&reloc, 0, sizeof(reloc)); + memset(&exec, 0, sizeof(exec)); + memset(&execbuf, 0, sizeof(execbuf)); + + exec.handle = gem_create(fd, 4096); + exec.relocation_count = 1; + exec.relocs_ptr = (uintptr_t)&reloc; + + len = 2; + if (gen >= 8) + len++; + b[0] = MI_BATCH_BUFFER_START | (len - 2); + b[len] = MI_BATCH_BUFFER_END; + b[len+1] = MI_NOOP; + gem_write(fd, exec.handle, 0, b, sizeof(b)); + + reloc.offset = 4; + reloc.target_handle = exec.handle; + reloc.read_domains = I915_GEM_DOMAIN_COMMAND; + + execbuf.buffers_ptr = (uintptr_t)&exec; + execbuf.buffer_count = 1; + execbuf.batch_len = sizeof(b); + execbuf.flags = ring; + gem_execbuf(fd, &execbuf); + + return (struct igt_hang_ring){ exec.handle, ban }; +} + +void igt_post_hang_ring(int fd, struct igt_hang_ring arg) +{ + struct local_i915_gem_context_param param; + + if (arg.handle == 0) + return; + + gem_set_domain(fd, arg.handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + gem_close(fd, arg.handle); + + param.context = 0; + param.size = 0; + param.param = LOCAL_CONTEXT_PARAM_BAN_PERIOD; + param.value = arg.ban; + gem_context_set_param(fd, ¶m); +} diff --git a/lib/igt_gt.h b/lib/igt_gt.h new file mode 100644 index 00000000..19bbcef2 --- /dev/null +++ b/lib/igt_gt.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef IGT_GT_H +#define IGT_GT_H + +int igt_can_hang_ring(int fd, int gen, int ring); + +struct igt_hang_ring { + unsigned handle; + unsigned ban; +} igt_hang_ring(int fd, int gen, int ring); +void igt_post_hang_ring(int fd, struct igt_hang_ring data); + +#endif /* IGT_GT_H */ diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c index dd48d0e6..5bca4559 100644 --- a/lib/ioctl_wrappers.c +++ b/lib/ioctl_wrappers.c @@ -1042,3 +1042,36 @@ off_t prime_get_size(int dma_buf_fd) return ret; } +int gem_context_get_param(int fd, struct local_i915_gem_context_param *p) +{ +#define LOCAL_I915_GEM_CONTEXT_GETPARAM 0x34 +#define LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_GETPARAM, struct local_i915_gem_context_param) + if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, p)) + return -1; + + errno = 0; + return 0; +} + +int gem_context_set_param(int fd, struct local_i915_gem_context_param *p) +{ +#define LOCAL_I915_GEM_CONTEXT_SETPARAM 0x35 +#define LOCAL_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_SETPARAM, struct local_i915_gem_context_param) + if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_SETPARAM, p)) + return -1; + + errno = 0; + return 0; +} + +int gem_context_has_param(int fd, uint64_t param) +{ + struct local_i915_gem_context_param p; + + p.context = 0; + p.param = param; + p.value = 0; + p.size = 0; + + return gem_context_get_param(fd, &p) == 0; +} diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h index 9e7edad5..2aa41987 100644 --- a/lib/ioctl_wrappers.h +++ b/lib/ioctl_wrappers.h @@ -104,4 +104,16 @@ int prime_handle_to_fd(int fd, uint32_t handle); uint32_t prime_fd_to_handle(int fd, int dma_buf_fd); off_t prime_get_size(int dma_buf_fd); +struct local_i915_gem_context_param { + uint32_t context; + uint32_t size; + uint64_t param; +#define LOCAL_CONTEXT_PARAM_BAN_PERIOD 0x1 + uint64_t value; +}; + +int gem_context_has_param(int fd, uint64_t param); +int gem_context_get_param(int fd, struct local_i915_gem_context_param *p); +int gem_context_set_param(int fd, struct local_i915_gem_context_param *p); + #endif /* IOCTL_WRAPPERS_H */ diff --git a/tests/gem_concurrent_blit.c b/tests/gem_concurrent_blit.c index 9d157b68..48ee48a6 100644 --- a/tests/gem_concurrent_blit.c +++ b/tests/gem_concurrent_blit.c @@ -49,11 +49,13 @@ #include "ioctl_wrappers.h" #include "drmtest.h" +#include "igt_aux.h" +#include "igt_core.h" +#include "igt_gt.h" #include "intel_bufmgr.h" #include "intel_batchbuffer.h" #include "intel_io.h" #include "intel_chipset.h" -#include "igt_aux.h" IGT_TEST_DESCRIPTION("Test of pread/pwrite behavior when writing to active" " buffers."); @@ -365,6 +367,7 @@ const int width = 512, height = 512; igt_render_copyfunc_t rendercopy; typedef void (*do_copy)(drm_intel_bo *dst, drm_intel_bo *src); +typedef struct igt_hang_ring (*do_hang)(void); static void render_copy_bo(drm_intel_bo *dst, drm_intel_bo *src) { @@ -454,11 +457,33 @@ static void wc_copy_bo(drm_intel_bo *dst, drm_intel_bo *src) munmap(s, size); } +static struct igt_hang_ring no_hang(void) +{ + return (struct igt_hang_ring){0, 0}; +} + +static struct igt_hang_ring bcs_hang(void) +{ + return igt_hang_ring(fd, gen, I915_EXEC_BLT); +} + +static struct igt_hang_ring rcs_hang(void) +{ + return igt_hang_ring(fd, gen, I915_EXEC_RENDER); +} + +static void hang_require(void) +{ + igt_require(igt_can_hang_ring(fd, gen, -1)); +} + static void do_overwrite_source(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, - do_copy do_copy_func) + do_copy do_copy_func, + do_hang do_hang_func) { + struct igt_hang_ring hang; int i; gem_quiescent_gpu(fd); @@ -468,17 +493,63 @@ static void do_overwrite_source(const struct access_mode *mode, } for (i = 0; i < num_buffers; i++) do_copy_func(dst[i], src[i]); + hang = do_hang_func(); for (i = num_buffers; i--; ) mode->set_bo(src[i], 0xdeadbeef, width, height); for (i = 0; i < num_buffers; i++) mode->cmp_bo(dst[i], i, width, height, dummy); + igt_post_hang_ring(fd, hang); +} + +static void do_overwrite_source__rev(const struct access_mode *mode, + drm_intel_bo **src, drm_intel_bo **dst, + drm_intel_bo *dummy, + do_copy do_copy_func, + do_hang do_hang_func) +{ + struct igt_hang_ring hang; + int i; + + gem_quiescent_gpu(fd); + for (i = 0; i < num_buffers; i++) { + mode->set_bo(src[i], i, width, height); + mode->set_bo(dst[i], ~i, width, height); + } + for (i = 0; i < num_buffers; i++) + do_copy_func(dst[i], src[i]); + hang = do_hang_func(); + for (i = 0; i < num_buffers; i++) + mode->set_bo(src[i], 0xdeadbeef, width, height); + for (i = num_buffers; i--; ) + mode->cmp_bo(dst[i], i, width, height, dummy); + igt_post_hang_ring(fd, hang); +} + +static void do_overwrite_source__one(const struct access_mode *mode, + drm_intel_bo **src, drm_intel_bo **dst, + drm_intel_bo *dummy, + do_copy do_copy_func, + do_hang do_hang_func) +{ + struct igt_hang_ring hang; + + gem_quiescent_gpu(fd); + mode->set_bo(src[0], 0, width, height); + mode->set_bo(dst[0], ~0, width, height); + do_copy_func(dst[0], src[0]); + hang = do_hang_func(); + mode->set_bo(src[0], 0xdeadbeef, width, height); + mode->cmp_bo(dst[0], 0, width, height, dummy); + igt_post_hang_ring(fd, hang); } static void do_early_read(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, - do_copy do_copy_func) + do_copy do_copy_func, + do_hang do_hang_func) { + struct igt_hang_ring hang; int i; gem_quiescent_gpu(fd); @@ -486,15 +557,19 @@ static void do_early_read(const struct access_mode *mode, mode->set_bo(src[i], 0xdeadbeef, width, height); for (i = 0; i < num_buffers; i++) do_copy_func(dst[i], src[i]); + hang = do_hang_func(); for (i = num_buffers; i--; ) mode->cmp_bo(dst[i], 0xdeadbeef, width, height, dummy); + igt_post_hang_ring(fd, hang); } static void do_gpu_read_after_write(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, - do_copy do_copy_func) + do_copy do_copy_func, + do_hang do_hang_func) { + struct igt_hang_ring hang; int i; gem_quiescent_gpu(fd); @@ -504,47 +579,54 @@ static void do_gpu_read_after_write(const struct access_mode *mode, do_copy_func(dst[i], src[i]); for (i = num_buffers; i--; ) do_copy_func(dummy, dst[i]); + hang = do_hang_func(); for (i = num_buffers; i--; ) mode->cmp_bo(dst[i], 0xabcdabcd, width, height, dummy); + igt_post_hang_ring(fd, hang); } typedef void (*do_test)(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, - do_copy do_copy_func); + do_copy do_copy_func, + do_hang do_hang_func); typedef void (*run_wrap)(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, do_test do_test_func, - do_copy do_copy_func); + do_copy do_copy_func, + do_hang do_hang_func); static void run_single(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, do_test do_test_func, - do_copy do_copy_func) + do_copy do_copy_func, + do_hang do_hang_func) { - do_test_func(mode, src, dst, dummy, do_copy_func); + do_test_func(mode, src, dst, dummy, do_copy_func, do_hang_func); } static void run_interruptible(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, do_test do_test_func, - do_copy do_copy_func) + do_copy do_copy_func, + do_hang do_hang_func) { int loop; for (loop = 0; loop < 10; loop++) - do_test_func(mode, src, dst, dummy, do_copy_func); + do_test_func(mode, src, dst, dummy, do_copy_func, do_hang_func); } static void run_forked(const struct access_mode *mode, drm_intel_bo **src, drm_intel_bo **dst, drm_intel_bo *dummy, do_test do_test_func, - do_copy do_copy_func) + do_copy do_copy_func, + do_hang do_hang_func) { const int old_num_buffers = num_buffers; @@ -555,6 +637,7 @@ static void run_forked(const struct access_mode *mode, drm_intel_bufmgr *bufmgr; /* recreate process local variables */ + fd = drm_open_any(); bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); drm_intel_bufmgr_gem_enable_reuse(bufmgr); @@ -567,18 +650,14 @@ static void run_forked(const struct access_mode *mode, dummy = mode->create_bo(bufmgr, width, height); for (int loop = 0; loop < 10; loop++) - do_test_func(mode, src, dst, dummy, do_copy_func); + do_test_func(mode, src, dst, dummy, + do_copy_func, do_hang_func); - /* as we borrow the fd, we need to reap our bo */ for (int i = 0; i < num_buffers; i++) { mode->release_bo(src[i]); mode->release_bo(dst[i]); } mode->release_bo(dummy); - - intel_batchbuffer_free(batch); - - drm_intel_bufmgr_destroy(bufmgr); } igt_waitchildren(); @@ -629,10 +708,13 @@ static void rcs_require(void) igt_require(rendercopy); } +static void no_require(void) +{ +} + static void run_basic_modes(const struct access_mode *mode, - drm_intel_bo **src, drm_intel_bo **dst, - drm_intel_bo *dummy, const char *suffix, + const char *suffix, run_wrap run_wrap_func) { const struct { @@ -647,27 +729,85 @@ run_basic_modes(const struct access_mode *mode, { "rcs", render_copy_bo, rcs_require }, { NULL, NULL } }, *p; + const struct { + const char *suffix; + do_hang hang; + void (*require)(void); + } hangs[] = { + { "", no_hang, no_require }, + { "-hang(bcs)", bcs_hang, hang_require }, + { "-hang(rcs)", rcs_hang, hang_require }, + { NULL, NULL }, + }, *h; + drm_intel_bo *src[MAX_NUM_BUFFERS], *dst[MAX_NUM_BUFFERS], *dummy = NULL; + drm_intel_bufmgr *bufmgr; - for (p = pipelines; p->prefix; p++) { - /* try to overwrite the source values */ - igt_subtest_f("%s-%s-overwrite-source%s", mode->name, p->prefix, suffix) { - p->require(); - run_wrap_func(mode, src, dst, dummy, - do_overwrite_source, p->copy); - } - /* try to read the results before the copy completes */ - igt_subtest_f("%s-%s-early-read%s", mode->name, p->prefix, suffix) { - p->require(); - run_wrap_func(mode, src, dst, dummy, - do_early_read, p->copy); - } + for (h = hangs; h->suffix; h++) { + for (p = pipelines; p->prefix; p++) { + igt_fixture { + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + drm_intel_bufmgr_gem_enable_reuse(bufmgr); + batch = intel_batchbuffer_alloc(bufmgr, devid); - /* and finally try to trick the kernel into loosing the pending write */ - igt_subtest_f("%s-%s-gpu-read-after-write%s", mode->name, p->prefix, suffix) { - p->require(); - run_wrap_func(mode, src, dst, dummy, - do_gpu_read_after_write, p->copy); + for (int i = 0; i < num_buffers; i++) { + src[i] = mode->create_bo(bufmgr, width, height); + dst[i] = mode->create_bo(bufmgr, width, height); + } + dummy = mode->create_bo(bufmgr, width, height); + } + + /* try to overwrite the source values */ + igt_subtest_f("%s-%s-overwrite-source-one%s%s", mode->name, p->prefix, suffix, h->suffix) { + h->require(); + p->require(); + run_wrap_func(mode, src, dst, dummy, + do_overwrite_source__one, + p->copy, h->hang); + } + + igt_subtest_f("%s-%s-overwrite-source%s%s", mode->name, p->prefix, suffix, h->suffix) { + h->require(); + p->require(); + run_wrap_func(mode, src, dst, dummy, + do_overwrite_source, + p->copy, h->hang); + } + igt_subtest_f("%s-%s-overwrite-source-rev%s%s", mode->name, p->prefix, suffix, h->suffix) { + h->require(); + p->require(); + run_wrap_func(mode, src, dst, dummy, + do_overwrite_source__rev, + p->copy, h->hang); + } + + /* try to read the results before the copy completes */ + igt_subtest_f("%s-%s-early-read%s%s", mode->name, p->prefix, suffix, h->suffix) { + h->require(); + p->require(); + run_wrap_func(mode, src, dst, dummy, + do_early_read, + p->copy, h->hang); + } + + /* and finally try to trick the kernel into loosing the pending write */ + igt_subtest_f("%s-%s-gpu-read-after-write%s%s", mode->name, p->prefix, suffix, h->suffix) { + h->require(); + p->require(); + run_wrap_func(mode, src, dst, dummy, + do_gpu_read_after_write, + p->copy, h->hang); + } + + igt_fixture { + for (int i = 0; i < num_buffers; i++) { + mode->release_bo(src[i]); + mode->release_bo(dst[i]); + } + mode->release_bo(dummy); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + } } } } @@ -675,39 +815,14 @@ run_basic_modes(const struct access_mode *mode, static void run_modes(const struct access_mode *mode) { - drm_intel_bo *src[MAX_NUM_BUFFERS], *dst[MAX_NUM_BUFFERS], *dummy = NULL; - drm_intel_bufmgr *bufmgr; - - igt_fixture { - bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); - drm_intel_bufmgr_gem_enable_reuse(bufmgr); - batch = intel_batchbuffer_alloc(bufmgr, devid); - - for (int i = 0; i < num_buffers; i++) { - src[i] = mode->create_bo(bufmgr, width, height); - dst[i] = mode->create_bo(bufmgr, width, height); - } - dummy = mode->create_bo(bufmgr, width, height); - } - - run_basic_modes(mode, src, dst, dummy, "", run_single); + run_basic_modes(mode, "", run_single); igt_fork_signal_helper(); - run_basic_modes(mode, src, dst, dummy, "-interruptible", run_interruptible); + run_basic_modes(mode, "-interruptible", run_interruptible); igt_stop_signal_helper(); - igt_fixture { - for (int i = 0; i < num_buffers; i++) { - mode->release_bo(src[i]); - mode->release_bo(dst[i]); - } - mode->release_bo(dummy); - intel_batchbuffer_free(batch); - drm_intel_bufmgr_destroy(bufmgr); - } - igt_fork_signal_helper(); - run_basic_modes(mode, src, dst, dummy, "-forked", run_forked); + run_basic_modes(mode, "-forked", run_forked); igt_stop_signal_helper(); } |