In order to control some of the finer detail of detecting when we missed an interrupt, replace the shell script with C. This version submits a hanging batch and uses a child process to unhang it, whilst the parent sleeps. As the child process is prevented from running whilst the parent is alive (as the child is a low priority normal process whereas the parent is a RT process), the child can only unhang the parent after i915_wait_request() has spun up and tried to enable the interrupt. In contrast, the shell script guessed a workload that should take long enough for the i915_spin_request() to miss the completion, but that was not guaranteed. A minor convenience of the C version is that we don't have to worry about install paths to find the binaries underneath. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> --- tests/Makefile.sources | 1 + tests/drv_missed_irq.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++ tests/drv_missed_irq_hang | 80 ---------------------- 3 files changed, 171 insertions(+), 80 deletions(-) create mode 100644 tests/drv_missed_irq.c delete mode 100755 tests/drv_missed_irq_hang diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 941568d..d74a93f 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -142,6 +142,7 @@ TESTS_progs = \ drm_vma_limiter_cached \ drm_vma_limiter_cpu \ drm_vma_limiter_gtt \ + drv_missed_irq \ gem_bad_length \ gem_cpu_reloc \ gem_cs_prefetch \ diff --git a/tests/drv_missed_irq.c b/tests/drv_missed_irq.c new file mode 100644 index 0000000..0b1cfb8 --- /dev/null +++ b/tests/drv_missed_irq.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2013 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. + * + */ + +#define _GNU_SOURCE +#include <sched.h> + +#include "igt.h" +#include "igt_stats.h" + +IGT_TEST_DESCRIPTION("Inject missed interrupts and make sure they are caught"); + +static void trigger_missed_interrupt(int fd, unsigned ring) +{ + const int gen = intel_gen(intel_get_drm_devid(fd)); + struct drm_i915_gem_exec_object2 obj; + struct drm_i915_gem_relocation_entry reloc; + struct drm_i915_gem_execbuffer2 execbuf; + uint32_t *batch; + int i; + + memset(&obj, 0, sizeof(obj)); + obj.handle = gem_create(fd, 4096); + obj.relocs_ptr = (uintptr_t)&reloc; + obj.relocation_count = 1; + + memset(&reloc, 0, sizeof(reloc)); + reloc.target_handle = obj.handle; /* recurse */ + reloc.presumed_offset = 0; + reloc.offset = sizeof(uint32_t); + reloc.delta = 0; + reloc.read_domains = I915_GEM_DOMAIN_COMMAND; + reloc.write_domain = 0; + + batch = gem_mmap__wc(fd, obj.handle, 0, 4096, PROT_WRITE); + gem_set_domain(fd, obj.handle, + I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); + + i = 0; + batch[i] = MI_BATCH_BUFFER_START; + if (gen >= 8) { + batch[i] |= 1 << 8 | 1; + batch[++i] = 0; + batch[++i] = 0; + } else if (gen >= 6) { + batch[i] |= 1 << 8; + batch[++i] = 0; + } else { + batch[i] |= 2 << 6; + batch[++i] = 0; + if (gen < 4) { + batch[i] |= 1; + reloc.delta = 1; + } + } + + memset(&execbuf, 0, sizeof(execbuf)); + execbuf.buffers_ptr = (uintptr_t)&obj; + execbuf.buffer_count = 1; + execbuf.flags = ring; + + execbuf.flags = ring; + if (__gem_execbuf(fd, &execbuf)) + goto out; + + igt_fork(child, 1) { + /* We are now a low priority child on the *same* CPU as the + * parent. We will have to wait for our parent to sleep + * (gem_sync -> i915_wait_request) before we run. + */ + *batch = MI_BATCH_BUFFER_END; + __sync_synchronize(); + } + + gem_sync(fd, obj.handle); + igt_waitchildren(); + +out: + gem_close(fd, obj.handle); + munmap(batch, 4096); +} + +static void bind_to_cpu(int cpu) +{ + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN); + struct sched_param rt = {.sched_priority = 99 }; + cpu_set_t allowed; + + igt_assert(sched_setscheduler(getpid(), SCHED_RR | SCHED_RESET_ON_FORK, &rt) == 0); + + CPU_ZERO(&allowed); + CPU_SET(cpu % ncpus, &allowed); + igt_assert(sched_setaffinity(getpid(), sizeof(cpu_set_t), &allowed) == 0); +} + +igt_simple_main +{ + const struct intel_execution_engine *e; + FILE *file; + unsigned expect_rings; + unsigned missed_rings; + int fd; + + igt_skip_on_simulation(); + + fd = drm_open_driver(DRIVER_INTEL); + gem_require_mmap_wc(fd); + + file = igt_debugfs_fopen("i915_ring_test_irq", "w"); + fprintf(file, "0x%x", -1); + fclose(file); + + file = igt_debugfs_fopen("i915_ring_test_irq", "r"); + fscanf(file, "%x", &expect_rings); + fclose(file); + + igt_debug("Testing rings %x\n", expect_rings); + + igt_fork_hang_detector(fd); + intel_detect_and_clear_missed_interrupts(fd); + + bind_to_cpu(0); + for (e = intel_execution_engines; e->name; e++) { + if (expect_rings == -1 && e->exec_id) + continue; + + if (expect_rings != -1 && e->exec_id == 0) + continue; + + igt_debug("Executing on ring %s [%x]\n", + e->name, e->exec_id | e->flags); + + trigger_missed_interrupt(fd, e->exec_id | e->flags); + } + + missed_rings = intel_detect_and_clear_missed_interrupts(fd); + igt_stop_hang_detector(); + + file = igt_debugfs_fopen("i915_ring_test_irq", "w"); + fprintf(file, "%x", 0); + fclose(file); + + if (expect_rings == -1) { + igt_assert_eq_u32(missed_rings, 1); + } else { + igt_assert_eq_u32(missed_rings, expect_rings); + } + + close(fd); +} diff --git a/tests/drv_missed_irq_hang b/tests/drv_missed_irq_hang deleted file mode 100755 index e76c7db..0000000 --- a/tests/drv_missed_irq_hang +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Testcase: Simulate missed breadcrumb interrupts -# - -SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )" -. $SOURCE_DIR/drm_lib.sh - -oldpath=`pwd` - -cd $i915_dfs_path - -function blt_wait { - $oldpath/$SOURCE_DIR/../benchmarks/gem_blt -r 1 -b 64 -t 1 -S > /dev/null -} - -function check_for_missed_irq { - test `cat i915_ring_missed_irq` != 0x00000000 -} - -function check_for_hang { - if cat i915_error_state | grep -v "no error state collected" > /dev/null ; then - echo "gpu hang reported" - exit $IGT_EXIT_FAILURE - fi -} - -if [ ! -f i915_ring_missed_irq ] ; then - echo "kernel doesn't support interrupt masking" - exit $IGT_EXIT_SKIP -fi - -# clear error state first -echo > i915_error_state -blt_wait -if check_for_missed_irq; then - echo "missed interrupts detected before starting test" - exit $IGT_EXIT_SKOP -fi -check_for_hang - -echo 0xf > i915_ring_test_irq -echo "Interrupts masked" -if test `cat i915_ring_test_irq` != 0x0000000f; then - echo "Failed to set interrupt mask" - exit $IGT_EXIT_FAILURE -fi - -blt_wait -if ! check_for_missed_irq; then - echo "missed interrupts undetected" - exit $IGT_EXIT_FAILURE -fi -check_for_hang - -echo 0 > i915_ring_test_irq -echo "Interrupts unmasked" -if test `cat i915_ring_test_irq` != 0x00000000; then - echo "Failed to clear interrupt mask" - exit $IGT_EXIT_FAILURE -fi - -blt_wait -check_for_hang - -echo 0 > i915_ring_missed_irq -echo "Cleared missed interrupts" -if test `cat i915_ring_missed_irq` != 0x00000000; then - echo "Failed to clear missed interrupts" - exit $IGT_EXIT_FAILURE -fi - -blt_wait -if check_for_missed_irq; then - echo "missed interrupts detected afterwards" - exit $IGT_EXIT_FAILURE -fi -check_for_hang - -exit $IGT_EXIT_SUCCESS -- 2.8.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx