Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/external/bsd/drm2 Add fence_is_later and fence_wait_any_...



details:   https://anonhg.NetBSD.org/src/rev/e4e823abeaa4
branches:  trunk
changeset: 835305:e4e823abeaa4
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Aug 27 14:01:01 2018 +0000

description:
Add fence_is_later and fence_wait_any_timeout.

diffstat:

 sys/external/bsd/drm2/include/linux/fence.h |    6 +-
 sys/external/bsd/drm2/linux/linux_fence.c   |  146 +++++++++++++++++++++++++++-
 2 files changed, 149 insertions(+), 3 deletions(-)

diffs (215 lines):

diff -r 26e632d3cafb -r e4e823abeaa4 sys/external/bsd/drm2/include/linux/fence.h
--- a/sys/external/bsd/drm2/include/linux/fence.h       Mon Aug 27 14:00:46 2018 +0000
+++ b/sys/external/bsd/drm2/include/linux/fence.h       Mon Aug 27 14:01:01 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fence.h,v 1.13 2018/08/27 13:54:59 riastradh Exp $     */
+/*     $NetBSD: fence.h,v 1.14 2018/08/27 14:01:01 riastradh Exp $     */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -86,6 +86,7 @@
 #define        fence_get               linux_fence_get
 #define        fence_get_rcu           linux_fence_get_rcu
 #define        fence_init              linux_fence_init
+#define        fence_is_later          linux_fence_is_later
 #define        fence_is_signaled       linux_fence_is_signaled
 #define        fence_is_signaled_locked linux_fence_is_signaled_locked
 #define        fence_put               linux_fence_put
@@ -93,6 +94,7 @@
 #define        fence_signal            linux_fence_signal
 #define        fence_signal_locked     linux_fence_signal_locked
 #define        fence_wait              linux_fence_wait
