[Intel-gfx] [PATCH i-g-t] tests/gem_buffered_svm_test: New tests for buffered SVM feature

Vinay Belgaumkar vinay.belgaumkar at intel.com
Thu Nov 19 14:24:07 PST 2015


These tests exercise the userptr ioctl to create shared buffers
between CPU and GPU. They contain error and normal usage scenarios.
They also contain a couple of stress tests which copy buffers between
CPU and GPU. These tests rely on the softpin patch in order to pin buffers
to a certain VA.

Caveat: These tests were designed to run on 64-bit system. Future work
includes adding logic to ensure these tests can run on 32-bit systems with
PPGTT support. Some tests are currently disabled for 32-bit systems for that
reason.

v2: Added cc and signed-off-by fields

v3: Fixed review comments, added helper functions. Removed userptr error
scenarios covered by existing userptr tests. Renamed to gem_softpin.c.
Modified stress test to have 100K buffers, it now runs for ~30 mins, checks
every element has been written to correctly, and pins buffers at different
VMAs.

Cc: Michel Thierry <michel.thierry at intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar at intel.com>
---
 tests/.gitignore       |    1 +
 tests/Makefile.sources |    1 +
 tests/gem_softpin.c    | 1252 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1254 insertions(+)
 create mode 100644 tests/gem_softpin.c

diff --git a/tests/.gitignore b/tests/.gitignore
index 80af9a7..424870b 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -21,6 +21,7 @@ gem_bad_blit
 gem_bad_length
 gem_bad_reloc
 gem_basic
+gem_softpin
 gem_caching
 gem_close_race
 gem_concurrent_all
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 8fb2de8..2008d4a 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -11,6 +11,7 @@ TESTS_progs_M = \
 	drv_hangman \
 	gem_bad_reloc \
 	gem_basic \
+	gem_softpin \
 	gem_caching \
 	gem_close_race \
 	gem_concurrent_blit \
