diff options
-rw-r--r-- | lib/Makefile.sources | 2 | ||||
-rw-r--r-- | lib/i915/gem_engine_topology.c | 282 | ||||
-rw-r--r-- | lib/i915/gem_engine_topology.h | 79 | ||||
-rw-r--r-- | lib/igt.h | 1 | ||||
-rw-r--r-- | lib/igt_gt.h | 2 | ||||
-rw-r--r-- | lib/meson.build | 1 |
6 files changed, 367 insertions, 0 deletions
diff --git a/lib/Makefile.sources b/lib/Makefile.sources index 97685823..ef96bd09 100644 --- a/lib/Makefile.sources +++ b/lib/Makefile.sources @@ -13,6 +13,8 @@ lib_source_list = \ i915/gem_ring.c \ i915/gem_mman.c \ i915/gem_mman.h \ + i915/gem_engine_topology.c \ + i915/gem_engine_topology.h \ i915_3d.h \ i915_reg.h \ i915_pciids.h \ diff --git a/lib/i915/gem_engine_topology.c b/lib/i915/gem_engine_topology.c new file mode 100644 index 00000000..7a4a1760 --- /dev/null +++ b/lib/i915/gem_engine_topology.c @@ -0,0 +1,282 @@ +/* + * Copyright © 2019 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 "drmtest.h" +#include "ioctl_wrappers.h" + +#include "i915/gem_engine_topology.h" + +#define DEFINE_CONTEXT_PARAM(e__, p__, c__, N__) \ + I915_DEFINE_CONTEXT_PARAM_ENGINES(e__, N__); \ + struct drm_i915_gem_context_param p__ = { \ + .param = I915_CONTEXT_PARAM_ENGINES, \ + .ctx_id = c__, \ + .size = SIZEOF_CTX_PARAM, \ + .value = to_user_pointer(&e__), \ + } + +static int __gem_query(int fd, struct drm_i915_query *q) +{ + int err = 0; + + if (igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q)) + err = -errno; + + errno = 0; + return err; +} + +static void gem_query(int fd, struct drm_i915_query *q) +{ + igt_assert_eq(__gem_query(fd, q), 0); +} + +static void query_engines(int fd, + struct drm_i915_query_engine_info *query_engines, + int length) +{ + struct drm_i915_query_item item = { }; + struct drm_i915_query query = { }; + + item.query_id = DRM_I915_QUERY_ENGINE_INFO; + query.items_ptr = to_user_pointer(&item); + query.num_items = 1; + item.length = length; + + item.data_ptr = to_user_pointer(query_engines); + + gem_query(fd, &query); +} + +static void ctx_map_engines(int fd, struct intel_engine_data *ed, + struct drm_i915_gem_context_param *param) +{ + struct i915_context_param_engines *engines = + (struct i915_context_param_engines *) param->value; + int i = 0; + + for (typeof(engines->engines[0]) *p = + &engines->engines[0]; + i < ed->nengines; i++, p++) { + p->engine_class = ed->engines[i].class; + p->engine_instance = ed->engines[i].instance; + } + + param->size = offsetof(typeof(*engines), engines[i]); + engines->extensions = 0; + + gem_context_set_param(fd, param); +} + +static void init_engine(struct intel_execution_engine2 *e2, + int class, int instance, uint64_t flags) +{ + const struct intel_execution_engine2 *__e2; + static const char *unknown_name = "unknown", + *virtual_name = "virtual"; + + e2->class = class; + e2->instance = instance; + e2->flags = flags; + + /* engine is a virtual engine */ + if (class == I915_ENGINE_CLASS_INVALID) { + e2->name = virtual_name; + e2->is_virtual = true; + return; + } + + __for_each_static_engine(__e2) + if (__e2->class == class && __e2->instance == instance) + break; + + if (__e2->name) { + e2->name = __e2->name; + } else { + igt_warn("found unknown engine (%d, %d)", class, instance); + e2->name = unknown_name; + } + + /* just to remark it */ + e2->is_virtual = false; +} + +static void query_engine_list(int fd, struct intel_engine_data *ed) +{ + uint8_t buff[SIZEOF_QUERY] = { }; + struct drm_i915_query_engine_info *query_engine = + (struct drm_i915_query_engine_info *) buff; + int i; + + query_engines(fd, query_engine, SIZEOF_QUERY); + + for (i = 0; i < query_engine->num_engines; i++) + init_engine(&ed->engines[i], + query_engine->engines[i].engine.engine_class, + query_engine->engines[i].engine.engine_instance, i); + + ed->nengines = query_engine->num_engines; +} + +struct intel_execution_engine2 * +intel_get_current_engine(struct intel_engine_data *ed) +{ + if (!ed->n) + ed->current_engine = &ed->engines[0]; + else if (ed->n >= ed->nengines) + ed->current_engine = NULL; + + return ed->current_engine; +} + +void intel_next_engine(struct intel_engine_data *ed) +{ + if (ed->n + 1 < ed->nengines) { + ed->n++; + ed->current_engine = &ed->engines[ed->n]; + } else { + ed->n = ed->nengines; + ed->current_engine = NULL; + } +} + +struct intel_execution_engine2 * +intel_get_current_physical_engine(struct intel_engine_data *ed) +{ + struct intel_execution_engine2 *e; + + for (e = intel_get_current_engine(ed); + e && e->is_virtual; + intel_next_engine(ed)) + ; + + return e; +} + +static int gem_topology_get_param(int fd, + struct drm_i915_gem_context_param *p) +{ + if (igt_only_list_subtests()) + return -ENODEV; + + if (__gem_context_get_param(fd, p)) + return -1; /* using default engine map */ + + if (!p->size) + return 0; + + p->size = (p->size - sizeof(struct i915_context_param_engines)) / + (offsetof(struct i915_context_param_engines, + engines[1]) - + sizeof(struct i915_context_param_engines)); + + igt_assert_f(p->size <= GEM_MAX_ENGINES, "unsupported engine count\n"); + + return 0; +} + +struct intel_engine_data intel_init_engine_list(int fd, uint32_t ctx_id) +{ + DEFINE_CONTEXT_PARAM(engines, param, ctx_id, GEM_MAX_ENGINES); + struct intel_engine_data engine_data = { }; + int i; + + if (gem_topology_get_param(fd, ¶m)) { + /* if kernel does not support engine/context mapping */ + const struct intel_execution_engine2 *e2; + + igt_debug("using pre-allocated engine list\n"); + + __for_each_static_engine(e2) { + struct intel_execution_engine2 *__e2 = + &engine_data.engines[engine_data.nengines]; + + if (!igt_only_list_subtests()) { + __e2->flags = gem_class_instance_to_eb_flags(fd, + e2->class, e2->instance); + + if (!gem_has_ring(fd, __e2->flags)) + continue; + } else { + __e2->flags = -1; /* 0xfff... */ + } + + __e2->name = e2->name; + __e2->instance = e2->instance; + __e2->class = e2->class; + __e2->is_virtual = false; + + engine_data.nengines++; + } + return engine_data; + } + + if (!param.size) { + query_engine_list(fd, &engine_data); + ctx_map_engines(fd, &engine_data, ¶m); + } else { + for (i = 0; i < param.size; i++) + init_engine(&engine_data.engines[i], + engines.engines[i].engine_class, + engines.engines[i].engine_instance, + i); + + engine_data.nengines = i; + } + + return engine_data; +} + +int gem_context_lookup_engine(int fd, uint64_t engine, uint32_t ctx_id, + struct intel_execution_engine2 *e) +{ + DEFINE_CONTEXT_PARAM(engines, param, ctx_id, GEM_MAX_ENGINES); + + if (!e || gem_topology_get_param(fd, ¶m) || !param.size) + return -EINVAL; + + e->class = engines.engines[engine].engine_class; + e->instance = engines.engines[engine].engine_instance; + + return 0; +} + +void gem_context_set_all_engines(int fd, uint32_t ctx) +{ + DEFINE_CONTEXT_PARAM(engines, param, ctx, GEM_MAX_ENGINES); + struct intel_engine_data engine_data = { }; + + if (!gem_topology_get_param(fd, ¶m) && !param.size) { + query_engine_list(fd, &engine_data); + ctx_map_engines(fd, &engine_data, ¶m); + } +} + +bool gem_has_engine_topology(int fd) +{ + struct drm_i915_gem_context_param param = { + .param = I915_CONTEXT_PARAM_ENGINES, + }; + + return !__gem_context_get_param(fd, ¶m); +} diff --git a/lib/i915/gem_engine_topology.h b/lib/i915/gem_engine_topology.h new file mode 100644 index 00000000..b40204b1 --- /dev/null +++ b/lib/i915/gem_engine_topology.h @@ -0,0 +1,79 @@ +/* + * Copyright © 2019 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. + */ + +#ifndef GEM_ENGINE_TOPOLOGY_H +#define GEM_ENGINE_TOPOLOGY_H + +#include "igt_gt.h" +#include "i915_drm.h" + +/* + * Limit what we support for simplicity due limitation in how much we + * can address via execbuf2. + */ +#define SIZEOF_CTX_PARAM offsetof(struct i915_context_param_engines, \ + engines[GEM_MAX_ENGINES]) +#define SIZEOF_QUERY offsetof(struct drm_i915_query_engine_info, \ + engines[GEM_MAX_ENGINES]) + +#define GEM_MAX_ENGINES I915_EXEC_RING_MASK + 1 + +struct intel_engine_data { + uint32_t nengines; + uint32_t n; + struct intel_execution_engine2 *current_engine; + struct intel_execution_engine2 engines[GEM_MAX_ENGINES]; +}; + +bool gem_has_engine_topology(int fd); +struct intel_engine_data intel_init_engine_list(int fd, uint32_t ctx_id); + +/* iteration functions */ +struct intel_execution_engine2 * +intel_get_current_engine(struct intel_engine_data *ed); + +struct intel_execution_engine2 * +intel_get_current_physical_engine(struct intel_engine_data *ed); + +void intel_next_engine(struct intel_engine_data *ed); + +int gem_context_lookup_engine(int fd, uint64_t engine, uint32_t ctx_id, + struct intel_execution_engine2 *e); + +void gem_context_set_all_engines(int fd, uint32_t ctx); + +#define __for_each_static_engine(e__) \ + for ((e__) = intel_execution_engines2; (e__)->name; (e__)++) + +#define for_each_context_engine(fd__, ctx__, e__) \ + for (struct intel_engine_data i__ = intel_init_engine_list(fd__, ctx__); \ + ((e__) = intel_get_current_engine(&i__)); \ + intel_next_engine(&i__)) + +/* needs to replace "for_each_physical_engine" when conflicts are fixed */ +#define __for_each_physical_engine(fd__, e__) \ + for (struct intel_engine_data i__ = intel_init_engine_list(fd__, 0); \ + ((e__) = intel_get_current_physical_engine(&i__)); \ + intel_next_engine(&i__)) + +#endif /* GEM_ENGINE_TOPOLOGY_H */ @@ -54,5 +54,6 @@ #include "media_spin.h" #include "rendercopy.h" #include "i915/gem_mman.h" +#include "i915/gem_engine_topology.h" #endif /* IGT_H */ diff --git a/lib/igt_gt.h b/lib/igt_gt.h index 475c0b3c..52b2f1ea 100644 --- a/lib/igt_gt.h +++ b/lib/igt_gt.h @@ -95,6 +95,8 @@ extern const struct intel_execution_engine2 { const char *name; int class; int instance; + uint64_t flags; + bool is_virtual; } intel_execution_engines2[]; unsigned int diff --git a/lib/meson.build b/lib/meson.build index 80736868..b6d8e6ca 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -5,6 +5,7 @@ lib_sources = [ 'i915/gem_submission.c', 'i915/gem_ring.c', 'i915/gem_mman.c', + 'i915/gem_engine_topology.c', 'igt_color_encoding.c', 'igt_debugfs.c', 'igt_device.c', |