[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