Commit cda9edd0 authored by Lionel Landwerlin's avatar Lionel Landwerlin Committed by Rodrigo Vivi

drm/i915: introduce a mechanism to extend execbuf2

We're planning to use this for a couple of new feature where we need
to provide additional parameters to execbuf.

v2: Check for invalid flags in execbuffer2 (Lionel)

v3: Rename I915_EXEC_EXT -> I915_EXEC_USE_EXTENSIONS (Chris)

v4: Rebase
    Move array fence parsing in i915_gem_do_execbuffer()
Signed-off-by: default avatarLionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20200804085954.350343-2-lionel.g.landwerlin@intel.com
Link: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/2901Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 3f8210fd
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "i915_gem_ioctls.h" #include "i915_gem_ioctls.h"
#include "i915_sw_fence_work.h" #include "i915_sw_fence_work.h"
#include "i915_trace.h" #include "i915_trace.h"
#include "i915_user_extensions.h"
struct eb_vma { struct eb_vma {
struct i915_vma *vma; struct i915_vma *vma;
...@@ -281,6 +282,13 @@ struct i915_execbuffer { ...@@ -281,6 +282,13 @@ struct i915_execbuffer {
int lut_size; int lut_size;
struct hlist_head *buckets; /** ht for relocation handles */ struct hlist_head *buckets; /** ht for relocation handles */
struct eb_vma_array *array; struct eb_vma_array *array;
struct i915_eb_fence {
struct drm_syncobj *syncobj; /* Use with ptr_mask_bits() */
} *fences;
u32 n_fences;
u64 extension_flags; /** Available extensions parameters */
}; };
static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb) static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
...@@ -1622,7 +1630,8 @@ static int i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) ...@@ -1622,7 +1630,8 @@ static int i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
return -EINVAL; return -EINVAL;
/* Kernel clipping was a DRI1 misfeature */ /* Kernel clipping was a DRI1 misfeature */
if (!(exec->flags & I915_EXEC_FENCE_ARRAY)) { if (!(exec->flags & (I915_EXEC_FENCE_ARRAY |
I915_EXEC_USE_EXTENSIONS))) {
if (exec->num_cliprects || exec->cliprects_ptr) if (exec->num_cliprects || exec->cliprects_ptr)
return -EINVAL; return -EINVAL;
} }
...@@ -2201,41 +2210,41 @@ eb_pin_engine(struct i915_execbuffer *eb, ...@@ -2201,41 +2210,41 @@ eb_pin_engine(struct i915_execbuffer *eb,
} }
static void static void
__free_fence_array(struct drm_syncobj **fences, unsigned int n) __free_fence_array(struct i915_eb_fence *fences, unsigned int n)
{ {
while (n--) while (n--)
drm_syncobj_put(ptr_mask_bits(fences[n], 2)); drm_syncobj_put(ptr_mask_bits(fences[n].syncobj, 2));
kvfree(fences); kvfree(fences);
} }
static struct drm_syncobj ** static int
get_fence_array(struct drm_i915_gem_execbuffer2 *args, get_fence_array(struct drm_i915_gem_execbuffer2 *args,
struct drm_file *file) struct i915_execbuffer *eb)
{ {
const unsigned long nfences = args->num_cliprects; const unsigned long nfences = args->num_cliprects;
struct drm_i915_gem_exec_fence __user *user; struct drm_i915_gem_exec_fence __user *user;
struct drm_syncobj **fences; struct i915_eb_fence *fences;
unsigned long n; unsigned long n;
int err; int err;
if (!(args->flags & I915_EXEC_FENCE_ARRAY)) if (!(args->flags & I915_EXEC_FENCE_ARRAY))
return NULL; return 0;
/* Check multiplication overflow for access_ok() and kvmalloc_array() */ /* Check multiplication overflow for access_ok() and kvmalloc_array() */
BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long)); BUILD_BUG_ON(sizeof(size_t) > sizeof(unsigned long));
if (nfences > min_t(unsigned long, if (nfences > min_t(unsigned long,
ULONG_MAX / sizeof(*user), ULONG_MAX / sizeof(*user),
SIZE_MAX / sizeof(*fences))) SIZE_MAX / sizeof(*fences)))
return ERR_PTR(-EINVAL); return -EINVAL;
user = u64_to_user_ptr(args->cliprects_ptr); user = u64_to_user_ptr(args->cliprects_ptr);
if (!access_ok(user, nfences * sizeof(*user))) if (!access_ok(user, nfences * sizeof(*user)))
return ERR_PTR(-EFAULT); return -EFAULT;
fences = kvmalloc_array(nfences, sizeof(*fences), fences = kvmalloc_array(nfences, sizeof(*fences),
__GFP_NOWARN | GFP_KERNEL); __GFP_NOWARN | GFP_KERNEL);
if (!fences) if (!fences)
return ERR_PTR(-ENOMEM); return -ENOMEM;
for (n = 0; n < nfences; n++) { for (n = 0; n < nfences; n++) {
struct drm_i915_gem_exec_fence fence; struct drm_i915_gem_exec_fence fence;
...@@ -2251,7 +2260,7 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args, ...@@ -2251,7 +2260,7 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args,
goto err; goto err;
} }
syncobj = drm_syncobj_find(file, fence.handle); syncobj = drm_syncobj_find(eb->file, fence.handle);
if (!syncobj) { if (!syncobj) {
DRM_DEBUG("Invalid syncobj handle provided\n"); DRM_DEBUG("Invalid syncobj handle provided\n");
err = -ENOENT; err = -ENOENT;
...@@ -2261,38 +2270,31 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args, ...@@ -2261,38 +2270,31 @@ get_fence_array(struct drm_i915_gem_execbuffer2 *args,
BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) & BUILD_BUG_ON(~(ARCH_KMALLOC_MINALIGN - 1) &
~__I915_EXEC_FENCE_UNKNOWN_FLAGS); ~__I915_EXEC_FENCE_UNKNOWN_FLAGS);
fences[n] = ptr_pack_bits(syncobj, fence.flags, 2); fences[n].syncobj = ptr_pack_bits(syncobj, fence.flags, 2);
} }
return fences; eb->fences = fences;
eb->n_fences = nfences;
return 0;
err: err:
__free_fence_array(fences, n); __free_fence_array(fences, n);
return ERR_PTR(err); return err;
}
static void
put_fence_array(struct drm_i915_gem_execbuffer2 *args,
struct drm_syncobj **fences)
{
if (fences)
__free_fence_array(fences, args->num_cliprects);
} }
static int static int
await_fence_array(struct i915_execbuffer *eb, await_fence_array(struct i915_execbuffer *eb)
struct drm_syncobj **fences)
{ {
const unsigned int nfences = eb->args->num_cliprects;
unsigned int n; unsigned int n;
int err; int err;
for (n = 0; n < nfences; n++) { for (n = 0; n < eb->n_fences; n++) {
struct drm_syncobj *syncobj; struct drm_syncobj *syncobj;
struct dma_fence *fence; struct dma_fence *fence;
unsigned int flags; unsigned int flags;
syncobj = ptr_unpack_bits(fences[n], &flags, 2); syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2);
if (!(flags & I915_EXEC_FENCE_WAIT)) if (!(flags & I915_EXEC_FENCE_WAIT))
continue; continue;
...@@ -2310,18 +2312,16 @@ await_fence_array(struct i915_execbuffer *eb, ...@@ -2310,18 +2312,16 @@ await_fence_array(struct i915_execbuffer *eb,
} }
static void static void
signal_fence_array(struct i915_execbuffer *eb, signal_fence_array(struct i915_execbuffer *eb)
struct drm_syncobj **fences)
{ {
const unsigned int nfences = eb->args->num_cliprects;
struct dma_fence * const fence = &eb->request->fence; struct dma_fence * const fence = &eb->request->fence;
unsigned int n; unsigned int n;
for (n = 0; n < nfences; n++) { for (n = 0; n < eb->n_fences; n++) {
struct drm_syncobj *syncobj; struct drm_syncobj *syncobj;
unsigned int flags; unsigned int flags;
syncobj = ptr_unpack_bits(fences[n], &flags, 2); syncobj = ptr_unpack_bits(eb->fences[n].syncobj, &flags, 2);
if (!(flags & I915_EXEC_FENCE_SIGNAL)) if (!(flags & I915_EXEC_FENCE_SIGNAL))
continue; continue;
...@@ -2370,12 +2370,38 @@ static void eb_request_add(struct i915_execbuffer *eb) ...@@ -2370,12 +2370,38 @@ static void eb_request_add(struct i915_execbuffer *eb)
mutex_unlock(&tl->mutex); mutex_unlock(&tl->mutex);
} }
static const i915_user_extension_fn execbuf_extensions[] = {
};
static int
parse_execbuf2_extensions(struct drm_i915_gem_execbuffer2 *args,
struct i915_execbuffer *eb)
{
eb->extension_flags = 0;
if (!(args->flags & I915_EXEC_USE_EXTENSIONS))
return 0;
/* The execbuf2 extension mechanism reuses cliprects_ptr. So we cannot
* have another flag also using it at the same time.
*/
if (eb->args->flags & I915_EXEC_FENCE_ARRAY)
return -EINVAL;
if (args->num_cliprects != 0)
return -EINVAL;
return i915_user_extensions(u64_to_user_ptr(args->cliprects_ptr),
execbuf_extensions,
ARRAY_SIZE(execbuf_extensions),
eb);
}
static int static int
i915_gem_do_execbuffer(struct drm_device *dev, i915_gem_do_execbuffer(struct drm_device *dev,
struct drm_file *file, struct drm_file *file,
struct drm_i915_gem_execbuffer2 *args, struct drm_i915_gem_execbuffer2 *args,
struct drm_i915_gem_exec_object2 *exec, struct drm_i915_gem_exec_object2 *exec)
struct drm_syncobj **fences)
{ {
struct drm_i915_private *i915 = to_i915(dev); struct drm_i915_private *i915 = to_i915(dev);
struct i915_execbuffer eb; struct i915_execbuffer eb;
...@@ -2405,6 +2431,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2405,6 +2431,9 @@ i915_gem_do_execbuffer(struct drm_device *dev,
eb.batch_len = args->batch_len; eb.batch_len = args->batch_len;
eb.trampoline = NULL; eb.trampoline = NULL;
eb.fences = NULL;
eb.n_fences = 0;
eb.batch_flags = 0; eb.batch_flags = 0;
if (args->flags & I915_EXEC_SECURE) { if (args->flags & I915_EXEC_SECURE) {
if (INTEL_GEN(i915) >= 11) if (INTEL_GEN(i915) >= 11)
...@@ -2441,10 +2470,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2441,10 +2470,18 @@ i915_gem_do_execbuffer(struct drm_device *dev,
} }
} }
err = eb_create(&eb); err = parse_execbuf2_extensions(args, &eb);
if (err) if (err)
goto err_out_fence; goto err_out_fence;
err = get_fence_array(args, &eb);
if (err)
goto err_arr_fence;
err = eb_create(&eb);
if (err)
goto err_arr_fence;
GEM_BUG_ON(!eb.lut_size); GEM_BUG_ON(!eb.lut_size);
err = eb_select_context(&eb); err = eb_select_context(&eb);
...@@ -2539,8 +2576,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2539,8 +2576,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
goto err_request; goto err_request;
} }
if (fences) { if (eb.n_fences) {
err = await_fence_array(&eb, fences); err = await_fence_array(&eb);
if (err) if (err)
goto err_request; goto err_request;
} }
...@@ -2571,8 +2608,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2571,8 +2608,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
i915_request_get(eb.request); i915_request_get(eb.request);
eb_request_add(&eb); eb_request_add(&eb);
if (fences) if (eb.n_fences)
signal_fence_array(&eb, fences); signal_fence_array(&eb);
if (out_fence) { if (out_fence) {
if (err == 0) { if (err == 0) {
...@@ -2600,6 +2637,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, ...@@ -2600,6 +2637,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
i915_gem_context_put(eb.gem_context); i915_gem_context_put(eb.gem_context);
err_destroy: err_destroy:
eb_destroy(&eb); eb_destroy(&eb);
err_arr_fence:
__free_fence_array(eb.fences, eb.n_fences);
err_out_fence: err_out_fence:
if (out_fence_fd != -1) if (out_fence_fd != -1)
put_unused_fd(out_fence_fd); put_unused_fd(out_fence_fd);
...@@ -2699,7 +2738,7 @@ i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data, ...@@ -2699,7 +2738,7 @@ i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data,
exec2_list[i].flags = 0; exec2_list[i].flags = 0;
} }
err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list, NULL); err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list);
if (exec2.flags & __EXEC_HAS_RELOC) { if (exec2.flags & __EXEC_HAS_RELOC) {
struct drm_i915_gem_exec_object __user *user_exec_list = struct drm_i915_gem_exec_object __user *user_exec_list =
u64_to_user_ptr(args->buffers_ptr); u64_to_user_ptr(args->buffers_ptr);
...@@ -2731,7 +2770,6 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, ...@@ -2731,7 +2770,6 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
struct drm_i915_private *i915 = to_i915(dev); struct drm_i915_private *i915 = to_i915(dev);
struct drm_i915_gem_execbuffer2 *args = data; struct drm_i915_gem_execbuffer2 *args = data;
struct drm_i915_gem_exec_object2 *exec2_list; struct drm_i915_gem_exec_object2 *exec2_list;
struct drm_syncobj **fences = NULL;
const size_t count = args->buffer_count; const size_t count = args->buffer_count;
int err; int err;
...@@ -2759,15 +2797,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, ...@@ -2759,15 +2797,7 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data,
return -EFAULT; return -EFAULT;
} }
if (args->flags & I915_EXEC_FENCE_ARRAY) { err = i915_gem_do_execbuffer(dev, file, args, exec2_list);
fences = get_fence_array(args, file);
if (IS_ERR(fences)) {
kvfree(exec2_list);
return PTR_ERR(fences);
}
}
err = i915_gem_do_execbuffer(dev, file, args, exec2_list, fences);
/* /*
* Now that we have begun execution of the batchbuffer, we ignore * Now that we have begun execution of the batchbuffer, we ignore
...@@ -2808,7 +2838,6 @@ end:; ...@@ -2808,7 +2838,6 @@ end:;
} }
args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS; args->flags &= ~__I915_EXEC_UNKNOWN_FLAGS;
put_fence_array(args, fences);
kvfree(exec2_list); kvfree(exec2_list);
return err; return err;
} }
......
...@@ -1046,6 +1046,10 @@ struct drm_i915_gem_exec_fence { ...@@ -1046,6 +1046,10 @@ struct drm_i915_gem_exec_fence {
__u32 flags; __u32 flags;
}; };
enum drm_i915_gem_execbuffer_ext {
DRM_I915_GEM_EXECBUFFER_EXT_MAX /* non-ABI */
};
struct drm_i915_gem_execbuffer2 { struct drm_i915_gem_execbuffer2 {
/** /**
* List of gem_exec_object2 structs * List of gem_exec_object2 structs
...@@ -1062,8 +1066,14 @@ struct drm_i915_gem_execbuffer2 { ...@@ -1062,8 +1066,14 @@ struct drm_i915_gem_execbuffer2 {
__u32 num_cliprects; __u32 num_cliprects;
/** /**
* This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY * This is a struct drm_clip_rect *cliprects if I915_EXEC_FENCE_ARRAY
* is not set. If I915_EXEC_FENCE_ARRAY is set, then this is a * & I915_EXEC_USE_EXTENSIONS are not set.
* struct drm_i915_gem_exec_fence *fences. *
* If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array
* of struct drm_i915_gem_exec_fence and num_cliprects is the length
* of the array.
*
* If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a
* single struct i915_user_extension and num_cliprects is 0.
*/ */
__u64 cliprects_ptr; __u64 cliprects_ptr;
#define I915_EXEC_RING_MASK (0x3f) #define I915_EXEC_RING_MASK (0x3f)
...@@ -1181,7 +1191,16 @@ struct drm_i915_gem_execbuffer2 { ...@@ -1181,7 +1191,16 @@ struct drm_i915_gem_execbuffer2 {
*/ */
#define I915_EXEC_FENCE_SUBMIT (1 << 20) #define I915_EXEC_FENCE_SUBMIT (1 << 20)
#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SUBMIT << 1)) /*
* Setting I915_EXEC_USE_EXTENSIONS implies that
* drm_i915_gem_execbuffer2.cliprects_ptr is treated as a pointer to an linked
* list of i915_user_extension. Each i915_user_extension node is the base of a
* larger structure. The list of supported structures are listed in the
* drm_i915_gem_execbuffer_ext enum.
*/
#define I915_EXEC_USE_EXTENSIONS (1 << 21)
#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1))
#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff)
#define i915_execbuffer2_set_context_id(eb2, context) \ #define i915_execbuffer2_set_context_id(eb2, context) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment