summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-06-17 15:19:44 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2016-06-17 18:59:32 +0100
commit001d665080c1be7d8fe97b557d7b6102175956b7 (patch)
treecf646ccbf1be579e7fea56230c9c93f94a375cad /tests
parentbe21fc064b6d9ded5ccae7205204c0d5a03cf9e5 (diff)
igt: Replace drv_missed_irq_hang script with a C-equivalent
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. Furthermore, from C we can trigger a missed interrupt on each engine. A minor convenience of the C version is that we don't have to worry about install paths to find the binaries underneath. References: https://bugs.freedesktop.org/show_bug.cgi?id=88437 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.sources2
-rw-r--r--tests/drv_missed_irq.c167
-rwxr-xr-xtests/drv_missed_irq_hang80
3 files changed, 168 insertions, 81 deletions
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4189acf0..656e0069 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -140,6 +140,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 \
@@ -210,7 +211,6 @@ TESTS_scripts_M = \
TESTS_scripts = \
debugfs_emon_crash \
drv_debugfs_reader \
- drv_missed_irq_hang \
drv_module_reload_basic \
kms_sysfs_edid_timing \
sysfs_l3_parity \
diff --git a/tests/drv_missed_irq.c b/tests/drv_missed_irq.c
new file mode 100644
index 00000000..66d20edb
--- /dev/null
+++ b/tests/drv_missed_irq.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright © 2016 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"
+
+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 e76c7db6..00000000
--- 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