/* * 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); }