Module Name: src
Committed By: riastradh
Date: Sun Dec 19 12:34:05 UTC 2021
Modified Files:
src/sys/external/bsd/drm2/linux: linux_dma_fence.c
Log Message:
drm: Rework dma_fence_wait_any_timeout.
- Yield the first index, not the most recently signalled one.
- Check again after last wakeup.
- Make sure to return positive for nontimeout.
- Handle ip=null.
To generate a diff of this commit:
cvs rdiff -u -r1.30 -r1.31 src/sys/external/bsd/drm2/linux/linux_dma_fence.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/drm2/linux/linux_dma_fence.c
diff -u src/sys/external/bsd/drm2/linux/linux_dma_fence.c:1.30 src/sys/external/bsd/drm2/linux/linux_dma_fence.c:1.31
--- src/sys/external/bsd/drm2/linux/linux_dma_fence.c:1.30 Sun Dec 19 12:31:11 2021
+++ src/sys/external/bsd/drm2/linux/linux_dma_fence.c Sun Dec 19 12:34:05 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_dma_fence.c,v 1.30 2021/12/19 12:31:11 riastradh Exp $ */
+/* $NetBSD: linux_dma_fence.c,v 1.31 2021/12/19 12:34:05 riastradh Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_dma_fence.c,v 1.30 2021/12/19 12:31:11 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_dma_fence.c,v 1.31 2021/12/19 12:34:05 riastradh Exp $");
#include <sys/atomic.h>
#include <sys/condvar.h>
@@ -685,9 +685,8 @@ struct wait_any {
struct wait_any1 {
kmutex_t lock;
kcondvar_t cv;
- bool done;
- uint32_t *ip;
struct wait_any *cb;
+ bool done;
} *common;
};
@@ -700,8 +699,6 @@ wait_any_cb(struct dma_fence *fence, str
mutex_enter(&cb->common->lock);
cb->common->done = true;
- if (cb->common->ip)
- *cb->common->ip = cb - cb->common->cb;
cv_broadcast(&cb->common->cv);
mutex_exit(&cb->common->lock);
}
@@ -712,6 +709,9 @@ wait_any_cb(struct dma_fence *fence, str
* Wait for any of fences[0], fences[1], fences[2], ...,
* fences[nfences-1] to be signalled. If ip is nonnull, set *ip
* to the index of the first one.
+ *
+ * Return -ERESTARTSYS if interrupted, 0 on timeout, or time
+ * remaining (at least 1) on success.
*/
long
dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t nfences,
@@ -723,6 +723,22 @@ dma_fence_wait_any_timeout(struct dma_fe
int start, end;
long ret = 0;
+ /* Optimistically check whether any are signalled. */
+ for (i = 0; i < nfences; i++) {
+ if (dma_fence_is_signaled(fences[i])) {
+ if (ip)
+ *ip = i;
+ return MAX(1, timeout);
+ }
+ }
+
+ /*
+ * If timeout is zero, we're just polling, so stop here as if
+ * we timed out instantly.
+ */
+ if (timeout == 0)
+ return 0;
+
/* Allocate an array of callback records. */
cb = kcalloc(nfences, sizeof(cb[0]), GFP_KERNEL);
if (cb == NULL) {
@@ -733,30 +749,23 @@ dma_fence_wait_any_timeout(struct dma_fe
/* 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;
- common.ip = ip;
common.cb = cb;
+ common.done = false;
- /* Add a callback to each of the fences, or stop here if we can't. */
+ /*
+ * Add a callback to each of the fences, or stop if already
+ * signalled.
+ */
for (i = 0; i < nfences; i++) {
cb[i].common = &common;
KASSERT(dma_fence_referenced_p(fences[i]));
ret = dma_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(DMA_FENCE_FLAG_SIGNALED_BIT, &fences[j]->flags)) {
+ if (ret) {
+ KASSERT(ret == -ENOENT);
if (ip)
- *ip = j;
- ret = 0;
+ *ip = i;
+ ret = MAX(1, timeout);
goto out1;
}
}
@@ -768,7 +777,6 @@ dma_fence_wait_any_timeout(struct dma_fe
mutex_enter(&common.lock);
while (timeout > 0 && !common.done) {
start = getticks();
- __insn_barrier();
if (intr) {
if (timeout != MAX_SCHEDULE_TIMEOUT) {
ret = -cv_timedwait_sig(&common.cv,
@@ -788,30 +796,36 @@ dma_fence_wait_any_timeout(struct dma_fe
}
}
end = getticks();
- __insn_barrier();
- if (ret) {
- if (ret == -ERESTART)
- ret = -ERESTARTSYS;
+ if (ret)
break;
- }
timeout -= MIN(timeout, (unsigned)end - (unsigned)start);
}
mutex_exit(&common.lock);
/*
+ * Test whether any of the fences has been signalled. If they
+ * have, return success.
+ */
+ for (j = 0; j < nfences; j++) {
+ if (dma_fence_is_signaled(fences[i])) {
+ if (ip)
+ *ip = j;
+ ret = MAX(1, timeout);
+ goto out1;
+ }
+ }
+
+ /*
* 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;
+ if (ret == -EINTR || ret == -ERESTART) {
+ ret = -ERESTARTSYS;
+ } else if (ret == -EWOULDBLOCK) {
+ ret = 0; /* timed out */
}
+ KASSERTMSG(ret == -ERESTARTSYS || ret >= 0, "ret=%ld", ret);
out1: while (i --> 0)
(void)dma_fence_remove_callback(fences[i], &cb[i].fcb);