All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests
@ 2019-03-20 20:01 Venkata Sandeep Dhanalakota
  2019-03-20 21:41 ` [igt-dev] ✓ Fi.CI.BAT: success for " Patchwork
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Venkata Sandeep Dhanalakota @ 2019-03-20 20:01 UTC (permalink / raw)
  To: igt-dev

From: "Venkata Sandeep, Dhanalakota" <venkata.s.dhanalakota@intel.com>

Sparse object is a proxy object that can link the pages from
other objects. Typical use case are huge continuos framebuffer
that is too big to handle scanout. Sparse object can used as
any other regular object after the pages from source object
are linked.
This patch introduces igt test to exercise various usages
of the sparse object, which include:
1) read/write/mmap sparse object after it is linked to various
   source objects which have backing pages in stolen memory,
   internal memory etc.
2) Feeding sparse object to execbuf after it is linked with
   source object.

Driver changes are posted here
https://cgit.freedesktop.org/~ickle/linux-2.6/
commit/?h=wip-sparseobject&id=cdd6f93f05c6606d7d01cb0e8596e21b2e7eef04

This is still WIP gets updated.
Compile-tested only.

Signed-off-by: Venkata Sandeep, Dhanalakota <venkata.s.dhanalakota@intel.com>
---
 include/drm-uapi/i915_drm.h   |   35 ++
 lib/Makefile.sources          |    2 +
 lib/i915/gem_sparse.c         |  123 ++++
 lib/i915/gem_sparse.h         |   35 ++
 lib/meson.build               |    1 +
 tests/Makefile.sources        |    3 +
 tests/i915/gem_sparseobject.c | 1013 +++++++++++++++++++++++++++++++++
 tests/meson.build             |    1 +
 8 files changed, 1213 insertions(+)
 create mode 100644 lib/i915/gem_sparse.c
 create mode 100644 lib/i915/gem_sparse.h
 create mode 100644 tests/i915/gem_sparseobject.c

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index 4ae1c6ff..d860dae2 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -239,6 +239,20 @@ typedef struct _drm_i915_sarea {
 
 } drm_i915_sarea_t;
 
+struct drm_i915_gem_set_pages {
+	__u32 dst_handle;
+	__u32 src_handle;
+
+	__u64 dst_offset;
+	__u64 src_offset;
+
+	__u64 dst_stride;
+	__u64 src_stride;
+
+	__u64 width;
+	__u64 height;
+};
+
 /* due to userspace building against these headers we need some compat here */
 #define planeA_x pipeA_x
 #define planeA_y pipeA_y
@@ -321,6 +335,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_PERF_ADD_CONFIG	0x37
 #define DRM_I915_PERF_REMOVE_CONFIG	0x38
 #define DRM_I915_QUERY			0x39
+#define DRM_I915_GEM_SET_PAGES		0x3a
 /* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
@@ -380,6 +395,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_PERF_ADD_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
 #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
 #define DRM_IOCTL_I915_QUERY			DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
+#define DRM_IOCTL_I915_GEM_SET_PAGES		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_SET_PAGES, struct drm_i915_gem_set_pages)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -666,6 +682,25 @@ struct drm_i915_gem_create {
 	__u32 pad;
 };
 
+struct drm_i915_gem_create_v2 {
+	/**
+	 * Requested size for the object.
+	 *
+	 * The (page-aligned) allocated size for the object will be returned.
+	 */
+	__u64 size;
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	__u32 handle;
+	__u32 pad;
+
+#define I915_CREATE_SPARSE_OBJECT (1 << 1)
+	__u32 flags;
+};
+
 struct drm_i915_gem_pread {
 	/** Handle for the object being read. */
 	__u32 handle;
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index cf272098..32d51529 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -9,6 +9,8 @@ lib_source_list =	 	\
 	i915/gem_scheduler.h	\
 	i915/gem_submission.c	\
 	i915/gem_submission.h	\
+	i915/gem_sparse.h	\
+	i915/gem_sparse.c	\
 	i915/gem_ring.h	\
 	i915/gem_ring.c	\
 	i915/gem_mman.c	\
diff --git a/lib/i915/gem_sparse.c b/lib/i915/gem_sparse.c
new file mode 100644
index 00000000..4f091b6d
--- /dev/null
+++ b/lib/i915/gem_sparse.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "ioctl_wrappers.h"
+#include "drmtest.h"
+
+#include "gem_sparse.h"
+
+#define LOCAL_IOCTL_I915_GEM_CREATE       DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create_v2)
+
+/**
+ * gem_create_sparse:
+ * @fd: open i915 drm file descriptor
+ * @size: desired size of the buffer
+ *
+ * This wraps the new GEM_CREATE ioctl, which allocates a new sparse gem buffer
+ * object of @size.
+ *
+ * Returns: The file-private handle of the created buffer object
+ */
+
+static
+int __gem_create_sparse(int fd, uint64_t size, uint32_t *out)
+{
+	struct drm_i915_gem_create_v2 create;
+	int err;
+
+	memset(&create, 0, sizeof(create));
+	create.handle = 0;
+	create.size = size;
+	create.flags = I915_CREATE_SPARSE_OBJECT;
+
+	err = 0;
+	if(igt_ioctl(fd, LOCAL_IOCTL_I915_GEM_CREATE, &create)==0)
+		*out = create.handle;
+	else
+		err = -errno;
+	errno = 0;
+	return err;
+}
+
+uint32_t gem_create_sparse(int i915, uint64_t size)
+{
+	uint32_t handle = 0;
+
+	igt_assert_eq(__gem_create_sparse(i915, size, &handle), 0);
+	igt_assert(handle);
+
+	return handle;
+}
+static
+int __gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	struct drm_i915_gem_set_pages set_pages;
+	int err;
+
+	set_pages.dst_handle = dst_handle;
+	set_pages.dst_offset = dst_offset;
+	set_pages.dst_stride = dst_stride;
+	set_pages.src_handle = src_handle;
+	set_pages.src_offset = src_offset;
+	set_pages.src_stride = src_stride;
+	set_pages.width = width;
+	set_pages.height = height;
+
+	err = 0;
+	if(igt_ioctl(fd, DRM_IOCTL_I915_GEM_SET_PAGES, &set_pages))
+		err = -errno;
+	errno = 0;
+	return err;
+}
+
+/**
+ * gem_set_pages:
+ * All parameters other than fd and handles are in units of pages.
+ * @fd: open i915 drm file descriptor
+ * @dst_handle: destination sparse object handle
+ * @dst_offset: offset in destination object where mapping is done
+ * @dst_stride: destination object stride
+ * @src_handle: source object handle
+ * @src_offset: offset in the source object
+ * @src_stride: src object stride
+ * @width: width of rectangle to map
+ * @height: height of rectange to map
+ *
+ * This wraps SET_PAGES ioctl, which maps pages from src object to the
+ * destination object.
+ */
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	igt_assert_eq(__gem_set_pages(fd, dst_handle, dst_offset, dst_stride,
+				      src_handle, src_offset, src_stride,
+				      width, height), 0);
+}
diff --git a/lib/i915/gem_sparse.h b/lib/i915/gem_sparse.h
new file mode 100644
index 00000000..71b35fb6
--- /dev/null
+++ b/lib/i915/gem_sparse.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef GEM_SPARSE_H
+#define GEM_SPARSE_H
+
+#include <stdint.h>
+
+uint32_t gem_create_sparse(int i915, uint64_t size);
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height);
+
+#endif /* GEM_SPARSE_H */
diff --git a/lib/meson.build b/lib/meson.build
index 0eb5585d..7baefa2c 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -3,6 +3,7 @@ lib_sources = [
 	'i915/gem_context.c',
 	'i915/gem_scheduler.c',
 	'i915/gem_submission.c',
+	'i915/gem_sparse.c',
 	'i915/gem_ring.c',
 	'i915/gem_mman.c',
 	'igt_color_encoding.c',
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 71ccf00a..96233a8b 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -270,6 +270,9 @@ gem_gtt_speed_SOURCES = i915/gem_gtt_speed.c
 TESTS_progs += gem_largeobject
 gem_largeobject_SOURCES = i915/gem_largeobject.c
 
+TESTS_progs += gem_sparseobject
+gem_sparseobject_SOURCES = i915/gem_sparseobject.c
+
 TESTS_progs += gem_linear_blits
 gem_linear_blits_SOURCES = i915/gem_linear_blits.c
 
diff --git a/tests/i915/gem_sparseobject.c b/tests/i915/gem_sparseobject.c
new file mode 100644
index 00000000..8fc00249
--- /dev/null
+++ b/tests/i915/gem_sparseobject.c
@@ -0,0 +1,1013 @@
+/*
+ * Copyright © 2008 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.
+ *
+ *
+ */
+
+#include "igt.h"
+#include "i915/gem_sparse.h"
+
+#include <stdlib.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 "drm.h"
+
+IGT_TEST_DESCRIPTION("This is a test to exercise sparse object and backing it with,"
+		     " allocation of object from stolen memory and shmem.");
+
+#define CLEAR(s) memset(&s, 0, sizeof(s))
+
+#define OBJ_SIZE (4 * 4096)
+#define PAGE_SIZE 4096
+#define TIMEOUT 20
+#define MAX_HANDLES 4096
+#define LARGE_OBJECT_SIZE  (16 * 1024 * 1024)
+#define MAX_USRPTR 20
+
+enum mmap_type{
+	GEM_MMAP_CPU,
+	GEM_MMAP_WC,
+	GEM_MMAP_GTT,
+	GEM_MMAP_NONE
+};
+
+enum gem_object_type {
+	GEM_OBJ_INTERNAL,
+	GEM_OBJ_USRPTR,
+	GEM_OBJ_STOLEN,
+	GEM_OBJ_SPARSE,
+	GEM_OBJ_LOCAL
+};
+
+uint64_t usrptr[MAX_USRPTR];
+static int usrcount;
+
+static uint32_t batch_create(int fd)
+{
+	const uint32_t bbe = MI_BATCH_BUFFER_END;
+	uint32_t handle;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, &bbe, sizeof(bbe));
+
+	return handle;
+}
+
+static uint32_t sparse_batch_create(int fd, uint32_t src_handle)
+{
+	uint32_t sparse_handle;
+
+	sparse_handle = gem_create_sparse(fd, 4096);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	return sparse_handle;
+}
+
+static void batch_fini(int fd, uint32_t handle)
+{
+	gem_sync(fd, handle); /* catch any GPU hang */
+	gem_close(fd, handle);
+}
+
+static void noop(int fd, uint32_t handle, unsigned ring)
+{
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 exec;
+	const uint32_t bbe = MI_BATCH_BUFFER_END;
+
+	gem_require_ring(fd, ring);
+
+	memset(&exec, 0, sizeof(exec));
+
+	gem_write(fd, handle, 0, &bbe, sizeof(bbe));
+	igt_until_timeout(5) {
+		memset(&exec, 0, sizeof(exec));
+		exec.handle = sparse_batch_create(fd, handle);
+
+		memset(&execbuf, 0, sizeof(execbuf));
+		execbuf.buffers_ptr = to_user_pointer(&exec);
+		execbuf.buffer_count = 1;
+		execbuf.flags = ring;
+		gem_execbuf(fd, &execbuf);
+
+		batch_fini(fd, exec.handle);
+	}
+}
+
+static void gtt(int fd, uint32_t src_handle, unsigned ring)
+{
+	struct drm_i915_gem_execbuffer2 *execbuf;
+	struct drm_i915_gem_exec_object2 *exec;
+	uint32_t sparse_handle;
+
+	gem_require_ring(fd, ring);
+
+	sparse_handle = gem_create_sparse(fd, 4096);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+		      src_handle, 0, 0, 1, 1);
+	gem_set_domain(fd, sparse_handle, I915_GEM_DOMAIN_GTT,
+		       I915_GEM_DOMAIN_GTT);
+	/*mmap the sparse object */
+	execbuf = gem_mmap__gtt(fd, sparse_handle, 4096, PROT_WRITE);
+	exec = (struct drm_i915_gem_exec_object2 *)(execbuf + 1);
+	gem_close(fd, sparse_handle);
+
+	exec->handle = batch_create(fd);
+
+	execbuf->buffers_ptr = to_user_pointer(exec);
+	execbuf->buffer_count = 1;
+	execbuf->flags = ring;
+
+	gem_execbuf(fd, execbuf);
+
+	batch_fini(fd, exec->handle);
+	munmap(execbuf, 4096);
+}
+
+/**
+ * mmaps on bo and returns a pointer to user
+ */
+static
+uint32_t gem_create_local(int fd, size_t size) {
+	/**
+	 * unitl local memory support is added
+	 * using stolen memory
+	 */
+	return gem_create_stolen(fd, size);
+}
+
+static
+uint32_t gem_create_usrptr(int fd, size_t size) {
+	uint32_t handle;
+	void *ptr;
+	static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, size) == 0);
+	gem_userptr(fd, ptr, PAGE_SIZE, 0, userptr_flags, &handle);
+	usrptr[usrcount++] = (uint64_t)ptr;
+	return handle;
+}
+
+static void *
+mmap_bo(int fd, uint32_t handle, enum mmap_type type)
+{
+	void *ptr;
+	switch (type) {
+	case GEM_MMAP_CPU:
+		ptr = gem_mmap__cpu(fd, handle, 0, PAGE_SIZE,
+				    PROT_READ | PROT_WRITE);
+		break;
+	case GEM_MMAP_WC:
+		ptr = gem_mmap__wc(fd, handle, 0, PAGE_SIZE,
+				   PROT_READ | PROT_WRITE);
+		break;
+	case GEM_MMAP_GTT:
+		ptr = gem_mmap__gtt(fd, handle, PAGE_SIZE,
+				    PROT_READ | PROT_WRITE);
+		break;
+	default:
+		return NULL;
+	}
+
+	return ptr;
+}
+
+static void
+fill_sources(int fd, uint32_t sources[], int size)
+{
+	int i;
+	for (i = 0; i < size; i++) {
+		switch(i) {
+		case GEM_OBJ_LOCAL:
+			sources[i] = gem_create_local(fd, OBJ_SIZE);
+			break;
+		case GEM_OBJ_INTERNAL:
+			sources[i] = gem_create(fd, OBJ_SIZE);
+				break;
+		case GEM_OBJ_USRPTR:
+			sources[i] = gem_create_usrptr(fd, OBJ_SIZE);
+				break;
+		case GEM_OBJ_STOLEN:
+			sources[i] = gem_create_stolen(fd, OBJ_SIZE);
+				break;
+		}
+	}
+}
+
+static void
+gem_link_sources(int fd, uint32_t sparse_handle, uint32_t sources[], int sz)
+{
+	int i;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	int npages = OBJ_SIZE/PAGE_SIZE;
+
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+	while(i < sz) {
+		uint32_t ht = 0;
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							 (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							 (height - 1)) - width);
+		char *data;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(fd, sources[i],
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(fd, sparse_handle, dst_offset, dst_stride,
+			      sources[i], src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from mapped from sources */
+		while (ht <= height) {
+			gem_read(fd, sparse_handle,
+				 dst_offset + (ht * dst_stride),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+		i++;
+	}
+}
+
+/*
+ * Randominly picks the source objects and links with
+ * sparse object at random offsets
+ */
+static void
+igt_gem_sparse_link_nsources(void)
+{
+	int size;
+	uint32_t sources[GEM_OBJ_SPARSE];
+	uint32_t sparse_handle;
+	int i;
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	igt_until_timeout(5 * TIMEOUT) {
+		CLEAR(sources);
+		size = rand() % GEM_OBJ_SPARSE;
+		fill_sources(fd, sources, size);
+		sparse_handle = gem_create_sparse(fd, LARGE_OBJECT_SIZE);
+		gem_link_sources(fd, sparse_handle, sources, size);
+		gem_close(fd, sparse_handle);
+		for (i = 0; i < usrcount; i++)
+			free((void *)usrptr[i]);
+		usrcount = 0;
+		CLEAR(usrptr);
+		for (i = 0; i < size; i++)
+			gem_close(fd, sources[i]);
+	}
+	close(fd);
+}
+
+static void
+igt_gem_sparse_link_stolen(void)
+{
+	int fd = drm_open_driver(DRIVER_INTEL);
+	uint32_t stolen_handle, sparse_handle;
+	uint32_t sources[1];
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	stolen_handle = gem_create_stolen(fd, OBJ_SIZE);
+	sources[0] = stolen_handle;
+	gem_link_sources(fd, sparse_handle, sources, 1);
+	gem_close(fd, sparse_handle);
+	gem_close(fd, stolen_handle);
+	close(fd);
+}
+
+static void
+igt_gem_sparse_link_usrptr(void)
+{
+	int fd = drm_open_driver(DRIVER_INTEL);
+	uint32_t usrptr_handle, sparse_handle;
+	static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+	void *ptr;
+	uint32_t sources[1];
+
+	igt_assert(posix_memalign(&ptr, OBJ_SIZE, PAGE_SIZE) == 0);
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	gem_userptr(fd, ptr, PAGE_SIZE, 0, userptr_flags, &usrptr_handle);
+	sources[0] = usrptr_handle;
+	gem_link_sources(fd, sparse_handle, sources, 1);
+	gem_close(fd, sparse_handle);
+	gem_close(fd, usrptr_handle);
+	free(ptr);
+	close(fd);
+}
+
+/* Smoke test with single destination sparse object */
+static void igt_gem_sparse_smoketest_single_destination(void)
+{
+	uint32_t sparse_handle, src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	int npages = OBJ_SIZE/PAGE_SIZE;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	char *data;
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	igt_until_timeout(TIMEOUT) {
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		uint32_t ht = 0;
+
+		src_handle = gem_create(fd, OBJ_SIZE);
+		handles[count++] = src_handle;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(fd, src_handle,
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(fd, sparse_handle, dst_offset, dst_stride,
+			      src_handle, src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from mapped from sources */
+		while (ht <= height) {
+			gem_read(fd, sparse_handle,
+				 dst_offset + (ht * dst_stride * PAGE_SIZE),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+	}
+	for (i = 0; i<count; i++)
+		gem_close(fd, handles[i]);
+	gem_close(fd, sparse_handle);
+	close(fd);
+}
+
+/* sparse object smoke test with single source */
+static void igt_gem_sparse_smoketest_single_source(void)
+{
+	uint32_t sparse_handle, src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	int npages = OBJ_SIZE / PAGE_SIZE;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	char *data;
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create(fd, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	igt_until_timeout(TIMEOUT) {
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		uint32_t ht = 0;
+
+		sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+		handles[count++] = sparse_handle;
+		data = expected;
+		while (ht <= height) {
+			gem_write(fd, src_handle,
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		gem_set_pages(fd, sparse_handle, dst_offset, dst_stride,
+			      src_handle, src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		while (ht <= height) {
+			gem_read(fd, sparse_handle,
+				 dst_offset + (ht * dst_stride * PAGE_SIZE),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, (width * PAGE_SIZE) * height) == 0);
+	}
+	for (i = 0; i<count; i++)
+		gem_close(fd, handles[i]);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+static void
+igt_gem_sparse_usrptr_execbuf(void)
+{
+	uint32_t src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	const struct intel_execution_engine *e;
+
+	src_handle = gem_create_usrptr(fd, OBJ_SIZE);
+
+	igt_fork_hang_detector(fd);
+
+	for (e = intel_execution_engines; e->name; e++) {
+		igt_subtest_f("basic-%s", e->name)
+			noop(fd, src_handle, e->exec_id | e->flags);
+		igt_subtest_f("gtt-%s", e->name)
+			gtt(fd, src_handle, e->exec_id | e->flags);
+	}
+
+	igt_stop_hang_detector();
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Basic test to verify sparse object read and write
+ * which is linked gem object created from usrptr
+ */
+static void igt_gem_sparse_usrptr_readwrite(void)
+{
+	uint32_t sparse_handle, src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_usrptr(fd, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	gem_write(fd, src_handle, 0, expected, PAGE_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+
+	gem_read(fd, sparse_handle, 0, buf, PAGE_SIZE);
+	igt_assert(memcmp(buf, expected, PAGE_SIZE) == 0);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	free((void *)usrptr[0]);
+	usrcount = 0;
+	close(fd);
+}
+
+/*
+ * Creating a sparse object mapping the pages
+ * from gem object created with usrptr and pread.
+ */
+static void igt_gem_sparse_usrptr_pread(void)
+{
+	int sparse_handle, src_handle;
+	char buf[PAGE_SIZE];
+	char expected[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_usrptr(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	CLEAR(expected);
+
+	gem_read(fd, sparse_handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	free((void *)usrptr[0]);
+	usrcount = 0;
+	close(fd);
+}
+
+/*
+ * Creating a sparse object which backed by
+ * gem object created from usrptr and test pwrite.
+ */
+static void igt_gem_sparse_usrptr_pwrite(void)
+{
+	int sparse_handle, src_handle;
+	char buf[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_usrptr(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	memset(buf, 0xfeedbeef, PAGE_SIZE);
+
+	gem_write(fd, sparse_handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	free((void *)usrptr[0]);
+	usrcount = 0;
+	close(fd);
+}
+
+/*
+ * igt case to test to mmap an sparse object
+ * with gem object created from usrptr
+ */
+static void igt_gem_sparse_usrptr_mmap(void)
+{
+	int sparse_handle, src_handle;
+	void *data;
+	int type;
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_usrptr(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	for (type = 0; type < GEM_MMAP_NONE; type++) {
+		data = mmap_bo(fd, sparse_handle, type);
+		/*
+		 * valid ptr should be returned for mmapping
+		 * sparse object
+		 */
+		igt_assert(data);
+		gem_munmap(data, PAGE_SIZE);
+	}
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	free((void *)usrptr[0]);
+	usrcount = 0;
+	close(fd);
+}
+
+static void
+igt_gem_sparse_stolen_execbuf(void)
+{
+	uint32_t src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	const struct intel_execution_engine *e;
+
+	src_handle = gem_create_stolen(fd, OBJ_SIZE);
+
+	igt_fork_hang_detector(fd);
+
+	for (e = intel_execution_engines; e->name; e++) {
+		igt_subtest_f("basic-%s", e->name)
+			noop(fd, src_handle, e->exec_id | e->flags);
+		igt_subtest_f("gtt-%s", e->name)
+			gtt(fd, src_handle, e->exec_id | e->flags);
+	}
+
+	igt_stop_hang_detector();
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Basic test to verify sparse object read and write
+ * which is linked stolen memory gem object.
+ */
+static void igt_gem_sparse_stolen_readwrite(void)
+{
+	uint32_t sparse_handle, src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_stolen(fd, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	gem_write(fd, src_handle, 0, expected, PAGE_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+
+	gem_read(fd, sparse_handle, 0, buf, PAGE_SIZE);
+	igt_assert(memcmp(buf, expected, PAGE_SIZE) == 0);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Creating a sparse object mapping the pages
+ * from stolen mem gem object and pread should read a zero.
+ */
+static void igt_gem_sparse_stolen_pread(void)
+{
+	int sparse_handle, src_handle;
+	char buf[PAGE_SIZE];
+	char expected[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_stolen(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	CLEAR(expected);
+
+	gem_read(fd, sparse_handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Creating a sparse object which backed by
+ * stolen memory gem object and test pwrite.
+ */
+static void igt_gem_sparse_stolen_pwrite(void)
+{
+	int sparse_handle, src_handle;
+	char buf[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_stolen(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	memset(buf, 0xfeedbeef, PAGE_SIZE);
+
+	gem_write(fd, sparse_handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * igt case to test if we can mmap an sparse object
+ * linked to stolen memory gem object
+ */
+static void igt_gem_sparse_stolen_mmap(void)
+{
+	int sparse_handle, src_handle;
+	void *data;
+	int type;
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create_stolen(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	for (type = 0; type < GEM_MMAP_NONE; type++) {
+		data = mmap_bo(fd, sparse_handle, type);
+		/*
+		 * valid ptr should be returned for mmapping
+		 * sparse object
+		 */
+		igt_assert(!data);
+		gem_munmap(data, PAGE_SIZE);
+	}
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+static void
+igt_gem_sparse_internal_execbuf(void)
+{
+	uint32_t src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	const struct intel_execution_engine *e;
+
+	src_handle = gem_create(fd, OBJ_SIZE);
+
+	igt_fork_hang_detector(fd);
+
+	for (e = intel_execution_engines; e->name; e++) {
+		igt_subtest_f("basic-%s", e->name)
+			noop(fd, src_handle, e->exec_id | e->flags);
+		igt_subtest_f("gtt-%s", e->name)
+			gtt(fd, src_handle, e->exec_id | e->flags);
+	}
+
+	igt_stop_hang_detector();
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Basic test to verify sparse object read and write
+ * which is linked internal gem object.
+ */
+static void igt_gem_sparse_internal_readwrite(void)
+{
+	uint32_t sparse_handle, src_handle;
+	int fd = drm_open_driver(DRIVER_INTEL);
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create(fd, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	gem_write(fd, src_handle, 0, expected, PAGE_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+
+	gem_read(fd, sparse_handle, 0, buf, PAGE_SIZE);
+	igt_assert(memcmp(buf, expected, PAGE_SIZE) == 0);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Creating a sparse object mapping the pages
+ * from gem object and pread.
+ */
+static void igt_gem_sparse_internal_pread(void)
+{
+	int sparse_handle, src_handle;
+	char buf[PAGE_SIZE];
+	char expected[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	CLEAR(expected);
+
+	gem_read(fd, sparse_handle, 1, buf, PAGE_SIZE);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Creating a sparse object which backed by
+ * internal memory gem object and test pwrite.
+ */
+static void igt_gem_sparse_internal_pwrite(void)
+{
+	int sparse_handle, src_handle;
+	char buf[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	memset(buf, 0xfeedbeef, PAGE_SIZE);
+
+	gem_write(fd, sparse_handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * igt case to test if we can mmap sparse object
+ * backed by gem object internal memory
+ */
+static void igt_gem_sparse_internal_mmap(void)
+{
+	int sparse_handle, src_handle;
+	void *data;
+	int type;
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	src_handle = gem_create(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 src_handle, 0, 0, 1, 1);
+	for (type = 0; type < GEM_MMAP_NONE; type++) {
+		data = mmap_bo(fd, sparse_handle, type);
+		/*
+		 * valid ptr should be returned for mmapping
+		 * sparse object
+		 */
+		igt_assert(!data);
+		gem_munmap(data, PAGE_SIZE);
+	}
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, src_handle);
+	close(fd);
+}
+
+/*
+ * Creating a sparse object without mapping the pages
+ * from any source object pread should read a zero.
+ */
+static void igt_gem_sparse_pread(void)
+{
+	int handle;
+	char buf[PAGE_SIZE];
+	char expected[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	handle = gem_create_sparse(fd, OBJ_SIZE);
+	CLEAR(expected);
+
+	gem_read(fd, handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, handle);
+	close(fd);
+}
+
+/*
+ * Creating a sparse object without mapping the pages
+ * from any source object pwrite should be backed by
+ * zero page.
+ */
+static void igt_gem_sparse_pwrite(void)
+{
+	int handle;
+	char buf[PAGE_SIZE];
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	handle = gem_create_sparse(fd, OBJ_SIZE);
+	memset(buf, 0xfeedbeef, PAGE_SIZE);
+
+	/*
+	 * gem_write should fail if it succeeds test should fail,
+	 * since there are no backing pages linked from any src object.
+	 */
+	gem_write(fd, handle, 0, buf, PAGE_SIZE);
+
+	gem_close(fd, handle);
+	close(fd);
+}
+
+/* igt case to test if we can mmap an empty sparse object */
+static void igt_gem_invalid_mmap(void)
+{
+	int handle;
+	void *data;
+	int type;
+	int fd = drm_open_driver(DRIVER_INTEL);
+
+	handle = gem_create_sparse(fd, OBJ_SIZE);
+
+	/**
+	 * These should fail. Hence cannot mmap.
+	 * Test fails if we are able successfully mmap.
+	 */
+	for (type = 0; type < GEM_MMAP_NONE; type++) {
+		data = mmap_bo(fd, handle, type);
+		/*
+		 * NULL should be returned for mmapping sparse object
+		 * without any pages linked from source object
+		 */
+		igt_assert(data);
+		gem_munmap(data, PAGE_SIZE);
+	}
+
+	gem_close(fd, handle);
+	close(fd);
+}
+/* Basic test to ensure we can create a linked object */
+static void igt_gem_sparse_linked(void)
+{
+	int fd = drm_open_driver(DRIVER_INTEL);
+	uint32_t sparse_handle, handle;
+
+	sparse_handle = gem_create_sparse(fd, OBJ_SIZE);
+	handle = gem_create(fd, OBJ_SIZE);
+	gem_set_pages(fd, sparse_handle, 0, 0,
+				 handle, 0, 0, 1, 1);
+
+	gem_close(fd, sparse_handle);
+	gem_close(fd, handle);
+	close(fd);
+}
+
+/* Basic test to ensure we can create an object */
+static void igt_gem_sparse_empty(void)
+{
+	int fd = drm_open_driver(DRIVER_INTEL);
+	uint32_t handle;
+
+	handle = gem_create_sparse(fd, LARGE_OBJECT_SIZE);
+	gem_close(fd, handle);
+	close(fd);
+}
+
+igt_simple_main
+{
+	igt_subtest("create_sparse_object")
+		igt_gem_sparse_empty();
+
+	igt_subtest("pwrite-unset-sparse-object")
+		igt_gem_sparse_pwrite();
+
+	igt_subtest("pread-unset-sparse-object")
+		igt_gem_sparse_pread();
+
+	igt_subtest("mmap-unset-sparse-object")
+		igt_gem_invalid_mmap();
+
+	igt_subtest("link-internel-object-sparse-object")
+		igt_gem_sparse_linked();
+
+	igt_subtest("pread-internal-sparse-object")
+		igt_gem_sparse_internal_pread();
+
+	igt_subtest("pwrite-internal-sparse-object")
+		igt_gem_sparse_internal_pwrite();
+
+	igt_subtest("readwrite-internal-sparse-object")
+		igt_gem_sparse_internal_readwrite();
+
+	igt_subtest("mmap-internal-sparse-object")
+		igt_gem_sparse_internal_mmap();
+
+	igt_subtest("execbuf-internal-linked-sparse-object")
+		igt_gem_sparse_internal_execbuf();
+
+	igt_subtest("link-usrptr-object-sparse-object")
+		igt_gem_sparse_link_usrptr();
+
+	igt_subtest("pread-usrptr-object-sparse-object")
+		igt_gem_sparse_usrptr_pread();
+
+	igt_subtest("pwrite-usrptr-object-sparse-object")
+		igt_gem_sparse_usrptr_pwrite();
+
+	igt_subtest("readwrite-usrptr-object-sparse-object")
+		igt_gem_sparse_usrptr_readwrite();
+
+	igt_subtest("mmap-usrptr-object-sparse-object")
+		igt_gem_sparse_usrptr_mmap();
+
+	igt_subtest("execbuf-usrptr-linked-sparse-object")
+		igt_gem_sparse_usrptr_execbuf();
+
+	igt_subtest("link-stolen-object-sparse-object")
+		igt_gem_sparse_link_stolen();
+
+	igt_subtest("pread-stolen-object-sparse-object")
+		igt_gem_sparse_stolen_pread();
+
+	igt_subtest("pwrite-stolen-object-sparse-object")
+		igt_gem_sparse_stolen_pwrite();
+
+	igt_subtest("readwrite-stolen-object-sparse-object")
+		igt_gem_sparse_stolen_readwrite();
+
+	igt_subtest("mmap-stolen-object-sparse-object")
+		igt_gem_sparse_stolen_mmap();
+
+	igt_subtest("execbuf-stolen-object-sparse-object")
+		igt_gem_sparse_stolen_execbuf();
+
+	igt_subtest("sparse_link_multiple_sources")
+		igt_gem_sparse_link_nsources();
+
+	igt_subtest("sparse_smoke_test_single_source")
+		igt_gem_sparse_smoketest_single_source();
+
+	igt_subtest("sparse_smoke_test_single_destination")
+		igt_gem_sparse_smoketest_single_destination();
+}
diff --git a/tests/meson.build b/tests/meson.build
index 9015f809..9bf12118 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -153,6 +153,7 @@ i915_progs = [
 	'gem_gtt_hog',
 	'gem_gtt_speed',
 	'gem_largeobject',
+	'gem_sparseobject',
 	'gem_linear_blits',
 	'gem_lut_handle',
 	'gem_madvise',
-- 
2.17.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for i915/gem_sparseobject: Add sparse object IGT tests
  2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
@ 2019-03-20 21:41 ` Patchwork
  2019-03-21  0:13   ` [igt-dev] " Chris Wilson
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Patchwork @ 2019-03-20 21:41 UTC (permalink / raw)
  To: Venkata Sandeep Dhanalakota; +Cc: igt-dev

== Series Details ==

Series: i915/gem_sparseobject: Add sparse object IGT tests
URL   : https://patchwork.freedesktop.org/series/58290/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5784 -> IGTPW_2672
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/58290/revisions/1/mbox/

Known issues
------------

  Here are the changes found in IGTPW_2672 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@i915_pm_rpm@module-reload:
    - fi-skl-6770hq:      PASS -> FAIL [fdo#108511]

  * igt@kms_busy@basic-flip-a:
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +1

  * igt@kms_chamelium@hdmi-crc-fast:
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] +62

  * igt@kms_chamelium@hdmi-edid-read:
    - fi-hsw-peppy:       NOTRUN -> SKIP [fdo#109271] +46

  * igt@kms_frontbuffer_tracking@basic:
    - fi-hsw-peppy:       NOTRUN -> DMESG-FAIL [fdo#102614] / [fdo#107814]
    - fi-byt-clapper:     PASS -> FAIL [fdo#103167]

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-blb-e6850:       PASS -> INCOMPLETE [fdo#107718]

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
    - fi-byt-clapper:     PASS -> FAIL [fdo#103191] / [fdo#107362]

  
#### Possible fixes ####

  * igt@i915_selftest@live_execlists:
    - fi-apl-guc:         INCOMPLETE [fdo#103927] / [fdo#109720] -> PASS

  * igt@i915_selftest@live_uncore:
    - fi-ivb-3770:        DMESG-FAIL [fdo#110210] -> PASS

  * igt@kms_frontbuffer_tracking@basic:
    - fi-icl-u3:          FAIL [fdo#103167] -> PASS

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - fi-byt-clapper:     FAIL [fdo#103191] / [fdo#107362] -> PASS +1

  
  [fdo#102614]: https://bugs.freedesktop.org/show_bug.cgi?id=102614
  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103191]: https://bugs.freedesktop.org/show_bug.cgi?id=103191
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#107362]: https://bugs.freedesktop.org/show_bug.cgi?id=107362
  [fdo#107718]: https://bugs.freedesktop.org/show_bug.cgi?id=107718
  [fdo#107814]: https://bugs.freedesktop.org/show_bug.cgi?id=107814
  [fdo#108511]: https://bugs.freedesktop.org/show_bug.cgi?id=108511
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109720]: https://bugs.freedesktop.org/show_bug.cgi?id=109720
  [fdo#110210]: https://bugs.freedesktop.org/show_bug.cgi?id=110210


Participating hosts (46 -> 40)
------------------------------

  Additional (2): fi-hsw-peppy fi-bsw-n3050 
  Missing    (8): fi-kbl-soraka fi-ilk-m540 fi-hsw-4200u fi-byt-squawks fi-bsw-cyan fi-ctg-p8600 fi-bdw-samus fi-skl-6700k2 


Build changes
-------------

    * IGT: IGT_4894 -> IGTPW_2672

  CI_DRM_5784: 7f9065d7aaa6abe9bc07e3694a8f3e2d5a91eebe @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2672: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2672/
  IGT_4894: fedd92f4022837e2c20e472b65bd7d0849f484a3 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

+igt@gem_sparseobject

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2672/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests
  2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
@ 2019-03-21  0:13   ` Chris Wilson
  2019-03-21  0:13   ` [igt-dev] " Chris Wilson
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Chris Wilson @ 2019-03-21  0:13 UTC (permalink / raw)
  To: intel-gfx; +Cc: igt-dev, Venkata, Sandeep

From: "Venkata Sandeep, Dhanalakota" <venkata.s.dhanalakota@intel.com>

Sparse object is a proxy object that can link the pages from
other objects. Typical use case are huge continuos framebuffer
that is too big to handle scanout. Sparse object can used as
any other regular object after the pages from source object
are linked.
This patch introduces igt test to exercise various usages
of the sparse object, which include:
1) read/write/mmap sparse object after it is linked to various
   source objects which have backing pages in stolen memory,
   internal memory etc.
2) Feeding sparse object to execbuf after it is linked with
   source object.

Driver changes are posted here
https://cgit.freedesktop.org/~ickle/linux-2.6/
commit/?h=wip-sparseobject&id=cdd6f93f05c6606d7d01cb0e8596e21b2e7eef04

This is still WIP gets updated.
Compile-tested only.

Signed-off-by: Venkata Sandeep, Dhanalakota <venkata.s.dhanalakota@intel.com>
---
I spent a bit of time gutting the test and run them against the actual
ioctl. Please use this as a base to rebuild the smoketests, 1:N, M:1
linkage, and consider some negative testing. Feel free to be creative!
-Chris
---
 include/drm-uapi/i915_drm.h   |  71 ++++
 lib/Makefile.sources          |   2 +
 lib/i915/gem_sparse.c         | 121 +++++++
 lib/i915/gem_sparse.h         |  35 ++
 lib/ioctl_wrappers.c          |  19 +-
 lib/ioctl_wrappers.h          |   1 +
 lib/meson.build               |   1 +
 tests/Makefile.sources        |   3 +
 tests/i915/gem_sparseobject.c | 608 ++++++++++++++++++++++++++++++++++
 tests/meson.build             |   1 +
 10 files changed, 855 insertions(+), 7 deletions(-)
 create mode 100644 lib/i915/gem_sparse.c
 create mode 100644 lib/i915/gem_sparse.h
 create mode 100644 tests/i915/gem_sparseobject.c

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index cb6d66178..3f32b3722 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -348,6 +348,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_QUERY			0x39
 #define DRM_I915_GEM_VM_CREATE		0x3a
 #define DRM_I915_GEM_VM_DESTROY		0x3b
+#define DRM_I915_GEM_SET_PAGES		0x3c
 /* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
@@ -380,6 +381,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_ENTERVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
 #define DRM_IOCTL_I915_GEM_LEAVEVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
 #define DRM_IOCTL_I915_GEM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
+#define DRM_IOCTL_I915_GEM_CREATE_EXT	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create_ext)
 #define DRM_IOCTL_I915_GEM_PREAD	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
 #define DRM_IOCTL_I915_GEM_PWRITE	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
 #define DRM_IOCTL_I915_GEM_MMAP		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
@@ -410,6 +412,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_QUERY			DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
 #define DRM_IOCTL_I915_GEM_VM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control)
 #define DRM_IOCTL_I915_GEM_VM_DESTROY	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control)
+#define DRM_IOCTL_I915_GEM_SET_PAGES	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_PAGES, struct drm_i915_gem_set_pages)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -599,6 +602,14 @@ typedef struct drm_i915_irq_wait {
  * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT.
  */
 #define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53
+
+/*
+ * Query the version of DRM_I915_GEM_CREATE supported.
+ * v0 - Initial version
+ * v1 - Adds flags and support for creating of sparse objects
+ */
+#define I915_PARAM_CREATE_VERSION	54
+
 /* Must be kept compact -- no holes and well documented */
 
 typedef struct drm_i915_getparam {
@@ -702,6 +713,25 @@ struct drm_i915_gem_create {
 	__u32 pad;
 };
 
+struct drm_i915_gem_create_ext {
+	/**
+	 * Requested size for the object.
+	 *
+	 * The (page-aligned) allocated size for the object will be returned.
+	 */
+	__u64 size;
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	__u32 handle;
+	__u32 pad;
+
+	__u64 flags;
+#define I915_GEM_CREATE_SPARSE 0x1
+};
+
 struct drm_i915_gem_pread {
 	/** Handle for the object being read. */
 	__u32 handle;
@@ -1356,6 +1386,20 @@ struct drm_i915_gem_madvise {
 	__u32 retained;
 };
 
+struct drm_i915_gem_set_pages {
+	__u32 dst_handle;
+	__u32 src_handle;
+
+	__u64 dst_offset;
+	__u64 src_offset;
+
+	__u64 dst_stride;
+	__u64 src_stride;
+
+	__u64 width;
+	__u64 height;
+};
+
 /* flags */
 #define I915_OVERLAY_TYPE_MASK 		0xff
 #define I915_OVERLAY_YUV_PLANAR 	0x01
@@ -1982,6 +2026,33 @@ struct drm_i915_query_item {
 	__u64 data_ptr;
 };
 
+struct i915_engine_hw_info_v1 {
+	__u64 flags;
+
+	__u16 uabi_class;
+	__u16 hw_class;
+	__u16 hw_id;
+	__u16 instance;
+
+	__u32 mmio_base;
+	__u32 context_size;
+
+	__u32 rsvd[10];
+};
+
+struct drm_i915_query_engine_hw_info_v1 {
+	__u32 num_engines;
+	__u32 flags;
+#define I915_QUERY_HW_INFO_HAS_HW_CLASS		(1u << 0)
+#define I915_QUERY_HW_INFO_HAS_HW_INSTANCE	(1u << 1)
+#define I915_QUERY_HW_INFO_HAS_HW_ID		(1u << 2)
+#define I915_QUERY_HW_INFO_HAS_MMIO_BASE	(1u << 3)
+#define I915_QUERY_HW_INFO_HAS_CONTEXT_SIZE	(1u << 4)
+	__u32 rsvd[14]; /* mbz */
+
+	struct i915_engine_hw_info_v1 engines[0];
+};
+
 struct drm_i915_query {
 	__u32 num_items;
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index a7074209a..aab8003e8 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -9,6 +9,8 @@ lib_source_list =	 	\
 	i915/gem_scheduler.h	\
 	i915/gem_submission.c	\
 	i915/gem_submission.h	\
+	i915/gem_sparse.h	\
+	i915/gem_sparse.c	\
 	i915/gem_ring.h	\
 	i915/gem_ring.c	\
 	i915/gem_mman.c	\
diff --git a/lib/i915/gem_sparse.c b/lib/i915/gem_sparse.c
new file mode 100644
index 000000000..0b0dc7d12
--- /dev/null
+++ b/lib/i915/gem_sparse.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "ioctl_wrappers.h"
+#include "drmtest.h"
+
+#include "gem_sparse.h"
+
+/**
+ * gem_create_sparse:
+ * @fd: open i915 drm file descriptor
+ * @size: desired size of the buffer
+ *
+ * This wraps the new GEM_CREATE ioctl, which allocates a new sparse gem buffer
+ * object of @size.
+ *
+ * Returns: The file-private handle of the created buffer object
+ */
+
+static int __gem_create_sparse(int fd, uint64_t size, uint32_t *out)
+{
+	struct drm_i915_gem_create_ext create = {
+		.size = size,
+		.flags = I915_GEM_CREATE_SPARSE,
+	};
+	int err;
+
+	if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create) == 0) {
+		*out = create.handle;
+		err = 0;
+	} else {
+		err = -errno;
+		igt_assume(err);
+	}
+
+	errno = 0;
+	return err;
+}
+
+uint32_t gem_create_sparse(int i915, uint64_t size)
+{
+	uint32_t handle = 0;
+
+	igt_assert_eq(__gem_create_sparse(i915, size, &handle), 0);
+	igt_assert(handle);
+
+	return handle;
+}
+static
+int __gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	struct drm_i915_gem_set_pages set_pages;
+	int err;
+
+	set_pages.dst_handle = dst_handle;
+	set_pages.dst_offset = dst_offset;
+	set_pages.dst_stride = dst_stride;
+	set_pages.src_handle = src_handle;
+	set_pages.src_offset = src_offset;
+	set_pages.src_stride = src_stride;
+	set_pages.width = width;
+	set_pages.height = height;
+
+	err = 0;
+	if(igt_ioctl(fd, DRM_IOCTL_I915_GEM_SET_PAGES, &set_pages))
+		err = -errno;
+	errno = 0;
+	return err;
+}
+
+/**
+ * gem_set_pages:
+ * All parameters other than fd and handles are in units of pages.
+ * @fd: open i915 drm file descriptor
+ * @dst_handle: destination sparse object handle
+ * @dst_offset: offset in destination object where mapping is done
+ * @dst_stride: destination object stride
+ * @src_handle: source object handle
+ * @src_offset: offset in the source object
+ * @src_stride: src object stride
+ * @width: width of rectangle to map
+ * @height: height of rectange to map
+ *
+ * This wraps SET_PAGES ioctl, which maps pages from src object to the
+ * destination object.
+ */
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	igt_assert_eq(__gem_set_pages(fd, dst_handle, dst_offset, dst_stride,
+				      src_handle, src_offset, src_stride,
+				      width, height), 0);
+}
diff --git a/lib/i915/gem_sparse.h b/lib/i915/gem_sparse.h
new file mode 100644
index 000000000..71b35fb60
--- /dev/null
+++ b/lib/i915/gem_sparse.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef GEM_SPARSE_H
+#define GEM_SPARSE_H
+
+#include <stdint.h>
+
+uint32_t gem_create_sparse(int i915, uint64_t size);
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height);
+
+#endif /* GEM_SPARSE_H */
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index a66eb4bc0..aa432fa9f 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -305,6 +305,17 @@ uint32_t gem_flink(int fd, uint32_t handle)
 	return flink.name;
 }
 
+int __gem_close(int fd, uint32_t handle)
+{
+	int err = 0;
+
+	if (igt_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &handle))
+		err = -errno;
+
+	errno = 0;
+	return err;
+}
+
 /**
  * gem_close:
  * @fd: open i915 drm file descriptor
@@ -315,13 +326,7 @@ uint32_t gem_flink(int fd, uint32_t handle)
  */
 void gem_close(int fd, uint32_t handle)
 {
-	struct drm_gem_close close_bo;
-
-	igt_assert_neq(handle, 0);
-
-	memset(&close_bo, 0, sizeof(close_bo));
-	close_bo.handle = handle;
-	do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+	igt_assert_eq(__gem_close(fd, handle), 0);
 }
 
 int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length)
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index ad93daffc..1361215b1 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -66,6 +66,7 @@ void gem_set_caching(int fd, uint32_t handle, uint32_t caching);
 uint32_t gem_get_caching(int fd, uint32_t handle);
 uint32_t gem_flink(int fd, uint32_t handle);
 uint32_t gem_open(int fd, uint32_t name);
+int __gem_close(int fd, uint32_t handle);
 void gem_close(int fd, uint32_t handle);
 int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length);
 void gem_write(int fd, uint32_t handle, uint64_t offset,  const void *buf, uint64_t length);
diff --git a/lib/meson.build b/lib/meson.build
index f95922330..45a6f424b 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -3,6 +3,7 @@ lib_sources = [
 	'i915/gem_context.c',
 	'i915/gem_scheduler.c',
 	'i915/gem_submission.c',
+	'i915/gem_sparse.c',
 	'i915/gem_ring.c',
 	'i915/gem_mman.c',
 	'i915/gem_vm.c',
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 8981a8ae7..cdd81cd30 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -275,6 +275,9 @@ gem_gtt_speed_SOURCES = i915/gem_gtt_speed.c
 TESTS_progs += gem_largeobject
 gem_largeobject_SOURCES = i915/gem_largeobject.c
 
+TESTS_progs += gem_sparseobject
+gem_sparseobject_SOURCES = i915/gem_sparseobject.c
+
 TESTS_progs += gem_linear_blits
 gem_linear_blits_SOURCES = i915/gem_linear_blits.c
 
diff --git a/tests/i915/gem_sparseobject.c b/tests/i915/gem_sparseobject.c
new file mode 100644
index 000000000..a063abb8d
--- /dev/null
+++ b/tests/i915/gem_sparseobject.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright © 2008 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.
+ *
+ *
+ */
+
+#include "igt.h"
+#include "i915/gem_sparse.h"
+
+#include <stdlib.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 "drm.h"
+
+IGT_TEST_DESCRIPTION("This is a test to exercise sparse object and backing it with,"
+		     " allocation of object from stolen memory and shmem.");
+
+#define OBJ_SIZE (4 * 4096)
+#define PAGE_SIZE 4096
+#define TIMEOUT 20
+#define MAX_HANDLES 4096
+#define LARGE_OBJECT_SIZE  (16 * 1024 * 1024)
+#define MAX_USRPTR 20
+
+enum mmap_type{
+	GEM_MMAP_CPU,
+	GEM_MMAP_WC,
+	GEM_MMAP_GTT,
+	GEM_MMAP_NONE
+};
+
+enum source_type {
+	UNSET,
+	SHMEM,
+	USERPTR,
+	__LAST_SOURCE__
+};
+
+void *__userptr[4096];
+
+/**
+ * mmaps on bo and returns a pointer to user
+ */
+static uint32_t gem_create_userptr(int i915, uint64_t size)
+{
+	uint32_t handle;
+	void *ptr;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, size) == 0);
+
+	gem_userptr(i915, ptr, size, 0, 0, &handle);
+
+	igt_assert(handle < ARRAY_SIZE(__userptr));
+	__userptr[handle] = ptr;
+
+	return handle;
+}
+
+static const char *source_name(enum source_type type)
+{
+	switch (type) {
+	case UNSET: return "unset";
+	case SHMEM: return "shmem";
+	case USERPTR: return "userptr";
+	default: igt_assert(0); return "unknown";
+	}
+}
+
+static uint32_t source_create(int i915, enum source_type type, uint64_t size)
+{
+	switch(type) {
+	case UNSET: return 0;
+	case SHMEM: return gem_create(i915, size);
+	case USERPTR: return gem_create_userptr(i915, size);
+	default: igt_assert(0); return 0;
+	}
+}
+
+static void source_destroy(int i915, uint32_t handle)
+{
+	if (!handle)
+		return;
+
+	gem_close(i915, handle);
+
+	free(__userptr[handle]);
+	__userptr[handle] = NULL;
+}
+
+#if 0
+static void *
+mmap_bo(int i915, uint32_t handle, enum mmap_type type)
+{
+	void *ptr;
+	switch (type) {
+	case GEM_MMAP_CPU:
+		ptr = gem_mmap__cpu(i915, handle, 0, PAGE_SIZE,
+				    PROT_READ | PROT_WRITE);
+		break;
+	case GEM_MMAP_WC:
+		ptr = gem_mmap__wc(i915, handle, 0, PAGE_SIZE,
+				   PROT_READ | PROT_WRITE);
+		break;
+	case GEM_MMAP_GTT:
+		ptr = gem_mmap__gtt(i915, handle, PAGE_SIZE,
+				    PROT_READ | PROT_WRITE);
+		break;
+	default:
+		return NULL;
+	}
+
+	return ptr;
+}
+
+static void
+fill_sources(int i915, uint32_t sources[], int size)
+{
+	for (int i = 0; i < size; i++)
+		sources[i] = source_create(i915, i, OBJ_SIZE);
+}
+
+static void
+gem_link_sources(int i915, uint32_t sparse_handle, uint32_t sources[], int sz)
+{
+	int i;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	int npages = OBJ_SIZE/PAGE_SIZE;
+
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+	while(i < sz) {
+		uint32_t ht = 0;
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		char *data;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(i915, sources[i],
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      sources[i], src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from mapped from sources */
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+		i++;
+	}
+}
+
+/*
+ * Randominly picks the source objects and links with
+ * sparse object at random offsets
+ */
+static void
+igt_gem_sparse_link_nsources(int i915)
+{
+	int size;
+	uint32_t sources[GEM_OBJ_SPARSE];
+	uint32_t sparse_handle;
+	int i;
+
+	igt_until_timeout(5 * TIMEOUT) {
+		size = rand() % GEM_OBJ_SPARSE;
+		fill_sources(i915, sources, size);
+		sparse_handle = gem_create_sparse(i915, LARGE_OBJECT_SIZE);
+		gem_link_sources(i915, sparse_handle, sources, size);
+		gem_close(i915, sparse_handle);
+		for (i = 0; i < usrcount; i++)
+			free((void *)usrptr[i]);
+		usrcount = 0;
+		for (i = 0; i < size; i++)
+			gem_close(i915, sources[i]);
+	}
+}
+
+/* Smoke test with single destination sparse object */
+static void igt_gem_sparse_smoketest_single_destination(int i915)
+{
+	uint32_t sparse_handle, src_handle;
+	int npages = OBJ_SIZE/PAGE_SIZE;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	char *data;
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	sparse_handle = gem_create_sparse(i915, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	igt_until_timeout(TIMEOUT) {
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		uint32_t ht = 0;
+
+		src_handle = gem_create(i915, OBJ_SIZE);
+		handles[count++] = src_handle;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(i915, src_handle,
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      src_handle, src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from mapped from sources */
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride * PAGE_SIZE),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+	}
+	for (i = 0; i<count; i++)
+		gem_close(i915, handles[i]);
+	gem_close(i915, sparse_handle);
+}
+
+/* sparse object smoke test with single source */
+static void igt_gem_sparse_smoketest_single_source(int i915)
+{
+	uint32_t sparse_handle, src_handle;
+	int npages = OBJ_SIZE / PAGE_SIZE;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	char *data;
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	sparse_handle = gem_create_sparse(i915, OBJ_SIZE);
+	src_handle = gem_create(i915, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	igt_until_timeout(TIMEOUT) {
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		uint32_t ht = 0;
+
+		sparse_handle = gem_create_sparse(i915, OBJ_SIZE);
+		handles[count++] = sparse_handle;
+		data = expected;
+		while (ht <= height) {
+			gem_write(i915, src_handle,
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      src_handle, src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride * PAGE_SIZE),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, (width * PAGE_SIZE) * height) == 0);
+	}
+	for (i = 0; i<count; i++)
+		gem_close(i915, handles[i]);
+	gem_close(i915, src_handle);
+}
+#endif
+
+static void igt_sparse_read(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	/* forwards */
+	if (src) {
+		for (uint32_t n = 0; n < 4; n++) {
+			gem_set_pages(i915,
+				      sparse, n, 0,
+				      src, n, 0,
+				      1, 1);
+			gem_write(i915, src, PAGE_SIZE * n, &n, sizeof(n));
+		}
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t expected = src ? n : 0;
+		uint32_t x;
+
+		gem_read(i915, sparse, PAGE_SIZE * n , &x, sizeof(x));
+		igt_assert_eq(x, expected);
+	}
+
+	if (src) {
+		for (uint32_t n = 0; n < 4; n++) {
+			gem_set_pages(i915,
+				      sparse, n, 0,
+				      src, 4 - n -1, 0,
+				      1, 1);
+			gem_write(i915, src,
+				  PAGE_SIZE * n + 1024, &n, sizeof(n));
+		}
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t expected = src ? 4 - n - 1 : 0;
+		uint32_t x;
+
+		gem_read(i915, sparse, PAGE_SIZE * n + 1024, &x, sizeof(x));
+		igt_assert_eq(x, expected);
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_write(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	/* forwards */
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = n, x;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		gem_write(i915, sparse, PAGE_SIZE * n , &ex, sizeof(ex));
+		gem_read(i915, src, PAGE_SIZE * n, &x, sizeof(x));
+
+		igt_assert_eq(x, ex);
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = 4 - n - 1, x;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, 4 - n - 1, 0,
+			      1, 1);
+
+		gem_write(i915, sparse, PAGE_SIZE * n + 1024, &ex, sizeof(ex));
+		gem_read(i915, src, PAGE_SIZE * ex + 1024, &x, sizeof(x));
+
+		igt_assert_eq(x, ex);
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_mmap(int i915, uint32_t src)
+{
+	uint32_t sparse;
+	uint32_t *ptr;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+	ptr = gem_mmap__gtt(i915, sparse, OBJ_SIZE, PROT_READ);
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = n;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		gem_write(i915, src, PAGE_SIZE * n , &ex, sizeof(ex));
+		igt_assert_eq(ptr[PAGE_SIZE * n / sizeof(*ptr)], ex);
+
+	}
+
+	munmap(ptr, OBJ_SIZE);
+	gem_close(i915, sparse);
+}
+
+static void store_dword(int i915, unsigned engine,
+			uint32_t dst, uint32_t offset,
+			uint32_t value)
+{
+	const int gen = intel_gen(intel_get_drm_devid(i915));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry reloc;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	uint32_t batch[16];
+	int i;
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	execbuf.buffers_ptr = to_user_pointer(obj);
+	execbuf.buffer_count = 2;
+	execbuf.flags = engine;
+	if (gen < 6)
+		execbuf.flags |= I915_EXEC_SECURE;
+
+	memset(obj, 0, sizeof(obj));
+	obj[0].handle = dst;
+	obj[1].handle = gem_create(i915, 4096);
+
+	memset(&reloc, 0, sizeof(reloc));
+	reloc.target_handle = obj[0].handle;
+	reloc.presumed_offset = 0;
+	reloc.offset = sizeof(uint32_t);
+	reloc.delta = offset;
+	reloc.read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc.write_domain = I915_GEM_DOMAIN_RENDER;
+	obj[1].relocs_ptr = to_user_pointer(&reloc);
+	obj[1].relocation_count = 1;
+
+	i = 0;
+	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
+	if (gen >= 8) {
+		batch[++i] = offset;
+		batch[++i] = 0;
+	} else if (gen >= 4) {
+		batch[++i] = 0;
+		batch[++i] = offset;
+		reloc.offset += sizeof(uint32_t);
+	} else {
+		batch[i]--;
+		batch[++i] = offset;
+	}
+	batch[++i] = value;
+	batch[++i] = MI_BATCH_BUFFER_END;
+	gem_write(i915, obj[1].handle, 0, batch, sizeof(batch));
+	gem_execbuf(i915, &execbuf);
+	gem_close(i915, obj[1].handle);
+}
+
+static void igt_sparse_execbuf(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	for (uint32_t n = 0; n < 4; n++) {
+		unsigned int engine;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		for_each_physical_engine(i915, engine) {
+			uint32_t ex = engine, x;
+
+			if (!gem_can_store_dword(i915, engine))
+				continue;
+
+			x = ~ex;
+			gem_write(i915, src, PAGE_SIZE * n , &x, sizeof(x));
+
+			store_dword(i915, engine, sparse, PAGE_SIZE * n, ex);
+			gem_sync(i915, sparse);
+
+			gem_read(i915, src, PAGE_SIZE * n , &x, sizeof(x));
+
+			igt_assert_eq(x, ex);
+		}
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_huge(int i915)
+{
+	uint32_t handle =
+		gem_create_sparse(i915, intel_get_total_ram_mb() << 24);
+
+	gem_set_domain(i915, handle, I915_GEM_DOMAIN_CPU, 0);
+	gem_close(i915, handle);
+}
+
+static int create_version(int i915)
+{
+	int val = 0;
+	struct drm_i915_getparam gp = {
+		gp.param = 54, /* CREATE_VERSION */
+		gp.value = &val,
+	};
+
+	ioctl(i915, DRM_IOCTL_I915_GETPARAM, &gp);
+	return val;
+}
+
+igt_main
+{
+	int i915 = -1;
+
+	igt_fixture {
+		i915 = drm_open_driver(DRIVER_INTEL);
+		igt_require_gem(i915);
+		igt_require(create_version(i915) >= 1);
+	}
+
+	igt_subtest("huge")
+		igt_sparse_huge(i915);
+
+	for (enum source_type type = UNSET; type < __LAST_SOURCE__; type++) {
+		const char *name = source_name(type);
+		uint32_t handle = 0;
+
+		igt_fixture {
+			handle = source_create(i915, type, OBJ_SIZE);
+		}
+
+		igt_subtest_f("%s-sparse-read", name)
+			igt_sparse_read(i915, handle);
+
+		igt_subtest_f("%s-sparse-write", name)
+			igt_sparse_write(i915, handle);
+
+		igt_subtest_f("%s-sparse-mmap", name)
+			igt_sparse_mmap(i915, handle);
+
+		igt_subtest_f("%s-sparse-execbuf", name)
+			igt_sparse_execbuf(i915, handle);
+
+		igt_fixture {
+			source_destroy(i915, handle);
+		}
+	}
+
+#if 0
+	igt_subtest("sparse_link_multiple_sources")
+		igt_gem_sparse_link_nsources(i915);
+
+	igt_subtest("sparse_smoke_test_single_source")
+		igt_gem_sparse_smoketest_single_source(i915);
+
+	igt_subtest("sparse_smoke_test_single_destination")
+		igt_gem_sparse_smoketest_single_destination(i915);
+#endif
+
+	igt_fixture {
+		close(i915);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 718d3eaff..e61a58dbb 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -156,6 +156,7 @@ i915_progs = [
 	'gem_gtt_hog',
 	'gem_gtt_speed',
 	'gem_largeobject',
+	'gem_sparseobject',
 	'gem_linear_blits',
 	'gem_lut_handle',
 	'gem_madvise',
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests
@ 2019-03-21  0:13   ` Chris Wilson
  0 siblings, 0 replies; 9+ messages in thread
From: Chris Wilson @ 2019-03-21  0:13 UTC (permalink / raw)
  To: intel-gfx; +Cc: igt-dev, Venkata, Sandeep

From: "Venkata Sandeep, Dhanalakota" <venkata.s.dhanalakota@intel.com>

Sparse object is a proxy object that can link the pages from
other objects. Typical use case are huge continuos framebuffer
that is too big to handle scanout. Sparse object can used as
any other regular object after the pages from source object
are linked.
This patch introduces igt test to exercise various usages
of the sparse object, which include:
1) read/write/mmap sparse object after it is linked to various
   source objects which have backing pages in stolen memory,
   internal memory etc.
2) Feeding sparse object to execbuf after it is linked with
   source object.

Driver changes are posted here
https://cgit.freedesktop.org/~ickle/linux-2.6/
commit/?h=wip-sparseobject&id=cdd6f93f05c6606d7d01cb0e8596e21b2e7eef04

This is still WIP gets updated.
Compile-tested only.

Signed-off-by: Venkata Sandeep, Dhanalakota <venkata.s.dhanalakota@intel.com>
---
I spent a bit of time gutting the test and run them against the actual
ioctl. Please use this as a base to rebuild the smoketests, 1:N, M:1
linkage, and consider some negative testing. Feel free to be creative!
-Chris
---
 include/drm-uapi/i915_drm.h   |  71 ++++
 lib/Makefile.sources          |   2 +
 lib/i915/gem_sparse.c         | 121 +++++++
 lib/i915/gem_sparse.h         |  35 ++
 lib/ioctl_wrappers.c          |  19 +-
 lib/ioctl_wrappers.h          |   1 +
 lib/meson.build               |   1 +
 tests/Makefile.sources        |   3 +
 tests/i915/gem_sparseobject.c | 608 ++++++++++++++++++++++++++++++++++
 tests/meson.build             |   1 +
 10 files changed, 855 insertions(+), 7 deletions(-)
 create mode 100644 lib/i915/gem_sparse.c
 create mode 100644 lib/i915/gem_sparse.h
 create mode 100644 tests/i915/gem_sparseobject.c

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index cb6d66178..3f32b3722 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -348,6 +348,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_QUERY			0x39
 #define DRM_I915_GEM_VM_CREATE		0x3a
 #define DRM_I915_GEM_VM_DESTROY		0x3b
