@@ -57,6 +57,7 @@ TESTS_progs = \
gem_ctx_bad_destroy \
gem_ctx_bad_exec \
gem_ctx_create \
+ gem_ctx_engines \
gem_ctx_exec \
gem_ctx_freq \
gem_ctx_isolation \
new file mode 100644
@@ -0,0 +1,236 @@
+/*
+ * Copyright © 2018 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 <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <drm.h>
+
+#include "i915/gem_context.h"
+
+struct i915_user_extension {
+ uint64_t next_extension;
+ uint64_t name;
+};
+
+struct i915_context_param_engines {
+ uint64_t extensions;
+
+ struct {
+ uint32_t class;
+ uint32_t instance;
+ } class_instance[0];
+};
+#define I915_CONTEXT_PARAM_ENGINES 0x9
+
+static bool has_context_engines(int i915)
+{
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = 0,
+ .param = I915_CONTEXT_PARAM_ENGINES,
+ };
+ return __gem_context_set_param(i915, ¶m) == 0;
+}
+
+static void invalid_engines(int i915)
+{
+ struct i915_context_param_engines stack = {}, *engines;
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = gem_context_create(i915),
+ .param = I915_CONTEXT_PARAM_ENGINES,
+ .value = to_user_pointer(&stack),
+ };
+ void *ptr;
+
+ param.size = 0;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), 0);
+
+ param.size = 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EINVAL);
+
+ param.size = sizeof(stack) - 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EINVAL);
+
+ param.size = sizeof(stack) + 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EINVAL);
+
+ param.size = 0;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), 0);
+
+ /* Create a single page surrounded by inaccessible nothingness */
+ ptr = mmap(NULL, 3 * 4096, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+ igt_assert(ptr != MAP_FAILED);
+
+ munmap(ptr, 4096);
+ engines = ptr + 4096;
+ munmap(ptr + 2 *4096, 4096);
+
+ param.size = sizeof(*engines) + sizeof(*engines->class_instance);
+ param.value = to_user_pointer(engines);
+
+ engines->class_instance[0].class = -1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -ENOENT);
+
+ mprotect(engines, 4096, PROT_READ);
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -ENOENT);
+
+ mprotect(engines, 4096, PROT_WRITE);
+ engines->class_instance[0].class = 0;
+ if (__gem_context_set_param(i915, ¶m)) /* XXX needs RCS */
+ goto out;
+
+ engines->extensions = to_user_pointer(ptr);
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ engines->extensions = 0;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), 0);
+
+ param.value = to_user_pointer(engines - 1);
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) - 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) - param.size + 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) + 4096;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) - param.size + 4096;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), 0);
+
+ param.value = to_user_pointer(engines) - param.size + 4096 + 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) + 4096;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) + 4096 - 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines) - 1;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines - 1);
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines - 1) + 4096;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+ param.value = to_user_pointer(engines - 1) + 4096 - sizeof(*engines->class_instance) / 2;
+ igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT);
+
+out:
+ munmap(engines, 4096);
+ gem_context_destroy(i915, param.ctx_id);
+}
+
+static void execute_one(int i915)
+{
+ struct one_engine {
+ uint64_t extensions;
+ uint32_t class;
+ uint32_t instance;
+ } engines;
+ struct drm_i915_gem_context_param param = {
+ .ctx_id = gem_context_create(i915),
+ .param = I915_CONTEXT_PARAM_ENGINES,
+ .size = sizeof(engines),
+ .value = to_user_pointer(&engines),
+ };
+ struct drm_i915_gem_exec_object2 obj = {
+ .handle = gem_create(i915, 4096),
+ };
+ struct drm_i915_gem_execbuffer2 execbuf = {
+ .buffers_ptr = to_user_pointer(&obj),
+ .buffer_count = 1,
+ .rsvd1 = param.ctx_id,
+ };
+ const uint32_t bbe = MI_BATCH_BUFFER_END;
+ const struct intel_execution_engine2 *e;
+
+ gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
+ memset(&engines, 0, sizeof(engines));
+
+ /* Unadulterated I915_EXEC_DEFAULT should work */
+ execbuf.flags = 0;
+ igt_assert_eq(__gem_execbuf(i915, &execbuf), 0);
+
+ for_each_engine_class_instance(i915, e) {
+ engines.class = e->class;
+ engines.instance = e->instance;
+ gem_context_set_param(i915, ¶m);
+
+ execbuf.flags = 0;
+ igt_assert_eq(__gem_execbuf(i915, &execbuf), -EINVAL);
+
+ execbuf.flags = 1;
+ igt_assert_eq(__gem_execbuf(i915, &execbuf), 0);
+
+ execbuf.flags = 2;
+ igt_assert_eq(__gem_execbuf(i915, &execbuf), -EINVAL);
+
+ /* XXX prove we used the right engine! */
+ }
+
+ /* Restore the defaults and check I915_EXEC_DEFAULT works again. */
+ param.size = 0;
+ gem_context_set_param(i915, ¶m);
+ execbuf.flags = 0;
+ igt_assert_eq(__gem_execbuf(i915, &execbuf), 0);
+
+ gem_close(i915, obj.handle);
+ gem_context_destroy(i915, param.ctx_id);
+}
+
+igt_main
+{
+ int i915 = -1;
+
+ igt_fixture {
+ i915 = drm_open_driver_render(DRIVER_INTEL);
+ igt_require_gem(i915);
+
+ gem_require_contexts(i915);
+ igt_require(has_context_engines(i915));
+ }
+
+ igt_subtest("invalid-engines")
+ invalid_engines(i915);
+
+ igt_subtest("execute-one")
+ execute_one(i915);
+}
@@ -40,6 +40,7 @@ test_progs = [
'gem_ctx_bad_destroy',
'gem_ctx_bad_exec',
'gem_ctx_create',
+ 'gem_ctx_engines',
'gem_ctx_exec',
'gem_ctx_isolation',
'gem_ctx_param',
To exercise the new I915_CONTEXT_PARAM_ENGINES and interactions with gem_execbuf(). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- tests/Makefile.sources | 1 + tests/gem_ctx_engines.c | 236 ++++++++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 3 files changed, 238 insertions(+) create mode 100644 tests/gem_ctx_engines.c