[igt-dev] [PATCH v13 6/9] lib/i915: add gem_engine_topology library

Chris Wilson chris at chris-wilson.co.uk
Wed Mar 20 09:56:01 UTC 2019


Quoting Andi Shyti (2019-03-19 23:44:38)
> The gem_engine_topology library is a set of functions that
> interface with the query and getparam/setparam ioctls.
> 
> The library's access point is the 'intel_init_engine_list()'
> function that, everytime is called, generates the list of active
> engines and returns them in a 'struct intel_engine_data'. The
> structure contains only the engines that are actively present in
> the GPU.
> 
> The function can work in both the cases that the query and
> getparam ioctls are implemented or not by the running kernel. In
> case they are implemented, a query is made to the driver to fetch
> the list of active engines. In case they are not implemented, the
> list is taken from the 'intel_execution_engines2' array and
> stored only after checking their presence.
> 
> Signed-off-by: Andi Shyti <andi.shyti at intel.com>
> ---
>  lib/Makefile.sources           |   2 +
>  lib/i915/gem_engine_topology.c | 192 +++++++++++++++++++++++++++++++++
>  lib/i915/gem_engine_topology.h |  41 +++++++
>  lib/meson.build                |   1 +
>  4 files changed, 236 insertions(+)
>  create mode 100644 lib/i915/gem_engine_topology.c
>  create mode 100644 lib/i915/gem_engine_topology.h
> 
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index cf2720981707..757bd7a17ebe 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 000000000000..4ddd9ca98b49
> --- /dev/null
> +++ b/lib/i915/gem_engine_topology.c
> @@ -0,0 +1,192 @@
> +/*
> + * 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 SIZEOF_CTX_PARAM       offsetof(struct i915_context_param_engines, \
> +                                       class_instance[I915_EXEC_RING_MASK + 1])
> +#define SIZEOF_QUERY           offsetof(struct drm_i915_query_engine_info, \
> +                                       engines[I915_EXEC_RING_MASK + 1])
> +
> +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)
> +{
> +       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 = SIZEOF_QUERY;
> +
> +       item.data_ptr = to_user_pointer(query_engines);
> +
> +       gem_query(fd, &query);
> +}
> +
> +static void map_engine_context(struct intel_engine_data *ed,
> +                              struct drm_i915_gem_context_param *ctx_param)
> +{
> +       struct i915_context_param_engines *ctx_engine =
> +                       (struct i915_context_param_engines*) ctx_param->value;
> +       int i = 0;
> +
> +       for (typeof(ctx_engine->class_instance[0]) *p =
> +                                       &ctx_engine->class_instance[0];
> +                                               i < ed->nengines; i++, p++) {
> +               p->engine_class = ed->engines[i].class;
> +               p->engine_instance = ed->engines[i].instance;
> +       }
> +
> +       ctx_param->size = offsetof(typeof(*ctx_engine), class_instance[i + 1]);
> +
> +       gem_context_set_param(ed->fd, ctx_param);
> +}
> +
> +static void dup_engine(struct intel_execution_engine2 *e2, const char *name,
> +                      uint16_t class, uint16_t instance, uint8_t flags)
> +{
> +       const char *class_names[] = { "rcs", "bcs", "vcs", "vecs" };
> +       char *__name;
> +
> +       /* if we don't recognise the class, then we mark it as "unk" */
> +       if (name) {
> +               e2->name = name;
> +       } else {
> +               if (class >= ARRAY_SIZE(class_names))
> +                       igt_assert(asprintf(&__name, "unk-%d:%d",
> +                                           class, instance) > 0);
> +               else
> +                       igt_assert(asprintf(&__name, "%s%d",
> +                                           class_names[class], instance) > 0);
> +
> +               e2->name = __name;
> +       }
> +
> +       e2->class    = class;
> +       e2->instance = instance;
> +       e2->flags    = flags;
> +
> +}
> +
> +static void query_engine_list(struct intel_engine_data *ed)
> +{
> +       uint8_t query_buffer[SIZEOF_QUERY] = { };
> +       struct drm_i915_query_engine_info *query_engine =
> +                       (struct drm_i915_query_engine_info *) query_buffer;
> +       int i;
> +
> +       query_engines(ed->fd, query_engine);
> +
> +       for (i = 0; i < query_engine->num_engines; i++)
> +               dup_engine(&ed->engines[i], NULL,
> +                          query_engine->engines[i].engine_class,
> +                          query_engine->engines[i].engine_instance, i + 1);
> +
> +       ed->nengines = query_engine->num_engines;
> +}
> +
> +struct intel_engine_data intel_init_engine_list(int fd, uint32_t ctx_id)
> +{
> +       struct intel_engine_data engine_data = {
> +               .fd = fd,
> +               .ctx = ctx_id,
> +       };
> +       uint8_t buff[SIZEOF_CTX_PARAM] = { };
> +       struct i915_context_param_engines *cengine =
> +                               (struct i915_context_param_engines *) buff;

Oi, noet. And just a single tab indent.

> +       struct drm_i915_gem_context_param cparam = {
> +               .param = I915_CONTEXT_PARAM_ENGINES,
> +               .ctx_id = ctx_id,
> +               .size = SIZEOF_CTX_PARAM,
> +               .value = to_user_pointer(cengine),
> +       };
> +       int ret, i;
> +
> +       cparam.value = to_user_pointer(cengine);
> +
> +       ret = __gem_context_get_param(fd, &cparam);
> +
> +       if (ret) {
> +               /* if kernel does not support engine/context mapping */
> +               const struct intel_execution_engine2 *e2;

Hmm, how does this distinguish against too many engines (more than can
fit into buf?). Both return -EINVAL iirc?

> +               igt_debug("using pre-allocated engine list\n");
> +
> +               __for_each_engine_class_instance(e2) {
> +                       uint64_t flags;
> +
> +                       if (!gem_has_engine(fd, e2->class, e2->instance))
> +                               continue;
> +
> +                       flags = gem_class_instance_to_eb_flags(fd, e2->class,
> +                                                              e2->instance);
> +
> +                       dup_engine(&engine_data.engines[engine_data.nengines],
> +                                  e2->name, e2->class, e2->instance, flags);
> +
> +                       engine_data.nengines++;
> +               }
> +
> +       } else if (cparam.size == sizeof(struct i915_context_param_engines)) {
> +               /* else if context doesn't have mapped engines */

No, that is cparam.size == 0.

sizeof(engines) is 0 valid engines, as constructed by the user, so
should be respected.

> +               query_engine_list(&engine_data);
> +               map_engine_context(&engine_data, &cparam);
> +
> +       } else {
> +               /* context has a list of mapped engines */
> +
> +               uint8_t nengines = (cparam.size -
> +                               sizeof(struct i915_context_param_engines)) /
> +                               sizeof(cengine->class_instance[0]);
> +
> +               for (i = 0; i < nengines - 1; i++)

Pardon?

> +                       dup_engine(&engine_data.engines[i], NULL,
> +                                  cengine->class_instance[i].engine_class,
> +                                  cengine->class_instance[i].engine_instance,
> +                                  i + 1);

This seems very suspect. If class/instance doesn't map to a known
engine, dup_engine() should be figuring it out, as the engine[] is
entirely at the arbitrary whim of the user.

> +               engine_data.nengines = i;
> +       }
> +
> +       return engine_data;
> +}

> +#include "i915_drm.h"
> +#include "igt_gt.h"
> +
> +struct intel_engine_data {
> +       int fd;
> +       uint32_t ctx;
> +
> +       uint32_t nengines;
> +       uint32_t n;
> +       struct intel_execution_engine2 engines[I915_EXEC_RING_MASK + 1];
> +};

This is the _iter. Pull the for_each_foo() into this patch so we can see
how it is put together.

At which point, do we need the (fd,ctx) here since they are parameters to
the for_each() and so available later?

Missing _iter_fini. Polish the for_each_foo() a bit more.
-Chris


More information about the igt-dev mailing list