xref: /netbsd-src/sys/external/bsd/drm2/linux/linux_dma_fence_array.c (revision 87ddc0b948c1af75d1f3c2b3fbbf58ca4da1409d)
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