From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jason Ekstrand Subject: Re: [PATCH] drm/syncobj: add sync obj wait interface. (v7) Date: Fri, 4 Aug 2017 16:39:22 -0700 Message-ID: References: <20170718064459.13741-1-airlied@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0051021816==" Return-path: Received: from mail-wr0-x22a.google.com (mail-wr0-x22a.google.com [IPv6:2a00:1450:400c:c0c::22a]) by gabe.freedesktop.org (Postfix) with ESMTPS id DDDDC6E166 for ; Fri, 4 Aug 2017 23:39:24 +0000 (UTC) Received: by mail-wr0-x22a.google.com with SMTP id y43so21547071wrd.3 for ; Fri, 04 Aug 2017 16:39:24 -0700 (PDT) In-Reply-To: <20170718064459.13741-1-airlied@gmail.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Dave Airlie Cc: Maling list - DRI developers List-Id: dri-devel@lists.freedesktop.org --===============0051021816== Content-Type: multipart/alternative; boundary="f403045f546cc2ccd00555f60135" --f403045f546cc2ccd00555f60135 Content-Type: text/plain; charset="UTF-8" I'm working on a VK_KHR_external_fence implementation based on this and have found some issues. :-) On Mon, Jul 17, 2017 at 11:44 PM, Dave Airlie wrote: > From: Dave Airlie > > This interface will allow sync object to be used to back > Vulkan fences. This API is pretty much the vulkan fence waiting > API, and I've ported the code from amdgpu. > > v2: accept relative timeout, pass remaining time back > to userspace. > v3: return to absolute timeouts. > v4: absolute zero = poll, > rewrite any/all code to have same operation for arrays > return -EINVAL for 0 fences. > v4.1: fixup fences allocation check, use u64_to_user_ptr > v5: move to sec/nsec, and use timespec64 for calcs. > v6: use -ETIME and drop the out status flag. (-ETIME > is suggested by ickle, I can feel a shed painting) > v7: talked to Daniel/Arnd, use ktime and ns everywhere. > > Signed-off-by: Dave Airlie > --- > drivers/gpu/drm/drm_internal.h | 2 + > drivers/gpu/drm/drm_ioctl.c | 2 + > drivers/gpu/drm/drm_syncobj.c | 135 ++++++++++++++++++++++++++++++ > +++++++++++ > include/uapi/drm/drm.h | 12 ++++ > 4 files changed, 151 insertions(+) > > diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal > .h > index 5cecc97..d71b50d 100644 > --- a/drivers/gpu/drm/drm_internal.h > +++ b/drivers/gpu/drm/drm_internal.h > @@ -157,3 +157,5 @@ int drm_syncobj_handle_to_fd_ioctl(struct drm_device > *dev, void *data, > struct drm_file *file_private); > int drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data, > struct drm_file *file_private); > +int drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, > + struct drm_file *file_private); > diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c > index f1e5681..385ce74 100644 > --- a/drivers/gpu/drm/drm_ioctl.c > +++ b/drivers/gpu/drm/drm_ioctl.c > @@ -657,6 +657,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = { > DRM_UNLOCKED|DRM_RENDER_ALLOW), > DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, > drm_syncobj_fd_to_handle_ioctl, > DRM_UNLOCKED|DRM_RENDER_ALLOW), > + DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_syncobj_wait_ioctl, > + DRM_UNLOCKED|DRM_RENDER_ALLOW), > }; > > #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) > diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c > index 89441bc..d23dcc6 100644 > --- a/drivers/gpu/drm/drm_syncobj.c > +++ b/drivers/gpu/drm/drm_syncobj.c > @@ -1,5 +1,7 @@ > /* > * Copyright 2017 Red Hat > + * Parts ported from amdgpu (fence wait code). > + * Copyright 2016 Advanced Micro Devices, Inc. > * > * Permission is hereby granted, free of charge, to any person obtaining a > * copy of this software and associated documentation files (the > "Software"), > @@ -31,6 +33,9 @@ > * that contain an optional fence. The fence can be updated with a new > * fence, or be NULL. > * > + * syncobj's can be waited upon, where it will wait for the underlying > + * fence. > + * > * syncobj's can be export to fd's and back, these fd's are opaque and > * have no other use case, except passing the syncobj between processes. > * > @@ -451,3 +456,133 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device > *dev, void *data, > return drm_syncobj_fd_to_handle(file_private, args->fd, > &args->handle); > } > + > +/** > + * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute > value > + * > + * @timeout_sec: timeout sec component, 0 for poll > + * @timeout_nsec: timeout nsec component in ns, 0 for poll > + * both must be 0 for poll. > + * > + * Calculate the timeout in jiffies from an absolute time in sec/nsec. > + */ > +static unsigned long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) > +{ > + ktime_t abs_timeout, timeout, max_jiffy_ktime; > + unsigned long timeout_jiffies; > + > + /* make 0 timeout means poll - absolute 0 doesn't seem valid */ > + if (timeout_nsec == 0) > + return 0; > + > + abs_timeout = ns_to_ktime(timeout_nsec); > + > + timeout = ktime_sub(abs_timeout, ktime_get()); > This can end you up with a negative timeout. dma_fence_wait_timeout will WARN_ON a negative timeout. > + > + max_jiffy_ktime = ns_to_ktime(jiffies_to_nsecs(MAX_JIFFY_OFFSET)); > + if (ktime_compare(timeout, max_jiffy_ktime)) > I think you want a > 0 here because otherwise this is a "!=" comparison which isn't what you want. Either that or use ktime_after(). > + return MAX_SCHEDULE_TIMEOUT - 1; > + > + timeout_jiffies = nsecs_to_jiffies(ktime_to_ns(timeout)); > + /* clamp timeout to avoid infinite timeout */ > + if (timeout_jiffies >= MAX_SCHEDULE_TIMEOUT) > + return MAX_SCHEDULE_TIMEOUT - 1; > + > + return timeout_jiffies + 1; > +} > + > +static int drm_syncobj_wait_fences(struct drm_device *dev, > + struct drm_file *file_private, > + struct drm_syncobj_wait *wait, > + struct dma_fence **fences) > +{ > + unsigned long timeout = drm_timeout_abs_to_jiffies(wai > t->timeout_nsec); > + int ret = 0; > + uint32_t first = ~0; > + > + if (wait->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) { > + int i; > + for (i = 0; i < wait->count_handles; i++) { > + ret = dma_fence_wait_timeout(fences[i], true, > timeout); > Various dma_fence callbacks (including, aparently, i915) return -ENOENT to indicate that the fence has already been signaled. We need to sanitize that to 0 or else we'll return early. > + > + if (ret < 0) > + return ret; > + if (ret == 0) > + break; > + timeout = ret; > + } > + first = 0; > + } else { > + ret = dma_fence_wait_any_timeout(fences, > + wait->count_handles, > + true, timeout, > + &first); > + } > + > + if (ret < 0) > + return ret; > + > + wait->first_signaled = first; > + if (ret == 0) > + return -ETIME; > + return 0; > +} > + > +int > +drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, > + struct drm_file *file_private) > +{ > + struct drm_syncobj_wait *args = data; > + uint32_t *handles; > + struct dma_fence **fences; > + int ret = 0; > + int i; > + > + if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) > + return -ENODEV; > + > + if (args->flags != 0 && args->flags != > DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL) > + return -EINVAL; > + > + if (args->count_handles == 0) > + return -EINVAL; > + > + /* Get the handles from userspace */ > + handles = kmalloc_array(args->count_handles, sizeof(uint32_t), > + GFP_KERNEL); > + if (handles == NULL) > + return -ENOMEM; > + > + if (copy_from_user(handles, > + u64_to_user_ptr(args->handles), > + sizeof(uint32_t) * args->count_handles)) { > + ret = -EFAULT; > + goto err_free_handles; > + } > + > + fences = kcalloc(args->count_handles, > + sizeof(struct dma_fence *), GFP_KERNEL); > + if (!fences) { > + ret = -ENOMEM; > + goto err_free_handles; > + } > + > + for (i = 0; i < args->count_handles; i++) { > + ret = drm_syncobj_fence_get(file_private, handles[i], > + &fences[i]); > + if (ret) > + goto err_free_fence_array; > + } > + > + ret = drm_syncobj_wait_fences(dev, file_private, > + args, fences); > + > +err_free_fence_array: > + for (i = 0; i < args->count_handles; i++) > + dma_fence_put(fences[i]); > + kfree(fences); > +err_free_handles: > + kfree(handles); > + > + return ret; > +} > diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h > index 101593a..0757c1a 100644 > --- a/include/uapi/drm/drm.h > +++ b/include/uapi/drm/drm.h > @@ -718,6 +718,17 @@ struct drm_syncobj_handle { > __u32 pad; > }; > > +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) > +struct drm_syncobj_wait { > + __u64 handles; > + /* absolute timeout */ > + __s64 timeout_nsec; > + __u32 count_handles; > + __u32 flags; > + __u32 first_signaled; /* only valid when not waiting all */ > + __u32 pad; > +}; > + > #if defined(__cplusplus) > } > #endif > @@ -840,6 +851,7 @@ extern "C" { > #define DRM_IOCTL_SYNCOBJ_DESTROY DRM_IOWR(0xC0, struct > drm_syncobj_destroy) > #define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct > drm_syncobj_handle) > #define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct > drm_syncobj_handle) > +#define DRM_IOCTL_SYNCOBJ_WAIT DRM_IOWR(0xC3, struct > drm_syncobj_wait) > > /** > * Device specific ioctls should only be in their respective headers > -- > 2.9.4 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel > --f403045f546cc2ccd00555f60135 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
I= 9;m working on a VK_KHR_external_fence implementation based on this and hav= e found some issues. :-)

