[igt-dev] [RFC v1] Data Port Coherency tests.

Tomasz Lis tomasz.lis at intel.com
Tue Mar 20 15:12:32 UTC 2018


From: "Lis, Tomasz" <tomasz.lis at intel.com>

This adds a new test binary, containing tests for the Data Port Coherency
option. The tests check whether the option is correctly set to proper GPU
register.
---
 include/drm-uapi/i915_drm.h      |  12 +-
 tests/Makefile.sources           |   1 +
 tests/gem_exec_cache_coherency.c | 307 +++++++++++++++++++++++++++++++++++++++
 tests/meson.build                |   1 +
 4 files changed, 320 insertions(+), 1 deletion(-)
 create mode 100644 tests/gem_exec_cache_coherency.c

diff --git a/include/drm-uapi/i915_drm.h b/include/drm-uapi/i915_drm.h
index 16e452a..a84e00f 100644
--- a/include/drm-uapi/i915_drm.h
+++ b/include/drm-uapi/i915_drm.h
@@ -529,6 +529,11 @@ typedef struct drm_i915_irq_wait {
  */
 #define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51
 
+/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to switch
+   Data Cache access into Data Port Coherency mode.
+ */
+#define I915_PARAM_HAS_EXEC_DATA_PORT_COHERENCY 52
+
 typedef struct drm_i915_getparam {
 	__s32 param;
 	/*
@@ -1048,7 +1053,12 @@ struct drm_i915_gem_execbuffer2 {
  */
 #define I915_EXEC_FENCE_ARRAY   (1<<19)
 
-#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_ARRAY<<1))
+/* Data Port Coherency capability will be switched before an exec call
+ * which has this flag different than previous call for the context.
+ */
+#define I915_EXEC_DATA_PORT_COHERENT   (1<<20)
+
+#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_DATA_PORT_COHERENT<<1))
 
 #define I915_EXEC_CONTEXT_ID_MASK	(0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 4e6f531..1e03011 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -73,6 +73,7 @@ TESTS_progs = \
 	gem_exec_basic \
 	gem_exec_big \
 	gem_exec_blt \
+	gem_exec_cache_coherency \
 	gem_exec_capture \
 	gem_exec_create \
 	gem_exec_faulting_reloc \
diff --git a/tests/gem_exec_cache_coherency.c b/tests/gem_exec_cache_coherency.c
new file mode 100644
index 0000000..1b57d35
--- /dev/null
+++ b/tests/gem_exec_cache_coherency.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+/** @file gem_exec_cache_coherency.c
+ *
+ * Check that the cache coherency at data port level setting is working.
+ */
+
+#include <sys/ioctl.h>
+
+#include "igt.h"
+#include "igt_gt.h"
+#include "igt_sysfs.h"
+
+enum {
+	NONE,
+	RESET,
+	RC6,
+	SUSPEND,
+	HIBERNATE,
+	MAX_COHERENCY_TEST_MODES
+};
+
+static const char * const test_modes[] = {
+	[NONE] = "settings",
+	[RESET] = "reset",
+	[RC6] = "rc6",
+	[SUSPEND] = "suspend",
+	[HIBERNATE] = "hibernate"
+};
+
+/** Make the test be performed on non-default context (created by the test) */
+#define COHERENCY_NON_DEFAULT_CTX	(1<<0)
+/** Check for test value separation between contexts */
+#define COHERENCY_CTX_SEPARATION	(1<<1)
+/** Value of all flags set */
+#define ALL_COHERENCY_FLAGS		(COHERENCY_NON_DEFAULT_CTX | \
+					COHERENCY_CTX_SEPARATION)
+
+/* IOCTL definitions */
+#define I915_CONTEXT_PARAM_COHERENCY	0x7
+
+/* Hardware registers */
+#define HDC_CHICKEN0		(0x7300)
+#define CNL_HDC_CHICKEN0	(0xE5F0)
+#define ICL_HDC_CHICKEN0	(0xE5F4)
+/** Coherency bit within chicken0 register */
+#define HDC_FORCE_NON_COHERENT	(1<<4)
+
+static uint32_t get_context_coherency_store_register(int fd, uint32_t engine)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	if (gen >= 11)
+		return ICL_HDC_CHICKEN0;
+	if (gen >= 10)
+		return CNL_HDC_CHICKEN0;
+	return HDC_CHICKEN0;
+}
+
+#define MI_STORE_REGISTER_MEM_64_BIT_ADDR	((0x24 << 23) | 2)
+
+static int create_read_batch(struct drm_i915_gem_relocation_entry *reloc,
+			     uint32_t *batch,
+			     uint32_t dst_handle,
+			     uint32_t size,
+			     uint32_t reg_base)
+{
+	unsigned int offset = 0;
+
+	for (uint32_t index = 0; index < size; index++, offset += 4) {
+		batch[offset]   = MI_STORE_REGISTER_MEM_64_BIT_ADDR;
+		batch[offset+1] = reg_base + (index * sizeof(uint32_t));
+		batch[offset+2] = index * sizeof(uint32_t);	/* reloc */
+		batch[offset+3] = 0;
+
+		reloc[index].offset = (offset + 2) * sizeof(uint32_t);
+		reloc[index].delta = index * sizeof(uint32_t);
+		reloc[index].target_handle = dst_handle;
+		reloc[index].write_domain = I915_GEM_DOMAIN_RENDER;
+		reloc[index].read_domains = I915_GEM_DOMAIN_RENDER;
+	}
+
+	batch[offset++] = MI_BATCH_BUFFER_END;
+	batch[offset++] = 0;
+
+	return offset * sizeof(uint32_t);
+}
+
+static void do_read_registers(int fd,
+			      uint32_t ctx_id,
+			      uint32_t dst_handle,
+			      uint32_t reg_base,
+			      uint32_t size,
+			      uint32_t engine_id,
+			      uint32_t exec_flags)
+{
+	struct drm_i915_gem_execbuffer2 execbuf;
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry reloc[size];
+	uint32_t batch[size * 4 + 4];
+	uint32_t handle = gem_create(fd, 4096);
+
+	memset(reloc, 0, sizeof(reloc));
+	memset(obj, 0, sizeof(obj));
+	memset(&execbuf, 0, sizeof(execbuf));
+
+	obj[0].handle = dst_handle;
+
+	obj[1].handle = handle;
+	obj[1].relocation_count = size;
+	obj[1].relocs_ptr = to_user_pointer(reloc);
+
+	execbuf.buffers_ptr = to_user_pointer(obj);
+	execbuf.buffer_count = 2;
+	execbuf.batch_len =
+		create_read_batch(reloc, batch, dst_handle, size, reg_base);
+	i915_execbuffer2_set_context_id(execbuf, ctx_id);
+	execbuf.flags = I915_EXEC_SECURE | exec_flags | engine_id;
+
+	gem_write(fd, handle, 0, batch, execbuf.batch_len);
+	gem_execbuf(fd, &execbuf);
+	gem_close(fd, handle);
+}
+
+static int gem_ioctl(int fd, unsigned long request, void *argp)
+{
+	int ret;
+
+	do {
+		ret = ioctl(fd, request, argp);
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+	return ret;
+}
+
+static int gem_get_param(int fd, uint32_t param)
+{
+	int value = 0;
+	drm_i915_getparam_t gp = {
+		.param = param,
+		.value = &value
+	};
+
+	igt_assert(gem_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) != -1);
+
+	return value;
+}
+
+/**
+ * check_chicken_register_coherency_flag:
+ * @fd: open i915 drm file descriptor
+ * @engine: engine
+ * @ctx_id: i915 context id
+ *
+ * Sends an exec call with given coherency state, and checks if the flag was
+ * set in hardware.
+ */
+static void check_chicken_register_coherency_flag(int fd,
+				    unsigned engine,
+				    uint32_t ctx_id,
+				    bool coherency_enable)
+{
+	const uint32_t reg_base = get_context_coherency_store_register(fd, engine);
+	uint32_t dst_handle = gem_create(fd, 4096);
+	uint32_t *read_regs;
+
+	do_read_registers(fd,
+			  ctx_id,
+			  dst_handle,
+			  reg_base,
+			  1,
+			  engine,
+			  coherency_enable ? I915_EXEC_DATA_PORT_COHERENT : 0);
+
+	read_regs = gem_mmap__cpu(fd, dst_handle, 0, 4096, PROT_READ);
+
+	gem_set_domain(fd, dst_handle, I915_GEM_DOMAIN_CPU, 0);
+	/* Coherency is enabled when non-hoherent bit is disabled */
+	igt_assert(((read_regs[0] & HDC_FORCE_NON_COHERENT) != 0) != coherency_enable);
+
+	munmap(read_regs, 4096);
+	gem_close(fd, dst_handle);
+}
+
+static uint32_t rc6_residency(int dir)
+{
+	return igt_sysfs_get_u32(dir, "power/rc6_residency_ms");
+}
+
+static void rc6_wait(int fd)
+{
+	int sysfs;
+	uint32_t residency;
+
+	sysfs = igt_sysfs_open(fd, NULL);
+	igt_assert_lte(0, sysfs);
+
+	residency = rc6_residency(sysfs);
+	igt_require(igt_wait(rc6_residency(sysfs) != residency, 10000, 2));
+
+	close(sysfs);
+}
+
+static void run_test(int fd, unsigned engine, unsigned flags, unsigned mode)
+{
+	uint32_t ctx_id = 0;
+	uint32_t ctx_clean_id;
+	uint32_t ctx_dirty_id;
+
+	gem_require_ring(fd, engine);
+	igt_require(gem_get_param(fd, I915_PARAM_HAS_EXEC_DATA_PORT_COHERENCY) == 1);
+	/* Only run RESET tests when GPU Reset functionality is available.
+	 */
+	if (mode == RESET)
+		igt_require(gem_gpu_reset_enabled(fd));
+
+	if (flags & COHERENCY_NON_DEFAULT_CTX)
+		ctx_id = gem_context_create(fd);
+
+	check_chicken_register_coherency_flag(fd, engine, ctx_id, 0);
+
+	if (flags & COHERENCY_CTX_SEPARATION) {
+		ctx_dirty_id = gem_context_create(fd);
+		check_chicken_register_coherency_flag(fd, engine, ctx_dirty_id, 0);
+	}
+
+	check_chicken_register_coherency_flag(fd, engine, ctx_id, 1);
+
+	/* Check if the values are preserved across power mode changes - one change per run */
+	switch (mode) {
+	case NONE:	break;
+	case RESET:	igt_force_gpu_reset(fd);	break;
+	case SUSPEND:	igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
+						      SUSPEND_TEST_NONE); break;
+	case HIBERNATE:	igt_system_suspend_autoresume(SUSPEND_STATE_DISK,
+						      SUSPEND_TEST_NONE); break;
+	case RC6:	rc6_wait(fd);			break;
+	}
+
+	check_chicken_register_coherency_flag(fd, engine, ctx_id, 1);
+
+	if (flags & COHERENCY_CTX_SEPARATION) {
+		ctx_clean_id = gem_context_create(fd);
+		check_chicken_register_coherency_flag(fd, engine, ctx_dirty_id, 0);
+		check_chicken_register_coherency_flag(fd, engine, ctx_clean_id, 0);
+		gem_context_destroy(fd, ctx_dirty_id);
+		gem_context_destroy(fd, ctx_clean_id);
+	}
+
+	if (ctx_id)
+		gem_context_destroy(fd, ctx_id);
+}
+
+igt_main
+{
+	const struct intel_execution_engine *e;
+	int fd = -1;
+
+	igt_fixture {
+		fd = drm_open_driver(DRIVER_INTEL);
+		igt_require_gem(fd);
+	}
+
+	for (e = intel_execution_engines; e->name; e++) {
+		/* Check only the render engine, which is also used for compute
+		 */
+		if (e->exec_id != I915_EXEC_RENDER)
+			continue;
+
+		for (unsigned mode = NONE; mode < MAX_COHERENCY_TEST_MODES; mode++) {
+			for (unsigned flags = 0; flags < ALL_COHERENCY_FLAGS + 1; flags++) {
+
+				igt_subtest_f("coherency-%s%s%s-%s",
+					      test_modes[mode],
+					      flags & COHERENCY_NON_DEFAULT_CTX ? "-ctx": "",
+					      flags & COHERENCY_CTX_SEPARATION ? "-sep": "",
+					      e->name) {
+					run_test(fd, e->exec_id | e->flags, flags, mode);
+				}
+			}
+		}
+	}
+
+	igt_fixture
+		close(fd);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 1176463..781fffe 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -50,6 +50,7 @@ test_progs = [
 	'gem_exec_basic',
 	'gem_exec_big',
 	'gem_exec_blt',
+	'gem_exec_cache_coherency',
 	'gem_exec_capture',
 	'gem_exec_create',
 	'gem_exec_faulting_reloc',
-- 
2.7.4



More information about the igt-dev mailing list