[PATCH igt 2/7] igt/gem_workarounds: Read the workaround registers from the active context

Chris Wilson
2017-09-29T15:26:55Z

The workarounds are only valid whilst the GPU is active. To be sure we
are reading the registers in the right state, issue the reads from the GPU.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
tests/gem_workarounds.c | 137 +++++++++++++++++++++++++++---------------------
1 file changed, 77 insertions(+), 60 deletions(-)

diff --git a/tests/gem_workarounds.c b/tests/gem_workarounds.c
index 5e30a7b8..074ffc0c 100644
--- a/tests/gem_workarounds.c
+++ b/tests/gem_workarounds.c
@@ -61,20 +61,6 @@ static struct write_only_list {
static struct intel_wa_reg *wa_regs;
static int num_wa_regs;

-static void wait_gpu(void)
-{
- int fd = drm_open_driver(DRIVER_INTEL);
- gem_quiescent_gpu(fd);
- close(fd);
-}
-
-static void test_hang_gpu(void)
-{
- int fd = drm_open_driver(DRIVER_INTEL);
- igt_post_hang_ring(fd, igt_hang_ring(fd, I915_EXEC_DEFAULT));
- close(fd);
-}
-
static void test_suspend_resume(void)
{
igt_info("Suspending the device ...\n");
@@ -96,49 +82,97 @@ static bool write_only(const uint32_t addr)
return false;
}

-static int workaround_fail_count(void)
+#define MI_STORE_REGISTER_MEM (0x24 << 23)
+
+static int workaround_fail_count(int fd)
{
- int i, fail_count = 0;
+ const int gen = intel_gen(intel_get_drm_devid(fd));
+ struct drm_i915_gem_exec_object2 obj[2];
+ struct drm_i915_gem_relocation_entry *reloc;
+ struct drm_i915_gem_execbuffer2 execbuf;
+ uint32_t result_sz, batch_sz;
+ uint32_t *base, *out;
+ int fail_count = 0;
+
+ reloc = calloc(num_wa_regs, sizeof(*reloc));
+ igt_assert(reloc);
+
+ result_sz = 4 * num_wa_regs;
+ result_sz = (result_sz + 4095) & -4096;
+
+ batch_sz = 16 * num_wa_regs;
+ batch_sz = (batch_sz + 4 + 4095) & -4096;
+
+ memset(obj, 0, sizeof(obj));
+ obj[0].handle = gem_create(fd, result_sz);
+ gem_set_caching(fd, obj[0].handle, 1);
+ obj[1].handle = gem_create(fd, batch_sz);
+ obj[1].relocs_ptr = to_user_pointer(reloc);
+ obj[1].relocation_count = num_wa_regs;
+
+ out = base = gem_mmap__cpu(fd, obj[1].handle, 0, batch_sz, PROT_WRITE);
+ for (int i = 0; i < num_wa_regs; i++) {
+ *out++ = MI_STORE_REGISTER_MEM | ((gen >= 8 ? 4 : 2) - 2);
+ *out++ = wa_regs[i].addr;
+ reloc[i].target_handle = obj[0].handle;
+ reloc[i].offset = (out - base) * sizeof(*out);
+ reloc[i].delta = i * sizeof(uint32_t);
+ reloc[i].read_domains = I915_GEM_DOMAIN_INSTRUCTION;
+ reloc[i].write_domain = I915_GEM_DOMAIN_INSTRUCTION;
+ *out++ = reloc[i].delta;
+ if (gen >= 8)
+ *out++ = 0;
+ }
+ *out++ = MI_BATCH_BUFFER_END;
+ munmap(base, batch_sz);
+
+ memset(&execbuf, 0, sizeof(execbuf));
+ execbuf.buffers_ptr = to_user_pointer(obj);
+ execbuf.buffer_count = 2;
+ gem_execbuf(fd, &execbuf);

- /* There is a small delay after coming ot of rc6 to the correct
- render context values will get loaded by hardware (bdw,chv).
- This here ensures that we have the correct context loaded before
- we start to read values */
- wait_gpu();
+ gem_set_domain(fd, obj[0].handle, I915_GEM_DOMAIN_CPU, 0);

igt_debug("Address\tval\t\tmask\t\tread\t\tresult\n");

- for (i = 0; i < num_wa_regs; ++i) {
- const uint32_t val = intel_register_read(wa_regs[i].addr);
- const bool ok = (wa_regs[i].value & wa_regs[i].mask) ==
- (val & wa_regs[i].mask);
+ out = gem_mmap__cpu(fd, obj[0].handle, 0, result_sz, PROT_READ);
+ for (int i = 0; i < num_wa_regs; i++) {
+ const bool ok =
+ (wa_regs[i].value & wa_regs[i].mask) ==
+ (out[i] & wa_regs[i].mask);
+ char buf[80];

- igt_debug("0x%05X\t0x%08X\t0x%08X\t0x%08X\t%s\n",
- wa_regs[i].addr, wa_regs[i].value, wa_regs[i].mask,
- val, ok ? "OK" : "FAIL");
+ snprintf(buf, sizeof(buf),
+ "0x%05X\t0x%08X\t0x%08X\t0x%08X",
+ wa_regs[i].addr, wa_regs[i].value, wa_regs[i].mask,
+ out[i]);

if (write_only(wa_regs[i].addr))
continue;

if (!ok) {
- igt_warn("0x%05X\t0x%08X\t0x%08X\t0x%08X\t%s\n",
- wa_regs[i].addr, wa_regs[i].value,
- wa_regs[i].mask,
- val, ok ? "OK" : "FAIL");
+ igt_warn("%s\tFAIL\n", buf);
fail_count++;
+ } else {
+ igt_debug("%s\tOK\n", buf);
}
}
+ munmap(out, result_sz);
+
+ gem_close(fd, obj[1].handle);
+ gem_close(fd, obj[0].handle);
+ free(reloc);

return fail_count;
}

-static void check_workarounds(enum operation op)
+static void check_workarounds(int fd, enum operation op)
{
- igt_assert_eq(workaround_fail_count(), 0);
+ igt_assert_eq(workaround_fail_count(fd), 0);

switch (op) {
case GPU_RESET:
- test_hang_gpu();
+ igt_force_gpu_reset(fd);
break;

case SUSPEND_RESUME:
@@ -152,40 +186,30 @@ static void check_workarounds(enum operation op)
igt_assert(0);
}

- igt_assert_eq(workaround_fail_count(), 0);
+ igt_assert_eq(workaround_fail_count(fd), 0);
}

igt_main
{
+ int device = -1;
+
igt_fixture {
- int device = drm_open_driver_master(DRIVER_INTEL);
- struct pci_device *pci_dev;
FILE *file;
char *line = NULL;
size_t line_size;
int i, fd;

+ device = drm_open_driver(DRIVER_INTEL);
igt_require_gem(device);

gen = intel_gen(intel_get_drm_devid(device));

- pci_dev = intel_get_pci_device();
- igt_require(pci_dev);
-
- intel_register_access_init(pci_dev, 0, device);
-
fd = igt_debugfs_open(device, "i915_wa_registers", O_RDONLY);
file = fdopen(fd, "r");
igt_assert(getline(&line, &line_size, file) > 0);
igt_debug("i915_wa_registers: %s", line);
sscanf(line, "Workarounds applied: %d", &num_wa_regs);
-
- /* For newer gens, the lri wa list has always something.
- * If it doesn't, go and add one. */
- if (gen >= 8)
- igt_assert_lt(0, num_wa_regs);
- else
- igt_assert_lte(0, num_wa_regs);
+ igt_require(num_wa_regs > 0);

wa_regs = malloc(num_wa_regs * sizeof(*wa_regs));
igt_assert(wa_regs);
@@ -205,21 +229,14 @@ igt_main
free(line);
fclose(file);
close(fd);
- close(device);
}

igt_subtest("basic-read")
- check_workarounds(SIMPLE_READ);
+ check_workarounds(device, SIMPLE_READ);

igt_subtest("reset")
- check_workarounds(GPU_RESET);
+ check_workarounds(device, GPU_RESET);

igt_subtest("suspend-resume")
- check_workarounds(SUSPEND_RESUME);
-
- igt_fixture {
- free(wa_regs);
- intel_register_access_fini();
- }
-
+ check_workarounds(device, SUSPEND_RESUME);
}