On Mon, Ju= l 17, 2017 at 11:44 PM, Dave Airlie <airlied@gmail.com> wrot= e:
From: Dave Airlie <airlied@redhat.com>

This interface will allow sync object to be used to back
Vulkan fences. This API is pretty much the vulkan fence waiting
API, and I've ported the code from amdgpu.

v2: accept relative timeout, pass remaining time back
to userspace.
v3: return to absolute timeouts.
v4: absolute zero =3D poll,
=C2=A0 =C2=A0 rewrite any/all code to have same operation for arrays
=C2=A0 =C2=A0 return -EINVAL for 0 fences.
v4.1: fixup fences allocation check, use u64_to_user_ptr
v5: move to sec/nsec, and use timespec64 for calcs.
v6: use -ETIME and drop the out status flag. (-ETIME
is suggested by ickle, I can feel a shed painting)
v7: talked to Daniel/Arnd, use ktime and ns everywhere.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
=C2=A0drivers/gpu/drm/drm_internal.h |=C2=A0 =C2=A02 +
=C2=A0drivers/gpu/drm/drm_ioctl.c=C2=A0 =C2=A0 |=C2=A0 =C2=A02 +
=C2=A0drivers/gpu/drm/drm_syncobj.c=C2=A0 | 135 ++++++++++++++++++++++= +++++++++++++++++++
=C2=A0include/uapi/drm/drm.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 12 ++= ++
=C2=A04 files changed, 151 insertions(+)

diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_inte= rnal.h
index 5cecc97..d71b50d 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -157,3 +157,5 @@ int drm_syncobj_handle_to_fd_ioctl(struct drm_devi= ce *dev, void *data,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct drm_file *file_p= rivate);
=C2=A0int drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void = *data,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0struct drm_file *file_p= rivate);
+int drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 struct drm_file *file_private);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index f1e5681..385ce74 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -657,6 +657,8 @@ static const struct drm_ioctl_desc drm_ioctls[] =3D { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 DRM_UNLOCKED|DRM_RENDER_ALLOW),
=C2=A0 =C2=A0 =C2=A0 =C2=A0 DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HAND= LE, drm_syncobj_fd_to_handle_ioctl,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 DRM_UNLOCKED|DRM_RENDER_ALLOW),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_= syncobj_wait_ioctl,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0DRM_UNLOCKED|DRM_RENDER_ALLOW),
=C2=A0};

=C2=A0#define DRM_CORE_IOCTL_COUNT=C2=A0 =C2=A0ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_synco= bj.c
index 89441bc..d23dcc6 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1,5 +1,7 @@
=C2=A0/*
=C2=A0 * Copyright 2017 Red Hat
+ * Parts ported from amdgpu (fence wait code).
+ * Copyright 2016 Advanced Micro Devices, Inc.
=C2=A0 *
=C2=A0 * Permission is hereby granted, free of charge, to any person obtain= ing a
=C2=A0 * copy of this software and associated documentation files (the &quo= t;Software"),
@@ -31,6 +33,9 @@
=C2=A0 * that contain an optional fence. The fence can be updated with a ne= w
=C2=A0 * fence, or be NULL.
=C2=A0 *
+ * syncobj's can be waited upon, where it will wait for the underlying=
+ * fence.
+ *
=C2=A0 * syncobj's can be export to fd's and back, these fd's a= re opaque and
=C2=A0 * have no other use case, except passing the syncobj between process= es.
=C2=A0 *
@@ -451,3 +456,133 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device= *dev, void *data,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return drm_syncobj_fd_to_handle(file_priva= te, args->fd,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &arg= s->handle);
=C2=A0}
+
+/**
+ * drm_timeout_abs_to_jiffies - calculate jiffies timeout from absolute va= lue
+ *
+ * @timeout_sec: timeout sec component, 0 for poll
+ * @timeout_nsec: timeout nsec component in ns, 0 for poll
+ * both must be 0 for poll.
+ *
+ * Calculate the timeout in jiffies from an absolute time in sec/nsec.
+ */
+static unsigned long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)=
+{
+=C2=A0 =C2=A0 =C2=A0 =C2=A0ktime_t abs_timeout, timeout, max_jiffy_ktime;<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned long timeout_jiffies;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0/* make 0 timeout means poll - absolute 0 doesn= 't seem valid */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (timeout_nsec =3D=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0abs_timeout =3D ns_to_ktime(timeout_nsec);
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0timeout =3D ktime_sub(abs_timeout, ktime_get())= ;

This can end you up with a negative t= imeout.=C2=A0 dma_fence_wait_timeout will WARN_ON a negative timeout.
=C2=A0
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0max_jiffy_ktime =3D ns_to_ktime(jiffies_to_nsec= s(MAX_JIFFY_OFFSET));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (ktime_compare(timeout, max_jiffy_ktime))

I think you want a > 0 here because ot= herwise this is a "!=3D" comparison which isn't what you want= .=C2=A0 Either that or use ktime_after().
=C2=A0
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return MAX_SCHEDULE= _TIMEOUT - 1;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0timeout_jiffies =3D nsecs_to_jiffies(ktime_to_n= s(timeout));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0/*=C2=A0 clamp timeout to avoid infinite timeou= t */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (timeout_jiffies >=3D MAX_SCHEDULE_TIMEOU= T)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return MAX_SCHEDULE= _TIMEOUT - 1;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0return timeout_jiffies + 1;
+}
+
+static int drm_syncobj_wait_fences(struct drm_device *dev,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 struct drm_file *file_private= ,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 struct drm_syncobj_wait *wait= ,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 struct dma_fence **fences) +{
+=C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned long timeout =3D drm_timeout_abs_to_ji= ffies(wait->timeout_nsec);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0int ret =3D 0;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t first =3D ~0;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (wait->flags & DRM_SYNCOBJ_WAIT_FLAGS= _WAIT_ALL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int i;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i <= ; wait->count_handles; i++) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0ret =3D dma_fence_wait_timeout(fences[i], true, timeout);

Various dma_fence callbacks (including, a= parently, i915) return -ENOENT to indicate that the fence has already been = signaled.=C2=A0 We need to sanitize that to 0 or else we'll return earl= y.
=C2=A0
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0if (ret < 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0if (ret =3D=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0timeout =3D ret;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0first =3D 0;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0} else {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D dma_fence_w= ait_any_timeout(fences,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 wait->count_handles,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 true, timeout,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 &first);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret < 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0wait->first_signaled =3D first;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret =3D=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ETIME;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0return 0;
+}
+
+int
+drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 struct drm_file *file_private)
+{
+=C2=A0 =C2=A0 =C2=A0 =C2=A0struct drm_syncobj_wait *args =3D data;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *handles;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0struct dma_fence **fences;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0int ret =3D 0;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0int i;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ= ))
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ENODEV;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (args->flags !=3D 0 && args->f= lags !=3D DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EINVAL;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (args->count_handles =3D=3D 0)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EINVAL;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Get the handles from userspace */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0handles =3D kmalloc_array(args->count_handles, sizeof(uint32_t),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0GFP_KERNEL);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (handles =3D=3D NULL)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -ENOMEM;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (copy_from_user(handles,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 u64_to_user_ptr(args->handles),
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 sizeof(uint32_t) * args->count_handles)) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -EFAULT; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto err_free_handl= es;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0fences =3D kcalloc(args->count_handles,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 sizeof(struct dma_fence *), GFP_KERNEL);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0if (!fences) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D -ENOMEM; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto err_free_handl= es;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < args->count_handles; i+= +) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D drm_syncobj= _fence_get(file_private, handles[i],
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0&fences[i]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0goto err_free_fence_array;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0}
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D drm_syncobj_wait_fences(dev, file_priva= te,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0args, fences); +
+err_free_fence_array:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < args->count_handles; i+= +)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dma_fence_put(fence= s[i]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(fences);
+err_free_handles:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0kfree(handles);
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0return ret;
+}
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 101593a..0757c1a 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -718,6 +718,17 @@ struct drm_syncobj_handle {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 __u32 pad;
=C2=A0};

