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);