[Intel-gfx] [PATCH igt] igt/gem_softpin: Remove false dependencies on esoteric features

Tvrtko Ursulin tvrtko.ursulin at linux.intel.com
Fri Jan 15 01:41:22 PST 2016


Hi,

On 14/01/16 11:02, Chris Wilson wrote:
> For softpinning, we do not require either userptr or extended ppgtt, so
> remove those requirements and make the tests work universally. (Certain
> ABI tests require large GTT, or per-process GTT.)
>
> In the process, make the tests more extensive - validate overlapping
> handling more careful, explicitly test no-relocation support, validate
> more ABI handling. And for fun, cause a kernel GPF.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>   tests/gem_softpin.c | 1313 +++++++++++++--------------------------------------
>   1 file changed, 324 insertions(+), 989 deletions(-)

Adding some people to Cc who could be potential reviewers. We were 
tracking blanket improvements agreed during code review of the initial 
version in VIZ-6951. I've put a reference to this patch in there.

Regards,

Tvrtko

> diff --git a/tests/gem_softpin.c b/tests/gem_softpin.c
> index 1cbde4e..f188559 100644
> --- a/tests/gem_softpin.c
> +++ b/tests/gem_softpin.c
> @@ -26,80 +26,10 @@
>    *
>    */
>
> -#include <unistd.h>
> -#include <stdlib.h>
> -#include <stdint.h>
> -#include <stdio.h>
> -#include <string.h>
> -#include <fcntl.h>
> -#include <inttypes.h>
> -#include <errno.h>
> -#include <sys/stat.h>
> -#include <sys/ioctl.h>
> -#include <sys/time.h>
> -#include <malloc.h>
> -#include "drm.h"
> -#include "ioctl_wrappers.h"
> -#include "drmtest.h"
> -#include "intel_chipset.h"
> -#include "intel_io.h"
> -#include "i915_drm.h"
> -#include <assert.h>
> -#include <sys/wait.h>
> -#include <sys/ipc.h>
> -#include <sys/shm.h>
> -#include "igt_kms.h"
> -#include <inttypes.h>
> -#include <sys/types.h>
> -#include <sys/stat.h>
> -
> -#define BO_SIZE 4096
> -#define MULTIPAGE_BO_SIZE 2 * BO_SIZE
> -#define STORE_BATCH_BUFFER_SIZE 4
> +#include "igt.h"
> +
>   #define EXEC_OBJECT_PINNED	(1<<4)
>   #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
> -#define SHARED_BUFFER_SIZE 4096
> -
> -typedef struct drm_i915_gem_userptr i915_gem_userptr;
> -
> -static uint32_t init_userptr(int fd, i915_gem_userptr *, void *ptr, uint64_t size);
> -static void *create_mem_buffer(uint64_t size);
> -static int gem_call_userptr_ioctl(int fd, i915_gem_userptr *userptr);
> -static void gem_pin_userptr_test(void);
> -static void gem_pin_bo_test(void);
> -static void gem_pin_invalid_vma_test(bool test_decouple_flags, bool test_canonical_offset);
> -static void gem_pin_overlap_test(void);
> -static void gem_pin_high_address_test(void);
> -
> -#define NO_PPGTT 0
> -#define ALIASING_PPGTT 1
> -#define FULL_32_BIT_PPGTT 2
> -#define FULL_48_BIT_PPGTT 3
> -/* uses_full_ppgtt
> - * Finds supported PPGTT details.
> - * @fd DRM fd
> - * @min can be
> - * 0 - No PPGTT
> - * 1 - Aliasing PPGTT
> - * 2 - Full PPGTT (32b)
> - * 3 - Full PPGTT (48b)
> - * RETURNS true/false if min support is present
> -*/
> -static bool uses_full_ppgtt(int fd, int min)
> -{
> -	struct drm_i915_getparam gp;
> -	int val = 0;
> -
> -	memset(&gp, 0, sizeof(gp));
> -	gp.param = 18; /* HAS_ALIASING_PPGTT */
> -	gp.value = &val;
> -
> -	if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
> -		return 0;
> -
> -	errno = 0;
> -	return val >= min;
> -}
>
>   /* has_softpin_support
>    * Finds if softpin feature is supported
> @@ -121,83 +51,6 @@ static bool has_softpin_support(int fd)
>   	return (val == 1);
>   }
>
> -/* gem_call_userptr_ioctl
> - * Helper to call ioctl - TODO: move to lib
> - * @fd - drm fd
> - * @userptr - pointer to initialised userptr
> - * RETURNS status of ioctl call
> -*/
> -static int gem_call_userptr_ioctl(int fd, i915_gem_userptr *userptr)
> -{
> -	int ret;
> -
> -	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_USERPTR, userptr);
> -
> -	if (ret)
> -		ret = errno;
> -
> -	return ret;
> -}
> -
> -/* init_userptr
> - * Helper that inits userptr an returns handle
> - * @fd - drm fd
> - * @userptr - pointer to empty userptr
> - * @ptr - buffer to be shared
> - * @size - size of buffer
> - * @ro - read only flag
> - * RETURNS handle to shared buffer
> -*/
> -static uint32_t init_userptr(int fd, i915_gem_userptr *userptr, void *ptr,
> -			     uint64_t size)
> -{
> -	int ret;
> -
> -	memset((void*)userptr, 0, sizeof(i915_gem_userptr));
> -
> -	userptr->user_ptr = (unsigned long)ptr; /* Need the cast to overcome compiler warning */
> -	userptr->user_size = size;
> -	userptr->flags = 0; /* use synchronized operation */
> -
> -	ret = gem_call_userptr_ioctl(fd, userptr);
> -	igt_assert_eq(ret, 0);
> -
> -	return userptr->handle;
> -}
> -
> -/* create_mem_buffer
> - * Creates a 4K aligned CPU buffer
> - * @size - size of buffer
> - * RETURNS pointer to buffer of @size
> -*/
> -static void *create_mem_buffer(uint64_t size)
> -{
> -	void *addr;
> -	int ret;
> -
> -	ret = posix_memalign(&addr, 4096, size);
> -	igt_assert(ret == 0);
> -
> -	return addr;
> -}
> -
> -/* setup_exec_obj
> - * populate exec object
> - * @exec - exec object
> - * @handle - handle to gem buffer
> - * @flags - any flags
> - * @offset - requested VMA
> -*/
> -static void setup_exec_obj(struct drm_i915_gem_exec_object2 *exec,
> -			   uint32_t handle, uint32_t flags,
> -			   uint64_t offset)
> -{
> -	memset(exec, 0, sizeof(struct drm_i915_gem_exec_object2));
> -	exec->handle = handle;
> -	exec->flags = flags;
> -	exec->offset = offset;
> -}
> -
>   /* gen8_canonical_addr
>    * Used to convert any address into canonical form, i.e. [63:48] == [47].
>    * Based on kernel's sign_extend64 implementation.
> @@ -210,904 +63,386 @@ static uint64_t gen8_canonical_addr(uint64_t address)
>   	return (__s64)(address << shift) >> shift;
>   }
>
> -/* gem_store_data_svm
> - * populate batch buffer with MI_STORE_DWORD_IMM command
> - * @fd: drm file descriptor
> - * @cmd_buf: batch buffer
> - * @vaddr: destination Virtual address
> - * @data: data to be store at destination
> - * @end: whether to end batch buffer or not
> -*/
> -static int gem_store_data_svm(int fd, uint32_t *cmd_buf, uint64_t vaddr,
> -			      uint32_t data, bool end)
> +static int __gem_execbuf(int fd, struct drm_i915_gem_execbuffer2 *eb)
>   {
> -	int i = 0;
> -
> -	cmd_buf[i++] = MI_STORE_DWORD_IMM;
> -	cmd_buf[i++] = vaddr & 0xFFFFFFFC;
> -	cmd_buf[i++] = (vaddr >> 32) & 0xFFFF; /* bits 32:47 */
> -
> -	cmd_buf[i++] = data;
> -	if (end) {
> -		cmd_buf[i++] = MI_BATCH_BUFFER_END;
> -		cmd_buf[i++] = 0;
> -	}
> -
> -	return(i * sizeof(uint32_t));
> +	int err = 0;
> +	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, eb))
> +		err = -errno;
> +	return err;
>   }
>
> -/* gem_store_data
> - * populate batch buffer with MI_STORE_DWORD_IMM command
> - * This one fills up reloc buffer as well
> - * @fd: drm file descriptor
> - * @cmd_buf: batch buffer
> - * @data: data to be store at destination
> - * @reloc - relocation entry
> - * @end: whether to end batch buffer or not
> -*/
> -static int gem_store_data(int fd, uint32_t *cmd_buf,
> -			  uint32_t handle, uint32_t data,
> -			  struct drm_i915_gem_relocation_entry *reloc,
> -			  bool end)
> +static void test_invalid(int fd)
>   {
> -	int i = 0;
> -
> -	cmd_buf[i++] = MI_STORE_DWORD_IMM;
> -	cmd_buf[i++] = 0; /* lower 31 bits of 48 bit address - 0 reloc needed */
> -	cmd_buf[i++] = 0; /* upper 15 bits of 48 bit address - 0 reloc needed */
> -	reloc->offset = 1 * sizeof(uint32_t);
> -	reloc->delta = 0;
> -	reloc->target_handle = handle;
> -	reloc->read_domains = I915_GEM_DOMAIN_RENDER;
> -	reloc->write_domain = I915_GEM_DOMAIN_RENDER;
> -	reloc->presumed_offset = 0;
> -	cmd_buf[i++] = data;
> -	if (end) {
> -		cmd_buf[i++] = MI_BATCH_BUFFER_END;
> -		cmd_buf[i++] = 0;
> +	const uint32_t bbe = MI_BATCH_BUFFER_END;
> +	struct drm_i915_gem_execbuffer2 execbuf;
> +	struct drm_i915_gem_exec_object2 object;
> +
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)&object;
> +	execbuf.buffer_count = 1;
> +
> +	memset(&object, 0, sizeof(object));
> +	object.handle = gem_create(fd, 2*4096);
> +	object.flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS | EXEC_OBJECT_PINNED;
> +	gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
> +
> +	/* Check invalid alignment */
> +	object.offset = 4096;
> +	object.alignment = 64*1024;
> +	igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
> +	object.alignment = 0;
> +
> +	/* Check wraparound */
> +	object.offset = -4096ULL;
> +	igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
> +
> +	/* Check beyond bounds of aperture */
> +	object.offset = gem_aperture_size(fd) - 4096;
> +	object.offset = gen8_canonical_addr(object.offset);
> +	igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
> +
> +	/* Check gen8 canonical addressing */
> +	if (gem_aperture_size(fd) > 1ull<<GEN8_HIGH_ADDRESS_BIT) {
> +		object.offset = 1ull << GEN8_HIGH_ADDRESS_BIT;
> +		igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
> +
> +		object.offset = gen8_canonical_addr(object.offset);
> +		igt_assert_eq(__gem_execbuf(fd, &execbuf), 0);
>   	}
>
> -	return (i * sizeof(uint32_t));
> -}
> +	/* Check extended range */
> +	if (gem_aperture_size(fd) > 1ull<<32) {
> +		object.flags = EXEC_OBJECT_PINNED;
> +		object.offset = 1ull<<32;
> +		igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
>
> -/* setup_execbuffer
> - * helper for buffer execution
> - * @execbuf - pointer to execbuffer
> - * @exec_object - pointer to exec object2 struct
> - * @ring - ring to be used
> - * @buffer_count - how manu buffers to submit
> - * @batch_length - length of batch buffer
> -*/
> -static void setup_execbuffer(struct drm_i915_gem_execbuffer2 *execbuf,
> -			     struct drm_i915_gem_exec_object2 *exec_object,
> -			     int ring, int buffer_count, int batch_length)
> -{
> -	execbuf->buffers_ptr = (unsigned long)exec_object;
> -	execbuf->buffer_count = buffer_count;
> -	execbuf->batch_start_offset = 0;
> -	execbuf->batch_len = batch_length;
> -	execbuf->cliprects_ptr = 0;
> -	execbuf->num_cliprects = 0;
> -	execbuf->DR1 = 0;
> -	execbuf->DR4 = 0;
> -	execbuf->flags = ring;
> -	i915_execbuffer2_set_context_id(*execbuf, 0);
> -	execbuf->rsvd2 = 0;
> -}
> -
> -/* submit_and_sync
> - * Helper function for exec and sync functions
> - * @fd - drm fd
> - * @execbuf - pointer to execbuffer
> - * @batch_buf_handle - batch buffer handle
> -*/
> -static void submit_and_sync(int fd, struct drm_i915_gem_execbuffer2 *execbuf,
> -			    uint32_t batch_buf_handle)
> -{
> -	gem_execbuf(fd, execbuf);
> -	gem_sync(fd, batch_buf_handle);
> -}
> -
> -/* gem_userptr_sync
> - * helper for syncing to CPU domain - copy/paste from userblit
> - * @fd - drm fd
> - * @handle - buffer handle to sync
> -*/
> -static void gem_userptr_sync(int fd, uint32_t handle)
> -{
> -	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> -}
> -
> -
> -/* gem_pin_userptr_test
> - * This test will create a shared buffer, and create a command
> - * for GPU to write data in it
> - * CPU will read and make sure expected value is obtained
> - * Malloc a 4K buffer
> - * Share buffer with with GPU by using userptr ioctl
> - * Create batch buffer to write DATA to first dword of buffer
> - * Use 0x1000 address as destination address in batch buffer
> - * Set EXEC_OBJECT_PINNED flag in exec object
> - * Set 'offset' in exec object to 0x1000
> - * Submit execbuffer
> - * Verify value of first DWORD in shared buffer matches DATA
> -*/
> -static void gem_pin_userptr_test(void)
> -{
> -	i915_gem_userptr userptr;
> -	int fd;
> -	uint32_t *shared_buffer;
> -	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[2];
> -	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE + 2];
> -	uint32_t batch_buf_handle, shared_buf_handle;
> -	int ring, len;
> -	const uint32_t data = 0x12345678;
> -	uint64_t pinning_offset = 0x1000;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, ALIASING_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -	batch_buf_handle = gem_create(fd, BO_SIZE);
> -
> -	/* create cpu buffer */
> -	shared_buffer = create_mem_buffer(BO_SIZE);
> -
> -	/* share with GPU */
> -	shared_buf_handle = init_userptr(fd, &userptr, shared_buffer,
> -					 BO_SIZE);
> -
> -	/* create command buffer with write command */
> -	len = gem_store_data_svm(fd, batch_buffer, pinning_offset, data, true);
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -
> -	/* submit command buffer */
> -	setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -	submit_and_sync(fd, &execbuf, batch_buf_handle);
> -	gem_userptr_sync(fd, shared_buf_handle);
> -
> -	/* Check if driver pinned the buffer as requested */
> -	igt_fail_on_f(exec_object2[0].offset != pinning_offset,
> -			"\nFailed to pin at requested offset");
> -	/* check on CPU to see if value changes */
> -	igt_fail_on_f(shared_buffer[0] != data,
> -		      "\nCPU read does not match GPU write,\
> -			expected: 0x%x, got: 0x%x\n",
> -			data, shared_buffer[0]);
> -
> -	gem_close(fd, batch_buf_handle);
> -	gem_close(fd, shared_buf_handle);
> -	close(fd);
> -	free(shared_buffer);
> +		object.offset = gen8_canonical_addr(object.offset);
> +		object.flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
> +		igt_assert_eq(__gem_execbuf(fd, &execbuf), 0);
> +	}
>   }
>
> -/* gem_pin_bo
> - * This test will test softpinning of a gem buffer object
> - * Malloc a 4K buffer
> - * Create batch buffer to write DATA to first dword of buffer
> - * Use 0x1000 address as destination address in batch buffer
> - * Set EXEC_OBJECT_PINNED flag in exec object
> - * Set 'offset' in exec object to 0x1000
> - * Submit execbuffer
> - * Verify value pinned offset matches the request
> -*/
> -static void gem_pin_bo_test(void)
> +static void test_softpin(int fd)
>   {
> -	int fd;
> +	const uint32_t size = 1024 * 1024;
> +	const uint32_t bbe = MI_BATCH_BUFFER_END;
>   	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[2];
> -	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE + 2];
> -	uint32_t batch_buf_handle, unshared_buf_handle;
> -	struct drm_i915_gem_relocation_entry reloc[4];
> -	int ring, len;
> -	uint32_t value;
> -	const uint32_t data = 0x12345678;
> -	uint64_t pinning_offset = 0x1000;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, ALIASING_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	batch_buf_handle = gem_create(fd, BO_SIZE);
> -
> -	/* create gem buffer */
> -	unshared_buf_handle = gem_create(fd, BO_SIZE);
> -
> -	/* create command buffer with write command */
> -	len = gem_store_data(fd, batch_buffer, unshared_buf_handle, data,
> -				reloc, true);
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -
> -	/* submit command buffer */
> -	setup_exec_obj(&exec_object2[0], unshared_buf_handle,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> -	exec_object2[1].relocation_count = 1;
> -	exec_object2[1].relocs_ptr = (unsigned long)reloc;
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -	submit_and_sync(fd, &execbuf, batch_buf_handle);
> -
> -	/* Check if driver pinned the buffer as requested */
> -	igt_fail_on_f(exec_object2[0].offset != pinning_offset,
> -			"\nFailed to pin at requested offset");
> -	gem_read(fd, unshared_buf_handle, 0, (void*)&value, 4);
> -	igt_assert(value == data);
> -
> -	gem_close(fd, batch_buf_handle);
> -	gem_close(fd, unshared_buf_handle);
> -	close(fd);
> -}
> -
> -
> -/* gem_multiple_process_test
> - * Run basic test simultaneously with multiple processes
> - * This will test pinning same VA separately in each process
> -
> - * fork();
> - * Execute basic test in parent/child processes
> -*/
> -#define MAX_NUM_PROCESSES 10
> -
> -static void gem_multiple_process_test(void)
> -{
> -	int fd;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, ALIASING_PPGTT));
> -	igt_require(has_softpin_support(fd));
> +	struct drm_i915_gem_exec_object2 object;
> +	uint64_t offset, end;
> +	int loop;
> +
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)&object;
> +	execbuf.buffer_count = 1;
> +	for (loop = 0; loop < 1024; loop++) {
> +		memset(&object, 0, sizeof(object));
> +		object.handle = gem_create(fd, 2*size);
> +		gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
> +
> +		/* Find a hole */
> +		gem_execbuf(fd, &execbuf);
> +		gem_close(fd, object.handle);
> +
> +		igt_debug("Made a 2 MiB hole: %08llx\n",
> +			  object.offset);
> +
> +		object.handle = gem_create(fd, size);
> +		gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
> +		object.flags |= EXEC_OBJECT_PINNED;
> +
> +		end = object.offset + size;
> +		for (offset = object.offset; offset <= end; offset += 4096) {
> +			object.offset = offset;
> +			gem_execbuf(fd, &execbuf);
> +			igt_assert_eq_u64(object.offset, offset);
> +		}
>
> -	igt_fork(child, MAX_NUM_PROCESSES) {
> -		gem_pin_userptr_test();
> +		gem_close(fd, object.handle);
>   	}
> -	igt_waitchildren();
> -
> -	close(fd);
> -}
> -
> -
> -/* gem_repin_test
> - * This test tries to repin a buffer at a previously pinned vma
> - * from a different execbuf.
> - * Malloc a 4K buffer
> - * Share buffer with with GPU by using userptr ioctl
> - * Create batch buffer to write DATA to first dword of buffer
> - * Use 0x1000 address as destination address in batch buffer
> - * Set EXEC_OBJECT_PINNED flag in exec object
> - * Set 'offset' in exec object to 0x1000 VMA
> - * Submit execbuffer
> - * Verify value of first DWORD in shared buffer matches DATA
> -
> - * Create second shared buffer
> - * Follow all steps above
> - * Execpt, for offset, use VMA of first buffer above
> - * Submit execbuffer
> - * Verify value of first DWORD in second shared buffer matches DATA
> -*/
> -static void gem_repin_test(void)
> -{
> -	i915_gem_userptr userptr;
> -	i915_gem_userptr userptr1;
> -	int fd;
> -	uint32_t *shared_buffer;
> -	uint32_t *shared_buffer1;
> -	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[2];
> -	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE + 2];
> -	uint32_t batch_buf_handle, shared_buf_handle, shared_buf_handle1;
> -	int ring, len;
> -	const uint32_t data = 0x12345678;
> -	uint64_t pinning_offset = 0x1000;
> -
> -	/* Create gem object */
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, ALIASING_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	batch_buf_handle = gem_create(fd, BO_SIZE);
> -
> -	/* create cpu buffer, set first elements to 0x0 */
> -	shared_buffer = create_mem_buffer(BO_SIZE);
> -	shared_buffer1 = create_mem_buffer(BO_SIZE);
> -	shared_buffer[0] = 0x0;
> -	shared_buffer1[0] = 0x0;
> -
> -	/* share with GPU and get handles */
> -	shared_buf_handle = init_userptr(fd, &userptr, shared_buffer,
> -					 BO_SIZE);
> -	shared_buf_handle1 = init_userptr(fd, &userptr1, shared_buffer1,
> -					  BO_SIZE);
> -
> -	/* create command buffer with write command */
> -	len = gem_store_data_svm(fd, batch_buffer, pinning_offset, data, true);
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -
> -	/* submit command buffer */
> -	setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -	submit_and_sync(fd, &execbuf, batch_buf_handle);
> -	gem_userptr_sync(fd, shared_buf_handle);
> -
> -	igt_assert(exec_object2[0].offset == pinning_offset);
> -	igt_assert(*shared_buffer == data);
> -
> -	/* Second buffer */
> -	/* create command buffer with write command */
> -	pinning_offset = exec_object2[0].offset;
> -	len = gem_store_data_svm(fd, batch_buffer, pinning_offset, data, true);
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -
> -	/* submit command buffer */
> -	/* Pin at shared_buffer, not shared_buffer1 */
> -	/* We are requesting address where another buffer was pinned previously */
> -	setup_exec_obj(&exec_object2[0], shared_buf_handle1,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -	submit_and_sync(fd, &execbuf, batch_buf_handle);
> -	gem_userptr_sync(fd, shared_buf_handle1);
> -
> -	igt_assert(exec_object2[0].offset == pinning_offset);
> -	igt_assert(*shared_buffer1 == data);
> -
> -	gem_close(fd, batch_buf_handle);
> -	gem_close(fd, shared_buf_handle);
> -	close(fd);
> -
> -	free(shared_buffer);
> -	free(shared_buffer1);
>   }
>
> -
> -/* gem_repin_overlap_test
> - * This test will attempt to pin two buffers at the same VMA as part of the same
> -   execbuffer object
> -
> - * Malloc a 4K buffer
> - * Share buffer with with GPU by using userptr ioctl
> - * Create second shared buffer
> - * Create batch buffer to write DATA to first dword of each buffer
> - * Use same virtual address as destination addresses in batch buffer
> - * Set EXEC_OBJECT_PINNED flag in both exec objects
> - * Set 'offset' in both exec objects to same VMA
> - * Submit execbuffer
> - * Command should return EINVAL, since we are trying to pin to same VMA
> -*/
> -static void gem_pin_overlap_test(void)
> +static void test_overlap(int fd)
>   {
> -	i915_gem_userptr userptr;
> -	i915_gem_userptr userptr1;
> -	int fd, ret;
> -	uint32_t *shared_buffer;
> -	uint32_t *shared_buffer1;
> +	const uint32_t size = 1024 * 1024;
> +	const uint32_t bbe = MI_BATCH_BUFFER_END;
>   	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[3];
> -	uint32_t shared_buf_handle, shared_buf_handle1;
> -	int ring, len;
> -	uint64_t pinning_offset = 0x1000;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, ALIASING_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	shared_buffer = create_mem_buffer(BO_SIZE);
> -	shared_buffer1 = create_mem_buffer(BO_SIZE * 2);
> -
> -	/* share with GPU */
> -	shared_buf_handle = init_userptr(fd, &userptr, shared_buffer,
> -					 BO_SIZE);
> -	shared_buf_handle1 = init_userptr(fd, &userptr1, shared_buffer1,
> -					  BO_SIZE * 2);
> -
> -	/* submit command buffer */
> -	setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -	setup_exec_obj(&exec_object2[1], shared_buf_handle1,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -
> -	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
> -
> -	/* expect to fail */
> -	igt_assert_neq(ret, 0);
> -	igt_assert(errno == EINVAL);
> +	struct drm_i915_gem_exec_object2 object[2];
> +	uint64_t offset;
> +	uint32_t handle;
> +
> +	handle = gem_create(fd, 3*size);
> +	gem_write(fd, handle, 0, &bbe, sizeof(bbe));
> +
> +	memset(object, 0, sizeof(object));
> +	object[0].handle = handle;
> +
> +	/* Find a hole */
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)object;
> +	execbuf.buffer_count = 1;
> +	gem_execbuf(fd, &execbuf);
> +
> +	igt_debug("Made a 3x1 MiB hole: %08llx\n",
> +		  object[0].offset);
> +
> +	object[0].handle = gem_create(fd, size);
> +	object[0].offset += size;
> +	object[0].flags |= EXEC_OBJECT_PINNED;
> +	object[1].handle = gem_create(fd, size);
> +	object[1].flags |= EXEC_OBJECT_PINNED;
> +	gem_write(fd, object[1].handle, 0, &bbe, sizeof(bbe));
> +	execbuf.buffer_count = 2;
> +
> +	/* Check that we fit into our hole */
> +	object[1].offset = object[0].offset - size;
> +	gem_execbuf(fd, &execbuf);
> +	igt_assert_eq_u64(object[1].offset + size, object[0].offset);
> +
> +	object[1].offset = object[0].offset + size;
> +	gem_execbuf(fd, &execbuf);
> +	igt_assert_eq_u64(object[1].offset - size, object[0].offset);
> +
> +	/* Try all possible page-aligned overlaps */
> +	for (offset = object[0].offset - size + 4096;
> +	     offset < object[0].offset + size;
> +	     offset += 4096) {
> +		object[1].offset = offset;
> +		igt_debug("[0]=[%08llx - %08llx] [1]=[%08llx - %08llx]\n",
> +			  (long long)object[0].offset,
> +			  (long long)object[0].offset + size,
> +			  (long long)object[1].offset,
> +			  (long long)object[1].offset + size);
> +		igt_assert_eq(__gem_execbuf(fd, &execbuf), -EINVAL);
> +		igt_assert_eq_u64(object[1].offset, offset);
> +	}
>
> -	close(fd);
> -	free(shared_buffer);
> -	free(shared_buffer1);
> +	gem_close(fd, object[1].handle);
> +	gem_close(fd, object[0].handle);
> +	gem_close(fd, handle);
>   }
>
> -/* gem_softpin_stress_test
> - * Stress test which creates 10K buffers and shares with GPU
> - * Create 100K uint32 buffers of size 4K each
> - * Share with GPU using userptr ioctl
> - * Create batch buffer to write DATA in first element of each buffer
> - * Pin each buffer to varying addresses starting from 0x800000000000 going below
> - * (requires offsets in canonical form)
> - * Execute Batch Buffer on Blit ring STRESS_NUM_LOOPS times
> - * Validate every buffer has DATA in first element
> - * Rinse and Repeat on Render ring
> -*/
> -#define STRESS_NUM_BUFFERS 100000
> -#define STRESS_NUM_LOOPS 100
> -#define STRESS_STORE_COMMANDS 4 * STRESS_NUM_BUFFERS
> -#define STRESS_START_ADDRESS 0x800000000000
> -static void gem_softpin_stress_test(void)
> +static uint64_t busy_batch(int fd)
>   {
> -	i915_gem_userptr userptr;
> -	int fd;
> -	uint32_t **shared_buffer;
> -	uint32_t *shared_handle;
> +	const int gen = intel_gen(intel_get_drm_devid(fd));
> +	const int has_64bit_reloc = gen >= 8;
>   	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 *exec_object2;
> -	uint32_t *batch_buffer;
> -	uint32_t batch_buf_handle;
> -	int ring, len;
> -	int buf, loop;
> -	uint64_t pinning_offset = STRESS_START_ADDRESS;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, FULL_48_BIT_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -
> -	/* Allocate blobs for all data structures */
> -	shared_handle = calloc(STRESS_NUM_BUFFERS, sizeof(uint32_t));
> -	shared_buffer = calloc(STRESS_NUM_BUFFERS, sizeof(uint32_t *));
> -	exec_object2 = calloc(STRESS_NUM_BUFFERS + 1,
> -				sizeof(struct drm_i915_gem_exec_object2));
> -	/* 4 dwords per buffer + 2 for the end of batchbuffer */
> -	batch_buffer = calloc(STRESS_STORE_COMMANDS + 2, sizeof(uint32_t));
> -	batch_buf_handle = gem_create(fd, (STRESS_STORE_COMMANDS + 2)*4);
> -
> -	/* create command buffer with write commands */
> -	len = 0;
> -	for(buf = 0; buf < STRESS_NUM_BUFFERS; buf++) {
> -		shared_buffer[buf] = create_mem_buffer(BO_SIZE);
> -		*shared_buffer[buf] = 0xFFFFFFFF;
> -
> -		/* share with GPU */
> -		shared_handle[buf] = init_userptr(fd, &userptr,
> -						  shared_buffer[buf],
> -						  BO_SIZE);
> -
> -		setup_exec_obj(&exec_object2[buf], shared_handle[buf],
> -			       EXEC_OBJECT_PINNED |
> -			       EXEC_OBJECT_SUPPORTS_48B_ADDRESS,
> -			       gen8_canonical_addr(pinning_offset));
> -		len += gem_store_data_svm(fd, batch_buffer + (len/4),
> -					  gen8_canonical_addr(pinning_offset),
> -					  buf, (buf == STRESS_NUM_BUFFERS-1)? \
> -					  true:false);
> -
> -		/* decremental 4K aligned address */
> -		pinning_offset -= ALIGN(BO_SIZE, 4096);
> -	}
> +	struct drm_i915_gem_exec_object2 object[2];
> +	uint32_t *map;
> +	int factor = 10;
> +	int i = 0;
>
> -	/* setup command buffer */
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -	setup_exec_obj(&exec_object2[STRESS_NUM_BUFFERS], batch_buf_handle,
> -		       0, 0);
> -
> -	/* We want to run this on BLT ring if possible */
> -	if (HAS_BLT_RING(intel_get_drm_devid(fd))) {
> -		ring = I915_EXEC_BLT;
> -
> -		setup_execbuffer(&execbuf, exec_object2, ring,
> -				 STRESS_NUM_BUFFERS + 1, len);
> -
> -		for (loop = 0; loop < STRESS_NUM_LOOPS; loop++) {
> -			submit_and_sync(fd, &execbuf, batch_buf_handle);
> -			/* Set pinning offset back to original value */
> -			pinning_offset = STRESS_START_ADDRESS;
> -			for(buf = 0; buf < STRESS_NUM_BUFFERS; buf++) {
> -				gem_userptr_sync(fd, shared_handle[buf]);
> -				igt_assert(exec_object2[buf].offset ==
> -					gen8_canonical_addr(pinning_offset));
> -				igt_fail_on_f(*shared_buffer[buf] != buf, \
> -				"Mismatch in buffer %d, iteration %d: 0x%08X\n", \
> -				buf, loop, *shared_buffer[buf]);
> -				pinning_offset -= ALIGN(BO_SIZE, 4096);
> -			}
> -			/* Reset the buffer entries for next iteration */
> -			for(buf = 0; buf < STRESS_NUM_BUFFERS; buf++) {
> -				*shared_buffer[buf] = 0xFFFFFFFF;
> -			}
> -		}
> +	memset(object, 0, sizeof(object));
> +	object[0].handle = gem_create(fd, 1024*1024);
> +	object[1].handle = gem_create(fd, 4096);
> +	map = gem_mmap__cpu(fd, object[1].handle, 0, 4096, PROT_WRITE);
> +	gem_set_domain(fd, object[1].handle,
> +		       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> +
> +	*map = MI_BATCH_BUFFER_END;
> +
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)object;
> +	execbuf.buffer_count = 2;
> +	if (gen >= 6)
> +		execbuf.flags = I915_EXEC_BLT;
> +	gem_execbuf(fd, &execbuf);
> +
> +	igt_debug("Active offsets = [%08llx, %08llx]\n",
> +		  object[0].offset, object[1].offset);
> +
> +#define COPY_BLT_CMD		(2<<29|0x53<<22|0x6)
> +#define BLT_WRITE_ALPHA		(1<<21)
> +#define BLT_WRITE_RGB		(1<<20)
> +	gem_set_domain(fd, object[1].handle,
> +		       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> +	while (factor--) {
> +		/* XY_SRC_COPY */
> +		map[i++] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB;
> +		if (has_64bit_reloc)
> +			map[i-1] += 2;
> +		map[i++] = 0xcc << 16 | 1 << 25 | 1 << 24 | (4*1024);
> +		map[i++] = 0;
> +		map[i++] = 256 << 16 | 1024;
> +		map[i++] = object[0].offset;
> +		if (has_64bit_reloc)
> +			map[i++] = object[0].offset >> 32;
> +		map[i++] = 0;
> +		map[i++] = 4096;
> +		map[i++] = object[0].offset;
> +		if (has_64bit_reloc)
> +			map[i++] = object[0].offset >> 32;
>   	}
> +	map[i++] = MI_BATCH_BUFFER_END;
> +	munmap(map, 4096);
>
> -	/* Now Render Ring */
> -	ring = I915_EXEC_RENDER;
> -	setup_execbuffer(&execbuf, exec_object2, ring,
> -			 STRESS_NUM_BUFFERS + 1, len);
> -	for (loop = 0; loop < STRESS_NUM_LOOPS; loop++) {
> -		submit_and_sync(fd, &execbuf, batch_buf_handle);
> -		pinning_offset = STRESS_START_ADDRESS;
> -		for(buf = 0; buf < STRESS_NUM_BUFFERS; buf++) {
> -			gem_userptr_sync(fd, shared_handle[buf]);
> -			igt_assert(exec_object2[buf].offset ==
> -				gen8_canonical_addr(pinning_offset));
> -			igt_fail_on_f(*shared_buffer[buf] != buf, \
> -			"Mismatch in buffer %d, \
> -			iteration %d: 0x%08X\n", buf, loop, *shared_buffer[buf]);
> -			pinning_offset -= ALIGN(BO_SIZE, 4096);
> -		}
> -		/* Reset the buffer entries for next iteration */
> -		for(buf = 0; buf < STRESS_NUM_BUFFERS; buf++) {
> -			*shared_buffer[buf] = 0xFFFFFFFF;
> -		}
> -	}
> -
> -	for(buf = 0; buf < STRESS_NUM_BUFFERS; buf++) {
> -		gem_close(fd, shared_handle[buf]);
> -		free(shared_buffer[buf]);
> -	}
> -	gem_close(fd, batch_buf_handle);
> -	close(fd);
> +	object[0].flags = EXEC_OBJECT_PINNED | EXEC_OBJECT_WRITE;
> +	object[1].flags = EXEC_OBJECT_PINNED;
> +	gem_execbuf(fd, &execbuf);
> +	gem_close(fd, object[0].handle);
> +	gem_close(fd, object[1].handle);
>
> -	free(shared_handle);
> -	free(shared_buffer);
> -	free(exec_object2);
> -	free(batch_buffer);
> +	return object[1].offset;
>   }
>
> -/* gem_write_multipage_buffer
> - * Create a buffer spanning multiple pages, and share with GPU.
> - * Write to every element of the buffer
> - * and verify correct contents.
> -
> - * Create 8K buffer
> - * Share with GPU using userptr ioctl
> - * Create batch buffer to write DATA in all elements of buffer
> - * Execute Batch Buffer
> - * Validate every element has DATA
> -*/
> -
> -#define DWORD_SIZE sizeof(uint32_t)
> -#define BB_SIZE ((MULTIPAGE_BO_SIZE / DWORD_SIZE) * STORE_BATCH_BUFFER_SIZE) + 2
> -#define NUM_DWORDS (MULTIPAGE_BO_SIZE/sizeof(uint32_t))
> -static void gem_write_multipage_buffer_test(void)
> +static void test_evict_active(int fd)
>   {
> -	i915_gem_userptr userptr;
> -	int fd;
> -	uint32_t *shared_buffer;
> -	uint32_t shared_handle;
> +	const uint32_t bbe = MI_BATCH_BUFFER_END;
>   	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[2];
> -	uint32_t batch_buffer[BB_SIZE];
> -	uint32_t batch_buf_handle;
> -	int ring, len, j;
> -	uint64_t pinning_offset=0x1000;
> -	uint64_t vaddr;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, ALIASING_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	batch_buf_handle = gem_create(fd, sizeof(batch_buffer));
> -	shared_buffer = create_mem_buffer(MULTIPAGE_BO_SIZE);
> -
> -	len = 0;
> -	memset(batch_buffer, 0, sizeof(batch_buffer));
> -	memset(shared_buffer, 0, MULTIPAGE_BO_SIZE);
> -
> -	/* share with GPU */
> -	shared_handle = init_userptr(fd, &userptr, shared_buffer,
> -				     MULTIPAGE_BO_SIZE);
> -	setup_exec_obj(&exec_object2[0], shared_handle,
> -		       EXEC_OBJECT_PINNED, pinning_offset);
> -
> -	/* create command buffer with write commands */
> -	vaddr = pinning_offset;
> -	for(j=0; j< NUM_DWORDS; j++) {
> -		len += gem_store_data_svm(fd, batch_buffer + (len/4), vaddr,
> -					  j,
> -					  (j == NUM_DWORDS - 1) ? true:false);
> -		vaddr += sizeof(shared_buffer[0]);  /* 4 bytes */
> -	}
> +	struct drm_i915_gem_exec_object2 object;
> +	uint64_t expected;
>
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> +	memset(&object, 0, sizeof(object));
> +	object.handle = gem_create(fd, 4096);
> +	gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
>
> -	/* submit command buffer */
> -	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> +	expected = busy_batch(fd);
> +	object.offset = expected;
> +	object.flags = EXEC_OBJECT_PINNED;
>
> -	ring = I915_EXEC_RENDER;
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -	submit_and_sync(fd, &execbuf, batch_buf_handle);
> -	gem_userptr_sync(fd, shared_handle);
> -
> -	igt_assert(exec_object2[0].offset == pinning_offset);
> -	for(j = 0; j < (MULTIPAGE_BO_SIZE/sizeof(uint32_t)); j++) {
> -		igt_fail_on_f(shared_buffer[j] != j,
> -		"Mismatch in index %d: 0x%08X\n", j, shared_buffer[j]);
> -	}
> +	/* Replace the active batch with ourselves, forcing an eviction */
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)&object;
> +	execbuf.buffer_count = 1;
>
> -	gem_close(fd, batch_buf_handle);
> -	gem_close(fd, shared_handle);
> -	close(fd);
> +	gem_execbuf(fd, &execbuf);
> +	gem_close(fd, object.handle);
>
> -	free(shared_buffer);
> +	igt_assert_eq_u64(object.offset, expected);
>   }
>
> -/* gem_pin_invalid_vma_test
> - * This test will request to pin a shared buffer to an invalid
> - * VMA  > 48-bit address if system supports 48B PPGTT; it also
> - * will test that any attempt of using a 48-bit address requires
> - * the SUPPORTS_48B_ADDRESS flag, and that 48-bit address need to be
> - * in canonical form (bits [63:48] == [47]).
> - * If system supports 32B PPGTT, it will test the equivalent invalid VMA
> - * Create shared buffer of size 4K
> - * Try and Pin object to invalid address
> -*/
> -static void gem_pin_invalid_vma_test(bool test_decouple_flags,
> -				     bool test_canonical_offset)
> +static void test_evict_hang(int fd)
>   {
> -	i915_gem_userptr userptr;
> -	int fd, ret;
> -	uint32_t *shared_buffer;
> +	const uint32_t bbe = MI_BATCH_BUFFER_END;
>   	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[1];
> -	uint32_t shared_buf_handle;
> -	int ring;
> -	uint64_t invalid_address_for_48b = 0x9000000000000; /* 52 bit address */
> -	uint64_t noncanonical_address_for_48b = 0xFF0000000000; /* 48 bit address in noncanonical form */
> -	uint64_t invalid_address_for_32b = 0x900000000; /* 36 bit address */
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, FULL_48_BIT_PPGTT) ||
> -		    uses_full_ppgtt(fd, FULL_32_BIT_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	shared_buffer = create_mem_buffer(BO_SIZE);
> -	*shared_buffer = 0xFFFFFFFF;
> -
> -	/* share with GPU */
> -	shared_buf_handle = init_userptr(fd, &userptr, shared_buffer, BO_SIZE);
> -
> -	if (uses_full_ppgtt(fd, FULL_48_BIT_PPGTT) && test_canonical_offset) {
> -		setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -			       EXEC_OBJECT_PINNED | EXEC_OBJECT_SUPPORTS_48B_ADDRESS,
> -			       noncanonical_address_for_48b);
> -	} else if (uses_full_ppgtt(fd, FULL_48_BIT_PPGTT) && !test_decouple_flags) {
> -		setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -			       EXEC_OBJECT_PINNED | EXEC_OBJECT_SUPPORTS_48B_ADDRESS,
> -			       invalid_address_for_48b);
> -	} else {
> -		/* This also fails in 48b without 48B_ADDRESS support flag */
> -		setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -			       EXEC_OBJECT_PINNED, invalid_address_for_32b);
> -	}
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 1, 0);
> +	struct drm_i915_gem_exec_object2 object;
> +	uint64_t expected;
> +	igt_hang_ring_t hang;
>
> -	/* Expect execbuf to fail */
> -	ret = drmIoctl(fd,
> -		       DRM_IOCTL_I915_GEM_EXECBUFFER2,
> -		       &execbuf);
> +	memset(&object, 0, sizeof(object));
> +	object.handle = gem_create(fd, 4096);
> +	gem_write(fd, object.handle, 0, &bbe, sizeof(bbe));
>
> -	igt_assert(errno == EINVAL);
> -	igt_assert_neq(ret, 0);
> +	hang = igt_hang_ctx(fd, 0, 0, 0, (uint64_t *)&expected);
> +	object.offset = expected;
> +	object.flags = EXEC_OBJECT_PINNED;
>
> -	gem_close(fd, shared_buf_handle);
> -	close(fd);
> -	free(shared_buffer);
> -}
> +	/* Replace the hanging batch with ourselves, forcing an eviction */
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)&object;
> +	execbuf.buffer_count = 1;
>
> +	gem_execbuf(fd, &execbuf);
> +	gem_close(fd, object.handle);
>
> -/* gem_pin_high_address_test
> - * This test will create a shared buffer, and create a command
> - * for GPU to write data in it. It will attempt to pin the buffer at address > 32 bits.
> - * CPU will read and make sure expected value is obtained
> +	igt_assert_eq_u64(object.offset, expected);
>
> - * Malloc a 4K buffer
> - * Share buffer with with GPU by using userptr ioctl
> - * Create batch buffer to write DATA to first dword of buffer
> - * Use virtual address of buffer as 0x1100000000 (> 32 bit)
> - * Set EXEC_OBJECT_PINNED flag in exec object
> - * Set 'offset' in exec object to shared buffer VMA
> - * Submit execbuffer
> - * Verify value of first DWORD in shared buffer matches DATA
> -*/
> +	igt_post_hang_ring(fd, hang);
> +}
>
> -static void gem_pin_high_address_test(void)
> +static void xchg_offset(void *array, unsigned i, unsigned j)
>   {
> -	i915_gem_userptr userptr;
> -	int fd;
> -	uint32_t *shared_buffer;
> -	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[2];
> -	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE + 2];
> -	uint32_t batch_buf_handle, shared_buf_handle;
> -	int ring, len;
> -	const uint32_t data = 0x12345678;
> -	uint64_t high_address = 0x1111FFFF000; /* 44 bit address */
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, FULL_48_BIT_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	batch_buf_handle = gem_create(fd, BO_SIZE);
> -
> -	/* create cpu buffer, set to all 0xF's */
> -	shared_buffer = create_mem_buffer(BO_SIZE);
> -	*shared_buffer = 0xFFFFFFFF;
> -
> -	/* share with GPU */
> -	shared_buf_handle = init_userptr(fd, &userptr, shared_buffer, BO_SIZE);
> -
> -	/* create command buffer with write command */
> -	len = gem_store_data_svm(fd, batch_buffer, high_address, data, true);
> -	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -
> -	/* submit command buffer */
> -	setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -		       EXEC_OBJECT_PINNED | EXEC_OBJECT_SUPPORTS_48B_ADDRESS, high_address);
> -	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> -
> -	ring = I915_EXEC_RENDER;
> -
> -	setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -	submit_and_sync(fd, &execbuf, batch_buf_handle);
> -	gem_userptr_sync(fd, shared_buf_handle);
> -
> -	igt_assert(exec_object2[0].offset == high_address);
> -	/* check on CPU to see if value changes */
> -	igt_fail_on_f(shared_buffer[0] != data,
> -		"\nCPU read does not match GPU write, \
> -		expected: 0x%x, got: 0x%x\n", data, shared_buffer[0]);
> -
> -	gem_close(fd, batch_buf_handle);
> -	gem_close(fd, shared_buf_handle);
> -	close(fd);
> -	free(shared_buffer);
> +	struct drm_i915_gem_exec_object2 *object = array;
> +	uint64_t tmp = object[i].offset;
> +	object[i].offset = object[j].offset;
> +	object[j].offset = tmp;
>   }
>
> -/* gem_pin_near_48Bit_test
> - * This test will create a shared buffer,
> - * and create a command for GPU to write data in it. It will attempt
> - * to pin the buffer at address > 47 bits <= 48-bit.
> - * CPU will read and make sure expected value is obtained.
> - * Note that we must submit addresses in canonical form, not only
> - * because the addresss will be validated, but also the returned offset
> - * will be in this format.
> -
> - * Malloc a 4K buffer
> - * Share buffer with with GPU by using userptr ioctl
> - * Create batch buffer to write DATA to first dword of buffer
> - * Use virtual address of buffer as range between 47-bit and 48-bit
> - * Set EXEC_OBJECT_PINNED flag in exec object
> - * Set 'offset' in exec object to shared buffer VMA
> - * Submit execbuffer
> - * Verify value of first DWORD in shared buffer matches DATA
> -*/
> -#define BEGIN_HIGH_ADDRESS 0x7FFFFFFFF000
> -#define END_HIGH_ADDRESS 0xFFFFFFFFC000
> -#define ADDRESS_INCREMENT 0x2000000000
> -static void gem_pin_near_48Bit_test(void)
> +static void test_noreloc(int fd)
>   {
> -	i915_gem_userptr userptr;
> -	int fd;
> -	uint32_t *shared_buffer;
> +	const int gen = intel_gen(intel_get_drm_devid(fd));
> +	const uint32_t size = 4096;
> +	const uint32_t bbe = MI_BATCH_BUFFER_END;
>   	struct drm_i915_gem_execbuffer2 execbuf;
> -	struct drm_i915_gem_exec_object2 exec_object2[2];
> -	uint32_t batch_buffer[BO_SIZE];
> -	uint32_t batch_buf_handle, shared_buf_handle;
> -	int ring, len;
> -	const uint32_t data = 0x12345678;
> -	uint64_t high_address, can_high_address;
> -
> -	fd = drm_open_driver(DRIVER_INTEL);
> -	igt_require(uses_full_ppgtt(fd, FULL_48_BIT_PPGTT));
> -	igt_require(has_softpin_support(fd));
> -
> -	batch_buf_handle = gem_create(fd, BO_SIZE);
> -
> -	/* create cpu buffer, set to all 0xF's */
> -	shared_buffer = create_mem_buffer(BO_SIZE);
> -	*shared_buffer = 0xFFFFFFFF;
> -
> -	/* share with GPU */
> -	shared_buf_handle = init_userptr(fd, &userptr, shared_buffer, BO_SIZE);
> -
> -	for (high_address = BEGIN_HIGH_ADDRESS; high_address <= END_HIGH_ADDRESS;
> -						high_address+=ADDRESS_INCREMENT) {
> -		can_high_address = gen8_canonical_addr(high_address);
> -		/* create command buffer with write command */
> -		len = gem_store_data_svm(fd, batch_buffer, can_high_address,
> -					data, true);
> -		gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
> -		/* submit command buffer */
> -		setup_exec_obj(&exec_object2[0], shared_buf_handle,
> -			       EXEC_OBJECT_PINNED | EXEC_OBJECT_SUPPORTS_48B_ADDRESS,
> -			       can_high_address);
> -		setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
> -
> -		ring = I915_EXEC_RENDER;
> -		setup_execbuffer(&execbuf, exec_object2, ring, 2, len);
> -		submit_and_sync(fd, &execbuf, batch_buf_handle);
> -		gem_userptr_sync(fd, shared_buf_handle);
> -
> -		igt_assert(exec_object2[0].offset == can_high_address);
> -		/* check on CPU to see if value changes */
> -		igt_fail_on_f(shared_buffer[0] != data,
> -		"\nCPU read does not match GPU write, expected: 0x%x, \
> -		got: 0x%x\n, 0x%"PRIx64"", data, shared_buffer[0], high_address);
> +	struct drm_i915_gem_exec_object2 object[257];
> +	uint64_t offset;
> +	uint32_t handle;
> +	uint32_t *batch, *b;
> +	int i, loop;
> +
> +	handle = gem_create(fd, (ARRAY_SIZE(object)+1)*size);
> +	gem_write(fd, handle, 0, &bbe, sizeof(bbe));
> +
> +	memset(object, 0, sizeof(object));
> +	object[0].handle = handle;
> +
> +	/* Find a hole */
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	execbuf.buffers_ptr = (unsigned long)object;
> +	execbuf.buffer_count = 1;
> +	gem_execbuf(fd, &execbuf);
> +	gem_close(fd, object[0].handle);
> +
> +	igt_debug("Made a %dx%d KiB hole: %08llx\n",
> +		  (int)ARRAY_SIZE(object), size/1024, object[0].offset);
> +
> +	offset = object[0].offset;
> +	for (i = 0; i < ARRAY_SIZE(object) - 1; i++) {
> +		object[i].handle = gem_create(fd, size);
> +		object[i].offset = offset + i*size;
> +		object[i].flags = EXEC_OBJECT_PINNED | EXEC_OBJECT_WRITE;
>   	}
> +	object[i].handle = gem_create(fd, 2*size);
> +	object[i].offset = offset + i*size;
> +	object[i].flags = EXEC_OBJECT_PINNED;
> +
> +	b = batch = gem_mmap__cpu(fd, object[i].handle, 0, 2*size, PROT_WRITE);
> +	gem_set_domain(fd, object[i].handle,
> +		       I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> +	for (i = 0; i < ARRAY_SIZE(object) - 1; i++) {
> +		*b++ = MI_STORE_DWORD_IMM;
> +		if (gen < 8) {
> +			*b++ = 0;
> +			*b++ = object[i].offset;
> +		} else {
> +			*b++ = object[i].offset;
> +			*b++ = object[i].offset >> 32;
> +		}
> +		*b++ = i;
> +	}
> +	*b++ = MI_BATCH_BUFFER_END;
> +	igt_assert(b - batch <= 2*size/sizeof(uint32_t));
> +	munmap(batch, size);
>
> -	gem_close(fd, batch_buf_handle);
> -	gem_close(fd, shared_buf_handle);
> -	close(fd);
> -	free(shared_buffer);
> -}
> +	execbuf.buffer_count = ARRAY_SIZE(object);
> +	for (loop = 0; loop < 1024; loop++) {
> +		igt_permute_array(object, ARRAY_SIZE(object)-1, xchg_offset);
> +		gem_execbuf(fd, &execbuf);
>
> +		for (i = 0; i < ARRAY_SIZE(object) - 1; i++) {
> +			uint32_t val;
>
> -int main(int argc, char* argv[])
> -{
> -	igt_subtest_init(argc, argv);
> -	igt_skip_on_simulation();
> -
> -	/* All tests need PPGTT support */
> -	igt_subtest("gem_pin_userptr") {
> -		gem_pin_userptr_test();
> -	}
> -	igt_subtest("gem_pin_bo") {
> -		gem_pin_bo_test();
> -	}
> -	igt_subtest("gem_multiple_process") {
> -		gem_multiple_process_test();
> -	}
> -	igt_subtest("gem_repin") {
> -		gem_repin_test();
> -	}
> -	igt_subtest("gem_pin_overlap") {
> -		gem_pin_overlap_test();
> -	}
> -	igt_subtest("gem_write_multipage_buffer") {
> -		gem_write_multipage_buffer_test();
> +			gem_read(fd, object[i].handle, 0, &val, sizeof(val));
> +			igt_assert_eq(val, (object[i].offset - offset)/ size);
> +		}
>   	}
> +	for (i = 0; i < ARRAY_SIZE(object); i++)
> +		gem_close(fd, object[i].handle);
> +}
>
> -	/* Following tests need 32/48 Bit PPGTT support */
> -	igt_subtest("gem_pin_invalid_vma") {
> -		gem_pin_invalid_vma_test(false, false);
> -	}
> +igt_main
> +{
> +	int fd = -1;
>
> -	/* Following tests need 48 Bit PPGTT support */
> -	igt_subtest("gen_pin_noncanonical_high_address") {
> -		gem_pin_invalid_vma_test(false, true);
> -	}
> -	igt_subtest("gem_pin_high_address_without_correct_flag") {
> -		gem_pin_invalid_vma_test(true, false);
> -	}
> -	igt_subtest("gem_softpin_stress") {
> -		gem_softpin_stress_test();
> -	}
> -	igt_subtest("gem_pin_high_address") {
> -		gem_pin_high_address_test();
> -	}
> -	igt_subtest("gem_pin_near_48Bit") {
> -		gem_pin_near_48Bit_test();
> +	igt_skip_on_simulation();
> +
> +	igt_fixture {
> +		fd = drm_open_driver(DRIVER_INTEL);
> +		igt_require(has_softpin_support(fd));
>   	}
>
> -	igt_exit();
> +	igt_subtest("invalid")
> +		test_invalid(fd);
> +	igt_subtest("softpin")
> +		test_softpin(fd);
> +	igt_subtest("overlap")
> +		test_overlap(fd);
> +	igt_subtest("noreloc")
> +		test_noreloc(fd);
> +	igt_subtest("evict-active")
> +		test_evict_active(fd);
> +	igt_subtest("evict-hang")
> +		test_evict_hang(fd);
> +
> +	igt_fixture
> +		close(fd);
>   }
>


More information about the Intel-gfx mailing list