+#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
+struct drm_syncobj_wait {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0__u64 handles;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0/* absolute timeout */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0__s64 timeout_nsec;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0__u32 count_handles;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0__u32 flags;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0__u32 first_signaled; /* only valid when not wa= iting all */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0__u32 pad;
+};
+
=C2=A0#if defined(__cplusplus)
=C2=A0}
=C2=A0#endif
@@ -840,6 +851,7 @@ extern "C" {
=C2=A0#define DRM_IOCTL_SYNCOBJ_DESTROY=C2=A0 =C2=A0 =C2=A0 DRM_IOWR(0xC0, = struct drm_syncobj_destroy)
=C2=A0#define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct drm_sync= obj_handle)
=C2=A0#define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct drm_sync= obj_handle)
+#define DRM_IOCTL_SYNCOBJ_WAIT=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DRM_IOWR(0= xC3, struct drm_syncobj_wait)

=C2=A0/**
=C2=A0 * Device specific ioctls should only be in their respective headers<= br> --
2.9.4

_______________________________________________
dri-devel mailing list
dri-de= vel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/l= istinfo/dri-devel

--f403045f546cc2ccd00555f60135-- --===============0051021816== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KZHJpLWRldmVs IG1haWxpbmcgbGlzdApkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHBzOi8vbGlz dHMuZnJlZWRlc2t0b3Aub3JnL21haWxtYW4vbGlzdGluZm8vZHJpLWRldmVsCg== --===============0051021816==--