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