+#define DRM_I915_GEM_SET_PAGES		0x3c
 /* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
@@ -380,6 +381,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_ENTERVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
 #define DRM_IOCTL_I915_GEM_LEAVEVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
 #define DRM_IOCTL_I915_GEM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
+#define DRM_IOCTL_I915_GEM_CREATE_EXT	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create_ext)
 #define DRM_IOCTL_I915_GEM_PREAD	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
 #define DRM_IOCTL_I915_GEM_PWRITE	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
 #define DRM_IOCTL_I915_GEM_MMAP		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
@@ -410,6 +412,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_QUERY			DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
 #define DRM_IOCTL_I915_GEM_VM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control)
 #define DRM_IOCTL_I915_GEM_VM_DESTROY	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control)
+#define DRM_IOCTL_I915_GEM_SET_PAGES	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_PAGES, struct drm_i915_gem_set_pages)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -599,6 +602,14 @@ typedef struct drm_i915_irq_wait {
  * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT.
  */
 #define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53
+
+/*
+ * Query the version of DRM_I915_GEM_CREATE supported.
+ * v0 - Initial version
+ * v1 - Adds flags and support for creating of sparse objects
+ */
+#define I915_PARAM_CREATE_VERSION	54
+
 /* Must be kept compact -- no holes and well documented */
 
 typedef struct drm_i915_getparam {
@@ -702,6 +713,25 @@ struct drm_i915_gem_create {
 	__u32 pad;
 };
 
+struct drm_i915_gem_create_ext {
+	/**
+	 * Requested size for the object.
+	 *
+	 * The (page-aligned) allocated size for the object will be returned.
+	 */
+	__u64 size;
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	__u32 handle;
+	__u32 pad;
+
+	__u64 flags;
+#define I915_GEM_CREATE_SPARSE 0x1
+};
+
 struct drm_i915_gem_pread {
 	/** Handle for the object being read. */
 	__u32 handle;
@@ -1356,6 +1386,20 @@ struct drm_i915_gem_madvise {
 	__u32 retained;
 };
 
+struct drm_i915_gem_set_pages {
+	__u32 dst_handle;
+	__u32 src_handle;
+
+	__u64 dst_offset;
+	__u64 src_offset;
+
+	__u64 dst_stride;
+	__u64 src_stride;
+
+	__u64 width;
+	__u64 height;
+};
+
 /* flags */
 #define I915_OVERLAY_TYPE_MASK 		0xff
 #define I915_OVERLAY_YUV_PLANAR 	0x01
@@ -1982,6 +2026,33 @@ struct drm_i915_query_item {
 	__u64 data_ptr;
 };
 
+struct i915_engine_hw_info_v1 {
+	__u64 flags;
+
+	__u16 uabi_class;
+	__u16 hw_class;
+	__u16 hw_id;
+	__u16 instance;
+
+	__u32 mmio_base;
+	__u32 context_size;
+
+	__u32 rsvd[10];
+};
+
+struct drm_i915_query_engine_hw_info_v1 {
+	__u32 num_engines;
+	__u32 flags;
+#define I915_QUERY_HW_INFO_HAS_HW_CLASS		(1u << 0)
+#define I915_QUERY_HW_INFO_HAS_HW_INSTANCE	(1u << 1)
+#define I915_QUERY_HW_INFO_HAS_HW_ID		(1u << 2)
+#define I915_QUERY_HW_INFO_HAS_MMIO_BASE	(1u << 3)
+#define I915_QUERY_HW_INFO_HAS_CONTEXT_SIZE	(1u << 4)
+	__u32 rsvd[14]; /* mbz */
+
+	struct i915_engine_hw_info_v1 engines[0];
+};
+
 struct drm_i915_query {
 	__u32 num_items;
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index a7074209a..aab8003e8 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -9,6 +9,8 @@ lib_source_list =	 	\
 	i915/gem_scheduler.h	\
 	i915/gem_submission.c	\
 	i915/gem_submission.h	\
+	i915/gem_sparse.h	\
+	i915/gem_sparse.c	\
 	i915/gem_ring.h	\
 	i915/gem_ring.c	\
 	i915/gem_mman.c	\
diff --git a/lib/i915/gem_sparse.c b/lib/i915/gem_sparse.c
new file mode 100644
index 000000000..0b0dc7d12
--- /dev/null
+++ b/lib/i915/gem_sparse.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "ioctl_wrappers.h"
+#include "drmtest.h"
+
+#include "gem_sparse.h"
+
+/**
+ * gem_create_sparse:
+ * @fd: open i915 drm file descriptor
+ * @size: desired size of the buffer
+ *
+ * This wraps the new GEM_CREATE ioctl, which allocates a new sparse gem buffer
+ * object of @size.
+ *
+ * Returns: The file-private handle of the created buffer object
+ */
+
+static int __gem_create_sparse(int fd, uint64_t size, uint32_t *out)
+{
+	struct drm_i915_gem_create_ext create = {
+		.size = size,
+		.flags = I915_GEM_CREATE_SPARSE,
+	};
+	int err;
+
+	if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create) == 0) {
+		*out = create.handle;
+		err = 0;
+	} else {
+		err = -errno;
+		igt_assume(err);
+	}
+
+	errno = 0;
+	return err;
+}
+
+uint32_t gem_create_sparse(int i915, uint64_t size)
+{
+	uint32_t handle = 0;
+
+	igt_assert_eq(__gem_create_sparse(i915, size, &handle), 0);
+	igt_assert(handle);
+
+	return handle;
+}
+static
+int __gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	struct drm_i915_gem_set_pages set_pages;
+	int err;
+
+	set_pages.dst_handle = dst_handle;
+	set_pages.dst_offset = dst_offset;
+	set_pages.dst_stride = dst_stride;
+	set_pages.src_handle = src_handle;
+	set_pages.src_offset = src_offset;
+	set_pages.src_stride = src_stride;
+	set_pages.width = width;
+	set_pages.height = height;
+
+	err = 0;
+	if(igt_ioctl(fd, DRM_IOCTL_I915_GEM_SET_PAGES, &set_pages))
+		err = -errno;
+	errno = 0;
+	return err;
+}
+
+/**
+ * gem_set_pages:
+ * All parameters other than fd and handles are in units of pages.
+ * @fd: open i915 drm file descriptor
+ * @dst_handle: destination sparse object handle
+ * @dst_offset: offset in destination object where mapping is done
+ * @dst_stride: destination object stride
+ * @src_handle: source object handle
+ * @src_offset: offset in the source object
+ * @src_stride: src object stride
+ * @width: width of rectangle to map
+ * @height: height of rectange to map
+ *
+ * This wraps SET_PAGES ioctl, which maps pages from src object to the
+ * destination object.
+ */
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	igt_assert_eq(__gem_set_pages(fd, dst_handle, dst_offset, dst_stride,
+				      src_handle, src_offset, src_stride,
+				      width, height), 0);
+}
diff --git a/lib/i915/gem_sparse.h b/lib/i915/gem_sparse.h
new file mode 100644
index 000000000..71b35fb60
--- /dev/null
+++ b/lib/i915/gem_sparse.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef GEM_SPARSE_H
+#define GEM_SPARSE_H
+
+#include <stdint.h>
+
+uint32_t gem_create_sparse(int i915, uint64_t size);
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height);
+
+#endif /* GEM_SPARSE_H */
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index a66eb4bc0..aa432fa9f 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -305,6 +305,17 @@ uint32_t gem_flink(int fd, uint32_t handle)
 	return flink.name;
 }
 
