diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/gen7_forcewake_mt.c | 108 |
1 files changed, 79 insertions, 29 deletions
diff --git a/tests/gen7_forcewake_mt.c b/tests/gen7_forcewake_mt.c index 07320ef9..164c7fd9 100644 --- a/tests/gen7_forcewake_mt.c +++ b/tests/gen7_forcewake_mt.c @@ -41,12 +41,15 @@ IGT_TEST_DESCRIPTION("Exercise a suspect workaround required for" " FORCEWAKE_MT."); #define FORCEWAKE_MT 0xa188 +#define READ_ONCE(x) (*(volatile typeof(x) *)(&(x))) struct thread { pthread_t thread; - void *mmio; + pthread_mutex_t *lock; + volatile uint32_t *forcewake_mt; int fd; int bit; + bool done; }; static const struct pci_id_match match[] = { @@ -77,46 +80,56 @@ static struct pci_device *__igfx_get(void) pci_iterator_destroy(iter); } + pci_device_probe(dev); return dev; } -static void *igfx_get_mmio(void) +static volatile uint32_t *igfx_mmio_forcewake_mt(void) { struct pci_device *pci = __igfx_get(); - void *mmio = NULL; - int error; - igt_skip_on(pci == NULL); - igt_skip_on(intel_gen(pci->device_id) != 7); + igt_require(pci && intel_gen(pci->device_id) == 7); - error = pci_device_probe(pci); - igt_assert_eq(error, 0); + intel_mmio_use_pci_bar(pci); - error = pci_device_map_range(pci, - pci->regions[0].base_addr, - 2*1024*1024, - PCI_DEV_MAP_FLAG_WRITABLE, - &mmio); - igt_assert_eq(error, 0); - igt_assert(mmio != NULL); - - return mmio; + return (volatile uint32_t *)((char *)igt_global_mmio + FORCEWAKE_MT); } static void *thread(void *arg) { + static const char acquire_error[] = "acquire"; + static const char release_error[] = "release"; + struct thread *t = arg; - uint32_t *forcewake_mt = (uint32_t *)((char *)t->mmio + FORCEWAKE_MT); - uint32_t bit = 1 << t->bit; + const uint32_t bit = 1 << t->bit; + volatile uint32_t *forcewake_mt = t->forcewake_mt; + void *result = NULL; + + while (!result && !READ_ONCE(t->done)) { + /* + * The HW is fubar; concurrent mmio access to even + * the FORCEWAKE_MT results in a machine lockup, nullifying + * the entire purpose of FORCEWAKE_MT... Sigh. + */ + pthread_mutex_lock(t->lock); - while (1) { *forcewake_mt = bit << 16 | bit; - igt_assert(*forcewake_mt & bit); + if (!igt_wait(*forcewake_mt & bit, 50, 1)) + result = (void *)acquire_error; + + /* Sleep to let another thread poke at a different bit */ + pthread_mutex_unlock(t->lock); + usleep(1000); + pthread_mutex_lock(t->lock); + *forcewake_mt = bit << 16; - igt_assert((*forcewake_mt & bit) == 0); + if (!igt_wait((*forcewake_mt & bit) == 0, 50, 1)) + result = (void *)release_error; + + pthread_mutex_unlock(t->lock); } - return NULL; + return result; } #define MI_STORE_REGISTER_MEM (0x24<<23) @@ -124,20 +137,30 @@ static void *thread(void *arg) igt_simple_main { struct thread t[16]; + pthread_mutex_t lock; + bool success = true; int i; + igt_assert(pthread_mutex_init(&lock, NULL) == 0); + + t[0].lock = &lock; t[0].fd = drm_open_driver(DRIVER_INTEL); - t[0].mmio = igfx_get_mmio(); + t[0].forcewake_mt = igfx_mmio_forcewake_mt(); + t[0].done = false; for (i = 2; i < 16; i++) { t[i] = t[0]; t[i].bit = i; - pthread_create(&t[i].thread, NULL, thread, &t[i]); + if (pthread_create(&t[i].thread, NULL, thread, &t[i])) { + igt_warn("Failed to create thread for BIT(%d)\n", i); + success = false; + goto error; + } } sleep(2); - for (i = 0; i < 1000; i++) { + igt_until_timeout(2) { uint32_t *p; struct drm_i915_gem_execbuffer2 execbuf; struct drm_i915_gem_exec_object2 exec[2]; @@ -186,19 +209,46 @@ igt_simple_main execbuf.batch_len = sizeof(b); execbuf.flags = I915_EXEC_SECURE; + pthread_mutex_lock(t[0].lock); gem_execbuf(t[0].fd, &execbuf); gem_sync(t[0].fd, exec[1].handle); + pthread_mutex_unlock(t[0].lock); p = gem_mmap__gtt(t[0].fd, exec[0].handle, 4096, PROT_READ); - igt_info("[%d]={ %08x %08x }\n", i, p[0], p[1]); - igt_assert(p[0] & 2); - igt_assert((p[1] & 2) == 0); + igt_debug("[%d]={ %08x %08x }\n", i, p[0], p[1]); + if ((p[0] & 2) == 0) { + igt_warn("Failed to acquire forcewake BIT(1) from batch\n"); + success = false; + } + if ((p[1] & 2)) { + igt_warn("Failed to release forcewake BIT(1) from batch\n"); + success = false; + } munmap(p, 4096); gem_close(t[0].fd, exec[0].handle); gem_close(t[0].fd, exec[1].handle); + if (!success) + break; usleep(1000); } + +error: + while (--i >= 2) { + void *result = (char *)"pthread_join to"; + + t[i].done = true; + pthread_join(t[i].thread, &result); + if (result) { + igt_warn("Thread BIT(%d) failed to %s forcewake\n", i, (char *)result); + success = false; + } + } + + /* And clear all forcewake bits before disappearing */ + *t[0].forcewake_mt = 0xfffe << 16; + + igt_assert(success); } |