[Intel-gfx] [PATCH 27/38] drm/i915: Introduce the i915_user_extension_method
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Tue Jan 22 09:31:31 UTC 2019
On 18/01/2019 14:00, Chris Wilson wrote:
> An idea for extending uABI inspired by Vulkan's extension chains.
> Instead of expanding the data struct for each ioctl every time we need
> to add a new feature, define an extension chain instead. As we add
> optional interfaces to control the ioctl, we define a new extension
> struct that can be linked into the ioctl data only when required by the
> user. The key advantage being able to ignore large control structs for
> optional interfaces/extensions, while being able to process them in a
> consistent manner.
>
> In comparison to other extensible ioctls, the key difference is the
> use of a linked chain of extension structs vs an array of tagged
> pointers. For example,
>
> struct drm_amdgpu_cs_chunk {
> __u32 chunk_id;
> __u32 length_dw;
> __u64 chunk_data;
> };
>
> struct drm_amdgpu_cs_in {
> __u32 ctx_id;
> __u32 bo_list_handle;
> __u32 num_chunks;
> __u32 _pad;
> __u64 chunks;
> };
>
> allows userspace to pass in array of pointers to extension structs, but
> must therefore keep constructing that array along side the command stream.
> In dynamic situations like that, a linked list is preferred and does not
> similar from extra cache line misses as the extension structs themselves
s/similar/suffer/ I think.
> must still be loaded separate to the chunks array.
>
> v2: Apply the tail call optimisation directly to nip the worry of stack
> overflow in the bud.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> drivers/gpu/drm/i915/Makefile | 1 +
> drivers/gpu/drm/i915/i915_user_extensions.c | 42 +++++++++++++++++++++
> drivers/gpu/drm/i915/i915_user_extensions.h | 20 ++++++++++
> include/uapi/drm/i915_drm.h | 20 ++++++++++
> 4 files changed, 83 insertions(+)
> create mode 100644 drivers/gpu/drm/i915/i915_user_extensions.c
> create mode 100644 drivers/gpu/drm/i915/i915_user_extensions.h
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 611115ed00db..f206fbc85cee 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -45,6 +45,7 @@ i915-y := i915_drv.o \
> i915_sw_fence.o \
> i915_syncmap.o \
> i915_sysfs.o \
> + i915_user_extensions.o \
> intel_csr.o \
> intel_device_info.o \
> intel_pm.o \
> diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c b/drivers/gpu/drm/i915/i915_user_extensions.c
> new file mode 100644
> index 000000000000..5d90c368f185
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/i915_user_extensions.c
> @@ -0,0 +1,42 @@
> +/*
> + * SPDX-License-Identifier: MIT
> + *
> + * Copyright © 2018 Intel Corporation
> + */
> +
> +#include <linux/sched/signal.h>
> +#include <linux/uaccess.h>
> +#include <uapi/drm/i915_drm.h>
> +
> +#include "i915_user_extensions.h"
> +
> +int i915_user_extensions(struct i915_user_extension __user *ext,
> + const i915_user_extension_fn *tbl,
> + unsigned long count,
I would be tempted to limit the count to unsigned int. 4 billion
extensions should be enough for everyone. :)
ABI can remain u64, but implementation I think in this form does not
need it.
> + void *data)
> +{
> + while (ext) {
> + int err;
> + u64 x;
> +
> + cond_resched();
> + if (signal_pending(current))
> + return -EINTR;
What was your thinking behind this? It feels like, since here we are not
doing any explicit wait/sleeps, that at this level the code shouldn't
bother with it.
> +
> + if (get_user(x, &ext->name))
> + return -EFAULT;
> +
> + err = -EINVAL;
> + if (x < count && tbl[x])
> + err = tbl[x](ext, data);
> + if (err)
> + return err;
We talked about providing unwind on failure ie. option for destructor
call backs. You gave up on that?
> +
> + if (get_user(x, &ext->next_extension))
> + return -EFAULT;
> +
> + ext = u64_to_user_ptr(x);
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/i915_user_extensions.h b/drivers/gpu/drm/i915/i915_user_extensions.h
> new file mode 100644
> index 000000000000..313a510b068a
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/i915_user_extensions.h
> @@ -0,0 +1,20 @@
> +/*
> + * SPDX-License-Identifier: MIT
> + *
> + * Copyright © 2018 Intel Corporation
> + */
> +
> +#ifndef I915_USER_EXTENSIONS_H
> +#define I915_USER_EXTENSIONS_H
> +
> +struct i915_user_extension;
> +
> +typedef int (*i915_user_extension_fn)(struct i915_user_extension __user *ext,
> + void *data);
> +
> +int i915_user_extensions(struct i915_user_extension __user *ext,
> + const i915_user_extension_fn *tbl,
> + unsigned long count,
> + void *data);
> +
> +#endif /* I915_USER_EXTENSIONS_H */
> diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> index 298b2e197744..6ee2221838da 100644
> --- a/include/uapi/drm/i915_drm.h
> +++ b/include/uapi/drm/i915_drm.h
> @@ -62,6 +62,26 @@ extern "C" {
> #define I915_ERROR_UEVENT "ERROR"
> #define I915_RESET_UEVENT "RESET"
>
> +/*
> + * i915_user_extension: Base class for defining a chain of extensions
> + *
> + * Many interfaces need to grow over time. In most cases we can simply
> + * extend the struct and have userspace pass in more data. Another option,
> + * as demonstrated by Vulkan's approach to providing extensions for forward
> + * and backward compatibility, is to use a list of optional structs to
> + * provide those extra details.
> + *
> + * The key advantage to using an extension chain is that it allows us to
> + * redefine the interface more easily than an ever growing struct of
> + * increasing complexity, and for large parts of that interface to be
> + * entirely optional. The downside is more pointer chasing; chasing across
> + * the __user boundary with pointers encapsulated inside u64.
> + */
> +struct i915_user_extension {
> + __u64 next_extension;
> + __u64 name;
s/name/id/ ?
> +};
> +
> /*
> * MOCS indexes used for GPU surfaces, defining the cacheability of the
> * surface data and the coherency for this data wrt. CPU vs. GPU accesses.
>
Regards,
Tvrtko
More information about the Intel-gfx
mailing list