+int __gem_close(int fd, uint32_t handle)
+{
+	int err = 0;
+
+	if (igt_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &handle))
+		err = -errno;
+
+	errno = 0;
+	return err;
+}
+
 /**
  * gem_close:
  * @fd: open i915 drm file descriptor
@@ -315,13 +326,7 @@ uint32_t gem_flink(int fd, uint32_t handle)
  */
 void gem_close(int fd, uint32_t handle)
 {
-	struct drm_gem_close close_bo;
-
-	igt_assert_neq(handle, 0);
-
-	memset(&close_bo, 0, sizeof(close_bo));
-	close_bo.handle = handle;
-	do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+	igt_assert_eq(__gem_close(fd, handle), 0);
 }
 
 int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length)
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index ad93daffc..1361215b1 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -66,6 +66,7 @@ void gem_set_caching(int fd, uint32_t handle, uint32_t caching);
 uint32_t gem_get_caching(int fd, uint32_t handle);
 uint32_t gem_flink(int fd, uint32_t handle);
 uint32_t gem_open(int fd, uint32_t name);
+int __gem_close(int fd, uint32_t handle);
 void gem_close(int fd, uint32_t handle);
 int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length);
 void gem_write(int fd, uint32_t handle, uint64_t offset,  const void *buf, uint64_t length);
