1 1.4 riastrad /* $NetBSD: linux_dma_fence_array.c,v 1.4 2021/12/19 12:39:56 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2021 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 riastrad * by Taylor R. Campbell. 9 1.1 riastrad * 10 1.1 riastrad * Redistribution and use in source and binary forms, with or without 11 1.1 riastrad * modification, are permitted provided that the following conditions 12 1.1 riastrad * are met: 13 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 14 1.1 riastrad * notice, this list of conditions and the following disclaimer. 15 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 17 1.1 riastrad * documentation and/or other materials provided with the distribution. 18 1.1 riastrad * 19 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 riastrad */ 31 1.1 riastrad 32 1.1 riastrad #include <sys/cdefs.h> 33 1.4 riastrad __KERNEL_RCSID(0, "$NetBSD: linux_dma_fence_array.c,v 1.4 2021/12/19 12:39:56 riastradh Exp $"); 34 1.1 riastrad 35 1.1 riastrad #include <sys/systm.h> 36 1.1 riastrad 37 1.1 riastrad #include <linux/dma-fence-array.h> 38 1.1 riastrad 39 1.2 riastrad static const char * 40 1.2 riastrad dma_fence_array_driver_name(struct dma_fence *fence) 41 1.2 riastrad { 42 1.4 riastrad return "dma_fence_array"; 43 1.2 riastrad } 44 1.2 riastrad 45 1.2 riastrad static const char * 46 1.2 riastrad dma_fence_array_timeline_name(struct dma_fence *fence) 47 1.2 riastrad { 48 1.4 riastrad return "unbound"; 49 1.2 riastrad } 50 1.2 riastrad 51 1.2 riastrad static void 52 1.2 riastrad dma_fence_array_done1(struct dma_fence *fence, struct dma_fence_cb *cb) 53 1.2 riastrad { 54 1.2 riastrad struct dma_fence_array_cb *C = 55 1.2 riastrad container_of(cb, struct dma_fence_array_cb, dfac_cb); 56 1.2 riastrad struct dma_fence_array *A = C->dfac_array; 57 1.2 riastrad 58 1.2 riastrad KASSERT(spin_is_locked(&A->dfa_lock)); 59 1.2 riastrad 60 1.2 riastrad if (fence->error && A->base.error == 1) { 61 1.2 riastrad KASSERT(fence->error != 1); 62 1.2 riastrad A->base.error = fence->error; 63 1.2 riastrad } 64 1.2 riastrad if (--A->dfa_npending) { 65 1.2 riastrad dma_fence_put(&A->base); 66 1.2 riastrad return; 67 1.2 riastrad } 68 1.2 riastrad 69 1.2 riastrad /* Last one out, hit the lights -- dma_fence_array_done. */ 70 1.2 riastrad irq_work_queue(&A->dfa_work); 71 1.2 riastrad } 72 1.2 riastrad 73 1.2 riastrad static void 74 1.2 riastrad dma_fence_array_done(struct irq_work *W) 75 1.2 riastrad { 76 1.2 riastrad struct dma_fence_array *A = container_of(W, struct dma_fence_array, 77 1.2 riastrad dfa_work); 78 1.2 riastrad 79 1.2 riastrad spin_lock(&A->dfa_lock); 80 1.2 riastrad if (A->base.error == 1) 81 1.2 riastrad A->base.error = 0; 82 1.2 riastrad dma_fence_signal_locked(&A->base); 83 1.2 riastrad spin_unlock(&A->dfa_lock); 84 1.2 riastrad 85 1.2 riastrad dma_fence_put(&A->base); 86 1.2 riastrad } 87 1.2 riastrad 88 1.2 riastrad static bool 89 1.2 riastrad dma_fence_array_enable_signaling(struct dma_fence *fence) 90 1.2 riastrad { 91 1.2 riastrad struct dma_fence_array *A = to_dma_fence_array(fence); 92 1.2 riastrad struct dma_fence_array_cb *C; 93 1.2 riastrad unsigned i; 94 1.2 riastrad int error; 95 1.2 riastrad 96 1.2 riastrad KASSERT(spin_is_locked(&A->dfa_lock)); 97 1.2 riastrad 98 1.2 riastrad for (i = 0; i < A->num_fences; i++) { 99 1.2 riastrad C = &A->dfa_cb[i]; 100 1.2 riastrad C->dfac_array = A; 101 1.2 riastrad dma_fence_get(&A->base); 102 1.2 riastrad if (dma_fence_add_callback(A->fences[i], &C->dfac_cb, 103 1.2 riastrad dma_fence_array_done1)) { 104 1.2 riastrad error = A->fences[i]->error; 105 1.2 riastrad if (error) { 106 1.2 riastrad KASSERT(error != 1); 107 1.2 riastrad if (A->base.error == 1) 108 1.2 riastrad A->base.error = error; 109 1.2 riastrad } 110 1.2 riastrad dma_fence_put(&A->base); 111 1.2 riastrad if (--A->dfa_npending == 0) { 112 1.2 riastrad if (A->base.error == 1) 113 1.2 riastrad A->base.error = 0; 114 1.2 riastrad return false; 115 1.2 riastrad } 116 1.2 riastrad } 117 1.2 riastrad } 118 1.2 riastrad 119 1.2 riastrad return true; 120 1.2 riastrad } 121 1.2 riastrad 122 1.2 riastrad static bool 123 1.2 riastrad dma_fence_array_signaled(struct dma_fence *fence) 124 1.2 riastrad { 125 1.2 riastrad struct dma_fence_array *A = to_dma_fence_array(fence); 126 1.2 riastrad 127 1.2 riastrad KASSERT(spin_is_locked(&A->dfa_lock)); 128 1.2 riastrad 129 1.2 riastrad return A->dfa_npending == 0; 130 1.2 riastrad } 131 1.2 riastrad 132 1.2 riastrad static void 133 1.2 riastrad dma_fence_array_release(struct dma_fence *fence) 134 1.2 riastrad { 135 1.2 riastrad struct dma_fence_array *A = to_dma_fence_array(fence); 136 1.2 riastrad unsigned i; 137 1.2 riastrad 138 1.2 riastrad for (i = 0; i < A->num_fences; i++) 139 1.2 riastrad dma_fence_put(A->fences[i]); 140 1.2 riastrad 141 1.2 riastrad kfree(A->fences); 142 1.3 riastrad spin_lock_destroy(&A->dfa_lock); 143 1.2 riastrad dma_fence_free(fence); 144 1.2 riastrad } 145 1.2 riastrad 146 1.2 riastrad static const struct dma_fence_ops dma_fence_array_ops = { 147 1.2 riastrad .get_driver_name = dma_fence_array_driver_name, 148 1.2 riastrad .get_timeline_name = dma_fence_array_timeline_name, 149 1.2 riastrad .enable_signaling = dma_fence_array_enable_signaling, 150 1.2 riastrad .signaled = dma_fence_array_signaled, 151 1.2 riastrad .release = dma_fence_array_release, 152 1.2 riastrad }; 153 1.2 riastrad 154 1.2 riastrad struct dma_fence_array * 155 1.2 riastrad dma_fence_array_create(int num_fences, struct dma_fence **fences, 156 1.2 riastrad unsigned context, unsigned seqno, bool signal_on_any) 157 1.2 riastrad { 158 1.2 riastrad struct dma_fence_array *A; 159 1.2 riastrad 160 1.2 riastrad /* 161 1.2 riastrad * Must be allocated with kmalloc or equivalent because 162 1.2 riastrad * dma-fence will free it with kfree. 163 1.2 riastrad */ 164 1.2 riastrad A = kzalloc(struct_size(A, dfa_cb, num_fences), GFP_KERNEL); 165 1.2 riastrad if (A == NULL) 166 1.2 riastrad return NULL; 167 1.2 riastrad 168 1.2 riastrad A->fences = fences; 169 1.2 riastrad A->num_fences = num_fences; 170 1.2 riastrad A->dfa_npending = signal_on_any ? 1 : num_fences; 171 1.2 riastrad 172 1.2 riastrad spin_lock_init(&A->dfa_lock); 173 1.2 riastrad dma_fence_init(&A->base, &dma_fence_array_ops, &A->dfa_lock, 174 1.2 riastrad context, seqno); 175 1.2 riastrad init_irq_work(&A->dfa_work, dma_fence_array_done); 176 1.2 riastrad 177 1.2 riastrad return A; 178 1.2 riastrad } 179 1.2 riastrad 180 1.1 riastrad bool 181 1.1 riastrad dma_fence_is_array(struct dma_fence *fence) 182 1.1 riastrad { 183 1.1 riastrad 184 1.2 riastrad return fence->ops == &dma_fence_array_ops; 185 1.1 riastrad } 186 1.1 riastrad 187 1.1 riastrad struct dma_fence_array * 188 1.1 riastrad to_dma_fence_array(struct dma_fence *fence) 189 1.1 riastrad { 190 1.1 riastrad 191 1.2 riastrad KASSERT(dma_fence_is_array(fence)); 192 1.2 riastrad return container_of(fence, struct dma_fence_array, base); 193 1.1 riastrad } 194