[igt-dev] [PATCH i-g-t v1] Data Port Cache Coherency tests.

Tomasz Lis tomasz.lis at intel.com
Wed Jun 20 15:14:38 UTC 2018


This adds a new test binary, containing tests for the Data Port Coherency
option. The tests check whether the option value is stored properly on the
kernel side, but also whether is is correctly set to proper GPU register.

Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Michal Winiarski <michal.winiarski at intel.com>

Signed-off-by: Tomasz Lis <tomasz.lis at intel.com>
---
 tests/Makefile.sources          |   1 +
 tests/gem_ctx_cache_coherency.c | 324 ++++++++++++++++++++++++++++++++++++++++
 tests/meson.build               |   1 +
 3 files changed, 326 insertions(+)
 create mode 100644 tests/gem_ctx_cache_coherency.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index ad62611..181ba9d 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -56,6 +56,7 @@ TESTS_progs = \
 	gem_cs_tlb \
 	gem_ctx_bad_destroy \
 	gem_ctx_bad_exec \
+	gem_ctx_cache_coherency \
 	gem_ctx_create \
 	gem_ctx_exec \
 	gem_ctx_isolation \
diff --git a/tests/gem_ctx_cache_coherency.c b/tests/gem_ctx_cache_coherency.c
new file mode 100644
index 0000000..715f212
--- /dev/null
+++ b/tests/gem_ctx_cache_coherency.c
@@ -0,0 +1,324 @@
+/*
+ * 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_ctx_cache_coherency.c
+ *
+ * Check that the Data port coherency settings are working.
+ */
+
+#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)
+{
+	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 | engine_id;
+
+	gem_write(fd, handle, 0, batch, execbuf.batch_len);
+	gem_execbuf(fd, &execbuf);
+	gem_close(fd, handle);
+}
+
+/**
+ * __gem_context_set_coherency:
+ * @fd: open i915 drm file descriptor
+ * @ctx_id: i915 context id
+ * @enable: desired context coherency state
+ *
+ * This function modifies Data port coherency property of the context.
+ *
+ * Returns: An integer equal to zero for success and negative for failure
+ */
+static int __gem_context_set_coherency(int fd, uint32_t ctx_id, int enable)
+{
+	struct drm_i915_gem_context_param p;
+
+	memset(&p, 0, sizeof(p));
+	p.ctx_id = ctx_id;
+	p.size = 0;
+	p.param = I915_CONTEXT_PARAM_COHERENCY;
+	p.value = enable;
+
+	return __gem_context_set_param(fd, &p);
+}
+
+/**
+ * gem_context_set_coherency:
+ * @fd: open i915 drm file descriptor
+ * @ctx_id: i915 context id
+ * @enable: desired context coherency state
+ *
+ * Like __gem_context_set_coherency(), except we assert on failure.
+ */
+static void gem_context_set_coherency(int fd, uint32_t ctx_id, int enable)
+{
+	igt_assert(__gem_context_set_coherency(fd, ctx_id, enable) == 0);
+}
+
+static int gem_context_get_coherency(int fd, uint32_t ctx_id)
+{
+	struct drm_i915_gem_context_param p;
+	memset(&p, 0, sizeof(p));
+	p.ctx_id = ctx_id;
+	p.size = 0;
+	p.param = I915_CONTEXT_PARAM_COHERENCY;
+
+	igt_assert(__gem_context_get_param(fd, &p) == 0);
+
+	return p.value;
+}
+
+static void check_chicken_register_coherency_flag(int fd,
+				    unsigned engine,
+				    uint32_t ctx_id)
+{
+	const uint32_t reg_base = get_context_coherency_store_register(fd, engine);
+	uint32_t dst_handle = gem_create(fd, 4096);
+	uint32_t *read_regs;
+	int fg_coherency;
+
+	fg_coherency = gem_context_get_coherency(fd, ctx_id);
+
+	do_read_registers(fd,
+			  ctx_id,
+			  dst_handle,
+			  reg_base,
+			  1,
+			  engine);
+
+	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) != fg_coherency);
+
+	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);
+	/* 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);
+
+	gem_context_set_coherency(fd, ctx_id, 1);
+
+	if (flags & COHERENCY_CTX_SEPARATION) {
+		ctx_dirty_id = gem_context_create(fd);
+		//gem_context_set_coherency(fd, ctx_dirty_id, 0); // this is default, no need to set
+		igt_assert(gem_context_get_coherency(fd, ctx_dirty_id) == 0);
+		check_chicken_register_coherency_flag(fd, engine, ctx_dirty_id);
+	}
+
+	igt_assert(gem_context_get_coherency(fd, ctx_id) == 1);
+	check_chicken_register_coherency_flag(fd, engine, ctx_id);
+
+	/* 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;
+	}
+
+	igt_assert(gem_context_get_coherency(fd, ctx_id) == 1);
+	check_chicken_register_coherency_flag(fd, engine, ctx_id);
+
+	if (flags & COHERENCY_CTX_SEPARATION) {
+		ctx_clean_id = gem_context_create(fd);
+		check_chicken_register_coherency_flag(fd, engine, ctx_dirty_id);
+		check_chicken_register_coherency_flag(fd, engine, ctx_clean_id);
+		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 cedb4ff..b7094ce 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -33,6 +33,7 @@ test_progs = [
 	'gem_cs_tlb',
 	'gem_ctx_bad_destroy',
 	'gem_ctx_bad_exec',
+	'gem_ctx_cache_coherency',
 	'gem_ctx_create',
 	'gem_ctx_exec',
 	'gem_ctx_isolation',
-- 
2.7.4



More information about the igt-dev mailing list