linux_dma_fence_chain.c revision 1.2 1 /* $NetBSD: linux_dma_fence_chain.c,v 1.2 2021/12/19 12:39:16 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: linux_dma_fence_chain.c,v 1.2 2021/12/19 12:39:16 riastradh Exp $");
34
35 #include <sys/types.h>
36
37 #include <linux/dma-fence.h>
38 #include <linux/dma-fence-chain.h>
39 #include <linux/spinlock.h>
40
41 static const struct dma_fence_ops dma_fence_chain_ops;
42
43 /*
44 * dma_fence_chain_init(chain, prev, fence, seqno)
45 *
46 * Initialize a new fence chain, and either start
47 */
48 void
49 dma_fence_chain_init(struct dma_fence_chain *chain, struct dma_fence *prev,
50 struct dma_fence *fence, uint64_t seqno)
51 {
52 uint64_t context = -1; /* XXX */
53
54 chain->prev_seqno = 0;
55 spin_lock_init(&chain->dfc_lock);
56
57 /* XXX we don't use these yet */
58 dma_fence_put(prev);
59 dma_fence_put(fence);
60
61 dma_fence_init(&chain->base, &dma_fence_chain_ops, &chain->dfc_lock,
62 context, seqno);
63 }
64
65 static void
66 dma_fence_chain_release(struct dma_fence *fence)
67 {
68 struct dma_fence_chain *chain = to_dma_fence_chain(fence);
69
70 KASSERT(chain);
71
72 spin_lock_destroy(&chain->dfc_lock);
73 dma_fence_free(&chain->base);
74 }
75
76 static const struct dma_fence_ops dma_fence_chain_ops = {
77 .release = dma_fence_chain_release,
78 };
79
80 /*
81 * to_dma_fence_chain(fence)
82 *
83 * If fence is nonnull and in a chain, return the chain.
84 * Otherwise return NULL.
85 */
86 struct dma_fence_chain *
87 to_dma_fence_chain(struct dma_fence *fence)
88 {
89
90 if (fence == NULL || fence->ops != &dma_fence_chain_ops)
91 return NULL;
92 return container_of(fence, struct dma_fence_chain, base);
93 }
94
95 /*
96 * dma_fence_chain_walk(fence)
97 *
98 * Return the next fence in the chain, or NULL if end of chain,
99 * after releasing any fences that have already been signalled.
100 */
101 struct dma_fence *
102 dma_fence_chain_walk(struct dma_fence *fence)
103 {
104
105 /* XXX */
106 dma_fence_put(fence);
107 return NULL;
108 }
109
110 /*
111 * dma_fence_chain_find_seqno(&fence, seqno)
112 *
113 * If seqno is zero, do nothing and succeed.
114 *
115 * Otherwise, if fence is not on a chain or if its sequence
116 * number has not yet reached seqno, fail with EINVAL.
117 *
118 * Otherwise, set fence to the first fence in the chain which
119 * will signal this sequence number.
120 */
121 int
122 dma_fence_chain_find_seqno(struct dma_fence **fencep, uint64_t seqno)
123 {
124 struct dma_fence_chain *chain;
125
126 if (seqno == 0)
127 return 0;
128
129 chain = to_dma_fence_chain(*fencep);
130 if (chain == NULL || chain->base.seqno < seqno)
131 return -EINVAL;
132
133 dma_fence_chain_for_each(*fencep, &chain->base) {
134 if ((*fencep)->context != chain->base.context ||
135 to_dma_fence_chain(*fencep)->prev_seqno < seqno)
136 break;
137 }
138
139 /* Release reference acquired by dma_fence_chain_for_each. */
140 dma_fence_put(&chain->base);
141
142 return 0;
143 }
144