1 /*
2 * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <linux/sched.h>
20 #include <linux/slab.h>
21 #include <linux/wait.h>
22 #include <linux/spinlock.h>
23 #include "hi_osal.h"
24 #include "securec.h"
25
26 #define FENCE_READY 1
27 #define FENCE_NOREADY 0
28 typedef struct osal_fence_ {
29 int module_id;
30 int fd;
31 wait_queue_head_t queue;
32 int condition;
33 void *private;
34 unsigned int private_size;
35 unsigned int ref;
36 struct osal_list_head node;
37 } osal_fence;
38
39 static int g_fd_no = 0; // 临时占用,一秒1000个,可使用49天
40
41 static DEFINE_SPINLOCK(lock);
42 static OSAL_LIST_HEAD(fence_list);
43
44 #define FENCE_PRIVATE_MAX_SIZE 0x100
45
osal_fence_try_del(osal_fence * fence)46 void osal_fence_try_del(osal_fence *fence)
47 {
48 if (fence->ref > 0) {
49 return;
50 }
51
52 osal_list_del(&fence->node);
53
54 if (fence->private != NULL) {
55 kfree(fence->private);
56 fence->private = NULL;
57 }
58
59 kfree(fence);
60 }
61
osal_fence_find_node(int fd,struct osal_list_head * list)62 osal_fence *osal_fence_find_node(int fd, struct osal_list_head *list)
63 {
64 osal_fence *fence_node = NULL;
65
66 osal_list_for_each_entry(fence_node, list, node) {
67 if (fence_node->fd == fd) {
68 return fence_node;
69 }
70 }
71
72 return NULL;
73 }
74
osal_fence_create(unsigned int module_id,int * fd,unsigned int private_size)75 int osal_fence_create(unsigned int module_id, int *fd, unsigned int private_size)
76 {
77 osal_fence *fence_node = NULL;
78 unsigned long flags;
79 errno_t err;
80
81 if (fd == NULL) {
82 return -1;
83 }
84
85 if (private_size > FENCE_PRIVATE_MAX_SIZE) {
86 return -1;
87 }
88
89 fence_node = kmalloc(sizeof(osal_fence), GFP_KERNEL);
90 if (fence_node == NULL) {
91 return -1;
92 }
93
94 err = memset_s(fence_node, sizeof(osal_fence), 0, sizeof(osal_fence));
95 if (err != EOK) {
96 kfree(fence_node);
97 return -1;
98 }
99
100 fence_node->private_size = private_size;
101 if (private_size != 0) {
102 fence_node->private = kmalloc(private_size, GFP_KERNEL);
103 if (fence_node->private == NULL) {
104 kfree(fence_node);
105 return -1;
106 }
107 } else {
108 fence_node->private = NULL;
109 }
110
111 fence_node->module_id = module_id;
112 fence_node->condition = FENCE_NOREADY;
113 fence_node->ref = 1;
114
115 init_waitqueue_head(&fence_node->queue);
116
117 spin_lock_irqsave(&lock, flags);
118 fence_node->fd = g_fd_no;
119 g_fd_no++;
120
121 osal_list_add_tail(&(fence_node->node), &fence_list);
122
123 *fd = fence_node->fd;
124
125 spin_unlock_irqrestore(&lock, flags);
126
127 return 0;
128 }
129 EXPORT_SYMBOL(osal_fence_create);
130
osal_fence_destroy(unsigned int module_id,int fd)131 int osal_fence_destroy(unsigned int module_id, int fd)
132 {
133 osal_fence *fence_node = NULL;
134 unsigned long flags;
135
136 spin_lock_irqsave(&lock, flags);
137
138 fence_node = osal_fence_find_node(fd, &fence_list);
139 if (fence_node == NULL) {
140 spin_unlock_irqrestore(&lock, flags);
141 return -1;
142 }
143
144 fence_node->ref--;
145
146 osal_fence_try_del(fence_node);
147
148 spin_unlock_irqrestore(&lock, flags);
149
150 return 0;
151 }
152 EXPORT_SYMBOL(osal_fence_destroy);
153
osal_fence_acquire_private(unsigned int module_id,int fd,void ** private)154 int osal_fence_acquire_private(unsigned int module_id, int fd, void **private)
155 {
156 osal_fence *fence_node = NULL;
157 unsigned long flags;
158
159 if (private == NULL) {
160 return -1;
161 }
162
163 spin_lock_irqsave(&lock, flags);
164
165 fence_node = osal_fence_find_node(fd, &fence_list);
166 if (fence_node == NULL) {
167 spin_unlock_irqrestore(&lock, flags);
168 return -1;
169 }
170
171 fence_node->ref++;
172
173 spin_unlock_irqrestore(&lock, flags);
174
175 *private = fence_node->private;
176
177 return 0;
178 }
179 EXPORT_SYMBOL(osal_fence_acquire_private);
180
osal_fence_release_private(unsigned int module_id,int fd,void * private)181 int osal_fence_release_private(unsigned int module_id, int fd, void *private)
182 {
183 osal_fence *fence_node = NULL;
184 unsigned long flags;
185
186 spin_lock_irqsave(&lock, flags);
187
188 fence_node = osal_fence_find_node(fd, &fence_list);
189 if (fence_node == NULL) {
190 spin_unlock_irqrestore(&lock, flags);
191 return -1;
192 }
193
194 fence_node->ref--;
195
196 osal_fence_try_del(fence_node);
197
198 spin_unlock_irqrestore(&lock, flags);
199
200 return 0;
201 }
202 EXPORT_SYMBOL(osal_fence_release_private);
203
osal_fence_signal(int fd)204 int osal_fence_signal(int fd)
205 {
206 osal_fence *fence_node = NULL;
207 unsigned long flags;
208
209 spin_lock_irqsave(&lock, flags);
210
211 fence_node = osal_fence_find_node(fd, &fence_list);
212 if (fence_node == NULL) {
213 spin_unlock_irqrestore(&lock, flags);
214 return -1;
215 }
216
217 fence_node->condition = FENCE_READY;
218
219 wake_up(&fence_node->queue);
220
221 spin_unlock_irqrestore(&lock, flags);
222
223 return 0;
224 }
225 EXPORT_SYMBOL(osal_fence_signal);
226
osal_fence_wait(int fd,unsigned int ms)227 int osal_fence_wait(int fd, unsigned int ms)
228 {
229 osal_fence *fence_node = NULL;
230 long timeout;
231 unsigned long flags;
232
233 spin_lock_irqsave(&lock, flags);
234
235 fence_node = osal_fence_find_node(fd, &fence_list);
236 if (fence_node == NULL) {
237 spin_unlock_irqrestore(&lock, flags);
238 return -1;
239 }
240
241 fence_node->ref++;
242
243 spin_unlock_irqrestore(&lock, flags);
244
245 timeout = wait_event_interruptible_timeout(fence_node->queue,
246 (fence_node->condition == FENCE_READY),
247 msecs_to_jiffies(ms));
248 spin_lock_irqsave(&lock, flags);
249 fence_node->ref--;
250 osal_fence_try_del(fence_node);
251 spin_unlock_irqrestore(&lock, flags);
252
253 if (timeout == 0) {
254 return -1;
255 }
256
257 return 0;
258 }
259 EXPORT_SYMBOL(osal_fence_wait);
260
osal_fence_trywait(int fd)261 int osal_fence_trywait(int fd)
262 {
263 osal_fence *fence_node = NULL;
264 unsigned long flags;
265
266 spin_lock_irqsave(&lock, flags);
267
268 fence_node = osal_fence_find_node(fd, &fence_list);
269 if (fence_node == NULL) {
270 spin_unlock_irqrestore(&lock, flags);
271 return -1;
272 }
273
274 if (fence_node->condition == FENCE_READY) {
275 spin_unlock_irqrestore(&lock, flags);
276 return 0;
277 }
278
279 spin_unlock_irqrestore(&lock, flags);
280
281 return -1; // not ready
282 }
283 EXPORT_SYMBOL(osal_fence_trywait);
284
285