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/3467c132f672
branches: trunk
changeset: 364692:3467c132f672
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 b78548f0ac96 -r 3467c132f672 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 b78548f0ac96 -r 3467c132f672 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