diff --git a/lib/meson.build b/lib/meson.build
index f95922330..45a6f424b 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -3,6 +3,7 @@ lib_sources = [
 	'i915/gem_context.c',
 	'i915/gem_scheduler.c',
 	'i915/gem_submission.c',
+	'i915/gem_sparse.c',
 	'i915/gem_ring.c',
 	'i915/gem_mman.c',
 	'i915/gem_vm.c',
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 8981a8ae7..cdd81cd30 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -275,6 +275,9 @@ gem_gtt_speed_SOURCES = i915/gem_gtt_speed.c
 TESTS_progs += gem_largeobject
 gem_largeobject_SOURCES = i915/gem_largeobject.c
 
+TESTS_progs += gem_sparseobject
+gem_sparseobject_SOURCES = i915/gem_sparseobject.c
+
 TESTS_progs += gem_linear_blits
 gem_linear_blits_SOURCES = i915/gem_linear_blits.c
 
diff --git a/tests/i915/gem_sparseobject.c b/tests/i915/gem_sparseobject.c
new file mode 100644
index 000000000..a063abb8d
--- /dev/null
+++ b/tests/i915/gem_sparseobject.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright © 2008 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.
+ *
+ *
+ */
+
+#include "igt.h"
+#include "i915/gem_sparse.h"
+
+#include <stdlib.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 "drm.h"
+
+IGT_TEST_DESCRIPTION("This is a test to exercise sparse object and backing it with,"
+		     " allocation of object from stolen memory and shmem.");
+
+#define OBJ_SIZE (4 * 4096)
+#define PAGE_SIZE 4096
+#define TIMEOUT 20
+#define MAX_HANDLES 4096
+#define LARGE_OBJECT_SIZE  (16 * 1024 * 1024)
+#define MAX_USRPTR 20
+
+enum mmap_type{
+	GEM_MMAP_CPU,
+	GEM_MMAP_WC,
+	GEM_MMAP_GTT,
+	GEM_MMAP_NONE
+};
+
+enum source_type {
+	UNSET,
+	SHMEM,
+	USERPTR,
+	__LAST_SOURCE__
+};
+
+void *__userptr[4096];
+
+/**
+ * mmaps on bo and returns a pointer to user
+ */
+static uint32_t gem_create_userptr(int i915, uint64_t size)
+{
+	uint32_t handle;
+	void *ptr;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, size) == 0);
+
+	gem_userptr(i915, ptr, size, 0, 0, &handle);
+
+	igt_assert(handle < ARRAY_SIZE(__userptr));
+	__userptr[handle] = ptr;
+
+	return handle;
+}
+
+static const char *source_name(enum source_type type)
+{
+	switch (type) {
+	case UNSET: return "unset";
+	case SHMEM: return "shmem";
+	case USERPTR: return "userptr";
+	default: igt_assert(0); return "unknown";
+	}
+}
+
+static uint32_t source_create(int i915, enum source_type type, uint64_t size)
+{
+	switch(type) {
+	case UNSET: return 0;
+	case SHMEM: return gem_create(i915, size);
+	case USERPTR: return gem_create_userptr(i915, size);
+	default: igt_assert(0); return 0;
+	}
+}
+
+static void source_destroy(int i915, uint32_t handle)
+{
+	if (!handle)
+		return;
+
+	gem_close(i915, handle);
+
+	free(__userptr[handle]);
+	__userptr[handle] = NULL;
+}
+
+#if 0
+static void *
+mmap_bo(int i915, uint32_t handle, enum mmap_type type)
+{
+	void *ptr;
+	switch (type) {
+	case GEM_MMAP_CPU:
+		ptr = gem_mmap__cpu(i915, handle, 0, PAGE_SIZE,
+				    PROT_READ | PROT_WRITE);
+		break;
+	case GEM_MMAP_WC:
+		ptr = gem_mmap__wc(i915, handle, 0, PAGE_SIZE,
+				   PROT_READ | PROT_WRITE);
+		break;
+	case GEM_MMAP_GTT:
+		ptr = gem_mmap__gtt(i915, handle, PAGE_SIZE,
+				    PROT_READ | PROT_WRITE);
+		break;
+	default:
+		return NULL;
+	}
+
+	return ptr;
+}
+
+static void
+fill_sources(int i915, uint32_t sources[], int size)
+{
+	for (int i = 0; i < size; i++)
+		sources[i] = source_create(i915, i, OBJ_SIZE);
+}
+
+static void
+gem_link_sources(int i915, uint32_t sparse_handle, uint32_t sources[], int sz)
+{
+	int i;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	int npages = OBJ_SIZE/PAGE_SIZE;
+
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+	while(i < sz) {
+		uint32_t ht = 0;
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		char *data;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(i915, sources[i],
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      sources[i], src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from mapped from sources */
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+		i++;
+	}
+}
+
+/*
+ * Randominly picks the source objects and links with
+ * sparse object at random offsets
+ */
+static void
+igt_gem_sparse_link_nsources(int i915)
+{
+	int size;
+	uint32_t sources[GEM_OBJ_SPARSE];
+	uint32_t sparse_handle;
+	int i;
+
+	igt_until_timeout(5 * TIMEOUT) {
+		size = rand() % GEM_OBJ_SPARSE;
+		fill_sources(i915, sources, size);
+		sparse_handle = gem_create_sparse(i915, LARGE_OBJECT_SIZE);
+		gem_link_sources(i915, sparse_handle, sources, size);
+		gem_close(i915, sparse_handle);
+		for (i = 0; i < usrcount; i++)
+			free((void *)usrptr[i]);
+		usrcount = 0;
+		for (i = 0; i < size; i++)
+			gem_close(i915, sources[i]);
+	}
+}
+
+/* Smoke test with single destination sparse object */
+static void igt_gem_sparse_smoketest_single_destination(int i915)
+{
+	uint32_t sparse_handle, src_handle;
+	int npages = OBJ_SIZE/PAGE_SIZE;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	char *data;
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	sparse_handle = gem_create_sparse(i915, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	igt_until_timeout(TIMEOUT) {
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		uint32_t ht = 0;
+
+		src_handle = gem_create(i915, OBJ_SIZE);
+		handles[count++] = src_handle;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(i915, src_handle,
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      src_handle, src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from mapped from sources */
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride * PAGE_SIZE),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+	}
+	for (i = 0; i<count; i++)
+		gem_close(i915, handles[i]);
+	gem_close(i915, sparse_handle);
+}
+
+/* sparse object smoke test with single source */
+static void igt_gem_sparse_smoketest_single_source(int i915)
+{
+	uint32_t sparse_handle, src_handle;
+	int npages = OBJ_SIZE / PAGE_SIZE;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	char *data;
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	sparse_handle = gem_create_sparse(i915, OBJ_SIZE);
+	src_handle = gem_create(i915, OBJ_SIZE);
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+
+	igt_until_timeout(TIMEOUT) {
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		uint32_t ht = 0;
+
+		sparse_handle = gem_create_sparse(i915, OBJ_SIZE);
+		handles[count++] = sparse_handle;
+		data = expected;
+		while (ht <= height) {
+			gem_write(i915, src_handle,
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      src_handle, src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride * PAGE_SIZE),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, (width * PAGE_SIZE) * height) == 0);
+	}
+	for (i = 0; i<count; i++)
+		gem_close(i915, handles[i]);
+	gem_close(i915, src_handle);
+}
+#endif
+
+static void igt_sparse_read(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	/* forwards */
+	if (src) {
+		for (uint32_t n = 0; n < 4; n++) {
+			gem_set_pages(i915,
+				      sparse, n, 0,
+				      src, n, 0,
+				      1, 1);
+			gem_write(i915, src, PAGE_SIZE * n, &n, sizeof(n));
+		}
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t expected = src ? n : 0;
+		uint32_t x;
+
+		gem_read(i915, sparse, PAGE_SIZE * n , &x, sizeof(x));
+		igt_assert_eq(x, expected);
+	}
+
+	if (src) {
+		for (uint32_t n = 0; n < 4; n++) {
+			gem_set_pages(i915,
+				      sparse, n, 0,
+				      src, 4 - n -1, 0,
+				      1, 1);
+			gem_write(i915, src,
+				  PAGE_SIZE * n + 1024, &n, sizeof(n));
+		}
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t expected = src ? 4 - n - 1 : 0;
+		uint32_t x;
+
+		gem_read(i915, sparse, PAGE_SIZE * n + 1024, &x, sizeof(x));
+		igt_assert_eq(x, expected);
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_write(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	/* forwards */
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = n, x;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		gem_write(i915, sparse, PAGE_SIZE * n , &ex, sizeof(ex));
+		gem_read(i915, src, PAGE_SIZE * n, &x, sizeof(x));
+
+		igt_assert_eq(x, ex);
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = 4 - n - 1, x;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, 4 - n - 1, 0,
+			      1, 1);
+
+		gem_write(i915, sparse, PAGE_SIZE * n + 1024, &ex, sizeof(ex));
+		gem_read(i915, src, PAGE_SIZE * ex + 1024, &x, sizeof(x));
+
+		igt_assert_eq(x, ex);
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_mmap(int i915, uint32_t src)
+{
+	uint32_t sparse;
+	uint32_t *ptr;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+	ptr = gem_mmap__gtt(i915, sparse, OBJ_SIZE, PROT_READ);
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = n;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		gem_write(i915, src, PAGE_SIZE * n , &ex, sizeof(ex));
+		igt_assert_eq(ptr[PAGE_SIZE * n / sizeof(*ptr)], ex);
+
+	}
+
+	munmap(ptr, OBJ_SIZE);
+	gem_close(i915, sparse);
+}
+
+static void store_dword(int i915, unsigned engine,
+			uint32_t dst, uint32_t offset,
+			uint32_t value)
+{
+	const int gen = intel_gen(intel_get_drm_devid(i915));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry reloc;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	uint32_t batch[16];
+	int i;
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	execbuf.buffers_ptr = to_user_pointer(obj);
+	execbuf.buffer_count = 2;
+	execbuf.flags = engine;
+	if (gen < 6)
+		execbuf.flags |= I915_EXEC_SECURE;
+
+	memset(obj, 0, sizeof(obj));
+	obj[0].handle = dst;
+	obj[1].handle = gem_create(i915, 4096);
+
+	memset(&reloc, 0, sizeof(reloc));
+	reloc.target_handle = obj[0].handle;
+	reloc.presumed_offset = 0;
+	reloc.offset = sizeof(uint32_t);
+	reloc.delta = offset;
+	reloc.read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc.write_domain = I915_GEM_DOMAIN_RENDER;
+	obj[1].relocs_ptr = to_user_pointer(&reloc);
+	obj[1].relocation_count = 1;
+
+	i = 0;
+	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
+	if (gen >= 8) {
+		batch[++i] = offset;
+		batch[++i] = 0;
+	} else if (gen >= 4) {
+		batch[++i] = 0;
+		batch[++i] = offset;
+		reloc.offset += sizeof(uint32_t);
+	} else {
+		batch[i]--;
+		batch[++i] = offset;
+	}
+	batch[++i] = value;
+	batch[++i] = MI_BATCH_BUFFER_END;
+	gem_write(i915, obj[1].handle, 0, batch, sizeof(batch));
+	gem_execbuf(i915, &execbuf);
+	gem_close(i915, obj[1].handle);
+}
+
+static void igt_sparse_execbuf(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	for (uint32_t n = 0; n < 4; n++) {
+		unsigned int engine;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		for_each_physical_engine(i915, engine) {
+			uint32_t ex = engine, x;
+
+			if (!gem_can_store_dword(i915, engine))
+				continue;
+
+			x = ~ex;
+			gem_write(i915, src, PAGE_SIZE * n , &x, sizeof(x));
+
+			store_dword(i915, engine, sparse, PAGE_SIZE * n, ex);
+			gem_sync(i915, sparse);
+
+			gem_read(i915, src, PAGE_SIZE * n , &x, sizeof(x));
+
+			igt_assert_eq(x, ex);
+		}
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_huge(int i915)
+{
+	uint32_t handle =
+		gem_create_sparse(i915, intel_get_total_ram_mb() << 24);
+
+	gem_set_domain(i915, handle, I915_GEM_DOMAIN_CPU, 0);
+	gem_close(i915, handle);
+}
+
+static int create_version(int i915)
+{
+	int val = 0;
+	struct drm_i915_getparam gp = {
+		gp.param = 54, /* CREATE_VERSION */
+		gp.value = &val,
+	};
+
+	ioctl(i915, DRM_IOCTL_I915_GETPARAM, &gp);
+	return val;
+}
+
+igt_main
+{
+	int i915 = -1;
+
+	igt_fixture {
+		i915 = drm_open_driver(DRIVER_INTEL);
+		igt_require_gem(i915);
+		igt_require(create_version(i915) >= 1);
+	}
+
+	igt_subtest("huge")
+		igt_sparse_huge(i915);
+
+	for (enum source_type type = UNSET; type < __LAST_SOURCE__; type++) {
+		const char *name = source_name(type);
+		uint32_t handle = 0;
+
+		igt_fixture {
+			handle = source_create(i915, type, OBJ_SIZE);
+		}
+
+		igt_subtest_f("%s-sparse-read", name)
+			igt_sparse_read(i915, handle);
+
+		igt_subtest_f("%s-sparse-write", name)
+			igt_sparse_write(i915, handle);
+
+		igt_subtest_f("%s-sparse-mmap", name)
+			igt_sparse_mmap(i915, handle);
+
+		igt_subtest_f("%s-sparse-execbuf", name)
+			igt_sparse_execbuf(i915, handle);
+
+		igt_fixture {
+			source_destroy(i915, handle);
+		}
+	}
+
+#if 0
+	igt_subtest("sparse_link_multiple_sources")
+		igt_gem_sparse_link_nsources(i915);
+
+	igt_subtest("sparse_smoke_test_single_source")
+		igt_gem_sparse_smoketest_single_source(i915);
+
+	igt_subtest("sparse_smoke_test_single_destination")
+		igt_gem_sparse_smoketest_single_destination(i915);
+#endif
+
+	igt_fixture {
+		close(i915);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 718d3eaff..e61a58dbb 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -156,6 +156,7 @@ i915_progs = [
 	'gem_gtt_hog',
 	'gem_gtt_speed',
 	'gem_largeobject',
+	'gem_sparseobject',
 	'gem_linear_blits',
 	'gem_lut_handle',
 	'gem_madvise',
-- 
2.20.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [igt-dev] ✗ Fi.CI.BAT: failure for i915/gem_sparseobject: Add sparse object IGT tests (rev2)
  2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
  2019-03-20 21:41 ` [igt-dev] ✓ Fi.CI.BAT: success for " Patchwork
  2019-03-21  0:13   ` [igt-dev] " Chris Wilson
@ 2019-03-21  1:10 ` Patchwork
  2019-03-21  5:14 ` [igt-dev] ✓ Fi.CI.IGT: success for i915/gem_sparseobject: Add sparse object IGT tests Patchwork
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Patchwork @ 2019-03-21  1:10 UTC (permalink / raw)
  To: Chris Wilson; +Cc: igt-dev

== Series Details ==

Series: i915/gem_sparseobject: Add sparse object IGT tests (rev2)
URL   : https://patchwork.freedesktop.org/series/58290/
State : failure

== Summary ==

Applying: i915/gem_sparseobject: Add sparse object IGT tests
Using index info to reconstruct a base tree...
M	include/drm-uapi/i915_drm.h
M	lib/Makefile.sources
M	lib/meson.build
M	tests/Makefile.sources
M	tests/meson.build
Falling back to patching base and 3-way merge...
Auto-merging tests/meson.build
Auto-merging tests/Makefile.sources
Auto-merging lib/meson.build
Auto-merging lib/Makefile.sources
Auto-merging include/drm-uapi/i915_drm.h
CONFLICT (content): Merge conflict in include/drm-uapi/i915_drm.h
Patch failed at 0001 i915/gem_sparseobject: Add sparse object IGT tests
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [igt-dev] ✓ Fi.CI.IGT: success for i915/gem_sparseobject: Add sparse object IGT tests
  2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
                   ` (2 preceding siblings ...)
  2019-03-21  1:10 ` [igt-dev] ✗ Fi.CI.BAT: failure for i915/gem_sparseobject: Add sparse object IGT tests (rev2) Patchwork
@ 2019-03-21  5:14 ` Patchwork
  2019-03-22 15:10 ` [igt-dev] ✓ Fi.CI.BAT: success for i915/gem_sparseobject: Add sparse object IGT tests (rev3) Patchwork
  2019-03-23 14:17 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  5 siblings, 0 replies; 9+ messages in thread
From: Patchwork @ 2019-03-21  5:14 UTC (permalink / raw)
  To: Chris Wilson; +Cc: igt-dev

== Series Details ==

Series: i915/gem_sparseobject: Add sparse object IGT tests
URL   : https://patchwork.freedesktop.org/series/58290/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5784_full -> IGTPW_2672_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/58290/revisions/1/mbox/

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in IGTPW_2672_full:

### IGT changes ###

#### Possible regressions ####

  * {igt@gem_sparseobject} (NEW):
    - shard-glk:          NOTRUN -> FAIL
    - shard-apl:          NOTRUN -> FAIL
    - shard-snb:          NOTRUN -> FAIL
    - shard-kbl:          NOTRUN -> FAIL
    - shard-hsw:          NOTRUN -> FAIL

  
New tests
---------

  New tests have been introduced between CI_DRM_5784_full and IGTPW_2672_full:

### New IGT tests (1) ###

  * igt@gem_sparseobject:
    - Statuses : 5 fail(s)
    - Exec time: [0.06, 0.14] s

  

Known issues
------------

  Here are the changes found in IGTPW_2672_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@kms_atomic_transition@3x-modeset-transitions:
    - shard-glk:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_atomic_transition@plane-all-modeset-transition:
    - shard-apl:          PASS -> INCOMPLETE [fdo#103927]

  * igt@kms_busy@extended-pageflip-hang-newfb-render-b:
    - shard-glk:          NOTRUN -> DMESG-WARN [fdo#107956]

  * igt@kms_busy@extended-pageflip-modeset-hang-oldfb-render-a:
    - shard-kbl:          PASS -> DMESG-WARN [fdo#107956] +2

  * igt@kms_concurrent@pipe-f:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_cursor_crc@cursor-64x21-onscreen:
    - shard-kbl:          PASS -> FAIL [fdo#103232] +1
    - shard-apl:          PASS -> FAIL [fdo#103232] +1

  * igt@kms_cursor_legacy@2x-long-cursor-vs-flip-legacy:
    - shard-hsw:          PASS -> FAIL [fdo#105767]

  * igt@kms_draw_crc@draw-method-rgb565-mmap-wc-xtiled:
    - shard-glk:          PASS -> FAIL [fdo#103184]

  * igt@kms_flip@2x-modeset-vs-vblank-race-interruptible:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271]

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-pwrite:
    - shard-glk:          NOTRUN -> SKIP [fdo#109271] +16

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-mmap-gtt:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] +5

  * igt@kms_plane_scaling@pipe-a-scaler-with-clipping-clamping:
    - shard-glk:          PASS -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_vblank@pipe-c-ts-continuation-modeset-rpm:
    - shard-kbl:          PASS -> FAIL [fdo#104894]
    - shard-apl:          PASS -> FAIL [fdo#104894]

  
#### Possible fixes ####

  * igt@i915_pm_rps@waitboost:
    - shard-hsw:          FAIL -> PASS

  * igt@kms_busy@extended-modeset-hang-newfb-render-c:
    - shard-hsw:          DMESG-WARN [fdo#107956] -> PASS

  * igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-b:
    - shard-kbl:          DMESG-WARN [fdo#107956] -> PASS

  * {igt@kms_plane@pixel-format-pipe-a-planes}:
    - shard-glk:          SKIP [fdo#109271] -> PASS

  * igt@kms_plane_alpha_blend@pipe-c-constant-alpha-max:
    - shard-glk:          FAIL [fdo#108145] -> PASS

  * igt@kms_rotation_crc@multiplane-rotation:
    - shard-kbl:          DMESG-FAIL [fdo#105763] -> PASS

  * igt@kms_setmode@basic:
    - shard-apl:          FAIL [fdo#99912] -> PASS

  
#### Warnings ####

  * igt@kms_plane_scaling@pipe-c-scaler-with-rotation:
    - shard-glk:          FAIL [fdo#110098] -> SKIP [fdo#109271] / [fdo#109278] +1

  * igt@kms_rotation_crc@multiplane-rotation-cropping-bottom:
    - shard-kbl:          FAIL [fdo#109016] -> DMESG-FAIL [fdo#105763]

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#103184]: https://bugs.freedesktop.org/show_bug.cgi?id=103184
  [fdo#103232]: https://bugs.freedesktop.org/show_bug.cgi?id=103232
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#104894]: https://bugs.freedesktop.org/show_bug.cgi?id=104894
  [fdo#105763]: https://bugs.freedesktop.org/show_bug.cgi?id=105763
  [fdo#105767]: https://bugs.freedesktop.org/show_bug.cgi?id=105767
  [fdo#107956]: https://bugs.freedesktop.org/show_bug.cgi?id=107956
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#109016]: https://bugs.freedesktop.org/show_bug.cgi?id=109016
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#110098]: https://bugs.freedesktop.org/show_bug.cgi?id=110098
  [fdo#99912]: https://bugs.freedesktop.org/show_bug.cgi?id=99912


Participating hosts (10 -> 5)
------------------------------

  Missing    (5): shard-skl pig-hsw-4770r pig-glk-j5005 shard-iclb pig-skl-6260u 


Build changes
-------------

    * IGT: IGT_4894 -> IGTPW_2672
    * Piglit: piglit_4509 -> None

  CI_DRM_5784: 7f9065d7aaa6abe9bc07e3694a8f3e2d5a91eebe @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2672: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2672/
  IGT_4894: fedd92f4022837e2c20e472b65bd7d0849f484a3 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2672/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests
  2019-03-21  0:13   ` [igt-dev] " Chris Wilson
  (?)
@ 2019-03-22 14:09   ` Venkata Sandeep Dhanalakota
  -1 siblings, 0 replies; 9+ messages in thread
From: Venkata Sandeep Dhanalakota @ 2019-03-22 14:09 UTC (permalink / raw)
  To: igt-dev

Sparse object is a proxy object that can link the pages from
other objects. Typical use case are huge continuos framebuffer
that is too big to handle scanout. Sparse object can used as
any other regular object after the pages from source object
are linked.
This patch introduces igt test to exercise various usages
of the sparse object, which include:
1) read/write/mmap sparse object after it is linked to various
   source objects which have backing pages in stolen memory,
   internal memory etc.
2) Feeding sparse object to execbuf after it is linked with
   source object.

Driver changes are posted here
https://cgit.freedesktop.org/~ickle/linux-2.6/
commit/?h=wip-sparseobject&id=cdd6f93f05c6606d7d01cb0e8596e21b2e7eef04

This is still WIP gets updated.
Compile-tested only.

Signed-off-by: Venkata Sandeep, Dhanalakota <venkata.s.dhanalakota@intel.com>
---
 include/drm-uapi/i915_drm.h   |  42 +++
 lib/Makefile.sources          |   2 +
 lib/i915/gem_sparse.c         | 121 +++++++
 lib/i915/gem_sparse.h         |  39 +++
 lib/ioctl_wrappers.c          |  19 +-
 lib/ioctl_wrappers.h          |   1 +
 lib/meson.build               |   1 +
 tests/Makefile.sources        |   3 +
 tests/i915/gem_sparseobject.c | 615 ++++++++++++++++++++++++++++++++++
 tests/meson.build             |   1 +
 10 files changed, 837 insertions(+), 7 deletions(-)
 create mode 100644 lib/i915/gem_sparse.c
 create mode 100644 lib/i915/gem_sparse.h
 create mode 100644 tests/i915/gem_sparseobject.c

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index 4ae1c6ff..3f614c85 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -321,6 +321,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_PERF_ADD_CONFIG	0x37
 #define DRM_I915_PERF_REMOVE_CONFIG	0x38
 #define DRM_I915_QUERY			0x39
+#define DRM_I915_GEM_SET_PAGES         0x3a
 /* Must be kept compact -- no holes */
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
@@ -353,6 +354,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_ENTERVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
 #define DRM_IOCTL_I915_GEM_LEAVEVT	DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
 #define DRM_IOCTL_I915_GEM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
+#define DRM_IOCTL_I915_GEM_CREATE_EXT	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create_ext)
 #define DRM_IOCTL_I915_GEM_PREAD	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
 #define DRM_IOCTL_I915_GEM_PWRITE	DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
 #define DRM_IOCTL_I915_GEM_MMAP		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
@@ -380,6 +382,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_PERF_ADD_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
 #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
 #define DRM_IOCTL_I915_QUERY			DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
+#define DRM_IOCTL_I915_GEM_SET_PAGES   DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_PAGES, struct drm_i915_gem_set_pages)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -563,6 +566,12 @@ typedef struct drm_i915_irq_wait {
  */
 #define I915_PARAM_MMAP_GTT_COHERENT	52
 
+/*
+ * Query the version of DRM_I915_GEM_CREATE supported.
+ * v0 - Initial version
+ * v1 - Adds flags and support for creating of sparse objects
+ */
+#define I915_PARAM_CREATE_VERSION      53
 /* Must be kept compact -- no holes and well documented */
 
 typedef struct drm_i915_getparam {
@@ -666,6 +675,25 @@ struct drm_i915_gem_create {
 	__u32 pad;
 };
 
+struct drm_i915_gem_create_ext {
+	/**
+	 * Requested size for the object.
+	 *
+	 * The (page-aligned) allocated size for the object will be returned.
+	 */
+	__u64 size;
+	/**
+	 * Returned handle for the object.
+	 *
+	 * Object handles are nonzero.
+	 */
+	__u32 handle;
+	__u32 pad;
+
+	__u64 flags;
+#define I915_GEM_CREATE_SPARSE 0x1
+};
+
 struct drm_i915_gem_pread {
 	/** Handle for the object being read. */
 	__u32 handle;
@@ -1311,6 +1339,20 @@ struct drm_i915_gem_madvise {
 	__u32 retained;
 };
 
+struct drm_i915_gem_set_pages {
+	__u32 dst_handle;
+	__u32 src_handle;
+
+	__u64 dst_offset;
+	__u64 src_offset;
+
+	__u64 dst_stride;
+	__u64 src_stride;
+
+	__u64 width;
+	__u64 height;
+};
+
 /* flags */
 #define I915_OVERLAY_TYPE_MASK 		0xff
 #define I915_OVERLAY_YUV_PLANAR 	0x01
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index cf272098..32d51529 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -9,6 +9,8 @@ lib_source_list =	 	\
 	i915/gem_scheduler.h	\
 	i915/gem_submission.c	\
 	i915/gem_submission.h	\
+	i915/gem_sparse.h	\
+	i915/gem_sparse.c	\
 	i915/gem_ring.h	\
 	i915/gem_ring.c	\
 	i915/gem_mman.c	\
diff --git a/lib/i915/gem_sparse.c b/lib/i915/gem_sparse.c
new file mode 100644
index 00000000..8f2a8a84
--- /dev/null
+++ b/lib/i915/gem_sparse.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "ioctl_wrappers.h"
+#include "drmtest.h"
+
+#include "gem_sparse.h"
+
+/**
+ * gem_create_sparse:
+ * @fd: open i915 drm file descriptor
+ * @size: desired size of the buffer
+ *
+ * This wraps the new GEM_CREATE ioctl, which allocates a new sparse gem buffer
+ * object of @size.
+ *
+ * Returns: The file-private handle of the created buffer object
+ */
+
+static int __gem_create_sparse(int fd, uint64_t size, uint32_t *out)
+{
+	struct drm_i915_gem_create_ext create = {
+		.size = size,
+		.flags = I915_GEM_CREATE_SPARSE,
+	};
+	int err;
+
+	if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create) == 0) {
+		*out = create.handle;
+		err = 0;
+	} else {
+		err = -errno;
+		igt_assume(err);
+	}
+
+	errno = 0;
+	return err;
+}
+
+uint32_t gem_create_sparse(int i915, uint64_t size)
+{
+	uint32_t handle = 0;
+
+	igt_assert_eq(__gem_create_sparse(i915, size, &handle), 0);
+	igt_assert(handle);
+
+	return handle;
+}
+
+int __gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	struct drm_i915_gem_set_pages set_pages;
+	int err;
+
+	set_pages.dst_handle = dst_handle;
+	set_pages.dst_offset = dst_offset;
+	set_pages.dst_stride = dst_stride;
+	set_pages.src_handle = src_handle;
+	set_pages.src_offset = src_offset;
+	set_pages.src_stride = src_stride;
+	set_pages.width = width;
+	set_pages.height = height;
+
+	err = 0;
+	if(igt_ioctl(fd, DRM_IOCTL_I915_GEM_SET_PAGES, &set_pages))
+		err = -errno;
+	errno = 0;
+	return err;
+}
+
+/**
+ * gem_set_pages:
+ * All parameters other than fd and handles are in units of pages.
+ * @fd: open i915 drm file descriptor
+ * @dst_handle: destination sparse object handle
+ * @dst_offset: offset in destination object where mapping is done
+ * @dst_stride: destination object stride
+ * @src_handle: source object handle
+ * @src_offset: offset in the source object
+ * @src_stride: src object stride
+ * @width: width of rectangle to map
+ * @height: height of rectange to map
+ *
+ * This wraps SET_PAGES ioctl, which maps pages from src object to the
+ * destination object.
+ */
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height)
+{
+	igt_assert_eq(__gem_set_pages(fd, dst_handle, dst_offset, dst_stride,
+				      src_handle, src_offset, src_stride,
+				      width, height), 0);
+}
diff --git a/lib/i915/gem_sparse.h b/lib/i915/gem_sparse.h
new file mode 100644
index 00000000..3248becf
--- /dev/null
+++ b/lib/i915/gem_sparse.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2017 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.
+ */
+
+#ifndef GEM_SPARSE_H
+#define GEM_SPARSE_H
+
+#include <stdint.h>
+
+uint32_t gem_create_sparse(int i915, uint64_t size);
+void gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height);
+
+int __gem_set_pages(int fd, uint32_t dst_handle, uint32_t dst_offset,
+		  uint32_t dst_stride, uint32_t src_handle,
+		  uint32_t src_offset, uint32_t src_stride,
+		  uint32_t width, uint32_t height);
+#endif /* GEM_SPARSE_H */
diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c
index a66eb4bc..aa432fa9 100644
--- a/lib/ioctl_wrappers.c
+++ b/lib/ioctl_wrappers.c
@@ -305,6 +305,17 @@ uint32_t gem_flink(int fd, uint32_t handle)
 	return flink.name;
 }
 
+int __gem_close(int fd, uint32_t handle)
+{
+	int err = 0;
+
+	if (igt_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &handle))
+		err = -errno;
+
+	errno = 0;
+	return err;
+}
+
 /**
  * gem_close:
  * @fd: open i915 drm file descriptor
@@ -315,13 +326,7 @@ uint32_t gem_flink(int fd, uint32_t handle)
  */
 void gem_close(int fd, uint32_t handle)
 {
-	struct drm_gem_close close_bo;
-
-	igt_assert_neq(handle, 0);
-
-	memset(&close_bo, 0, sizeof(close_bo));
-	close_bo.handle = handle;
-	do_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+	igt_assert_eq(__gem_close(fd, handle), 0);
 }
 
 int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length)
diff --git a/lib/ioctl_wrappers.h b/lib/ioctl_wrappers.h
index ad93daff..1361215b 100644
--- a/lib/ioctl_wrappers.h
+++ b/lib/ioctl_wrappers.h
@@ -66,6 +66,7 @@ void gem_set_caching(int fd, uint32_t handle, uint32_t caching);
 uint32_t gem_get_caching(int fd, uint32_t handle);
 uint32_t gem_flink(int fd, uint32_t handle);
 uint32_t gem_open(int fd, uint32_t name);
+int __gem_close(int fd, uint32_t handle);
 void gem_close(int fd, uint32_t handle);
 int __gem_write(int fd, uint32_t handle, uint64_t offset, const void *buf, uint64_t length);
 void gem_write(int fd, uint32_t handle, uint64_t offset,  const void *buf, uint64_t length);
diff --git a/lib/meson.build b/lib/meson.build
index 0eb5585d..7baefa2c 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -3,6 +3,7 @@ lib_sources = [
 	'i915/gem_context.c',
 	'i915/gem_scheduler.c',
 	'i915/gem_submission.c',
+	'i915/gem_sparse.c',
 	'i915/gem_ring.c',
 	'i915/gem_mman.c',
 	'igt_color_encoding.c',
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 71ccf00a..96233a8b 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -270,6 +270,9 @@ gem_gtt_speed_SOURCES = i915/gem_gtt_speed.c
 TESTS_progs += gem_largeobject
 gem_largeobject_SOURCES = i915/gem_largeobject.c
 
+TESTS_progs += gem_sparseobject
+gem_sparseobject_SOURCES = i915/gem_sparseobject.c
+
 TESTS_progs += gem_linear_blits
 gem_linear_blits_SOURCES = i915/gem_linear_blits.c
 
diff --git a/tests/i915/gem_sparseobject.c b/tests/i915/gem_sparseobject.c
new file mode 100644
index 00000000..2117198a
--- /dev/null
+++ b/tests/i915/gem_sparseobject.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright © 2008 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.
+ *
+ *
+ */
+
+#include "igt.h"
+#include "i915/gem_sparse.h"
+
+#include <stdlib.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 "drm.h"
+
+IGT_TEST_DESCRIPTION("This is a test to exercise sparse object and backing it with,"
+		     " allocation of object from stolen memory and shmem.");
+
+#define U64_MAX         ((uint64_t)~0ULL)
+#define U32_MAX         ((uint32_t)~0ULL)
+#define OBJ_SIZE 	(4 * 4096)
+#define PAGE_SIZE 	4096
+#define TIMEOUT 	20
+#define MAX_HANDLES 	4096
+#define LARGE_OBJECT_SIZE  (16 * 1024 * 1024)
+#define MAX_USRPTR 	20
+#define MAX_SRC_OBJECTS 20
+#define MAX_PATTERN	3
+
+enum source_type {
+	UNSET,
+	SHMEM,
+	USERPTR,
+	__LAST_SOURCE__
+};
+
+void *__userptr[4096];
+
+uint32_t patterns[] = { 0x0,
+			0xdeadbeef,
+		        0xfeedbeef};
+
+static uint32_t gem_create_userptr(int i915, uint64_t size)
+{
+	uint32_t handle;
+	void *ptr;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, size) == 0);
+
+	gem_userptr(i915, ptr, size, 0, 0, &handle);
+
+	igt_assert(handle < ARRAY_SIZE(__userptr));
+	__userptr[handle] = ptr;
+
+	return handle;
+}
+
+static const char *source_name(enum source_type type)
+{
+	switch (type) {
+	case UNSET: return "unset";
+	case SHMEM: return "shmem";
+	case USERPTR: return "userptr";
+	default: igt_assert(0); return "unknown";
+	}
+}
+
+static uint32_t source_create(int i915, enum source_type type, uint64_t size)
+{
+	switch(type) {
+	case UNSET: return 0;
+	case SHMEM: return gem_create(i915, size);
+	case USERPTR: return gem_create_userptr(i915, size);
+	default: igt_assert(0); return 0;
+	}
+}
+
+static void source_destroy(int i915, uint32_t handle)
+{
+	if (!handle)
+		return;
+
+	gem_close(i915, handle);
+
+	free(__userptr[handle]);
+	__userptr[handle] = NULL;
+}
+
+static void
+fill_sources(int i915, uint32_t sources[], int size, bool fill)
+{
+	enum source_type type;
+	type = SHMEM;
+	for (int i = 0; i < size; i++, type++) {
+		if ((i % (__LAST_SOURCE__ - 1) == 0))
+			type = SHMEM;
+		sources[i] = source_create(i915, type, OBJ_SIZE);
+		if (fill)
+			gem_write(i915, sources[i], 0,
+				  &patterns[type], sizeof(uint32_t));
+	}
+}
+
+static void
+gem_link_sources(int i915, uint32_t sparse_handle, uint32_t sources[], int sz)
+{
+	int i;
+	char expected[OBJ_SIZE];
+	char buf[OBJ_SIZE];
+	int npages = OBJ_SIZE / PAGE_SIZE;
+
+	memset(expected, 0xfeedbeef, OBJ_SIZE);
+	i = 0;
+	while(i < sz) {
+		uint32_t ht = 0;
+		uint32_t src_stride = (rand() % (npages - 1)) + 1;
+		uint32_t dst_stride = (rand() % (npages - 1)) + 1;
+		uint32_t width = rand() % min(src_stride, dst_stride);
+		uint32_t height = rand() % max(src_stride, dst_stride);
+		uint32_t src_offset = rand() % (npages - (src_stride *
+							  (height - 1)) - width);
+		uint32_t dst_offset = rand() % (npages - (dst_stride *
+							  (height - 1)) - width);
+		char *data;
+		data = expected;
+		/* Write a pattern into src object */
+		while (ht <= height) {
+			gem_write(i915, sources[i],
+				  src_offset + (ht * src_stride * PAGE_SIZE),
+				  data, width * PAGE_SIZE);
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+
+		/* ioctl to link pages from src to sparse object */
+		gem_set_pages(i915, sparse_handle, dst_offset, dst_stride,
+			      sources[i], src_offset, src_stride, width, height);
+		ht = 0;
+		data = buf;
+		/* read back the data from sparse */
+		while (ht <= height) {
+			gem_read(i915, sparse_handle,
+				 dst_offset + (ht * dst_stride),
+				 data, (width * PAGE_SIZE));
+			data += (width * PAGE_SIZE);
+			ht++;
+		}
+		igt_assert(memcmp(buf, expected, width * height * PAGE_SIZE) == 0);
+		i++;
+	}
+}
+
+static void
+set_verify_pages(int i915, uint32_t sparse, uint32_t sources[], int size)
+{
+	uint32_t type, x, i;
+
+	for (i = 0; i < size; i++)
+		gem_set_pages(i915, sparse, i, 0,
+			      sources[i], 0, 0, 1, 1);
+	type = 1;
+	for (i = 0; i < size; i++) {
+		gem_read(i915, sparse, PAGE_SIZE * i,
+			 &x, sizeof(x));
+		igt_assert_neq_u32(x, patterns[type]);
+		if (++type == MAX_PATTERN)
+			type = 1;
+	}
+}
+
+/*
+ * Randomly picks the source objects and links with
+ * sparse object.
+ */
+static void
+igt_gem_sparse_link_nsources(int i915)
+{
+	int size;
+	uint32_t sources[MAX_SRC_OBJECTS];
+	uint32_t sparse;
+	int i;
+
+	sparse = gem_create_sparse(i915, U64_MAX);
+	igt_until_timeout(5 * TIMEOUT) {
+		size = rand() % MAX_SRC_OBJECTS;
+		fill_sources(i915, sources, size, true);
+		set_verify_pages(i915, sparse, sources, size);
+		gem_close(i915, sparse);
+		for (i = 0; i < size; i++)
+			source_destroy(i915, sources[i]);
+	}
+}
+
+/* Smoke test with single destination sparse object N:1 smoke */
+static void igt_gem_sparse_smoketest_single_destination(int i915)
+{
+	uint32_t sparse;
+	uint32_t sources[MAX_HANDLES];
+	int size, i;
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+	igt_until_timeout(TIMEOUT) {
+		size = rand() % MAX_SRC_OBJECTS;
+		fill_sources(i915, sources, size, false);
+		gem_link_sources(i915, sparse, sources, size);
+		for (i = 0; i < size; i++)
+			source_destroy(i915, sources[i]);
+		gem_close(i915, sparse);
+	}
+}
+
+/* sparse object smoke test with single source 1:N smoketest */
+static void igt_gem_sparse_smoketest_single_source(int i915)
+{
+	uint32_t sparse, src[1];
+	uint32_t handles[MAX_HANDLES];
+	int count, i;
+
+	src[0] = gem_create(i915, OBJ_SIZE);
+	count = 0;
+	igt_until_timeout(TIMEOUT) {
+		sparse = gem_create_sparse(i915, OBJ_SIZE);
+		handles[count++] = sparse;
+		gem_link_sources(i915, sparse, src, 1);
+	}
+	for (i = 0; i < count; i++)
+		gem_close(i915, handles[i]);
+	source_destroy(i915, src[0]);
+}
+
+static void igt_sparse_read(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	/* forwards */
+	if (src) {
+		for (uint32_t n = 0; n < 4; n++) {
+			gem_set_pages(i915,
+				      sparse, n, 0,
+				      src, n, 0,
+				      1, 1);
+			gem_write(i915, src, PAGE_SIZE * n, &n, sizeof(n));
+		}
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t expected = src ? n : 0;
+		uint32_t x;
+
+		gem_read(i915, sparse, PAGE_SIZE * n , &x, sizeof(x));
+		igt_assert_eq(x, expected);
+	}
+
+	if (src) {
+		for (uint32_t n = 0; n < 4; n++) {
+			gem_set_pages(i915,
+				      sparse, n, 0,
+				      src, 4 - n -1, 0,
+				      1, 1);
+			gem_write(i915, src,
+				  PAGE_SIZE * n + 1024, &n, sizeof(n));
+		}
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t expected = src ? 4 - n - 1 : 0;
+		uint32_t x;
+
+		gem_read(i915, sparse, PAGE_SIZE * n + 1024, &x, sizeof(x));
+		igt_assert_eq(x, expected);
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_write(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	/* forwards */
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = n, x;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		gem_write(i915, sparse, PAGE_SIZE * n , &ex, sizeof(ex));
+		gem_read(i915, src, PAGE_SIZE * n, &x, sizeof(x));
+
+		igt_assert_eq(x, ex);
+	}
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = 4 - n - 1, x;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, 4 - n - 1, 0,
+			      1, 1);
+
+		gem_write(i915, sparse, PAGE_SIZE * n + 1024, &ex, sizeof(ex));
+		gem_read(i915, src, PAGE_SIZE * ex + 1024, &x, sizeof(x));
+
+		igt_assert_eq(x, ex);
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_mmap(int i915, uint32_t src)
+{
+	uint32_t sparse;
+	uint32_t *ptr;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+	ptr = gem_mmap__gtt(i915, sparse, OBJ_SIZE, PROT_READ);
+
+	for (uint32_t n = 0; n < 4; n++) {
+		uint32_t ex = n;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		gem_write(i915, src, PAGE_SIZE * n , &ex, sizeof(ex));
+		igt_assert_eq(ptr[PAGE_SIZE * n / sizeof(*ptr)], ex);
+
+	}
+
+	munmap(ptr, OBJ_SIZE);
+	gem_close(i915, sparse);
+}
+
+static void store_dword(int i915, unsigned engine,
+			uint32_t dst, uint32_t offset,
+			uint32_t value)
+{
+	const int gen = intel_gen(intel_get_drm_devid(i915));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry reloc;
+	struct drm_i915_gem_execbuffer2 execbuf;
+	uint32_t batch[16];
+	int i;
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	execbuf.buffers_ptr = to_user_pointer(obj);
+	execbuf.buffer_count = 2;
+	execbuf.flags = engine;
+	if (gen < 6)
+		execbuf.flags |= I915_EXEC_SECURE;
+
+	memset(obj, 0, sizeof(obj));
+	obj[0].handle = dst;
+	obj[1].handle = gem_create(i915, 4096);
+
+	memset(&reloc, 0, sizeof(reloc));
+	reloc.target_handle = obj[0].handle;
+	reloc.presumed_offset = 0;
+	reloc.offset = sizeof(uint32_t);
+	reloc.delta = offset;
+	reloc.read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc.write_domain = I915_GEM_DOMAIN_RENDER;
+	obj[1].relocs_ptr = to_user_pointer(&reloc);
+	obj[1].relocation_count = 1;
+
+	i = 0;
+	batch[i] = MI_STORE_DWORD_IMM | (gen < 6 ? 1 << 22 : 0);
+	if (gen >= 8) {
+		batch[++i] = offset;
+		batch[++i] = 0;
+	} else if (gen >= 4) {
+		batch[++i] = 0;
+		batch[++i] = offset;
+		reloc.offset += sizeof(uint32_t);
+	} else {
+		batch[i]--;
+		batch[++i] = offset;
+	}
+	batch[++i] = value;
+	batch[++i] = MI_BATCH_BUFFER_END;
+	gem_write(i915, obj[1].handle, 0, batch, sizeof(batch));
+	gem_execbuf(i915, &execbuf);
+	gem_close(i915, obj[1].handle);
+}
+
+static void igt_sparse_execbuf(int i915, uint32_t src)
+{
+	uint32_t sparse;
+
+	igt_require(src);
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	for (uint32_t n = 0; n < 4; n++) {
+		unsigned int engine;
+
+		gem_set_pages(i915,
+			      sparse, n, 0,
+			      src, n, 0,
+			      1, 1);
+
+		for_each_physical_engine(i915, engine) {
+			uint32_t ex = engine, x;
+
+			if (!gem_can_store_dword(i915, engine))
+				continue;
+
+			x = ~ex;
+			gem_write(i915, src, PAGE_SIZE * n , &x, sizeof(x));
+
+			store_dword(i915, engine, sparse, PAGE_SIZE * n, ex);
+			gem_sync(i915, sparse);
+
+			gem_read(i915, src, PAGE_SIZE * n , &x, sizeof(x));
+
+			igt_assert_eq(x, ex);
+		}
+	}
+
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_invalid_sparse_read(int i915)
+{
+	uint32_t sparse;
+	struct drm_i915_gem_pread gem_pread;
+	char buf[256];
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+
+	memset(&gem_pread, 0, sizeof(gem_pread));
+	gem_pread.handle = sparse;
+	gem_pread.offset = OBJ_SIZE;
+	gem_pread.size = 256;
+	gem_pread.data_ptr = to_user_pointer(buf);
+
+	igt_fail_on(!drmIoctl(i915, DRM_IOCTL_I915_GEM_PREAD, &gem_pread));
+}
+
+static void igt_sparse_invalid_link(int i915)
+{
+	uint32_t sparse, src;
+	uint32_t npages = OBJ_SIZE / PAGE_SIZE;
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+	src = gem_create(i915, OBJ_SIZE);
+
+	/* width > src_stride */
+	igt_fail_on(!__gem_set_pages(i915, sparse, 0, 3,
+		      src, 0, 1, 2, 2));
+
+	/* width > dest_stride */
+	igt_fail_on(!__gem_set_pages(i915, sparse, 0, 1,
+		      src, 0, 3, 2, 2));
+
+	/* width cannot be zero */
+	igt_fail_on(!__gem_set_pages(i915, sparse, 0, 1,
+		      src, 0, 1, -1, 0));
+
+	/* overflows */
+	igt_fail_on(!__gem_set_pages(i915, sparse, 0, U32_MAX,
+		      src, 0, 2, 2, 2));
+
+	/* link outside of dst object */
+	igt_fail_on(!__gem_set_pages(i915, sparse, npages - 1, 2,
+		      src, 0, 2, 3, 3));
+
+	/* linking pages which are outside of src object */
+	igt_fail_on(!__gem_set_pages(i915, sparse, 0, 2,
+		      src, npages - 1, 2, 3, 3));
+}
+
+static void igt_sparse_invalid_source(int i915)
+{
+	uint32_t sparse, src;
+
+	sparse = gem_create_sparse(i915, OBJ_SIZE);
+	src = 0x10101001;
+	igt_fail_on(!__gem_set_pages(i915, sparse, 0, 0,
+		      src, 0, 0, 1, 1));
+	gem_close(i915, sparse);
+}
+
+static void igt_sparse_invalid_size(int i915)
+{
+	struct drm_i915_gem_create_ext create = {
+		.size = 0,
+		.flags = I915_GEM_CREATE_SPARSE,
+	};
+	igt_fail_on(!igt_ioctl(i915, DRM_IOCTL_I915_GEM_CREATE_EXT,
+			       &create));
+}
+
+static void igt_sparse_huge(int i915)
+{
+	uint32_t handle =
+		gem_create_sparse(i915, intel_get_total_ram_mb() << 24);
+
+	gem_set_domain(i915, handle, I915_GEM_DOMAIN_CPU, 0);
+	gem_close(i915, handle);
+}
+
+static int create_version(int i915)
+{
+	int val = 0;
+	struct drm_i915_getparam gp = {
+		gp.param = 54, /* CREATE_VERSION */
+		gp.value = &val,
+	};
+
+	ioctl(i915, DRM_IOCTL_I915_GETPARAM, &gp);
+	return val;
+}
+
+igt_main
+{
+	int i915 = -1;
+
+	igt_fixture {
+		i915 = drm_open_driver(DRIVER_INTEL);
+		igt_require_gem(i915);
+		igt_require(create_version(i915) >= 1);
+	}
+
+	igt_subtest("huge")
+		igt_sparse_huge(i915);
+
+	/* sparse_size = 0 */
+	igt_subtest("sparse_invalid_size")
+		igt_sparse_invalid_size(i915);
+
+	/* src_handle = -1 */
+	igt_subtest("sparse_invalid_source")
+		igt_sparse_invalid_source(i915);
+
+	igt_subtest("sparse_invalid_link")
+		igt_sparse_invalid_link(i915);
+
+	/* reading outside sizeof sparse */
+	igt_subtest("sparse_invalid_pread")
+		igt_sparse_invalid_sparse_read(i915);
+
+
+	for (enum source_type type = UNSET; type < __LAST_SOURCE__; type++) {
+		const char *name = source_name(type);
+		uint32_t handle = 0;
+
+		igt_fixture {
+			handle = source_create(i915, type, OBJ_SIZE);
+		}
+
+		igt_subtest_f("%s-sparse-read", name)
+			igt_sparse_read(i915, handle);
+
+		igt_subtest_f("%s-sparse-write", name)
+			igt_sparse_write(i915, handle);
+
+		igt_subtest_f("%s-sparse-mmap", name)
+			igt_sparse_mmap(i915, handle);
+
+		igt_subtest_f("%s-sparse-execbuf", name)
+			igt_sparse_execbuf(i915, handle);
+
+		igt_fixture {
+			source_destroy(i915, handle);
+		}
+	}
+
+	igt_subtest("sparse_link_multiple_sources")
+		igt_gem_sparse_link_nsources(i915);
+
+	igt_subtest("sparse_smoke_test_single_source")
+		igt_gem_sparse_smoketest_single_source(i915);
+
+	igt_subtest("sparse_smoke_test_single_destination")
+		igt_gem_sparse_smoketest_single_destination(i915);
+
+	igt_fixture {
+		close(i915);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 9015f809..9bf12118 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -153,6 +153,7 @@ i915_progs = [
 	'gem_gtt_hog',
 	'gem_gtt_speed',
 	'gem_largeobject',
+	'gem_sparseobject',
 	'gem_linear_blits',
 	'gem_lut_handle',
 	'gem_madvise',
-- 
2.17.1

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for i915/gem_sparseobject: Add sparse object IGT tests (rev3)
  2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
                   ` (3 preceding siblings ...)
  2019-03-21  5:14 ` [igt-dev] ✓ Fi.CI.IGT: success for i915/gem_sparseobject: Add sparse object IGT tests Patchwork
@ 2019-03-22 15:10 ` Patchwork
  2019-03-23 14:17 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  5 siblings, 0 replies; 9+ messages in thread
From: Patchwork @ 2019-03-22 15:10 UTC (permalink / raw)
  To: Venkata Sandeep Dhanalakota; +Cc: igt-dev

== Series Details ==

Series: i915/gem_sparseobject: Add sparse object IGT tests (rev3)
URL   : https://patchwork.freedesktop.org/series/58290/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5795 -> IGTPW_2691
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/58290/revisions/3/mbox/

Known issues
------------

  Here are the changes found in IGTPW_2691 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_basic@cs-compute:
    - fi-kbl-8809g:       NOTRUN -> FAIL [fdo#108094]

  * igt@amdgpu/amd_basic@cs-gfx:
    - fi-skl-6700k2:      NOTRUN -> SKIP [fdo#109271] +41

  * igt@amdgpu/amd_basic@query-info:
    - fi-bsw-kefka:       NOTRUN -> SKIP [fdo#109271] +55

  * igt@gem_ctx_param@basic:
    - fi-gdg-551:         NOTRUN -> SKIP [fdo#109271] +106

  * igt@gem_exec_basic@gtt-bsd:
    - fi-bwr-2160:        NOTRUN -> SKIP [fdo#109271] +103

  * igt@gem_exec_basic@readonly-bsd:
    - fi-pnv-d510:        NOTRUN -> SKIP [fdo#109271] +76

  * igt@gem_exec_basic@readonly-bsd1:
    - fi-snb-2520m:       NOTRUN -> SKIP [fdo#109271] +57

  * igt@gem_exec_gttfill@basic:
    - fi-skl-gvtdvm:      NOTRUN -> SKIP [fdo#109271] +41

  * igt@gem_exec_suspend@basic-s3:
    - fi-blb-e6850:       PASS -> INCOMPLETE [fdo#107718]

  * igt@kms_busy@basic-flip-a:
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +1

  * igt@kms_busy@basic-flip-c:
    - fi-gdg-551:         NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-bwr-2160:        NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-bsw-kefka:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-pnv-d510:        NOTRUN -> SKIP [fdo#109271] / [fdo#109278]
    - fi-snb-2520m:       NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_chamelium@hdmi-crc-fast:
    - fi-bsw-n3050:       NOTRUN -> SKIP [fdo#109271] +62

  * igt@kms_force_connector_basic@force-edid:
    - fi-kbl-x1275:       NOTRUN -> SKIP [fdo#109271] +45

  
#### Possible fixes ####

  * igt@amdgpu/amd_basic@userptr:
    - fi-kbl-8809g:       DMESG-WARN [fdo#108965] -> PASS

  * igt@i915_selftest@live_execlists:
    - fi-apl-guc:         INCOMPLETE [fdo#103927] / [fdo#109720] -> PASS

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#107718]: https://bugs.freedesktop.org/show_bug.cgi?id=107718
  [fdo#108094]: https://bugs.freedesktop.org/show_bug.cgi?id=108094
  [fdo#108965]: https://bugs.freedesktop.org/show_bug.cgi?id=108965
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109720]: https://bugs.freedesktop.org/show_bug.cgi?id=109720


Participating hosts (33 -> 36)
------------------------------

  Additional (10): fi-skl-gvtdvm fi-bsw-n3050 fi-bwr-2160 fi-snb-2520m fi-kbl-x1275 fi-gdg-551 fi-pnv-d510 fi-bsw-kefka fi-skl-lmem fi-skl-6700k2 
  Missing    (7): fi-kbl-soraka fi-ilk-m540 fi-hsw-4200u fi-bsw-cyan fi-ctg-p8600 fi-bxt-j4205 fi-bdw-samus 


Build changes
-------------

    * IGT: IGT_4899 -> IGTPW_2691

  CI_DRM_5795: 9b13e20521f1b66a20161bd3afd6727f383db604 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2691: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2691/
  IGT_4899: ba96339c238180b38d05d7fa2dca772d49eee332 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools



== Testlist changes ==

+igt@gem_sparseobject@huge
+igt@gem_sparseobject@shmem-sparse-execbuf
+igt@gem_sparseobject@shmem-sparse-mmap
+igt@gem_sparseobject@shmem-sparse-read
+igt@gem_sparseobject@shmem-sparse-write
+igt@gem_sparseobject@sparse_invalid_link
+igt@gem_sparseobject@sparse_invalid_pread
+igt@gem_sparseobject@sparse_invalid_size
+igt@gem_sparseobject@sparse_invalid_source
+igt@gem_sparseobject@sparse_link_multiple_sources
+igt@gem_sparseobject@sparse_smoke_test_single_destination
+igt@gem_sparseobject@sparse_smoke_test_single_source
+igt@gem_sparseobject@unset-sparse-execbuf
+igt@gem_sparseobject@unset-sparse-mmap
+igt@gem_sparseobject@unset-sparse-read
+igt@gem_sparseobject@unset-sparse-write
+igt@gem_sparseobject@userptr-sparse-execbuf
+igt@gem_sparseobject@userptr-sparse-mmap
+igt@gem_sparseobject@userptr-sparse-read
+igt@gem_sparseobject@userptr-sparse-write

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2691/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [igt-dev] ✓ Fi.CI.IGT: success for i915/gem_sparseobject: Add sparse object IGT tests (rev3)
  2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
                   ` (4 preceding siblings ...)
  2019-03-22 15:10 ` [igt-dev] ✓ Fi.CI.BAT: success for i915/gem_sparseobject: Add sparse object IGT tests (rev3) Patchwork
@ 2019-03-23 14:17 ` Patchwork
  5 siblings, 0 replies; 9+ messages in thread
From: Patchwork @ 2019-03-23 14:17 UTC (permalink / raw)
  To: Venkata Sandeep Dhanalakota; +Cc: igt-dev

== Series Details ==

Series: i915/gem_sparseobject: Add sparse object IGT tests (rev3)
URL   : https://patchwork.freedesktop.org/series/58290/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5795_full -> IGTPW_2691_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/58290/revisions/3/mbox/

New tests
---------

  New tests have been introduced between CI_DRM_5795_full and IGTPW_2691_full:

### New IGT tests (20) ###

  * igt@gem_sparseobject@huge:
    - Statuses : 2 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@shmem-sparse-execbuf:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@shmem-sparse-mmap:
    - Statuses : 3 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@shmem-sparse-read:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@shmem-sparse-write:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_invalid_link:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_invalid_pread:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_invalid_size:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_invalid_source:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_link_multiple_sources:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_smoke_test_single_destination:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@sparse_smoke_test_single_source:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@unset-sparse-execbuf:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@unset-sparse-mmap:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@unset-sparse-read:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@unset-sparse-write:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@userptr-sparse-execbuf:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@userptr-sparse-mmap:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@userptr-sparse-read:
    - Statuses : 5 skip(s)
    - Exec time: [0.0] s

  * igt@gem_sparseobject@userptr-sparse-write:
    - Statuses : 4 skip(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in IGTPW_2691_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ctx_param@invalid-param-set:
    - shard-snb:          NOTRUN -> FAIL [fdo#109674]

  * igt@gem_mocs_settings@mocs-rc6-render:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] +78

  * {igt@gem_sparseobject@shmem-sparse-mmap} (NEW):
    - shard-hsw:          NOTRUN -> SKIP [fdo#109271] +19

  * {igt@gem_sparseobject@unset-sparse-read} (NEW):
    - shard-glk:          NOTRUN -> SKIP [fdo#109271] +18

  * {igt@gem_sparseobject@userptr-sparse-write} (NEW):
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] +31

  * igt@gem_tiled_swapping@non-threaded:
    - shard-hsw:          PASS -> INCOMPLETE [fdo#103540] +1

  * igt@kms_busy@extended-modeset-hang-newfb-render-a:
    - shard-snb:          PASS -> DMESG-WARN [fdo#110222]

  * igt@kms_busy@extended-modeset-hang-newfb-render-b:
    - shard-hsw:          PASS -> DMESG-WARN [fdo#110222] +2

  * igt@kms_busy@extended-modeset-hang-newfb-render-c:
    - shard-apl:          NOTRUN -> DMESG-WARN [fdo#110222]

  * igt@kms_busy@extended-pageflip-hang-newfb-render-c:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +11

  * igt@kms_busy@extended-pageflip-modeset-hang-oldfb-render-c:
    - shard-kbl:          NOTRUN -> DMESG-WARN [fdo#110222]

  * igt@kms_cursor_crc@cursor-256x256-sliding:
    - shard-kbl:          PASS -> FAIL [fdo#103232]
    - shard-apl:          PASS -> FAIL [fdo#103232]

  * igt@kms_flip@flip-vs-expired-vblank:
    - shard-glk:          PASS -> FAIL [fdo#105363]

  * igt@kms_flip@flip-vs-modeset-interruptible:
    - shard-snb:          PASS -> INCOMPLETE [fdo#105411]

  * igt@kms_frontbuffer_tracking@fbc-suspend:
    - shard-kbl:          PASS -> INCOMPLETE [fdo#103665]

  * igt@kms_plane_alpha_blend@pipe-b-constant-alpha-max:
    - shard-apl:          NOTRUN -> FAIL [fdo#108145]

  * igt@kms_rotation_crc@multiplane-rotation-cropping-top:
    - shard-kbl:          PASS -> FAIL [fdo#109016]

  * igt@kms_setmode@basic:
    - shard-apl:          PASS -> FAIL [fdo#99912]
    - shard-glk:          PASS -> FAIL [fdo#99912]
    - shard-kbl:          PASS -> FAIL [fdo#99912]

  * igt@kms_universal_plane@disable-primary-vs-flip-pipe-d:
    - shard-kbl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +3

  * igt@kms_universal_plane@universal-plane-gen9-features-pipe-d:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +4

  * igt@kms_vblank@pipe-c-ts-continuation-suspend:
    - shard-apl:          PASS -> FAIL [fdo#104894]
    - shard-kbl:          PASS -> FAIL [fdo#104894]

  * igt@perf_pmu@rc6:
    - shard-kbl:          PASS -> SKIP [fdo#109271]

  * igt@prime_nv_api@i915_nv_reimport_twice_check_flink_name:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] +67

  
#### Possible fixes ####

  * igt@kms_atomic_transition@1x-modeset-transitions-nonblocking:
    - shard-apl:          FAIL [fdo#109660] -> PASS
    - shard-kbl:          FAIL [fdo#109660] -> PASS

  * igt@kms_atomic_transition@2x-modeset-transitions-fencing:
    - shard-hsw:          SKIP [fdo#109271] -> PASS +1

  * igt@kms_busy@extended-modeset-hang-newfb-render-b:
    - shard-glk:          DMESG-WARN [fdo#110222] -> PASS

  * igt@kms_busy@extended-modeset-hang-newfb-with-reset-render-a:
    - shard-hsw:          DMESG-WARN [fdo#110222] -> PASS
    - shard-kbl:          DMESG-WARN [fdo#110222] -> PASS

  * igt@kms_cursor_legacy@2x-long-flip-vs-cursor-atomic:
    - shard-glk:          FAIL [fdo#104873] -> PASS

  * igt@kms_flip@plain-flip-ts-check:
    - shard-glk:          FAIL [fdo#100368] -> PASS

  * igt@kms_plane_alpha_blend@pipe-b-constant-alpha-max:
    - shard-glk:          FAIL [fdo#108145] -> PASS

  * igt@kms_setmode@basic:
    - shard-hsw:          FAIL [fdo#99912] -> PASS

  * igt@kms_vblank@pipe-b-ts-continuation-suspend:
    - shard-kbl:          FAIL [fdo#104894] -> PASS
    - shard-apl:          FAIL [fdo#104894] -> PASS

  * igt@perf_pmu@semaphore-wait-vcs0:
    - shard-apl:          INCOMPLETE [fdo#103927] -> PASS

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#100368]: https://bugs.freedesktop.org/show_bug.cgi?id=100368
  [fdo#103232]: https://bugs.freedesktop.org/show_bug.cgi?id=103232
  [fdo#103540]: https://bugs.freedesktop.org/show_bug.cgi?id=103540
  [fdo#103665]: https://bugs.freedesktop.org/show_bug.cgi?id=103665
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#104873]: https://bugs.freedesktop.org/show_bug.cgi?id=104873
  [fdo#104894]: https://bugs.freedesktop.org/show_bug.cgi?id=104894
  [fdo#105363]: https://bugs.freedesktop.org/show_bug.cgi?id=105363
  [fdo#105411]: https://bugs.freedesktop.org/show_bug.cgi?id=105411
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#109016]: https://bugs.freedesktop.org/show_bug.cgi?id=109016
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109660]: https://bugs.freedesktop.org/show_bug.cgi?id=109660
  [fdo#109674]: https://bugs.freedesktop.org/show_bug.cgi?id=109674
  [fdo#110222]: https://bugs.freedesktop.org/show_bug.cgi?id=110222
  [fdo#99912]: https://bugs.freedesktop.org/show_bug.cgi?id=99912


Participating hosts (10 -> 5)
------------------------------

  Missing    (5): shard-skl pig-hsw-4770r pig-glk-j5005 shard-iclb pig-skl-6260u 


Build changes
-------------

    * IGT: IGT_4899 -> IGTPW_2691
    * Piglit: piglit_4509 -> None

  CI_DRM_5795: 9b13e20521f1b66a20161bd3afd6727f383db604 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_2691: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2691/
  IGT_4899: ba96339c238180b38d05d7fa2dca772d49eee332 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_2691/
_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-03-23 14:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-20 20:01 [igt-dev] [PATCH i-g-t] i915/gem_sparseobject: Add sparse object IGT tests Venkata Sandeep Dhanalakota
2019-03-20 21:41 ` [igt-dev] ✓ Fi.CI.BAT: success for " Patchwork
2019-03-21  0:13 ` [PATCH i-g-t] " Chris Wilson
2019-03-21  0:13   ` [igt-dev] " Chris Wilson
2019-03-22 14:09   ` Venkata Sandeep Dhanalakota
2019-03-21  1:10 ` [igt-dev] ✗ Fi.CI.BAT: failure for i915/gem_sparseobject: Add sparse object IGT tests (rev2) Patchwork
2019-03-21  5:14 ` [igt-dev] ✓ Fi.CI.IGT: success for i915/gem_sparseobject: Add sparse object IGT tests Patchwork
2019-03-22 15:10 ` [igt-dev] ✓ Fi.CI.BAT: success for i915/gem_sparseobject: Add sparse object IGT tests (rev3) Patchwork
2019-03-23 14:17 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.