From patchwork Thu Mar 14 14:19:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 10852965 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C3F8F17DF for ; Thu, 14 Mar 2019 14:20:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AD20D2A381 for ; Thu, 14 Mar 2019 14:20:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A10692A422; Thu, 14 Mar 2019 14:20:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 440E92A381 for ; Thu, 14 Mar 2019 14:20:06 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7AB146E2EC; Thu, 14 Mar 2019 14:20:03 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from fireflyinternet.com (mail.fireflyinternet.com [109.228.58.192]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4AF156E2E0; Thu, 14 Mar 2019 14:19:59 +0000 (UTC) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from haswell.alporthouse.com (unverified [78.156.65.138]) by fireflyinternet.com (Firefly Internet (M1)) with ESMTP id 15889945-1500050 for multiple; Thu, 14 Mar 2019 14:19:45 +0000 From: Chris Wilson To: intel-gfx@lists.freedesktop.org Date: Thu, 14 Mar 2019 14:19:36 +0000 Message-Id: <20190314141939.26246-22-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190314141939.26246-1-chris@chris-wilson.co.uk> References: <20190314141939.26246-1-chris@chris-wilson.co.uk> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH i-g-t 22/25] i915: Add gem_ctx_engines X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: igt-dev@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP To exercise the new I915_CONTEXT_PARAM_ENGINES and interactions with gem_execbuf(). Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Andi Shyti --- tests/Makefile.sources | 1 + tests/i915/gem_ctx_engines.c | 441 +++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 3 files changed, 443 insertions(+) create mode 100644 tests/i915/gem_ctx_engines.c diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 7e06c969f..2f5612b07 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -22,6 +22,7 @@ TESTS_progs = \ drm_mm \ drm_read \ i915/gem_ctx_clone \ + i915/gem_ctx_engines \ i915/gem_ctx_shared \ i915/gem_vm_create \ kms_3d \ diff --git a/tests/i915/gem_ctx_engines.c b/tests/i915/gem_ctx_engines.c new file mode 100644 index 000000000..588ecf196 --- /dev/null +++ b/tests/i915/gem_ctx_engines.c @@ -0,0 +1,441 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "i915/gem_context.h" + +#define engine_class(e, n) ((e)->class_instance[(n)].engine_class) +#define engine_instance(e, n) ((e)->class_instance[(n)].engine_instance) + +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), + }; + uint32_t handle; + 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].engine_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].engine_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); + + handle = gem_create(i915, 4096 * 3); + ptr = gem_mmap__gtt(i915, handle, 4096 * 3, PROT_READ); + gem_close(i915, handle); + + munmap(ptr, 4096); + munmap(ptr + 8192, 4096); + + param.value = to_user_pointer(ptr + 4096); + igt_assert_eq(__gem_context_set_param(i915, ¶m), 0); + + param.value = to_user_pointer(ptr); + igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT); + + param.value = to_user_pointer(ptr) + 4095; + igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT); + + param.value = to_user_pointer(ptr) + 8192; + igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT); + + param.value = to_user_pointer(ptr) + 12287; + igt_assert_eq(__gem_context_set_param(i915, ¶m), -EFAULT); + + munmap(ptr + 4096, 4096); + +out: + munmap(engines, 4096); + gem_context_destroy(i915, param.ctx_id); +} + +static void idempotent(int i915) +{ + I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1); + I915_DEFINE_CONTEXT_PARAM_ENGINES(expected , I915_EXEC_RING_MASK + 1); + struct drm_i915_gem_context_param p = { + .ctx_id = gem_context_create(i915), + .param = I915_CONTEXT_PARAM_ENGINES, + .value = to_user_pointer(&engines), + .size = sizeof(engines), + }; + const size_t base = sizeof(struct i915_context_param_engines); + const struct intel_execution_engine2 *e; + int idx; + + /* What goes in, must come out. And what comes out, must go in */ + + gem_context_get_param(i915, &p); + igt_assert_eq(p.size, 0); /* atm default is to use legacy ring mask */ + + idx = 0; + memset(&engines, 0, sizeof(engines)); + for_each_engine_class_instance(i915, e) { + engines.class_instance[idx].engine_class = e->class; + engines.class_instance[idx].engine_instance = e->instance; + idx++; + } + idx *= sizeof(*engines.class_instance); + p.size = base + idx; + gem_context_set_param(i915, &p); + + memcpy(&expected, &engines, sizeof(expected)); + + gem_context_get_param(i915, &p); + igt_assert_eq(p.size, base + idx); + igt_assert(!memcmp(&expected, &engines, idx)); + + p.size = base; + gem_context_set_param(i915, &p); + gem_context_get_param(i915, &p); + igt_assert_eq(p.size, base); + + /* and it should not have overwritten the previous contents */ + igt_assert(!memcmp(&expected, &engines, idx)); + + memset(&engines, 0, sizeof(engines)); + engines.class_instance[0].engine_class = I915_ENGINE_CLASS_INVALID; + engines.class_instance[0].engine_instance = I915_ENGINE_CLASS_INVALID_NONE; + idx = sizeof(*engines.class_instance); + p.size = base + idx; + gem_context_set_param(i915, &p); + + memcpy(&expected, &engines, sizeof(expected)); + + gem_context_get_param(i915, &p); + igt_assert_eq(p.size, base + idx); + igt_assert(!memcmp(&expected, &engines, idx)); + + memset(&engines, 0, sizeof(engines)); + p.size = sizeof(engines); + gem_context_set_param(i915, &p); + + memcpy(&expected, &engines, sizeof(expected)); + + gem_context_get_param(i915, &p); + igt_assert_eq(p.size, sizeof(engines)); + igt_assert(!memcmp(&expected, &engines, idx)); + + gem_context_destroy(i915, p.ctx_id); +} + +static void execute_one(int i915) +{ + I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1); + struct drm_i915_gem_context_param param = { + .ctx_id = gem_context_create(i915), + .param = I915_CONTEXT_PARAM_ENGINES, + .value = to_user_pointer(&engines), + /* .size to be filled in later */ + }; + 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)); + + /* Unadulterated I915_EXEC_DEFAULT should work */ + execbuf.flags = 0; + igt_assert_eq(__gem_execbuf(i915, &execbuf), 0); + gem_sync(i915, obj.handle); + + for_each_engine_class_instance(i915, e) { + struct drm_i915_gem_busy busy = { .handle = obj.handle }; + + for (int i = -1; i <= I915_EXEC_RING_MASK; i++) { + igt_spin_t *spin; + + memset(&engines, 0, sizeof(engines)); + engine_class(&engines, 0) = e->class; + engine_instance(&engines, 0) = e->instance; + param.size = offsetof(typeof(engines), class_instance[1]); + gem_context_set_param(i915, ¶m); + + spin = igt_spin_batch_new(i915, + .ctx = param.ctx_id, + .engine = 0); + + igt_debug("Testing with map of %d engines\n", i + 1); + memset(&engines.class_instance, -1, sizeof(engines.class_instance)); + if (i != -1) { + engine_class(&engines, i) = e->class; + engine_instance(&engines, i) = e->instance; + } + param.size = sizeof(uint64_t) + (i + 1) * sizeof(uint32_t); + gem_context_set_param(i915, ¶m); + + for (int j = 0; j <= I915_EXEC_RING_MASK; j++) { + int err; + + execbuf.flags = j; + err =__gem_execbuf(i915, &execbuf); + if (j == i) { + igt_assert_f(err == 0, + "Failed to report the valid engine for slot %d\n", + i); + } else { + igt_assert_f(err == -EINVAL, + "Failed to report an invalid engine for slot %d (valid at %d)\n", + j, i); + } + } + + do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy); + if (i != -1) { + igt_assert_eq(busy.busy, 1 << (e->class + 16)); + } else { + igt_assert_eq(busy.busy, 0); + } + + igt_spin_batch_free(i915, spin); + + gem_sync(i915, obj.handle); + do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy); + igt_assert_eq(busy.busy, 0); + } + } + + /* 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); +} + +static void execute_oneforall(int i915) +{ + I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1); + struct drm_i915_gem_context_param param = { + .ctx_id = gem_context_create(i915), + .param = I915_CONTEXT_PARAM_ENGINES, + .value = to_user_pointer(&engines), + .size = sizeof(engines), + }; + const struct intel_execution_engine2 *e; + + for_each_engine_class_instance(i915, e) { + memset(&engines, 0, sizeof(engines)); + for (int i = 0; i <= I915_EXEC_RING_MASK; i++) { + engine_class(&engines, i) = e->class; + engine_instance(&engines, i) = e->instance; + } + gem_context_set_param(i915, ¶m); + + for (int i = 0; i <= I915_EXEC_RING_MASK; i++) { + struct drm_i915_gem_busy busy = {}; + igt_spin_t *spin; + + spin = __igt_spin_batch_new(i915, + .ctx = param.ctx_id, + .engine = i); + + busy.handle = spin->handle; + do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy); + igt_assert_eq(busy.busy, 1 << (e->class + 16)); + + igt_spin_batch_free(i915, spin); + } + } + + gem_context_destroy(i915, param.ctx_id); +} + +static void execute_allforone(int i915) +{ + I915_DEFINE_CONTEXT_PARAM_ENGINES(engines , I915_EXEC_RING_MASK + 1); + struct drm_i915_gem_context_param param = { + .ctx_id = gem_context_create(i915), + .param = I915_CONTEXT_PARAM_ENGINES, + .value = to_user_pointer(&engines), + }; + const struct intel_execution_engine2 *e; + int i; + + i = 0; + memset(&engines, 0, sizeof(engines)); + for_each_engine_class_instance(i915, e) { + engine_class(&engines, i) = e->class; + engine_instance(&engines, i) = e->instance; + i++; + } + param.size = sizeof(uint64_t) + i * sizeof(uint32_t); + gem_context_set_param(i915, ¶m); + + i = 0; + for_each_engine_class_instance(i915, e) { + struct drm_i915_gem_busy busy = {}; + igt_spin_t *spin; + + spin = __igt_spin_batch_new(i915, + .ctx = param.ctx_id, + .engine = i++); + + busy.handle = spin->handle; + do_ioctl(i915, DRM_IOCTL_I915_GEM_BUSY, &busy); + igt_assert_eq(busy.busy, 1 << (e->class + 16)); + + igt_spin_batch_free(i915, spin); + } + + 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("idempotent") + idempotent(i915); + + igt_subtest("execute-one") + execute_one(i915); + + igt_subtest("execute-oneforall") + execute_oneforall(i915); + + igt_subtest("execute-allforone") + execute_allforone(i915); +} diff --git a/tests/meson.build b/tests/meson.build index e005c79c4..abfc85f46 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -110,6 +110,7 @@ i915_progs = [ 'gem_ctx_bad_destroy', 'gem_ctx_clone', 'gem_ctx_create', + 'gem_ctx_engines', 'gem_ctx_exec', 'gem_ctx_isolation', 'gem_ctx_param',