+#define        fence_wait_any_timeout  linux_fence_wait_any_timeout
 #define        fence_wait_timeout      linux_fence_wait_timeout
 
 void   fence_init(struct fence *, const struct fence_ops *, spinlock_t *,
@@ -102,6 +104,7 @@
 
 unsigned
        fence_context_alloc(unsigned);
+bool   fence_is_later(struct fence *, struct fence *);
 
 struct fence *
        fence_get(struct fence *);
@@ -119,6 +122,7 @@
 int    fence_signal_locked(struct fence *);
 long   fence_default_wait(struct fence *, bool, long);
 long   fence_wait(struct fence *, bool);
+long   fence_wait_any_timeout(struct fence **, uint32_t, bool, long);
 long   fence_wait_timeout(struct fence *, bool, long);
 
 static inline void
diff -r 26e632d3cafb -r e4e823abeaa4 sys/external/bsd/drm2/linux/linux_fence.c
--- a/sys/external/bsd/drm2/linux/linux_fence.c Mon Aug 27 14:00:46 2018 +0000
+++ b/sys/external/bsd/drm2/linux/linux_fence.c Mon Aug 27 14:01:01 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_fence.c,v 1.4 2018/08/27 14:00:46 riastradh Exp $        */
+/*     $NetBSD: linux_fence.c,v 1.5 2018/08/27 14:01:01 riastradh Exp $        */
 
 /*-
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_fence.c,v 1.4 2018/08/27 14:00:46 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_fence.c,v 1.5 2018/08/27 14:01:01 riastradh Exp $");
 
 #include <sys/atomic.h>
 #include <sys/condvar.h>
@@ -121,6 +121,27 @@
 }
 
 /*
+ * fence_is_later(a, b)
+ *
+ *     True if the sequence number of fence a is later than the
+ *     sequence number of fence b.  Since sequence numbers wrap
+ *     around, we define this to mean that the sequence number of
+ *     fence a is no more than INT_MAX past the sequence number of
+ *     fence b.
+ *
+ *     The two fences must have the same context.
+ */
+bool
+fence_is_later(struct fence *a, struct fence *b)
+{
+
+       KASSERTMSG(a->context == b->context, "incommensurate fences"
+           ": %u @ %p =/= %u @ %p", a->context, a, b->context, b);
+
+       return a->seqno - b->seqno < INT_MAX;
+}
+
+/*
  * fence_get(fence)
  *
  *     Acquire a reference to fence.  The fence must not be being
@@ -400,6 +421,127 @@
        return 0;
 }
 
+struct wait_any {
+       struct fence_cb fcb;
+       struct wait_any1 {
+               kmutex_t        lock;
+               kcondvar_t      cv;
+               bool            done;
+       }               *common;
+};
+
+static void
+wait_any_cb(struct fence *fence, struct fence_cb *fcb)
+{
+       struct wait_any *cb = container_of(fcb, struct wait_any, fcb);
+
+       mutex_enter(&cb->common->lock);
+       cb->common->done = true;
+       cv_broadcast(&cb->common->cv);
+       mutex_exit(&cb->common->lock);
+}
+
+/*
+ * fence_wait_any_timeout(fence, nfences, intr, timeout)
+ *
+ *     Wait for any of fences[0], fences[1], fences[2], ...,
+ *     fences[nfences-1] to be signaled.
+ */
+long
+fence_wait_any_timeout(struct fence **fences, uint32_t nfences, bool intr,
+    long timeout)
+{
+       struct wait_any1 common;
+       struct wait_any *cb;
+       uint32_t i, j;
+       int start, end;
+       long ret = 0;
+
+       /* Allocate an array of callback records.  */
+       cb = kcalloc(nfences, sizeof(cb[0]), GFP_KERNEL);
+       if (cb == NULL) {
+               ret = -ENOMEM;
+               goto out0;
+       }
+
+       /* Initialize a mutex and condvar for the common wait.  */
+       mutex_init(&common.lock, MUTEX_DEFAULT, IPL_VM);
+       cv_init(&common.cv, "fence");
+       common.done = false;
+
+       /* Add a callback to each of the fences, or stop here if we can't.  */
+       for (i = 0; i < nfences; i++) {
+               cb[i].common = &common;
+               ret = fence_add_callback(fences[i], &cb[i].fcb, &wait_any_cb);
+               if (ret)
+                       goto out1;
+       }
+
+       /*
+        * Test whether any of the fences has been signalled.  If they
+        * have, stop here.  If the haven't, we are guaranteed to be
+        * notified by one of the callbacks when they have.
+        */
+       for (j = 0; j < nfences; j++) {
+               if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fences[j]->flags))
+                       goto out1;
+       }
+
+       /*
+        * None of them was ready immediately.  Wait for one of the
+        * callbacks to notify us when it is done.
+        */
+       mutex_enter(&common.lock);
+       while (timeout > 0 && !common.done) {
+               start = hardclock_ticks;
+               if (intr) {
+                       if (timeout != MAX_SCHEDULE_TIMEOUT) {
+                               ret = -cv_timedwait_sig(&common.cv,
+                                   &common.lock, MIN(timeout, /* paranoia */
+                                       MAX_SCHEDULE_TIMEOUT));
+                       } else {
+                               ret = -cv_wait_sig(&common.cv, &common.lock);
+                       }
+               } else {
+                       if (timeout != MAX_SCHEDULE_TIMEOUT) {
+                               ret = -cv_timedwait(&common.cv,
+                                   &common.lock, MIN(timeout, /* paranoia */
+                                       MAX_SCHEDULE_TIMEOUT));
+                       } else {
+                               cv_wait(&common.cv, &common.lock);
+                               ret = 0;
+                       }
+               }
+               end = hardclock_ticks;
+               if (ret)
+                       break;
+               timeout -= MIN(timeout, (unsigned)end - (unsigned)start);
+       }
+       mutex_exit(&common.lock);
+
+       /*
+        * Massage the return code: if we were interrupted, return
+        * ERESTARTSYS; if cv_timedwait timed out, return 0; otherwise
+        * return the remaining time.
+        */
+       if (ret < 0) {
+               if (ret == -EINTR || ret == -ERESTART)
+                       ret = -ERESTARTSYS;
+               if (ret == -EWOULDBLOCK)
+                       ret = 0;
+       } else {
+               KASSERT(ret == 0);
+               ret = timeout;
+       }
+
+out1:  while (i --> 0)
+               (void)fence_remove_callback(fences[i], &cb[i].fcb);
+       cv_destroy(&common.cv);
+       mutex_destroy(&common.lock);
+       kfree(cb);
+out0:  return ret;
+}
+
 /*
  * fence_wait_timeout(fence, intr, timeout)
  *



Home | Main Index | Thread Index | Old Index