[igt-dev] [PATCH] i915/gem_exec_tlb: Look for stale TLB entries
Kamil Konieczny
kamil.konieczny at linux.intel.com
Fri Jul 29 10:22:43 UTC 2022
Hi,
I only glanced over code and have some nits, see below.
On 2022-07-27 at 13:58:48 +0200, Mauro Carvalho Chehab wrote:
> From: Chris Wilson <chris at chris-wilson.co.uk>
>
> When we remove an object from the ppGTT, we replace its PTE by pointing
> the address back to the scratch page. Fresh access to that address will
> then report the absence of the page, and return the scratch page
> instead. However, concurrent access to that address will reuse the TLB
> address cache and so continue to read the stale physical page, unless
> the TLB are flushed (prior to the page going out of scope).
>
> Reported-by: Tvrtko Ursulin <tvrtko.ursulin at linux.intel.com>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin at linux.intel.com>
> Signed-off-by: Mauro Carvalho Chehab <mchehab at kernel.org>
> ---
> lib/i915/intel_memory_region.c | 4 +-
> lib/i915/intel_memory_region.h | 4 +-
> tests/i915/gem_exec_tlb.c | 1124 ++++++++++++++++++++++++++++++++
> tests/i915/gem_gpgpu_fill.c | 2 +
> tests/meson.build | 1 +
> 5 files changed, 1131 insertions(+), 4 deletions(-)
> create mode 100644 tests/i915/gem_exec_tlb.c
>
> diff --git a/lib/i915/intel_memory_region.c b/lib/i915/intel_memory_region.c
> index 93a18982c140..568bace949f6 100644
> --- a/lib/i915/intel_memory_region.c
> +++ b/lib/i915/intel_memory_region.c
> @@ -198,7 +198,7 @@ bool gem_has_lmem(int fd)
> /* A version of gem_create_in_memory_region_list which can be allowed to
> fail so that the object creation can be retried */
> int __gem_create_in_memory_region_list(int fd, uint32_t *handle, uint64_t *size, uint32_t flags,
> - struct drm_i915_gem_memory_class_instance *mem_regions,
> + const struct drm_i915_gem_memory_class_instance *mem_regions,
> int num_regions)
Please split this into separate patch.
> {
> struct drm_i915_gem_create_ext_memory_regions ext_regions = {
> @@ -234,7 +234,7 @@ int __gem_create_in_memory_region_list(int fd, uint32_t *handle, uint64_t *size,
> * @num_regions: @mem_regions length
> */
> uint32_t gem_create_in_memory_region_list(int fd, uint64_t size, uint32_t flags,
> - struct drm_i915_gem_memory_class_instance *mem_regions,
> + const struct drm_i915_gem_memory_class_instance *mem_regions,
> int num_regions)
> {
> uint32_t handle;
> diff --git a/lib/i915/intel_memory_region.h b/lib/i915/intel_memory_region.h
> index e1bfe0ca653a..fd04df83b53b 100644
> --- a/lib/i915/intel_memory_region.h
> +++ b/lib/i915/intel_memory_region.h
> @@ -65,11 +65,11 @@ unsigned int gem_get_lmem_region_count(int fd);
> bool gem_has_lmem(int fd);
>
> int __gem_create_in_memory_region_list(int fd, uint32_t *handle, uint64_t *size, uint32_t flags,
> - struct drm_i915_gem_memory_class_instance *mem_regions,
> + const struct drm_i915_gem_memory_class_instance *mem_regions,
> int num_regions);
>
> uint32_t gem_create_in_memory_region_list(int fd, uint64_t size, uint32_t flags,
> - struct drm_i915_gem_memory_class_instance *mem_regions,
> + const struct drm_i915_gem_memory_class_instance *mem_regions,
> int num_regions);
>
> /*
> diff --git a/tests/i915/gem_exec_tlb.c b/tests/i915/gem_exec_tlb.c
> new file mode 100644
> index 000000000000..ab5c91d6d8fa
> --- /dev/null
> +++ b/tests/i915/gem_exec_tlb.c
> @@ -0,0 +1,1124 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +#include <fcntl.h>
> +#include <sched.h>
> +#include <sys/ioctl.h>
> +#include <sys/poll.h>
> +#include <sys/socket.h>
> +
> +#include "drmtest.h"
> +#include "i830_reg.h"
> +#include "i915/gem.h"
> +#include "i915/gem_create.h"
> +#include "i915/gem_engine_topology.h"
> +#include "i915/gem_mman.h"
> +#include "i915/intel_memory_region.h"
> +#include "igt_aux.h"
> +#include "igt_gt.h"
> +#include "intel_chipset.h"
> +#include "ioctl_wrappers.h"
Please add global test description here.
> +
> +#define TOLERANCE 20 /* ms, allow for a little propagation delay */
> +#define SZ_512K (512 << 10)
> +#define SZ_1M (1 << 20)
> +#define SZ_2M (2 << 20)
> +
> +#define SHRINK 0x1
> +
> +#define NSEC64 ((uint64_t)NSEC_PER_SEC)
> +
> +#define MI_BATCH_BUFFER_START (0x31 << 23)
> +#define MI_COND_BATCH_BUFFER_END (0x36 << 23)
> +#define MI_DO_COMPARE (1 << 21)
> +#define MI_STORE_DATA_IMM (0x20 << 23)
> +#define MI_LOAD_REGISTER_IMM (0x22 << 23)
> +#define MI_STORE_REGISTER_MEM (0x24 << 23)
> +#define MI_LOAD_REGISTER_MEM (0x29 << 23)
> +#define MI_SEMAPHORE_WAIT (0x1c << 23)
> +#define MI_SEMAPHORE_POLL (1 << 15)
> +#define MI_SEMAPHORE_SAD_GT_SDD (0 << 12)
> +#define MI_SEMAPHORE_SAD_GTE_SDD (1 << 12)
> +#define MI_SEMAPHORE_SAD_LT_SDD (2 << 12)
> +#define MI_SEMAPHORE_SAD_LTE_SDD (3 << 12)
> +#define MI_SEMAPHORE_SAD_EQ_SDD (4 << 12)
> +#define MI_SEMAPHORE_SAD_NEQ_SDD (5 << 12)
> +
> +#define MI_MATH (0x1a << 23)
> +#define MI_MATH_INSTR(opcode, op1, op2) ((opcode) << 20 | (op1) << 10 | (op2))
> +/* Opcodes for MI_MATH_INSTR */
> +#define MI_MATH_NOOP MI_MATH_INSTR(0x000, 0x0, 0x0)
> +#define MI_MATH_LOAD(op1, op2) MI_MATH_INSTR(0x080, op1, op2)
> +#define MI_MATH_LOADINV(op1, op2) MI_MATH_INSTR(0x480, op1, op2)
> +#define MI_MATH_LOAD0(op1) MI_MATH_INSTR(0x081, op1)
> +#define MI_MATH_LOAD1(op1) MI_MATH_INSTR(0x481, op1)
> +#define MI_MATH_ADD MI_MATH_INSTR(0x100, 0x0, 0x0)
> +#define MI_MATH_SUB MI_MATH_INSTR(0x101, 0x0, 0x0)
> +#define MI_MATH_AND MI_MATH_INSTR(0x102, 0x0, 0x0)
> +#define MI_MATH_OR MI_MATH_INSTR(0x103, 0x0, 0x0)
> +#define MI_MATH_XOR MI_MATH_INSTR(0x104, 0x0, 0x0)
> +#define MI_MATH_STORE(op1, op2) MI_MATH_INSTR(0x180, op1, op2)
> +#define MI_MATH_STOREINV(op1, op2) MI_MATH_INSTR(0x580, op1, op2)
> +/* Registers used as operands in MI_MATH_INSTR */
> +#define MI_MATH_REG(x) (x)
> +#define MI_MATH_REG_SRCA 0x20
> +#define MI_MATH_REG_SRCB 0x21
> +#define MI_MATH_REG_ACCU 0x31
> +#define MI_MATH_REG_ZF 0x32
> +#define MI_MATH_REG_CF 0x33
> +
> +#define XY_SRC_COPY (2 << 29 | 0x53 << 22)
> +#define XY_COLOR (2 << 29 | 0x50 << 22)
> +
> +#define CS_GPR(x) ((base) + 0x600 + 8 * (x))
> +#define CS_TIMESTAMP ((base) + 0x358)
> +
> +static uint32_t __batch_create(int i915, uint32_t offset)
> +{
> + const uint32_t bbe = MI_BATCH_BUFFER_END;
> + uint32_t handle;
> +
> + handle = gem_create(i915, offset + 4);
> + gem_write(i915, handle, offset, &bbe, sizeof(bbe));
> +
> + return handle;
> +}
> +
> +static uint32_t batch_create(int i915)
> +{
> + return __batch_create(i915, 0);
> +}
> +
> +static void bind_at(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *e,
> + uint32_t handle, uint64_t addr, uint64_t size)
> +{
> + struct drm_i915_gem_exec_object2 obj[2] = {
> + { .handle = handle, .offset = addr, .pad_to_size = size, .flags = EXEC_OBJECT_PINNED },
> + { batch_create(i915) }
> + };
> + struct drm_i915_gem_execbuffer2 execbuf = {
> + .buffers_ptr = to_user_pointer(obj),
> + .buffer_count = ARRAY_SIZE(obj),
> + .flags = e->flags,
> + .rsvd1 = ctx->id,
> + };
> +
> + gem_execbuf(i915, &execbuf);
> + gem_sync(i915, obj[1].handle);
> + gem_close(i915, obj[1].handle);
> +}
> +
> +static unsigned long offset_in_page(void *addr)
> +{
> + return (uintptr_t)addr & 4095;
> +}
> +
> +static uint32_t __read_at(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *e,
> + const uint32_t base,
> + uint64_t addr, uint64_t from)
> +{
> + const int gen = intel_gen(intel_get_drm_devid(i915));
> + const int use_64b_addr = gen >= 8;
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = gem_create(i915, 4096),
> + .offset = from,
> + .flags = EXEC_OBJECT_PINNED
> + };
> + struct drm_i915_gem_execbuffer2 execbuf = {
> + .batch_len = 64,
> + .buffers_ptr = to_user_pointer(&obj),
> + .buffer_count = 1,
> + .flags = e->flags,
> + .rsvd1 = ctx->id,
> + };
> + uint32_t *map =
> + gem_mmap__device_coherent(i915, obj.handle,
> + 0, 4096, PROT_WRITE);
> + uint32_t *cs = map;
> + uint32_t value;
> +
> + *cs++ = MI_NOOP | 0x1234;
> +
> + *cs++ = MI_LOAD_REGISTER_MEM | (1 + use_64b_addr);
> + *cs++ = CS_GPR(4);
> + *cs++ = addr;
> + *cs++ = addr >> 32;
> +
> + *cs++ = MI_STORE_REGISTER_MEM | (1 + use_64b_addr);
> + *cs++ = CS_GPR(4);
> + *cs++ = from;
> + *cs++ = from >> 32;
> +
> + *cs++ = MI_BATCH_BUFFER_END;
> +
> + gem_execbuf(i915, &execbuf);
> + gem_sync(i915, obj.handle);
> + gem_close(i915, obj.handle);
> + value = *map;
> + munmap(map, 4096);
> +
> + igt_assert_neq(value, 0x1234);
> + return value;
> +}
> +
> +static uint32_t read_at(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *e,
> + uint64_t addr, uint64_t from)
> +{
> + return __read_at(i915, ctx, e, gem_engine_mmio_base(i915, e->name),
> + addr, from);
> +}
> +
> +static uint32_t copy_from(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *e,
> + uint64_t addr, uint64_t from)
> +{
> + const int gen = intel_gen(intel_get_drm_devid(i915));
> + const int use_64b_addr = gen >= 8;
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = gem_create(i915, 4096),
> + .offset = from,
> + .flags = EXEC_OBJECT_PINNED
> + };
> + struct drm_i915_gem_execbuffer2 execbuf = {
> + .batch_len = 64,
> + .buffers_ptr = to_user_pointer(&obj),
> + .buffer_count = 1,
> + .flags = e->flags,
> + .rsvd1 = ctx->id,
> + };
> + uint32_t *map =
> + gem_mmap__device_coherent(i915, obj.handle,
> + 0, 4096, PROT_WRITE);
> + uint32_t *cs = map;
> + uint32_t value;
> +
> + *cs++ = MI_NOOP | 0x1234;
> +
> + *cs++ = XY_SRC_COPY | (3 << 20) | (6 + 2 * use_64b_addr);
> + *cs++ = 3 << 24 | 0xcc << 16 | 4096;
> + *cs++ = 0;
> + *cs++ = 1 << 16 | 1;
> + *cs++ = from;
> + if (use_64b_addr)
> + *cs++ = from >> 32;
> + *cs++ = 0;
> + *cs++ = 4096;
> + *cs++ = addr;
> + if (use_64b_addr)
> + *cs++ = addr >> 32;
> +
> + *cs++ = MI_BATCH_BUFFER_END;
> +
> + gem_execbuf(i915, &execbuf);
> + gem_sync(i915, obj.handle);
> + gem_close(i915, obj.handle);
> + value = *map;
> + munmap(map, 4096);
> +
> + igt_assert_neq(value, 0x1234);
> + return value;
> +}
> +
> +static uint64_t find_hole(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *e,
> + uint64_t size)
> +{
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = __batch_create(i915, 4 * size),
> + };
> + struct drm_i915_gem_execbuffer2 execbuf = {
> + .buffers_ptr = to_user_pointer(&obj),
> + .buffer_count = 1,
> + .flags = e->flags,
> + .rsvd1 = ctx->id,
> + };
> + uint64_t hole;
> +
> + gem_execbuf(i915, &execbuf);
> + hole = obj.offset + size; /* leave a guard on either side */
> + gem_close(i915, obj.handle);
> +
> + obj.handle = batch_create(i915),
> + obj.offset += 3 * size;
> + gem_execbuf(i915, &execbuf); /* force an unbind of hole */
> +
> + gem_sync(i915, obj.handle);
> + gem_close(i915, obj.handle);
> +
> + return hole;
> +}
> +
> +static uint32_t stale_create(int i915,
> + const struct gem_memory_region *mr,
> + uint64_t size, uint8_t val)
> +{
> + uint32_t handle, *map;
> +
> + handle = gem_create_in_memory_region_list(i915, size, 0, &mr->ci, 1);
> +
> + map = gem_mmap__device_coherent(i915, handle, 0, size, PROT_WRITE);
> + gem_set_domain(i915, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> + memset(map, val, size);
> + munmap(map, size);
> +
> + return handle;
> +}
> +
> +static uint32_t userptr_create(int i915, uint64_t size, uint8_t val, void **ptr
> +)
> +{
> + uint32_t handle;
> +
> + *ptr = mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
> + igt_assert(*ptr != MAP_FAILED);
> + memset(*ptr, val, size);
> +
> + gem_userptr(i915, *ptr, 4096, 0, 0, &handle);
> + return handle;
> +}
> +
> +
> +static bool has_mi_cond_bb_end(int i915)
> +{
> + uint32_t devid = intel_get_drm_devid(i915);
> +
> + return intel_gen(devid) >= 6;
> +}
> +
> +static bool has_xy_src_copy(int i915)
> +{
> + uint32_t devid = intel_get_drm_devid(i915);
> +
> + return true;
> + return intel_gen(devid) < 12; // < PVC
> +}
> +
> +static int has_secure_batches(int i915)
> +{
> + int v = -1;
> + drm_i915_getparam_t gp = {
> + .param = I915_PARAM_HAS_SECURE_BATCHES,
> + .value = &v,
> + };
> +
> + drmIoctl(i915, DRM_IOCTL_I915_GETPARAM, &gp);
> +
> + return v > 0;
> +}
> +
> +static bool has_mi_math(int i915, const struct intel_execution_engine2 *e)
> +{
> + uint32_t devid = intel_get_drm_devid(i915);
> +
> + if (intel_gen(devid) >= 8)
> + return true;
> +
> + if (!IS_HASWELL(devid))
> + return false;
> +
> + if (!has_secure_batches(i915))
> + return false;
> +
> + return e == NULL || e->class == I915_ENGINE_CLASS_RENDER;
> +}
> +
> +static void check_mmap(int i915, uint32_t handle, const uint32_t *hwsp)
> +{
> + unsigned long count = 0;
> +
> + while (gem_bo_busy(i915, handle)) {
> + uint32_t *map, sq;
> +
> + map = mmap(0, 4096, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
> + if (map == MAP_FAILED)
> + continue;
> +
> + for (int i = 0; i < 5; i++) {
> + sq = READ_ONCE(*hwsp);
> + while (READ_ONCE(*hwsp) == sq && gem_bo_busy(i915, handle))
> + sched_yield();
> +
> + sq = READ_ONCE(map[rand() % 1024]);
> + if (sq)
> + break;
> + }
> +
> + munmap(map, 4096);
> + igt_assert_f(!sq,
> + "Found %x in a new (clear) anonymous mmap after %lu tries!\n",
> + sq, count);
> + count++;
> + }
> +
> + igt_info("%s(%d) count:%lu\n", __func__, getpid(), count);
> +}
> +
> +static void check_bo(int i915, uint32_t handle, const uint32_t *hwsp)
> +{
> + int fd = gem_reopen_driver(i915);
> + unsigned long count = 0;
> +
> + while (gem_bo_busy(i915, handle)) {
> + uint32_t *map, sq;
> +
> + sq = gem_create(fd, 4096);
> + map = gem_mmap__device_coherent(fd, sq, 0, 4096, PROT_READ);
> + gem_close(fd, sq);
> +
> + for (int i = 0; i < 5; i++) {
> + sq = READ_ONCE(*hwsp);
> + while (READ_ONCE(*hwsp) == sq && gem_bo_busy(i915, handle))
> + sched_yield();
> +
> + sq = READ_ONCE(map[rand() % 1024]);
> + if (sq)
> + break;
> + }
> +
> + munmap(map, 4096);
> + igt_assert_f(!sq,
> + "Found %x in a new (clear) buffer after %lu tries!\n",
> + sq, count);
> + count++;
> +
> + }
> +
> + igt_info("%s(%d) count:%lu\n", __func__, getpid(), count);
> +}
> +
> +static bool
> +find_engine(int i915, const intel_ctx_t *ctx, int class, int instance,
> + struct intel_execution_engine2 *out)
> +{
> + const struct intel_execution_engine2 *e;
> +
> + for_each_ctx_engine(i915, ctx, e) {
> + if (e->class == class && e->instance == instance) {
> + memcpy(out, e, sizeof(*out));
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static bool find_bcs0(int i915, const intel_ctx_t *ctx, struct intel_execution_engine2 *out)
> +{
> + return find_engine(i915, ctx, I915_ENGINE_CLASS_COPY, 0, out);
> +}
> +
> +static void writer_at(int i915, const intel_ctx_t *ctx,
> + uint32_t handle, uint32_t *map,
> + const struct intel_execution_engine2 *e,
> + const uint32_t base,
> + uint64_t addr, uint64_t from)
> +{
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = handle,
> + .offset = from,
> + .flags = EXEC_OBJECT_PINNED
> + };
> + struct drm_i915_gem_execbuffer2 execbuf = {
> + .batch_start_offset = 256,
> + .buffers_ptr = to_user_pointer(&obj),
> + .buffer_count = 1,
> + .flags = e->flags,
> + .rsvd1 = ctx->id,
> + };
> + const int gen = intel_gen(intel_get_drm_devid(i915));
> + const int use_64b_addr = gen >= 8;
> + uint32_t *cs, *jmp;
> +
> + igt_assert(use_64b_addr || (addr >> 32) == 0);
> + igt_assert(use_64b_addr || (from >> 32) == 0);
> +
> + cs = map + execbuf.batch_start_offset / sizeof(*map);
> +
> + *cs++ = MI_LOAD_REGISTER_IMM | (5 - 2);
> + *cs++ = CS_GPR(0);
> + *cs++ = 0;
> + *cs++ = CS_GPR(0) + 4;
> + *cs++ = 0;
> +
> + *cs++ = MI_LOAD_REGISTER_IMM | (5 - 2);
> + *cs++ = CS_GPR(1);
> + *cs++ = 1;
> + *cs++ = CS_GPR(1) + 4;
> + *cs++ = 0;
> +
> + while (offset_in_page(cs) & 63)
> + cs++;
> + jmp = cs;
> +
> + /* Keep writing to the victim address */
> + *cs++ = XY_COLOR | (3 << 20) | (4 + use_64b_addr);
> + *cs++ = 3 << 24 | 0xf0 << 16 | 4096;
> + *cs++ = 0;
> + *cs++ = 1 << 16 | 1024;
> + *cs++ = addr;
> + if (use_64b_addr)
> + *cs++ = addr >> 32;
> + *cs++ = 0xdeadbeef;
> +
> + *cs++ = MI_FLUSH_DW;
> + *cs++ = 0;
> +
> + /* Increment a seqno for each pass */
> + *cs++ = MI_MATH | (5 - 2);
> + *cs++ = MI_MATH_LOAD(MI_MATH_REG_SRCA, MI_MATH_REG(0));
> + *cs++ = MI_MATH_LOAD(MI_MATH_REG_SRCB, MI_MATH_REG(1));
> + *cs++ = MI_MATH_ADD;
> + *cs++ = MI_MATH_STORE(MI_MATH_REG(0), MI_MATH_REG_ACCU);
> +
> + *cs++ = MI_STORE_REGISTER_MEM | (1 + use_64b_addr);
> + *cs++ = CS_GPR(0);
> + *cs++ = from;
> + *cs++ = from >> 32;
> +
> + map[2] = 0xffffffff;
> + map[3] = 0xffffffff;
> + *cs++ = MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE | (1 + use_64b_addr);
> + *cs++ = MI_BATCH_BUFFER_END;
> + *cs++ = from + 8;
> + *cs++ = from >> 32;
> +
> + *cs++ = MI_BATCH_BUFFER_START | 1 << 8 | use_64b_addr;
> + *cs++ = from + offset_in_page(jmp);
> + *cs++ = from >> 32;
> +
> + *cs++ = MI_BATCH_BUFFER_END; /* not reached */
> +
> + igt_debug("Running writer for %"PRIx64" at %"PRIx64" on %s\n",
> + addr, from, e->name);
> + gem_execbuf(i915, &execbuf);
> +
> + /* Wait until the batch is executing */
> + while (!READ_ONCE(*map) && gem_bo_busy(i915, handle))
> + ;
> + igt_assert(gem_bo_busy(i915, handle));
> +}
> +
> +static void close_clear(int i915, const intel_ctx_t *ctx,
> + const struct gem_memory_region *mr,
> + const struct intel_execution_engine2 *bcs0,
> + const struct intel_execution_engine2 *bind)
> +{
> + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + const uint32_t base =
> + gem_engine_mmio_base(i915, intel_gen(intel_get_drm_devid(i915)) >= 8 ? "bcs0" : "rcs0");
> + uint32_t stale, handle, sample, poison;
> + uint64_t hole;
> + uint32_t *map;
> +
> + stale = stale_create(i915, mr, 4096, 0);
> +
> + hole = find_hole(i915, ctx, bind, SZ_2M);
> + poison = read_at(i915, ctx, bind, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" contains poison:%x\n", hole, poison);
> +
> + /* Bind and sanitycheck reading the address returns our page */
> + bind_at(i915, ctx, bcs0, stale, hole, 8192);
> + sample = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_1M);
> + igt_assert_eq_u32(sample, 0);
> +
> + handle = gem_create(i915, 4096);
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_WRITE);
> +
> + writer_at(i915, ctx, handle, map, bcs0, base, hole, hole + SZ_1M);
> +
> + sample = read_at(i915, ctx, bind, hole, hole + SZ_512K);
> + igt_debug("Closing hole:%"PRIx64" on %s, sample:%x\n", hole, bind->name, sample);
> + igt_assert_eq_u32(sample, 0xdeadbeef);
> + gem_close(i915, stale);
> +
> + igt_fork(child, 2 * ncpus)
> + check_mmap(i915, handle, map);
> + igt_fork(child, 2 * ncpus)
> + check_bo(i915, handle, map);
> +
> + sleep(10);
> + map[2] = MI_BATCH_BUFFER_END;
> +
> + sample = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_512K);
> + igt_debug("Rechecking hole:%"PRIx64", sample:%x\n", hole, sample);
> +
> + igt_waitchildren();
> +
> + writer_at(i915, ctx, handle, map, bcs0, base, hole, hole + SZ_1M);
> + map[2] = MI_BATCH_BUFFER_END;
> + poison = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_512K);
> + igt_debug("Scratch overwritten? hole:%"PRIx64", sample:%x\n", hole, poison);
> + igt_assert_eq_u32(sample, poison);
> + munmap(map, 4096);
> + gem_close(i915, handle);
> +}
> +
> +static void madv_clear(int i915, const intel_ctx_t *ctx,
> + const struct gem_memory_region *mr,
> + const struct intel_execution_engine2 *bcs0,
> + const struct intel_execution_engine2 *bind)
> +{
> + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + const uint32_t base =
> + gem_engine_mmio_base(i915, intel_gen(intel_get_drm_devid(i915)) >= 8 ? "bcs0" : "rcs0");
> + uint32_t stale, handle, sample, poison;
> + uint64_t hole;
> + uint32_t *map;
> +
> + stale = stale_create(i915, mr, 4096, 0);
> +
> + hole = find_hole(i915, ctx, bind, SZ_2M);
> + poison = read_at(i915, ctx, bind, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" contains poison:%x\n", hole, poison);
> +
> + /* Bind and sanitycheck reading the address returns our page */
> + bind_at(i915, ctx, bcs0, stale, hole, 8192);
> + sample = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_1M);
> + igt_assert_eq_u32(sample, 0);
> +
> + handle = gem_create(i915, 4096);
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_WRITE);
> +
> + writer_at(i915, ctx, handle, map, bcs0, base, hole, hole + SZ_1M);
> +
> + /* Unbind hole by overlapping the range with a fresh vma */
> + sample = read_at(i915, ctx, bind, hole, hole + SZ_512K);
> + igt_debug("Evicting hole:%"PRIx64" on %s, sample:%x\n", hole, bind->name, sample);
> + igt_assert_eq_u32(sample, 0xdeadbeef);
> + bind_at(i915, ctx, bind, stale, hole + 4096, 0);
> + sample = read_at(i915, ctx, bind, hole, hole + SZ_512K);
> + igt_debug("Checking hole:%"PRIx64", sample:%x\n", hole, sample);
> + igt_assert_eq_u32(sample, poison);
> +
> + if (gem_madvise(i915, stale, I915_MADV_DONTNEED))
> + igt_drop_caches_set(i915, DROP_SHRINK_ALL);
> +
> + /* Check that we did indeed purge the stale buffer */
> + igt_assert(!gem_madvise(i915, stale, I915_MADV_DONTNEED));
> +
> + igt_fork(child, 2 * ncpus)
> + check_mmap(i915, handle, map);
> + igt_fork(child, 2 * ncpus)
> + check_bo(i915, handle, map);
> +
> + sleep(10);
> + map[2] = MI_BATCH_BUFFER_END;
> +
> + sample = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_512K);
> + igt_debug("Rechecking hole:%"PRIx64", sample:%x\n", hole, sample);
> +
> + igt_waitchildren();
> +
> + writer_at(i915, ctx, handle, map, bcs0, base, hole, hole + SZ_1M);
> + map[2] = MI_BATCH_BUFFER_END;
> + poison = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_512K);
> + igt_debug("Scratch overwritten? hole:%"PRIx64", sample:%x\n", hole, poison);
> + igt_assert_eq_u32(sample, poison);
> + munmap(map, 4096);
> + gem_close(i915, handle);
> + gem_close(i915, stale);
> +}
> +
> +static void userptr_clear(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *bcs0,
> + const struct intel_execution_engine2 *bind,
> + unsigned int flags)
> +{
> + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + const uint32_t base =
> + gem_engine_mmio_base(i915, intel_gen(intel_get_drm_devid(i915)) >= 8 ? "bcs0" : "rcs0");
> + uint32_t stale, handle, sample, poison;
> + uint64_t hole;
> + uint32_t *map;
> + void *ptr;
> +
> + stale = userptr_create(i915, 4096, 0, &ptr);
> +
> + hole = find_hole(i915, ctx, bind, SZ_2M);
> + poison = read_at(i915, ctx, bind, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" contains poison:%x\n", hole, poison);
> +
> + /* Bind and sanitycheck reading the address returns our page */
> + bind_at(i915, ctx, bcs0, stale, hole, 8192);
> + sample = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_1M);
> + igt_assert_eq_u32(sample, 0);
> +
> + handle = gem_create(i915, 4096);
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_WRITE);
> +
> + writer_at(i915, ctx, handle, map, bcs0, base, hole, hole + SZ_1M);
> +
> + /* Unbind hole by overlapping the range with a fresh vma */
> + sample = read_at(i915, ctx, bind, hole, hole + SZ_512K);
> + igt_debug("Evicting hole:%"PRIx64" on %s, sample:%x\n", hole, bind->name, sample);
> + igt_assert_eq_u32(sample, 0xdeadbeef);
> + bind_at(i915, ctx, bind, stale, hole + 4096, 0);
> + sample = read_at(i915, ctx, bind, hole, hole + SZ_512K);
> + igt_debug("Checking hole:%"PRIx64", sample:%x\n", hole, sample);
> + igt_assert_eq_u32(sample, poison);
> + munmap(ptr, 4096);
> + if (flags & SHRINK)
> + igt_drop_caches_set(i915, DROP_SHRINK_ALL);
> +
> + igt_fork(child, 2 * ncpus)
> + check_mmap(i915, handle, map);
> + igt_fork(child, 2 * ncpus)
> + check_bo(i915, handle, map);
> +
> + sleep(10);
> + map[2] = MI_BATCH_BUFFER_END;
> +
> + sample = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_512K);
> + igt_debug("Rechecking hole:%"PRIx64", sample:%x\n", hole, sample);
> +
> + igt_waitchildren();
> +
> + writer_at(i915, ctx, handle, map, bcs0, base, hole, hole + SZ_1M);
> + map[2] = MI_BATCH_BUFFER_END;
> + poison = __read_at(i915, ctx, bcs0, base, hole, hole + SZ_512K);
> + igt_debug("Scratch overwritten? hole:%"PRIx64", sample:%x\n", hole, poison);
> + igt_assert_eq_u32(sample, poison);
> + munmap(map, 4096);
> + gem_close(i915, handle);
> + gem_close(i915, stale);
> +}
> +
> +static void clear_tlb(int i915)
> +{
> + struct intel_execution_engine2 bcs0, bind;
> + const intel_ctx_t *ctx;
> +
> + /* See if we can retain a TLB entry past address reuse. */
> +
> + igt_fixture {
> + const struct intel_execution_engine2 *e;
> + bool found;
> +
> + igt_require(has_xy_src_copy(i915));
> + igt_require(has_mi_cond_bb_end(i915));
> +
> + ctx = intel_ctx_create_all_physical(i915);
> +
> + igt_require(find_bcs0(i915, ctx, &bcs0));
> + igt_require(has_mi_math(i915, &bcs0));
> +
> + found = false;
> + for_each_ctx_engine(i915, ctx, e) {
> + if (e->flags != bcs0.flags) {
> + memcpy(&bind, e, sizeof(bind));
> + found = true;
> + break;
> + }
> + }
> + igt_require(found);
> + igt_debug("Writing with %s, issuing binds with %s\n",
> + bcs0.name, bind.name);
> + }
> +
Please add descriptions before new tests.
> + igt_subtest_with_dynamic("close-clear") {
> + for_each_memory_region(r, i915) {
> + igt_dynamic_f("%s", r->name)
> + close_clear(i915, ctx, r, &bcs0, &bind);
> + }
> + }
> +
> + igt_subtest_with_dynamic("madv-clear") {
> + for_each_memory_region(r, i915) {
> + if (r->ci.memory_class) /* XXX how to purge lmem? */
> + continue;
> +
> + igt_dynamic_f("%s", r->name)
> + madv_clear(i915, ctx, r, &bcs0, &bind);
> + }
> + }
> +
> + igt_subtest("u-unmap-clear")
> + userptr_clear(i915, ctx, &bcs0, &bind, 0);
> + igt_subtest("u-shrink-clear")
> + userptr_clear(i915, ctx, &bcs0, &bind, SHRINK);
> +}
> +
> +static void dumb_writer_at(int i915, const intel_ctx_t *ctx,
> + uint32_t handle, uint32_t *map,
> + const struct intel_execution_engine2 *e,
> + uint64_t addr, uint64_t from)
> +{
> + struct drm_i915_gem_exec_object2 obj = {
> + .handle = handle,
> + .offset = from,
> + .flags = EXEC_OBJECT_PINNED
> + };
> + struct drm_i915_gem_execbuffer2 execbuf = {
> + .buffers_ptr = to_user_pointer(&obj),
> + .buffer_count = 1,
> + .flags = e->flags,
> + .rsvd1 = ctx->id,
> + };
> + const int gen = intel_gen(intel_get_drm_devid(i915));
> + const bool uses_parser = gem_has_cmdparser(i915);
> + const int use_flush_dw = gen >= 6;
> + const int use_64b_addr = gen >= 8;
> + uint32_t *cs, *jmp;
> +
> + igt_assert(use_64b_addr || (addr >> 32) == 0);
> + igt_assert(use_64b_addr || (from >> 32) == 0);
> +
> + if (uses_parser)
> + execbuf.batch_start_offset = 256;
> +
> + cs = map + execbuf.batch_start_offset / sizeof(*map);
> + jmp = cs;
> +
> + /* Keep writing to the victim address */
> + *cs++ = XY_COLOR | (3 << 20) | (4 + use_64b_addr);
> + *cs++ = 3 << 24 | 0xf0 << 16 | 4096;
> + *cs++ = 0;
> + *cs++ = 1 << 16 | 1024;
> + *cs++ = addr;
> + if (use_64b_addr)
> + *cs++ = addr >> 32;
> + *cs++ = 0xdeadbeef;
> +
> + if (use_flush_dw) {
> + *cs++ = MI_FLUSH_DW;
> + *cs++ = 0;
> + } else {
> + *cs++ = MI_FLUSH;
> + }
> +
> + if (uses_parser) {
> + map[0] = 0xffffffff;
> + map[1] = 0xffffffff;
> + *cs++ = MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE | (1 + use_64b_addr);
> + *cs++ = MI_BATCH_BUFFER_END;
> + *cs++ = from;
> + *cs++ = from >> 32;
> + }
> +
> + *cs++ = MI_BATCH_BUFFER_START | 1 << 8 | use_64b_addr;
> + *cs++ = from + offset_in_page(jmp);
> + *cs++ = from >> 32;
> +
> + *cs++ = MI_BATCH_BUFFER_END; /* not reached */
> +
> + igt_debug("Running writer for %"PRIx64" at %"PRIx64" on %s\n",
> + addr, from, e->name);
> + gem_execbuf(i915, &execbuf);
> +}
> +
> +static void dumb_mmap(int i915, uint32_t handle)
> +{
> + unsigned long count = 0;
> +
> + while (gem_bo_busy(i915, handle)) {
> + uint32_t *map, sq;
> +
> + map = mmap(0, 4096, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
> + if (map == MAP_FAILED)
> + continue;
> +
> + for (int i = 0; i < 5; i++) {
> + usleep(1000);
> + sq = READ_ONCE(map[rand() % 1024]);
> + if (sq)
> + break;
> + }
> +
> + munmap(map, 4096);
> + igt_assert_f(!sq,
> + "Found %x in a new (clear) anonymous mmap! after %lu tries\n",
> + sq, count);
> + count++;
> + }
> +
> + igt_info("%s(%d) count:%lu\n", __func__, getpid(), count);
> +}
> +
> +static void dumb_bo(int i915, uint32_t handle)
> +{
> + int fd = gem_reopen_driver(i915);
> + unsigned long count = 0;
> +
> + while (gem_bo_busy(i915, handle)) {
> + uint32_t *map, sq;
> +
> + sq = gem_create(fd, 4096);
> + map = gem_mmap__device_coherent(fd, sq, 0, 4096, PROT_READ);
> + gem_close(fd, sq);
> +
> + for (int i = 0; i < 5; i++) {
> + usleep(1000);
> + sq = READ_ONCE(map[rand() % 1024]);
> + if (sq)
> + break;
> + }
> +
> + munmap(map, 4096);
> + igt_assert_f(!sq,
> + "Found %x in a new (clear) buffer after %lu tries!\n",
> + sq, count);
> + count++;
> + }
> +
> + igt_info("%s(%d) count:%lu\n", __func__, getpid(), count);
> +}
> +
> +static void __spin_until_write(uint32_t *map)
> +{
> + while (!READ_ONCE(*map))
> + sched_yield();
> +}
> +
> +static void spin_until_write(int i915, uint32_t handle)
> +{
> + uint32_t *map;
> +
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_READ);
> + __spin_until_write(map);
> + munmap(map, 4096);
> +}
> +
> +static void close_dumb(int i915, const intel_ctx_t *ctx,
> + const struct gem_memory_region *mr,
> + const struct intel_execution_engine2 *bcs0)
> +{
> + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + uint32_t stale, handle, sample, poison;
> + uint64_t hole;
> + uint32_t *map;
> +
> + stale = stale_create(i915, mr, 4096, 0);
> +
> + hole = find_hole(i915, ctx, bcs0, SZ_2M);
> + poison = copy_from(i915, ctx, bcs0, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" contains poison:%x\n", hole, poison);
> +
> + /* Bind and sanitycheck reading the address returns our page */
> + bind_at(i915, ctx, bcs0, stale, hole, 8192);
> + sample = copy_from(i915, ctx, bcs0, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" replaced with value:%x\n", hole, sample);
> + igt_assert_eq_u32(sample, 0);
> +
> + handle = gem_create(i915, 4096);
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_WRITE);
> +
> + dumb_writer_at(i915, ctx, handle, map, bcs0, hole, hole + SZ_1M);
> + spin_until_write(i915, stale);
> + igt_debug("Closing stale object\n");
> + gem_close(i915, stale);
> +
> + igt_fork(child, 2 * ncpus)
> + dumb_mmap(i915, handle);
> + igt_fork(child, 2 * ncpus)
> + dumb_bo(i915, handle);
> +
> + sleep(10);
> + *map = MI_BATCH_BUFFER_END;
> +
> + sample = copy_from(i915, ctx, bcs0, hole, hole + SZ_512K);
> + igt_debug("Rechecking hole:%"PRIx64", sample:%x\n", hole, sample);
> +
> + igt_waitchildren();
> +
> + dumb_writer_at(i915, ctx, handle, map, bcs0, hole, hole + SZ_1M);
> + *map = MI_BATCH_BUFFER_END;
> + poison = read_at(i915, ctx, bcs0, hole, hole + SZ_512K);
> + igt_debug("Scratch overwritten? hole:%"PRIx64", sample:%x\n", hole, poison);
> + igt_assert_eq_u32(sample, poison);
> + munmap(map, 4096);
> + gem_close(i915, handle);
> +}
> +
> +static void madv_dumb(int i915, const intel_ctx_t *ctx,
> + const struct gem_memory_region *mr,
> + const struct intel_execution_engine2 *bcs0)
> +{
> + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + uint32_t stale, handle, sample, poison;
> + uint64_t hole;
> + uint32_t *map;
> +
> + stale = stale_create(i915, mr, 4096, 0);
> +
> + hole = find_hole(i915, ctx, bcs0, SZ_2M);
> + poison = copy_from(i915, ctx, bcs0, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" contains poison:%x\n", hole, poison);
> +
> + /* Bind and sanitycheck reading the address returns our page */
> + bind_at(i915, ctx, bcs0, stale, hole, 8192);
> + sample = copy_from(i915, ctx, bcs0, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" replaced with value:%x\n", hole, sample);
> + igt_assert_eq_u32(sample, 0);
> +
> + handle = gem_create(i915, 4096);
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_WRITE);
> +
> + dumb_writer_at(i915, ctx, handle, map, bcs0, hole, hole + SZ_1M);
> + spin_until_write(i915, stale);
> + igt_debug("Purging stale object\n");
> + if (gem_madvise(i915, stale, I915_MADV_DONTNEED))
> + igt_drop_caches_set(i915, DROP_SHRINK_ALL);
> +
> + /* Check that we did indeed purge the stale buffer */
> + igt_assert(!gem_madvise(i915, stale, I915_MADV_DONTNEED));
> +
> + igt_fork(child, 2 * ncpus)
> + dumb_mmap(i915, handle);
> + igt_fork(child, 2 * ncpus)
> + dumb_bo(i915, handle);
> +
> + sleep(10);
> + *map = MI_BATCH_BUFFER_END;
> +
> + sample = copy_from(i915, ctx, bcs0, hole, hole + SZ_512K);
> + igt_debug("Rechecking hole:%"PRIx64", sample:%x\n", hole, sample);
> +
> + igt_waitchildren();
> +
> + dumb_writer_at(i915, ctx, handle, map, bcs0, hole, hole + SZ_1M);
> + *map = MI_BATCH_BUFFER_END;
> + poison = read_at(i915, ctx, bcs0, hole, hole + SZ_512K);
> + igt_debug("Scratch overwritten? hole:%"PRIx64", sample:%x\n", hole, poison);
> + igt_assert_eq_u32(sample, poison);
> + munmap(map, 4096);
> + gem_close(i915, stale);
> + gem_close(i915, handle);
> +}
> +
> +static void userptr_dumb(int i915, const intel_ctx_t *ctx,
> + const struct intel_execution_engine2 *bcs0,
> + unsigned int flags)
> +{
> + const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
> + uint32_t stale, handle, sample, poison;
> + uint64_t hole;
> + uint32_t *map;
> + void *ptr;
> +
> + stale = userptr_create(i915, 4096, 0, &ptr);
> +
> + hole = find_hole(i915, ctx, bcs0, SZ_2M);
> + poison = copy_from(i915, ctx, bcs0, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" contains poison:%x\n", hole, poison);
> +
> + /* Bind and sanitycheck reading the address returns our page */
> + bind_at(i915, ctx, bcs0, stale, hole, 8192);
> + sample = copy_from(i915, ctx, bcs0, hole, hole + SZ_1M);
> + igt_debug("2M hole:%"PRIx64" replaced with value:%x\n", hole, sample);
> + igt_assert_eq_u32(sample, 0);
> +
> + handle = gem_create(i915, 4096);
> + map = gem_mmap__device_coherent(i915, handle, 0, 4096, PROT_WRITE);
> +
> + dumb_writer_at(i915, ctx, handle, map, bcs0, hole, hole + SZ_1M);
> + __spin_until_write(ptr);
> + igt_debug("Release userptr\n");
> + munmap(ptr, 4096);
> + if (flags & SHRINK)
> + igt_drop_caches_set(i915, DROP_SHRINK_ALL);
> +
> + igt_fork(child, 2 * ncpus)
> + dumb_mmap(i915, handle);
> + igt_fork(child, 2 * ncpus)
> + dumb_bo(i915, handle);
> +
> + sleep(10);
> + *map = MI_BATCH_BUFFER_END;
> +
> + sample = copy_from(i915, ctx, bcs0, hole, hole + SZ_512K);
> + igt_debug("Rechecking hole:%"PRIx64", sample:%x\n", hole, sample);
> +
> + igt_waitchildren();
> +
> + dumb_writer_at(i915, ctx, handle, map, bcs0, hole, hole + SZ_1M);
> + *map = MI_BATCH_BUFFER_END;
> + poison = read_at(i915, ctx, bcs0, hole, hole + SZ_512K);
> + igt_debug("Scratch overwritten? hole:%"PRIx64", sample:%x\n", hole, poison);
> + igt_assert_eq_u32(sample, poison);
> + munmap(map, 4096);
> + gem_close(i915, handle);
> + gem_close(i915, stale);
> +}
> +
> +static bool find_blitter(int i915, const intel_ctx_t *ctx, struct intel_execution_engine2 *out)
> +{
> + if (find_engine(i915, ctx, I915_ENGINE_CLASS_COPY, 0, out))
> + return true;
> +
> + if (intel_gen(intel_get_drm_devid(i915)) >= 6)
> + return false;
> +
> + return find_engine(i915, ctx, I915_ENGINE_CLASS_RENDER, 0, out);
> +}
> +
> +static void dumb_tlb(int i915)
> +{
> + struct intel_execution_engine2 blt;
> + const intel_ctx_t *ctx;
> +
> + /*
> + * A simplified test for running across all generations. Nothing fancy,
> + * just keep writing to stale addresses looking for a retained TLB
> + * entry.
> + */
> +
> + igt_fixture {
> + ctx = intel_ctx_create_all_physical(i915);
> + igt_require(has_xy_src_copy(i915));
> + igt_require(find_blitter(i915, ctx, &blt));
> + }
> +
> + igt_subtest_with_dynamic("close-dumb") {
> + for_each_memory_region(r, i915) {
> + igt_dynamic_f("%s", r->name)
> + close_dumb(i915, ctx, r, &blt);
> + }
> + }
> +
> + igt_subtest_with_dynamic("madv-dumb") {
> + for_each_memory_region(r, i915) {
> + if (r->ci.memory_class) /* XXX how to purge lmem? */
> + continue;
> +
> + igt_dynamic_f("%s", r->name)
> + madv_dumb(i915, ctx, r, &blt);
> + }
> + }
> +
> + igt_subtest("u-unmap-dumb")
> + userptr_dumb(i915, ctx, &blt, 0);
> +
> + igt_subtest("u-shrink-dumb")
> + userptr_dumb(i915, ctx, &blt, SHRINK);
> +
> + igt_fixture
> + intel_ctx_destroy(i915, ctx);
> +}
> +
> +igt_main
> +{
> + int i915 = -1;
> +
> + igt_fixture {
> + i915 = drm_open_driver(DRIVER_INTEL);
> + igt_require_gem(i915);
> +
> + igt_fork_hang_detector(i915);
> + }
> +
> + igt_subtest_group
> + clear_tlb(i915);
> +
> + igt_subtest_group
> + dumb_tlb(i915);
> +
> + igt_fixture {
> + igt_stop_hang_detector();
> + close(i915);
> + }
> +}
> diff --git a/tests/i915/gem_gpgpu_fill.c b/tests/i915/gem_gpgpu_fill.c
> index 74a227f678e7..397f6c38a879 100644
> --- a/tests/i915/gem_gpgpu_fill.c
> +++ b/tests/i915/gem_gpgpu_fill.c
> @@ -152,6 +152,8 @@ igt_main
> region_set = get_memory_region_set(region_info,
> I915_SYSTEM_MEMORY,
> I915_DEVICE_MEMORY);
> +
> + igt_fork_hang_detector(data.drm_fd);
> }
Split this to separate patch (looks like a fix).
Regards,
Kamil
>
> igt_subtest_with_dynamic("basic") {
> diff --git a/tests/meson.build b/tests/meson.build
> index b548dc3b4444..6546adb3ed51 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -147,6 +147,7 @@ i915_progs = [
> 'gem_exec_schedule',
> 'gem_exec_store',
> 'gem_exec_suspend',
> + 'gem_exec_tlb',
> 'gem_exec_whisper',
> 'gem_fd_exhaustion',
> 'gem_fence_thrash',
> --
> 2.36.1
>
More information about the igt-dev
mailing list