diff --git a/tests/gem_softpin.c b/tests/gem_softpin.c
new file mode 100644
index 0000000..aed607c
--- /dev/null
+++ b/tests/gem_softpin.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Vinay Belgaumkar <vinay.belgaumkar at intel.com>
+      Thomas Daniel <thomas.daniel at intel.com>
+ *
+ */
+
+#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 OBJECT_SIZE 16384
+#define BO_SIZE 4 * 4096
+#define MULTIPAGE_BO_SIZE 4 * BO_SIZE
+#define STORE_BATCH_BUFFER_SIZE 6
+#define STRESS_BATCH_BUFFER_SIZE 5
+#define EXEC_OBJECT_PINNED	(1<<4)
+#define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
+#define SHARED_BUFFER_SIZE 4096
+#define NUM_EXEC_OBJECTS 2
+
+typedef struct drm_i915_gem_userptr i915_gem_userptr;
+
+static void gem_create_userptr_struct(i915_gem_userptr*, void* ptr, __u64 size, bool read_only);
+static void *create_mem_buffer(__u64 size);
+static int gem_call_userptr_ioctl(int fd, i915_gem_userptr *userptr);
+static void gem_basic_test(void);
+static void gem_pin_invalid_vma_test(void);
+static void gem_pin_overlap_test(void);
+static void gem_shmem_test(void);
+static void gem_pin_high_address_test(void);
+static void gem_pin_mmap_anonymous_test(void);
+static void gem_pin_mmap_file_test(void);
+
+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;
+}
+
+static void gem_create_userptr_struct(i915_gem_userptr *userptr, void* ptr, __u64 size, bool read_only)
+{
+	memset((void*)userptr, 0, sizeof(i915_gem_userptr));
+
+	userptr->user_ptr = (uintptr_t)ptr;
+	userptr->user_size = size;
+	userptr->flags = I915_USERPTR_UNSYNCHRONIZED;
+
+	if (read_only)
+		userptr->flags |= I915_USERPTR_READ_ONLY;
+}
+
+/*  Creates a 4K aligned CPU buffer 
+ *  @size - size of buffer
+ *  RETURNS pointer to buffer of @size
+*/
+
+static void* create_mem_buffer(__u64 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, __u32 handle, __u32 flags, __u64 offset)
+{
+	memset(exec, 0, sizeof(struct drm_i915_gem_exec_object2));
+	exec->handle = handle;
+	exec->flags = flags;
+	exec->offset = offset;
+}
+
+/*  
+ * gem_store_data_svm - populate batch buffer with MI_STORE_DWORD_IMM command
+ * @fd: drm file descriptor
+ * @buf: batch buffer
+ * @buffer_size: size of buffer
+ * @addr: 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)
+{
+	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));
+}
+
+/*  
+ * gem_store_data - populate batch buffer with MI_STORE_DWORD_IMM command
+ * This one fills up reloc buffer as well 
+ * @fd: drm file descriptor
+ * @buf: batch buffer
+ * @buffer_size: size of buffer
+ * @addr: destination Virtual address
+ * @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)
+{
+	int i = 0;
+
+	cmd_buf[i++] = MI_STORE_DWORD_IMM;
+	cmd_buf[i++] = 0; /* lower 31 bits of 48 bit address - 0 because reloc is needed */
+	cmd_buf[i++] = 0; /* upper 15 bits of 48 bit address - 0 because reloc is 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;
+	reloc++;
+	cmd_buf[i++] = data;
+	if (end){ 
+		cmd_buf[i++] = MI_BATCH_BUFFER_END;
+		cmd_buf[i++] = 0;
+	}
+
+	return (i * sizeof(uint32_t));
+}
+
+/* Helper function for filling execbuffer struct */
+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 = (uintptr_t)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;
+}
+
+/* Helper function for exec and sync functions */
+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_basic_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
+ *  @valid_shared_buffer - whether test with valid malloc'd buffer or not
+
+   if (valid_shared_buffer == true)
+   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
+
+   if (valid_shared_buffer == false)
+   Declare null buffer
+   Call Userptr ioctl with null buffer
+   Run Basic Test
+   Test should fail at submit execbuffer
+*/
+static void gem_basic_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE];
+	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);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	/* create cpu buffer, set to all 0xF's */
+	shared_buffer = create_mem_buffer(BO_SIZE);
+	
+	/* share with GPU */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_buf_handle = userptr.handle;
+
+	/* create command buffer with write command */
+	len = gem_store_data_svm(fd, batch_buffer, pinning_offset, data, true);
+	igt_assert_lte(len, STORE_BATCH_BUFFER_SIZE * 4);
+
+	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 = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	/* 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);
+	close(fd);
+
+	free(shared_buffer);
+}
+
+/*  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)
+{
+	igt_fork(child, MAX_NUM_PROCESSES) {
+		gem_basic_test();
+	}
+	igt_waitchildren();
+}
+
+
+/* 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, ret;
+	uint32_t* shared_buffer = NULL;
+	uint32_t* shared_buffer1 = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE];
+	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);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	/* create cpu buffer, set to all 0xF's */
+	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 */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	//gem_create_userptr_struct(&userptr1, shared_buffer1, BO_SIZE * 2, false); 
+	gem_create_userptr_struct(&userptr1, shared_buffer1, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr1);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_buf_handle = userptr.handle;
+	shared_buf_handle1 = userptr1.handle;
+
+	/* 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 = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	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 */
+	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 = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	igt_assert(*shared_buffer1 == data);
+
+	gem_close(fd, batch_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
+
+ at code
+   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
+ at endcode
+**/
+static void gem_pin_overlap_test(void)
+{
+	i915_gem_userptr userptr;
+	i915_gem_userptr userptr1;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	uint32_t* shared_buffer1 = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS + 1];
+	uint32_t batch_buffer[BO_SIZE];
+	uint32_t batch_buf_handle, shared_buf_handle, shared_buf_handle1;
+	int ring, len;
+	const uint32_t data = 0x12345678;
+	uint64_t pinning_offset = 0x1000;
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	shared_buffer = create_mem_buffer(BO_SIZE);
+	shared_buffer1 = create_mem_buffer(BO_SIZE * 2);
+
+	/* share with GPU */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	gem_create_userptr_struct(&userptr1, shared_buffer1, BO_SIZE * 2, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr1);
+	igt_assert_eq(ret, 0);
+
+	shared_buf_handle = userptr.handle;
+	shared_buf_handle1 = userptr1.handle;
+
+	len = gem_store_data_svm(fd, batch_buffer, pinning_offset, data, false);
+	len += gem_store_data_svm(fd, (batch_buffer + len/4), 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], shared_buf_handle1, EXEC_OBJECT_PINNED, pinning_offset);
+	setup_exec_obj(&exec_object2[2], batch_buf_handle, 0, 0);
+
+	ring = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS+1, len);
+
+	ret = drmIoctl(fd,
+	      DRM_IOCTL_I915_GEM_EXECBUFFER2,
+	      &execbuf);
+
+	/* expect to fail */
+	igt_assert_neq(ret, 0);
+	igt_assert(errno == 22);
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+
+	free(shared_buffer);
+	free(shared_buffer1);
+}
+
+
+/*  gem_evict_test
+ *  create shared buffer, pin it
+ *  create normal buffer
+ *  try and relocate to shared location
+ *  Opens: How to detect eviction occured? 
+ *  i915_gem_gtt - debugfs api - grep it for the page? 
+
+    Create a gem buffer of 4K
+    Malloc a 4K buffer
+    Share buffer with GPU using userptr ioctl
+    Create a batch buffer to write 0x11111111 and 0x22222222 in above 2 buffers
+    Pin Shared buffer to offset '0' in GTT
+    Create reloc buffer to ensure gem buffer is relocated to GTT
+    Submit execbuffer
+    Verify shared buffer has 0x22222222 as expected
+    Obtain offset of where gem object has been placed from exec object field
+    Try to pin shared buffer at that address using 'offset' field in exec object
+    Prevent relocation by setting relocation_count = 0
+    Submit execbuffer
+    Shared buffer will be pinned to previous address of gem object
+    Unshared buffer will be evicted, since relocation is not allowed
+    Second batch buffer will write 0x11111111 to shared buffer instead of unshared
+    Verify shared buffer contains 0x11111111
+    Reverse order of instructions in batch buffer to write to unshared first
+*/
+
+static void gem_evict_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_relocation_entry reloc[4];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS + 1];
+	uint32_t batch_buffer[STORE_BATCH_BUFFER_SIZE * 2];
+	uint32_t batch_buf_handle, shared_buf_handle, unshared_buf_handle;
+	int ring, len;
+	uint32_t data1, data2;
+	uint32_t value;
+	uint64_t pinning_offset = 0;
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+	unshared_buf_handle = gem_create(fd, BO_SIZE);
+
+	shared_buffer = create_mem_buffer(BO_SIZE);
+	*shared_buffer = 0xFFFFFFFF;
+
+	/* share with GPU */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_buf_handle = userptr.handle;
+
+	/* create command buffer with write commands */
+	data1 = 0x11111111;
+	data2 = 0x22222222;
+	len = gem_store_data(fd, batch_buffer, unshared_buf_handle, data1, reloc, false);
+	len += gem_store_data_svm(fd, batch_buffer + (len/4), pinning_offset, data2, true);
+	igt_assert_lte(len, STORE_BATCH_BUFFER_SIZE * 2 * 4);
+	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], unshared_buf_handle, 0, 0);
+	setup_exec_obj(&exec_object2[2], batch_buf_handle, 0, 0);
+
+	exec_object2[2].relocation_count = 1;
+	exec_object2[2].relocs_ptr = (uintptr_t)reloc;
+	ring = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS+1, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	igt_assert(*shared_buffer == data2);
+	gem_read(fd, unshared_buf_handle, 0, (void*)&value, 4);
+	igt_assert(value == data1);
+
+
+	*shared_buffer = 0xffffffff;
+	/* Now cause eviction of unshared buffer by pinning shared buffer there */
+	exec_object2[0].offset = exec_object2[1].offset;
+	/* Prevent relocation */
+	exec_object2[2].relocation_count = 0;
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	igt_assert(*shared_buffer == data1);
+	igt_assert(exec_object2[0].offset != exec_object2[1].offset);
+	/* Unshared buffer gets evicted, and retains its value, since no batch buffer writes to it */
+	gem_read(fd, unshared_buf_handle, 0, (void*)&value, 4);
+	igt_assert(value == data1);
+
+	/* Now lets do it again with the objects listed in reverse order... */
+	*shared_buffer = 0xffffffff;
+	setup_exec_obj(&exec_object2[0], unshared_buf_handle, 0, 0);
+	setup_exec_obj(&exec_object2[1], shared_buf_handle, EXEC_OBJECT_PINNED, 0);
+
+	exec_object2[2].relocation_count = 1;
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	igt_assert(*shared_buffer == data2);
+	*shared_buffer = 0xffffffff;
+	/* Now cause eviction of unshared buffer by pinning shared buffer there */
+	exec_object2[1].offset = exec_object2[0].offset;
+	/* Prevent relocation */
+	exec_object2[2].relocation_count = 0;
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	igt_assert(*shared_buffer == data1);
+	igt_assert(exec_object2[0].offset != exec_object2[1].offset);
+	gem_read(fd, unshared_buf_handle, 0, (void*)&value, 4);
+	igt_assert(value == data1);
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+
+	free(shared_buffer);
+}
+
+/** 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
+   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 100240
+#define STRESS_NUM_LOOPS 1
+#define STORE_COMMANDS 4 * STRESS_NUM_BUFFERS
+
+static void gem_softpin_stress_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer[STRESS_NUM_BUFFERS];
+	uint32_t shared_handle[STRESS_NUM_BUFFERS];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[STRESS_NUM_BUFFERS + 1];
+	uint32_t batch_buffer[STORE_COMMANDS + 2]; /* 4 dwords per buffer + 2 for the end of batchbuffer */
+	uint32_t batch_buf_handle;
+	int ring, len, i, j;
+	uint64_t pinning_offset = 0x800000000000;
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, sizeof(batch_buffer));
+
+	/* create command buffer with write commands */
+	len = 0;
+	for(i = 0; i < STRESS_NUM_BUFFERS; i++) 
+	{
+		shared_buffer[i] = create_mem_buffer(BO_SIZE);
+		*shared_buffer[i] = 0xFFFFFFFF;
+
+		/* share with GPU */
+		gem_create_userptr_struct(&userptr, shared_buffer[i], BO_SIZE, false);
+		ret = gem_call_userptr_ioctl(fd, &userptr);
+		igt_assert_eq(ret, 0);
+
+		/* Get handle for shared buffer */
+		shared_handle[i] = userptr.handle;
+
+		setup_exec_obj(&exec_object2[i], shared_handle[i], EXEC_OBJECT_PINNED, pinning_offset);
+		len += gem_store_data_svm(fd, batch_buffer + (len/4), pinning_offset, i , (i == STRESS_NUM_BUFFERS-1) ? true:false);
+		
+		pinning_offset -= 0x200000; /* incremental 4K aligned address */
+	}
+	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
+
+	/* submit command buffer */
+	setup_exec_obj(&exec_object2[STRESS_NUM_BUFFERS], batch_buf_handle, 0, 0);
+
+	ring = 0;
+	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 (i = 0; i < STRESS_NUM_LOOPS; i++){
+		submit_and_sync(fd, &execbuf, batch_buf_handle);
+		for(j = 0; j < STRESS_NUM_BUFFERS; j++){
+			igt_fail_on_f(*shared_buffer[j] != j,
+				      "Mismatch in buffer %d, iteration %d: 0x%08X\n", j, i, *shared_buffer[j]);
+		}
+	}
+
+	// Now Render Ring
+	ring = I915_EXEC_RENDER;
+	execbuf.flags = ring;
+	for (i = 0; i < STRESS_NUM_LOOPS; i++){
+		submit_and_sync(fd, &execbuf, batch_buf_handle);
+		for(j = 0; j < STRESS_NUM_BUFFERS; j++){
+			igt_fail_on_f(*shared_buffer[j] != j,
+				      "Mismatch in buffer %d, iteration %d: 0x%08X\n", j, i, *shared_buffer[j]);
+		}
+	}
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+
+	for(i = 0; i < STRESS_NUM_BUFFERS; i++) 
+	{
+		free(shared_buffer[i]);
+	}
+}
+
+/*  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 16K uint32 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
+ */
+static void gem_write_multipage_buffer_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer;
+	uint32_t shared_handle;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[(4 * BO_SIZE) + 2];
+	uint32_t batch_buf_handle;
+	int ring, len, j;
+	uint64_t pinning_offset=0x1000;
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, sizeof(batch_buffer));
+
+	/* create command buffer with write commands */
+	len = 0;
+	shared_buffer = create_mem_buffer(MULTIPAGE_BO_SIZE);
+	memset(batch_buffer, 0, sizeof(batch_buffer));
+
+	memset(shared_buffer, 0, MULTIPAGE_BO_SIZE);
+
+	/* share with GPU */
+	gem_create_userptr_struct(&userptr, shared_buffer, MULTIPAGE_BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_handle = userptr.handle;
+
+	setup_exec_obj(&exec_object2[0], shared_handle, EXEC_OBJECT_PINNED, pinning_offset);
+
+	/* Every element of buffer */
+	for(j=0; j< (BO_SIZE); j++) /* BO_SIZE because it is 16K 4 byte entries */
+	{
+		len += gem_store_data_svm(fd, batch_buffer + (len/4), pinning_offset, j, (j == ((BO_SIZE)-1)) ? true:false);
+		pinning_offset += sizeof(shared_buffer[0]);  /* 4 bytes */
+	}
+	
+	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
+
+	// submit command buffer
+	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
+
+	ring = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	for(j = 0; j < (BO_SIZE); j++) 
+	{
+		igt_fail_on_f(shared_buffer[j] != j,
+			      "Mismatch in index %d: 0x%08X\n", j, shared_buffer[j]);
+	}
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+
+	free(shared_buffer);
+}
+
+/** This test will request to pin a shared buffer to an invalid
+    VMA  > 48-bit address
+
+   Create shared buffer of size 4K
+   Try and Pin object to address 0x9000000000000
+**/
+static void gem_pin_invalid_vma_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[BO_SIZE];
+	uint32_t batch_buf_handle, shared_buf_handle;
+	int ring, len;
+	const uint32_t data = 0x12345678;
+	uint64_t invalid_address = 0x9000000000000; /* 52 bit address */
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	shared_buffer = create_mem_buffer(BO_SIZE);
+	*shared_buffer = 0xFFFFFFFF;
+	
+	// share with GPU
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	shared_buf_handle = userptr.handle;
+
+	len = gem_store_data_svm(fd, batch_buffer, invalid_address, data, true);
+	gem_write(fd, batch_buf_handle, 0, batch_buffer, len);
+
+	setup_exec_obj(&exec_object2[0], shared_buf_handle, EXEC_OBJECT_PINNED, invalid_address);
+	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
+
+	ring = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+
+	/* Expect execbuf to fail */
+	ret = drmIoctl(fd,
+	       DRM_IOCTL_I915_GEM_EXECBUFFER2,
+	       &execbuf);
+
+	igt_assert_neq(ret, 0);
+	
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+
+	free(shared_buffer);
+}
+
+#define SHM_KEY 56789
+#define SHMEM_SIZE 4096
+/*  gem_shmem_svm_test - Test userptr ioctl with shared memory
+ * This test creates a sysV IPC buffer and shares with GPU. 
+ * It will send GPU commands to write DATA in the buffer and 
+ * validate it on the CPU side when the command completes.
+
+ * Create arbitrary shmem id
+ * Use shmat to attach a 4K uint32 buffer to above id
+ * Share buffer with GPU using userptr ioctl
+ * Create Batch buffer to write DATA in the first element
+ * submit execbuffer
+ * Validate on CPU side that DATA was indeed written
+ */
+static void gem_shmem_test(void)
+{
+	int shmid;
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[BO_SIZE];
+	uint32_t batch_buf_handle, shared_buf_handle;
+	int ring, len;
+	const uint32_t data = 0x12345678;
+	uint64_t pinning_offset = 0x1000;
+
+	shmid = shmget(SHM_KEY, SHMEM_SIZE, IPC_CREAT);
+	igt_assert_neq(shmid, -1);
+
+	shared_buffer = shmat(shmid, NULL, 0);	      
+	igt_assert(shared_buffer != (void*)-1);
+
+	memset(shared_buffer, 0, SHMEM_SIZE);
+	shared_buffer[0] = 0xFFFFFFFF;
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	gem_create_userptr_struct(&userptr, shared_buffer, SHMEM_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	shared_buf_handle = userptr.handle;
+	
+	/* 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 = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+
+	/* 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]);
+
+	ret = shmdt(shared_buffer);
+	igt_assert_eq(ret, 0);
+}
+
+/*  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
+
+   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
+*/
+
+static void gem_pin_high_address_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	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 = 0x1111FFFF000; /* 44 bit address */
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	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 */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_buf_handle = userptr.handle;
+ 
+	/* 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 = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	/* 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);
+	close(fd);
+	free(shared_buffer);
+}
+
+/*  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
+
+   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)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	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;
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	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 */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_buf_handle = userptr.handle;
+
+	for (high_address = BEGIN_HIGH_ADDRESS; high_address <= END_HIGH_ADDRESS; 
+						high_address+=ADDRESS_INCREMENT){
+		/* 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 = 0;
+		if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+			ring = I915_EXEC_BLT;
+
+
+		setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+		submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+		/* 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);
+	}
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+	free(shared_buffer);
+}
+
+/*  gem_pin_mmap_anonymous_test - This test will create a mmap anonymous buffer and
+ *  share with GPU. It will run basic test on this buffer. 
+
+   Create a anonymous mmap buffer
+   Share buffer with with GPU by using userptr ioctl
+   Create batch buffer to write DATA to first dword of buffer
+   Set EXEC_OBJECT_PINNED flag in exec object
+   Set 'offset' in exec object to pinning_offset VMA
+   Submit execbuffer
+   Verify value of first DWORD in shared buffer matches DATA
+*/
+void gem_pin_mmap_anonymous_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	uint32_t* shared_buffer = NULL;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[BO_SIZE];
+	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);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	/* create anonymus mmap buffer, set to all 0xF's */
+	shared_buffer = mmap(NULL, BO_SIZE, PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	igt_fail_on_f(shared_buffer == (void *)-1,
+		      "mmap call failed with %s\n", strerror(errno));
+
+	*shared_buffer = 0xFFFFFFFF;
+
+	/* share with GPU */
+	gem_create_userptr_struct(&userptr, shared_buffer, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+
+	/* Get handle for shared buffer */
+	shared_buf_handle = userptr.handle;
+
+	/* 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 = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_BLT;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	// 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);
+	close(fd);
+	igt_fail_on_f(munmap(shared_buffer, BO_SIZE) != 0,
+		      "munmap failed with: %s", strerror(errno));
+}
+
+/*  gem_pin_mmap_file_test - This test will use mmap command to map
+ *  a file in memory. It will then attempt to share the buffer with GPU
+ *  using the userptr ioctl. It will verify if CPU/GPU writes are consistent
+
+   open/create a file
+   lseek into the file and write some arbitrary data
+   this allows the mmap'd page to become resident
+   use mmap command to map the file into memory
+   Share buffer with with GPU by using userptr ioctl
+   Create batch buffer to write DATA to first dword of buffer
+   Set EXEC_OBJECT_PINNED flag in exec object
+   Set 'offset' in exec object to pinning_offest VMA
+   Submit execbuffer
+   Verify value of first DWORD in shared buffer matches DATA
+   Close file
+*/
+void gem_pin_mmap_file_test(void)
+{
+	i915_gem_userptr userptr;
+	int fd, ret;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec_object2[NUM_EXEC_OBJECTS];
+	uint32_t batch_buffer[BO_SIZE];
+	uint32_t batch_buf_handle, dest_buf_handle;
+	int ring, len;
+	const uint32_t data = 0x12345678;
+        int fdout;
+	uint32_t *dest;
+	const char filename[] = "/tmp/svm_mmap.txt";
+	uint64_t pinning_offset = 0x1000;
+
+	fdout = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0640);
+	igt_fail_on_f(fdout < 0, "Cannot open output file\n");
+
+	/* Do this to ensure backing physical memory for the file */
+	/* go to the location corresponding to the last byte */
+	if (lseek (fdout, BO_SIZE, SEEK_SET) == -1)
+		igt_info("lseek error");
+
+	/* write a dummy byte at the last location */
+	if (write (fdout, "", 1) != 1)
+		igt_info("write error");
+
+	fd = drm_open_driver(DRIVER_INTEL);
+	batch_buf_handle = gem_create(fd, BO_SIZE);
+
+	/* create anonymus mmap buffer, set to all 0xF's */
+	dest = mmap(0, BO_SIZE, PROT_WRITE, MAP_SHARED, fdout, 0);
+	igt_fail_on_f(dest == (void *)-1,
+		      "mmap call failed with %s\n", strerror(errno));
+	*dest = 0x11111111;
+
+	gem_create_userptr_struct(&userptr, dest, BO_SIZE, false);
+	ret = gem_call_userptr_ioctl(fd, &userptr);
+	igt_assert_eq(ret, 0);
+	dest_buf_handle = userptr.handle;
+
+	/* 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], dest_buf_handle, EXEC_OBJECT_PINNED, pinning_offset);
+	setup_exec_obj(&exec_object2[1], batch_buf_handle, 0, 0);
+
+	ring = 0;
+	if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+		ring = I915_EXEC_RENDER;
+
+	setup_execbuffer(&execbuf, exec_object2, ring, NUM_EXEC_OBJECTS, len);
+	submit_and_sync(fd, &execbuf, batch_buf_handle);
+
+	/* check on CPU to see if value changes */
+	igt_fail_on_f(*dest != data,
+		      "\nCPU read does not match GPU write, expected: 0x%x, got: 0x%x\n", data, dest[0]);
+
+	gem_close(fd, batch_buf_handle);
+	close(fd);
+	igt_fail_on_f(munmap(dest, BO_SIZE) != 0,
+		      "munmap failed with: %s", strerror(errno));
+	close(fdout);
+}
+
+
+int main(int argc, char* argv[])
+{
+	igt_subtest_init(argc, argv);
+	igt_skip_on_simulation();
+
+	igt_subtest("gem_basic"){
+		gem_basic_test();
+	}
+	igt_subtest("gem_multiple_process"){
+		gem_multiple_process_test();
+	}
+	igt_subtest("gem_repin"){
+		gem_repin_test();
+	}
+	igt_subtest("gem_evict"){
+		gem_evict_test();
+	}
+	igt_subtest("gem_softpin_stress"){
+		gem_softpin_stress_test();
+	}
+	igt_subtest("gem_pin_overlap"){
+		gem_pin_overlap_test();
+	}
+	igt_subtest("gem_shmem"){
+		gem_shmem_test();
+	}
+	igt_subtest("gem_write_multipage_buffer"){
+		gem_write_multipage_buffer_test();
+	}
+	igt_subtest("gem_pin_high_address"){
+		gem_pin_high_address_test();
+	}
+	igt_subtest("gem_pin_near_48Bit"){
+		gem_pin_near_48Bit_test();
+	}
+	igt_subtest("gem_pin_invalid_vma"){
+		gem_pin_invalid_vma_test();
+	}
+	igt_subtest("gem_pin_mmap_anon"){
+		gem_pin_mmap_anonymous_test();
+	}
+	igt_subtest("gem_pin_mmap_file"){
+		gem_pin_mmap_file_test();
+	}
+
+	igt_exit();
+}
-- 
1.9.1



More information about the Intel-gfx mailing list