1 /*
2  * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdarg.h>
7 #include <stdbool.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <sys/cdefs.h>
11 
12 #include "esp_private/regdma_link.h"
13 
14 #include "esp_heap_caps.h"
15 #include "esp_log.h"
16 #include "esp_regdma.h"
17 
18 #include <zephyr/sys/util.h>
19 
20 #define REGDMA_LINK_ADDR_ALIGN      (4)
21 #define REGDMA_LINK_MEM_TYPE_CAPS   (MALLOC_CAP_DMA | MALLOC_CAP_DEFAULT)
22 
regdma_link_new_continuous(void * backup,void * buff,int len,void * restore,void * next,bool skip_b,bool skip_r,int id,uint32_t module)23 void * regdma_link_new_continuous(void *backup, void *buff, int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
24 {
25     regdma_link_continuous_t *link = (regdma_link_continuous_t *)heap_caps_aligned_alloc(
26             REGDMA_LINK_ADDR_ALIGN,
27             buff ? sizeof(regdma_link_continuous_t) : (sizeof(regdma_link_continuous_t) + (len<<2)),
28             REGDMA_LINK_MEM_TYPE_CAPS
29         );
30     if (link) {
31         memset(link, 0, buff ? sizeof(regdma_link_continuous_t) : (sizeof(regdma_link_continuous_t) + (len<<2)));
32         void *buf = buff ? buff : (void *)(link->buff);
33         link = regdma_link_init_continuous(link, buf, backup, len, restore, next, skip_b, skip_r, id, module);
34         return (void *)((char *)link + offsetof(regdma_link_continuous_t, head));
35     }
36     return NULL;
37 }
38 
regdma_link_new_addr_map(void * backup,void * buff,uint32_t bitmap[4],int len,void * restore,void * next,bool skip_b,bool skip_r,int id,uint32_t module)39 void * regdma_link_new_addr_map(void *backup, void *buff, uint32_t bitmap[4], int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
40 {
41     regdma_link_addr_map_t *link = (regdma_link_addr_map_t *)heap_caps_aligned_alloc(
42             REGDMA_LINK_ADDR_ALIGN,
43             buff ? sizeof(regdma_link_addr_map_t) : (sizeof(regdma_link_addr_map_t) + (len<<2)),
44             REGDMA_LINK_MEM_TYPE_CAPS
45         );
46     if (link) {
47         memset(link, 0, buff ? sizeof(regdma_link_addr_map_t) : (sizeof(regdma_link_addr_map_t) + (len<<2)));
48         void *buf = buff ? buff : (void *)(link->buff);
49         link = regdma_link_init_addr_map(link, buf, backup, bitmap, len, restore, next, skip_b, skip_r, id, module);
50         return (void *)((char *)link + offsetof(regdma_link_addr_map_t, head));
51     }
52     return NULL;
53 }
54 
regdma_link_new_write(void * backup,uint32_t value,uint32_t mask,void * next,bool skip_b,bool skip_r,int id,uint32_t module)55 void * regdma_link_new_write(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
56 {
57     regdma_link_write_wait_t *link = (regdma_link_write_wait_t *)heap_caps_aligned_alloc(
58             REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
59     if (link) {
60         memset(link, 0, sizeof(regdma_link_write_wait_t));
61         link = regdma_link_init_write(link, backup, value, mask, next, skip_b, skip_r, id, module);
62         return (void *)((char *)link + offsetof(regdma_link_write_wait_t, head));
63     }
64     return NULL;
65 }
66 
regdma_link_new_wait(void * backup,uint32_t value,uint32_t mask,void * next,bool skip_b,bool skip_r,int id,uint32_t module)67 void * regdma_link_new_wait(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
68 {
69     regdma_link_write_wait_t *link = (regdma_link_write_wait_t *)heap_caps_aligned_alloc(
70             REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
71     if (link) {
72         memset(link, 0, sizeof(regdma_link_write_wait_t));
73         link = regdma_link_init_wait(link, backup, value, mask, next, skip_b, skip_r, id, module);
74         return (void *)((char *)link + offsetof(regdma_link_write_wait_t, head));
75     }
76     return NULL;
77 }
78 
regdma_link_new_branch_continuous(void * backup,void * buff,int len,void * restore,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)79 void * regdma_link_new_branch_continuous(void *backup, void *buff, int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
80 {
81     regdma_link_branch_continuous_t *link = (regdma_link_branch_continuous_t *)heap_caps_aligned_alloc(
82             REGDMA_LINK_ADDR_ALIGN,
83             buff ? sizeof(regdma_link_branch_continuous_t) : (sizeof(regdma_link_branch_continuous_t) + (len<<2)),
84             REGDMA_LINK_MEM_TYPE_CAPS
85         );
86     if (link) {
87         memset(link, 0, buff ? sizeof(regdma_link_branch_continuous_t) : (sizeof(regdma_link_branch_continuous_t) + (len<<2)));
88         void *buf = buff ? buff : (void *)(link->buff);
89         link = regdma_link_init_branch_continuous(link, buf, backup, len, restore, next, skip_b, skip_r, id, module);
90         return (void *)((char *)link + offsetof(regdma_link_branch_continuous_t, head));
91     }
92     return NULL;
93 }
94 
regdma_link_new_branch_addr_map(void * backup,void * buff,uint32_t bitmap[4],int len,void * restore,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)95 void * regdma_link_new_branch_addr_map(void *backup, void *buff, uint32_t bitmap[4], int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
96 {
97     regdma_link_branch_addr_map_t *link = (regdma_link_branch_addr_map_t *)heap_caps_aligned_alloc(
98             REGDMA_LINK_ADDR_ALIGN,
99             buff ? sizeof(regdma_link_branch_addr_map_t) : (sizeof(regdma_link_branch_addr_map_t) + (len<<2)),
100             REGDMA_LINK_MEM_TYPE_CAPS
101         );
102     if (link) {
103         memset(link, 0, buff ? sizeof(regdma_link_branch_addr_map_t) : (sizeof(regdma_link_branch_addr_map_t) + (len<<2)));
104         void *buf = buff ? buff : (void *)(link->buff);
105         link = regdma_link_init_branch_addr_map(link, buf, backup, bitmap, len, restore, next, skip_b, skip_r, id, module);
106         return (void *)((char *)link + offsetof(regdma_link_branch_addr_map_t, head));
107     }
108     return NULL;
109 }
110 
regdma_link_new_branch_write(void * backup,uint32_t value,uint32_t mask,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)111 void * regdma_link_new_branch_write(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
112 {
113     regdma_link_branch_write_wait_t *link = (regdma_link_branch_write_wait_t *)heap_caps_aligned_alloc(
114             REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_branch_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
115     if (link) {
116         memset(link, 0, sizeof(regdma_link_branch_write_wait_t));
117         link = regdma_link_init_branch_write(link, backup, value, mask, next, skip_b, skip_r, id, module);
118         return (void *)((char *)link + offsetof(regdma_link_branch_write_wait_t, head));
119     }
120     return NULL;
121 }
122 
regdma_link_new_branch_wait(void * backup,uint32_t value,uint32_t mask,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)123 void * regdma_link_new_branch_wait(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
124 {
125     regdma_link_branch_write_wait_t *link = (regdma_link_branch_write_wait_t *)heap_caps_aligned_alloc(
126             REGDMA_LINK_ADDR_ALIGN, sizeof(regdma_link_branch_write_wait_t), REGDMA_LINK_MEM_TYPE_CAPS);
127     if (link) {
128         memset(link, 0, sizeof(regdma_link_branch_write_wait_t));
129         link = regdma_link_init_branch_wait(link, backup, value, mask, next, skip_b, skip_r, id, module);
130         return (void *)((char *)link + offsetof(regdma_link_branch_write_wait_t, head));
131     }
132     return NULL;
133 }
134 
regdma_link_new_continuous_default(void * backup,int len,void * restore,void * next,bool skip_b,bool skip_r,int id,uint32_t module)135 void * regdma_link_new_continuous_default(void *backup, int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
136 {
137     return regdma_link_new_continuous(backup, NULL, len, restore, next, skip_b, skip_r, id, module);
138 }
139 
regdma_link_new_addr_map_default(void * backup,uint32_t bitmap[4],int len,void * restore,void * next,bool skip_b,bool skip_r,int id,uint32_t module)140 void * regdma_link_new_addr_map_default(void *backup, uint32_t bitmap[4], int len, void *restore, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
141 {
142     return regdma_link_new_addr_map(backup, NULL, bitmap, len, restore, next, skip_b, skip_r, id, module);
143 }
144 
regdma_link_new_write_default(void * backup,uint32_t value,uint32_t mask,void * next,bool skip_b,bool skip_r,int id,uint32_t module)145 void * regdma_link_new_write_default(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
146 {
147     return regdma_link_new_write(backup, value, mask, next, skip_b, skip_r, id, module);
148 }
149 
regdma_link_new_wait_default(void * backup,uint32_t value,uint32_t mask,void * next,bool skip_b,bool skip_r,int id,uint32_t module)150 void * regdma_link_new_wait_default(void *backup, uint32_t value, uint32_t mask, void *next, bool skip_b, bool skip_r, int id, uint32_t module)
151 {
152     return regdma_link_new_wait(backup, value, mask, next, skip_b, skip_r, id, module);
153 }
154 
regdma_link_new_branch_continuous_default(void * backup,int len,void * restore,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)155 void * regdma_link_new_branch_continuous_default(void *backup, int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
156 {
157     return regdma_link_new_branch_continuous(backup, NULL, len, restore, next, skip_b, skip_r, id, module);
158 }
159 
regdma_link_new_branch_addr_map_default(void * backup,uint32_t bitmap[4],int len,void * restore,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)160 void * regdma_link_new_branch_addr_map_default(void *backup, uint32_t bitmap[4], int len, void *restore, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
161 {
162     return regdma_link_new_branch_addr_map(backup, NULL, bitmap, len, restore, next, skip_b, skip_r, id, module);
163 }
164 
regdma_link_new_branch_write_default(void * backup,uint32_t value,uint32_t mask,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)165 void * regdma_link_new_branch_write_default(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
166 {
167     return regdma_link_new_branch_write(backup, value, mask, next, skip_b, skip_r, id, module);
168 }
169 
regdma_link_new_branch_wait_default(void * backup,uint32_t value,uint32_t mask,regdma_entry_buf_t * next,bool skip_b,bool skip_r,int id,uint32_t module)170 void * regdma_link_new_branch_wait_default(void *backup, uint32_t value, uint32_t mask, regdma_entry_buf_t *next, bool skip_b, bool skip_r, int id, uint32_t module)
171 {
172     return regdma_link_new_branch_wait(backup, value, mask, next, skip_b, skip_r, id, module);
173 }
174 
175 
regdma_link_init_continuous_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)176 static void * regdma_link_init_continuous_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
177 {
178     regdma_entry_buf_t next;
179 
180     memset(next, 0, sizeof(regdma_entry_buf_t));
181     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
182         next[i] = va_arg(args, void *);
183     }
184     return regdma_link_new_continuous_default((void *)(config->continuous.backup), config->head.length,
185             (void *)(config->continuous.restore), next[0], config->head.skip_b,
186                 config->head.skip_r, config->id, module);
187 }
188 
regdma_link_init_addr_map_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)189 static void * regdma_link_init_addr_map_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
190 {
191     regdma_entry_buf_t next;
192 
193     memset(next, 0, sizeof(regdma_entry_buf_t));
194     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
195         next[i] = va_arg(args, void *);
196     }
197     return regdma_link_new_addr_map_default((void *)(config->addr_map.backup), (void *)(config->addr_map.map),
198             config->head.length, (void *)(config->addr_map.restore), next[0], config->head.skip_b,
199                 config->head.skip_r, config->id, module);
200 }
201 
regdma_link_init_write_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)202 static void * regdma_link_init_write_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
203 {
204     regdma_entry_buf_t next;
205 
206     memset(next, 0, sizeof(regdma_entry_buf_t));
207     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
208         next[i] = va_arg(args, void *);
209     }
210     return regdma_link_new_write_default((void *)(config->write_wait.backup), config->write_wait.value,
211             config->write_wait.mask, next[0], config->head.skip_b, config->head.skip_r,
212                 config->id, module);
213 }
214 
regdma_link_init_wait_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)215 static void * regdma_link_init_wait_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
216 {
217     regdma_entry_buf_t next;
218 
219     memset(next, 0, sizeof(regdma_entry_buf_t));
220     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
221         next[i] = va_arg(args, void *);
222     }
223     return regdma_link_new_wait_default((void *)(config->write_wait.backup), config->write_wait.value,
224             config->write_wait.mask, next[0], config->head.skip_b, config->head.skip_r,
225                 config->id, module);
226 }
227 
regdma_link_init_branch_continuous_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)228 static void * regdma_link_init_branch_continuous_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
229 {
230     regdma_entry_buf_t next;
231 
232     memset(next, 0, sizeof(regdma_entry_buf_t));
233     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
234         next[i] = va_arg(args, void *);
235     }
236     return regdma_link_new_branch_continuous_default((void *)(config->continuous.backup),
237             config->head.length, (void *)(config->continuous.restore), &next,
238                 config->head.skip_b, config->head.skip_r, config->id, module);
239 }
240 
regdma_link_init_branch_addr_map_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)241 static void * regdma_link_init_branch_addr_map_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
242 {
243     regdma_entry_buf_t next;
244 
245     memset(next, 0, sizeof(regdma_entry_buf_t));
246     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
247         next[i] = va_arg(args, void *);
248     }
249     return regdma_link_new_branch_addr_map_default((void *)(config->addr_map.backup),
250             (void *)(config->addr_map.map), config->head.length, (void *)(config->addr_map.restore),
251                 &next, config->head.skip_b, config->head.skip_r, config->id, module);
252 }
253 
regdma_link_init_branch_write_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)254 static void * regdma_link_init_branch_write_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
255 {
256     regdma_entry_buf_t next;
257 
258     memset(next, 0, sizeof(regdma_entry_buf_t));
259     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
260         next[i] = va_arg(args, void *);
261     }
262     return regdma_link_new_branch_write_default((void *)(config->write_wait.backup),
263             config->write_wait.value, config->write_wait.mask, &next, config->head.skip_b,
264                 config->head.skip_r, config->id, module);
265 }
266 
regdma_link_init_branch_wait_wrapper(const regdma_link_config_t * config,uint32_t module,int n,va_list args)267 static void * regdma_link_init_branch_wait_wrapper(const regdma_link_config_t *config, uint32_t module, int n, va_list args)
268 {
269     regdma_entry_buf_t next;
270 
271     memset(next, 0, sizeof(regdma_entry_buf_t));
272     for (int i = 0; i < n && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
273         next[i] = va_arg(args, void *);
274     }
275     return regdma_link_new_branch_wait_default((void *)(config->write_wait.backup),
276             config->write_wait.value, config->write_wait.mask, &next, config->head.skip_b,
277                 config->head.skip_r, config->id, module);
278 }
279 
regdma_link_init_wrapper(const regdma_link_config_t * config,bool branch,uint32_t module,int nentry,va_list args)280 static void * regdma_link_init_wrapper(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, va_list args)
281 {
282     typedef void * (*init_fn_t)(const void *, uint32_t, int, va_list);
283 
284     const static init_fn_t initfn[] = {
285         [0] = (init_fn_t)regdma_link_init_continuous_wrapper,  /* REGDMA_LINK_MODE_CONTINUOUS */
286         [1] = (init_fn_t)regdma_link_init_addr_map_wrapper,    /* REGDMA_LINK_MODE_ADDR_MAP */
287         [2] = (init_fn_t)regdma_link_init_write_wrapper,       /* REGDMA_LINK_MODE_WRITE */
288         [3] = (init_fn_t)regdma_link_init_wait_wrapper         /* REGDMA_LINK_MODE_WAIT */
289     };
290     const static init_fn_t initfn_b[] = {
291         [0] = (init_fn_t)regdma_link_init_branch_continuous_wrapper,
292         [1] = (init_fn_t)regdma_link_init_branch_addr_map_wrapper,
293         [2] = (init_fn_t)regdma_link_init_branch_write_wrapper,
294         [3] = (init_fn_t)regdma_link_init_branch_wait_wrapper
295     };
296 
297     assert((config->head.mode < ARRAY_SIZE(initfn)) && (config->head.mode < ARRAY_SIZE(initfn_b)));
298 
299     init_fn_t pfn = branch ? initfn_b[config->head.mode] : initfn[config->head.mode];
300     return (*pfn)(config, module, nentry, args);
301 }
302 
regdma_link_init(const regdma_link_config_t * config,bool branch,uint32_t module,int nentry,...)303 void * regdma_link_init(const regdma_link_config_t *config, bool branch, uint32_t module, int nentry, ...)
304 {
305     assert(config != NULL);
306 
307     va_list args;
308     va_start(args, nentry);
309     void * link = regdma_link_init_wrapper(config, branch, module, nentry, args);
310     va_end(args);
311     return link;
312 }
313 
regdma_link_get_next_continuous_wrapper(void * link)314 static void * regdma_link_get_next_continuous_wrapper(void *link)
315 {
316     regdma_link_continuous_t *continuous = CONTAINER_OF(link, regdma_link_continuous_t, head);
317     return (void *)(continuous->body.next);
318 }
319 
regdma_link_get_next_addr_map_wrapper(void * link)320 static void * regdma_link_get_next_addr_map_wrapper(void *link)
321 {
322     regdma_link_addr_map_t *addr_map = CONTAINER_OF(link, regdma_link_addr_map_t, head);
323     return (void *)(addr_map->body.next);
324 }
325 
regdma_link_get_next_write_wait_wrapper(void * link)326 static void * regdma_link_get_next_write_wait_wrapper(void *link)
327 {
328     regdma_link_write_wait_t *write_wait = CONTAINER_OF(link, regdma_link_write_wait_t, head);
329     return (void *)(write_wait->body.next);
330 }
331 
regdma_link_get_next_branch_continuous_wrapper(void * link)332 static regdma_entry_buf_t * regdma_link_get_next_branch_continuous_wrapper(void *link)
333 {
334     regdma_link_branch_continuous_t *branch_continuous = CONTAINER_OF(link, regdma_link_branch_continuous_t, head);
335     return &branch_continuous->body.next;
336 }
337 
regdma_link_get_next_branch_addr_map_wrapper(void * link)338 static regdma_entry_buf_t * regdma_link_get_next_branch_addr_map_wrapper(void *link)
339 {
340     regdma_link_branch_addr_map_t *branch_addr_map = CONTAINER_OF(link, regdma_link_branch_addr_map_t, head);
341     return &branch_addr_map->body.next;
342 }
343 
regdma_link_get_next_branch_write_wait_wrapper(void * link)344 static regdma_entry_buf_t * regdma_link_get_next_branch_write_wait_wrapper(void *link)
345 {
346     regdma_link_branch_write_wait_t *branch_write_wait = CONTAINER_OF(link, regdma_link_branch_write_wait_t, head);
347     return &branch_write_wait->body.next;
348 }
349 
regdma_link_get_next(void * link,int entry)350 static void * regdma_link_get_next(void *link, int entry)
351 {
352     if (link) {
353         regdma_link_head_t head = REGDMA_LINK_HEAD(link);
354         if (head.branch) {
355             typedef regdma_entry_buf_t * (*get_nextfn1_t)(void *);
356             const static get_nextfn1_t nextfn1[] = {
357                 [0] = (get_nextfn1_t)regdma_link_get_next_branch_continuous_wrapper,
358                 [1] = (get_nextfn1_t)regdma_link_get_next_branch_addr_map_wrapper,
359                 [2] = (get_nextfn1_t)regdma_link_get_next_branch_write_wait_wrapper,
360                 [3] = (get_nextfn1_t)regdma_link_get_next_branch_write_wait_wrapper
361             };
362             assert(head.mode < ARRAY_SIZE(nextfn1));
363             regdma_entry_buf_t *next = (*nextfn1[head.mode])(link);
364             if ((entry < REGDMA_LINK_ENTRY_NUM) && (*next)[entry] && (head.eof == 0)) {
365                 return (*next)[entry];
366             }
367         } else {
368             typedef void * (*get_nextfn0_t)(void *);
369             const static get_nextfn0_t nextfn0[] = {
370                 [0] = (get_nextfn0_t)regdma_link_get_next_continuous_wrapper,
371                 [1] = (get_nextfn0_t)regdma_link_get_next_addr_map_wrapper,
372                 [2] = (get_nextfn0_t)regdma_link_get_next_write_wait_wrapper,
373                 [3] = (get_nextfn0_t)regdma_link_get_next_write_wait_wrapper
374             };
375             assert(head.mode < ARRAY_SIZE(nextfn0));
376             void *next = (*nextfn0[head.mode])(link);
377             if (next && (head.eof == 0)) {
378                 return next;
379             }
380         }
381     }
382     return NULL;
383 }
384 
regdma_link_recursive_impl(void * link,int entry,int depth,void (* hook)(void *,int,int))385 static void * regdma_link_recursive_impl(void *link, int entry, int depth, void (*hook)(void *, int, int))
386 {
387     assert(entry < REGDMA_LINK_ENTRY_NUM);
388 
389     if (link) {
390         regdma_link_recursive_impl(regdma_link_get_next(link, entry), entry, depth+1, hook);
391         if (hook) {
392             (*hook)(link, entry, depth);
393         }
394     }
395     return link;
396 }
397 
regdma_link_recursive(void * link,int entry,void (* hook)(void *,int,int))398 void * regdma_link_recursive(void *link, int entry, void (*hook)(void *, int, int))
399 {
400     return regdma_link_recursive_impl(link, entry, 0, hook);
401 }
402 
regdma_link_get_instance(void * link)403 static void * regdma_link_get_instance(void *link)
404 {
405     void * container_memaddr[] = {
406         (void *)CONTAINER_OF(link, regdma_link_continuous_t, head),
407         (void *)CONTAINER_OF(link, regdma_link_addr_map_t, head),
408         (void *)CONTAINER_OF(link, regdma_link_write_wait_t, head),
409         (void *)CONTAINER_OF(link, regdma_link_write_wait_t, head),
410         (void *)CONTAINER_OF(link, regdma_link_branch_continuous_t, head),
411         (void *)CONTAINER_OF(link, regdma_link_branch_addr_map_t, head),
412         (void *)CONTAINER_OF(link, regdma_link_branch_write_wait_t, head),
413         (void *)CONTAINER_OF(link, regdma_link_branch_write_wait_t, head)
414     };
415     regdma_link_head_t head = REGDMA_LINK_HEAD(link);
416     int it = (head.branch << 2) | head.mode;
417     assert(it < ARRAY_SIZE(container_memaddr));
418 
419     return container_memaddr[it];
420 }
regdma_link_get_stats(void * link)421 static regdma_link_stats_t * regdma_link_get_stats(void *link)
422 {
423     const static size_t stats_offset[] = {
424         offsetof(regdma_link_continuous_t, stat),
425         offsetof(regdma_link_addr_map_t, stat),
426         offsetof(regdma_link_write_wait_t, stat),
427         offsetof(regdma_link_write_wait_t, stat),
428         offsetof(regdma_link_branch_continuous_t, stat),
429         offsetof(regdma_link_branch_addr_map_t, stat),
430         offsetof(regdma_link_branch_write_wait_t, stat),
431         offsetof(regdma_link_branch_write_wait_t, stat)
432     };
433     regdma_link_head_t head = REGDMA_LINK_HEAD(link);
434     int it = (head.branch << 2) | head.mode;
435     assert(it < ARRAY_SIZE(stats_offset));
436 
437     return (regdma_link_stats_t *)((char *)regdma_link_get_instance(link) + stats_offset[it]);
438 }
439 
regdma_link_update_stats_wrapper(void * link,int entry,int depth)440 static void regdma_link_update_stats_wrapper(void *link, int entry, int depth)
441 {
442     if (link == NULL) {
443         return;
444     }
445     regdma_link_update_stats(regdma_link_get_stats(link), entry, depth);
446 }
447 
regdma_link_iterator(void * link,int entry,void (* hook)(void *,int,int))448 static void regdma_link_iterator(void *link, int entry, void (*hook)(void *, int, int))
449 {
450     assert(entry < REGDMA_LINK_ENTRY_NUM);
451 
452     int iter = 0;
453     while (link) {
454         if (hook) {
455             (*hook)(link, entry, iter++);
456         }
457         link = regdma_link_get_next(link, entry);
458     }
459 }
460 
regdma_link_stats(void * link,int entry)461 void regdma_link_stats(void *link, int entry)
462 {
463     regdma_link_iterator(link, entry, regdma_link_update_stats_wrapper);
464 }
465 
regdma_link_destroy_wrapper(void * link,int entry,int depth)466 static void regdma_link_destroy_wrapper(void *link, int entry, int depth)
467 {
468     if (link == NULL) {
469         return;
470     }
471     regdma_link_stats_t *stat = regdma_link_get_stats(link);
472     stat->ref &= ~BIT(entry);
473     if (stat->ref == 0) {
474         free(regdma_link_get_instance(link));
475     }
476 }
477 
regdma_link_destroy(void * link,int entry)478 void regdma_link_destroy(void *link, int entry)
479 {
480     regdma_link_recursive_impl(link, entry, 0, regdma_link_destroy_wrapper);
481 }
482 
regdma_find_link_by_pos(void * link,int entry,int pos)483 void * regdma_find_link_by_pos(void *link, int entry, int pos)
484 {
485     assert(entry < REGDMA_LINK_ENTRY_NUM);
486 
487     void *next = link;
488     if (link) {
489         int iter = 0;
490         do {
491             if (pos == iter++) {
492                 break;
493             }
494         } while ((next = regdma_link_get_next(next, entry)) != NULL);
495     }
496     return next;
497 }
498 
regdma_find_link_by_id(void * link,int entry,int id)499 void * regdma_find_link_by_id(void *link, int entry, int id)
500 {
501     assert(entry < REGDMA_LINK_ENTRY_NUM);
502 
503     void *find_addr = NULL;
504     void *next = link;
505     if (link) {
506         int linkid = 0;
507         do {
508             regdma_link_head_t head = REGDMA_LINK_HEAD(next);
509             if (head.branch) {
510                 regdma_link_branch_continuous_t *continuous = (regdma_link_branch_continuous_t *)regdma_link_get_instance(next);
511                 linkid = continuous->stat.id;
512             } else {
513                 regdma_link_continuous_t *continuous = (regdma_link_continuous_t *)regdma_link_get_instance(next);
514                 linkid = continuous->stat.id;
515             }
516             if (linkid == id) {
517                 find_addr = next;
518                 break;
519             }
520         } while ((next = regdma_link_get_next(next, entry)) != NULL);
521     }
522     return find_addr;
523 }
524 
regdma_link_set_write_wait_content(void * link,uint32_t value,uint32_t mask)525 void regdma_link_set_write_wait_content(void *link, uint32_t value, uint32_t mask)
526 {
527     if (link) {
528         regdma_link_head_t head = REGDMA_LINK_HEAD(link);
529         if (head.mode == REGDMA_LINK_MODE_WRITE || head.mode == REGDMA_LINK_MODE_WAIT) {
530             if (head.branch) {
531                 regdma_link_branch_write_wait_t *write_wait = (regdma_link_branch_write_wait_t *)regdma_link_get_instance(link);
532                 write_wait->body.value = value;
533                 write_wait->body.mask = mask;
534             } else {
535                 regdma_link_write_wait_t *write_wait = (regdma_link_write_wait_t *)regdma_link_get_instance(link);
536                 write_wait->body.value = value;
537                 write_wait->body.mask = mask;
538             }
539         }
540     }
541 }
542 
regdma_link_update_continuous_next_wrapper(void * link,void * next)543 static void regdma_link_update_continuous_next_wrapper(void *link, void *next)
544 {
545     regdma_link_continuous_t *continuous = CONTAINER_OF(link, regdma_link_continuous_t, head);
546     continuous->body.next = next;
547 }
548 
regdma_link_update_addr_map_next_wrapper(void * link,void * next)549 static void regdma_link_update_addr_map_next_wrapper(void *link, void *next)
550 {
551     regdma_link_addr_map_t *addr_map = CONTAINER_OF(link, regdma_link_addr_map_t, head);
552     addr_map->body.next = next;
553 }
554 
regdma_link_update_write_wait_next_wrapper(void * link,void * next)555 static void regdma_link_update_write_wait_next_wrapper(void *link, void *next)
556 {
557     regdma_link_write_wait_t *write_wait = CONTAINER_OF(link, regdma_link_write_wait_t, head);
558     write_wait->body.next = next;
559 }
560 
regdma_link_update_branch_continuous_next_wrapper(void * link,regdma_entry_buf_t * next)561 static void regdma_link_update_branch_continuous_next_wrapper(void *link, regdma_entry_buf_t *next)
562 {
563     regdma_link_branch_continuous_t *branch_continuous = CONTAINER_OF(link, regdma_link_branch_continuous_t, head);
564     for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
565         branch_continuous->body.next[i] = (*next)[i];
566     }
567 }
568 
regdma_link_update_branch_addr_map_next_wrapper(void * link,regdma_entry_buf_t * next)569 static void regdma_link_update_branch_addr_map_next_wrapper(void *link, regdma_entry_buf_t *next)
570 {
571     regdma_link_branch_addr_map_t *branch_addr_map = CONTAINER_OF(link, regdma_link_branch_addr_map_t, head);
572     for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
573         branch_addr_map->body.next[i] = (*next)[i];
574     }
575 }
576 
regdma_link_update_branch_write_wait_next_wrapper(void * link,regdma_entry_buf_t * next)577 static void regdma_link_update_branch_write_wait_next_wrapper(void *link, regdma_entry_buf_t *next)
578 {
579     regdma_link_branch_write_wait_t *branch_write_wait = CONTAINER_OF(link, regdma_link_branch_write_wait_t, head);
580     for (int i = 0; i < REGDMA_LINK_ENTRY_NUM; i++) {
581         branch_write_wait->body.next[i] = (*next)[i];
582     }
583 }
584 
regdma_link_update_next(void * link,int nentry,...)585 void regdma_link_update_next(void *link, int nentry, ...)
586 {
587     va_list args;
588     va_start(args, nentry);
589     if (link) {
590         regdma_entry_buf_t next;
591         memset(next, 0, sizeof(regdma_entry_buf_t));
592         for (int i = 0; i < nentry && i < REGDMA_LINK_ENTRY_NUM; i++) { // Ignore more arguments
593             next[i] = va_arg(args, void *);
594         }
595 
596         regdma_link_head_t head = REGDMA_LINK_HEAD(link);
597         if (head.branch) {
598             typedef void (*update_branch_fn_t)(void *, regdma_entry_buf_t *);
599             static const update_branch_fn_t updatefn_b[] = {
600                 [0] = regdma_link_update_branch_continuous_next_wrapper,
601                 [1] = regdma_link_update_branch_addr_map_next_wrapper,
602                 [2] = regdma_link_update_branch_write_wait_next_wrapper,
603                 [3] = regdma_link_update_branch_write_wait_next_wrapper
604             };
605             assert((head.mode < ARRAY_SIZE(updatefn_b)));
606             (*updatefn_b[head.mode])(link, &next);
607         } else {
608             typedef void (*update_fn_t)(void *, void *);
609             static const update_fn_t updatefn[] = {
610                 [0] = regdma_link_update_continuous_next_wrapper,
611                 [1] = regdma_link_update_addr_map_next_wrapper,
612                 [2] = regdma_link_update_write_wait_next_wrapper,
613                 [3] = regdma_link_update_write_wait_next_wrapper
614             };
615             assert((head.mode < ARRAY_SIZE(updatefn)));
616             (*updatefn[head.mode])(link, next[0]);
617         }
618     }
619     va_end(args);
620 }
621 
regdma_link_get_owner_bitmap(void * link,void * tail,int entry)622 uint32_t regdma_link_get_owner_bitmap(void *link, void *tail, int entry)
623 {
624     assert(entry < REGDMA_LINK_ENTRY_NUM);
625 
626     uint32_t owner = 0;
627     void *next = link;
628     if (link) {
629         do {
630             owner |= regdma_link_get_stats(next)->ref;
631             if (next == tail) {
632                 break;
633             }
634         } while ((next = regdma_link_get_next(next, entry)) != NULL);
635     }
636     return owner;
637 }
638 
regdma_find_module_link_head(void * link,void * tail,int entry,uint32_t module)639 void * regdma_find_module_link_head(void *link, void *tail, int entry, uint32_t module)
640 {
641     assert(entry < REGDMA_LINK_ENTRY_NUM);
642 
643     void *find_link = NULL;
644     void *next = link;
645     if (link) {
646         do {
647             if (regdma_link_get_stats(next)->module & module) {
648                 find_link = next;
649                 break;
650             }
651             if (next == tail) {
652                 break;
653             }
654         } while ((next = regdma_link_get_next(next, entry)) != NULL);
655     }
656     return find_link;
657 }
658 
regdma_find_module_link_tail(void * link,void * tail,int entry,uint32_t module)659 void * regdma_find_module_link_tail(void *link, void *tail, int entry, uint32_t module)
660 {
661     assert(entry < REGDMA_LINK_ENTRY_NUM);
662 
663     void *find_tail = NULL;
664     void *next = link;
665     if (link) {
666         do {
667             if (next != tail) {
668                 void *temp = regdma_link_get_next(next, entry);
669                 if ((regdma_link_get_stats(next)->module & module) &&
670                    !(regdma_link_get_stats(temp)->module & module)) {
671                     find_tail = next;
672                     break;
673                 }
674             } else {
675                 if (regdma_link_get_stats(next)->module & module) {
676                     find_tail = next;
677                     break;
678                 }
679             }
680         } while ((next = regdma_link_get_next(next, entry)) != NULL);
681     }
682     return find_tail;
683 }
684 
regdma_find_next_module_link_head(void * link,void * tail,int entry,uint32_t module)685 void * regdma_find_next_module_link_head(void *link, void *tail, int entry, uint32_t module)
686 {
687     assert(entry < REGDMA_LINK_ENTRY_NUM);
688     void *find_tail = regdma_find_module_link_tail(link, tail, entry, module);
689     if (find_tail && find_tail != tail) {
690         return regdma_link_get_next(find_tail, entry);
691     }
692     return NULL;
693 }
694 
regdma_find_prev_module_link_tail(void * link,void * tail,int entry,uint32_t module)695 void * regdma_find_prev_module_link_tail(void *link, void *tail, int entry, uint32_t module)
696 {
697     assert(entry < REGDMA_LINK_ENTRY_NUM);
698     void *find_head = regdma_find_module_link_head(link, tail, entry, module);
699     void *next = link;
700     if (find_head && find_head != link) {
701         do {
702             if (regdma_link_get_next(next, entry) == find_head) {
703                 return next;
704             }
705             if (next == tail) {
706                 break;
707             }
708         } while ((next = regdma_link_get_next(next, entry)) != NULL);
709     }
710     return NULL;
711 }
712 
regdma_link_get_config_mode(const regdma_link_config_t * config)713 regdma_link_mode_t regdma_link_get_config_mode(const regdma_link_config_t *config)
714 {
715     assert(config != NULL);
716     return (regdma_link_mode_t)config->head.mode;
717 }
718 
719 #if REGDMA_LINK_DBG
720 static __attribute__((unused)) const char *TAG = "regdma_link";
721 
print_info_link_data(FILE * out,const uint32_t buf[],int len)722 static void print_info_link_data(FILE *out, const uint32_t buf[], int len)
723 {
724     for (int i = 0; i < len; i++) {
725         fprintf(out, ((i + 1) % 8) ? "%08lx " : "%08lx\n", buf[i]);
726     }
727     if (len % 8) {
728         fprintf(out, "\n");
729     }
730 }
731 
print_info_continuous_wrapper(FILE * out,void * link)732 static void print_info_continuous_wrapper(FILE *out, void *link)
733 {
734     regdma_link_head_t head = REGDMA_LINK_HEAD(link);
735     regdma_link_continuous_t *cons = CONTAINER_OF(link, regdma_link_continuous_t, head);
736     fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:%p, backup:%p, restore:%p, buff:%p\n",
737              cons->stat.module, cons->stat.id, link, *(uint32_t *)&cons->head, cons->body.next,
738              cons->body.backup, cons->body.restore, cons->body.mem);
739     print_info_link_data(out, (const uint32_t *)cons->body.mem, head.length);
740 }
741 
print_info_addr_map_wrapper(FILE * out,void * link)742 static void print_info_addr_map_wrapper(FILE *out, void *link)
743 {
744     regdma_link_head_t head = REGDMA_LINK_HEAD(link);
745     regdma_link_addr_map_t *map = CONTAINER_OF(link, regdma_link_addr_map_t, head);
746     fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:%p, backup:%p, restore:%p, buff:%p, map:{%lx,%lx,%lx,%lx}\n",
747             map->stat.module, map->stat.id, link, *(uint32_t *)&map->head, map->body.next, map->body.backup,
748             map->body.restore, map->body.mem, map->body.map[0], map->body.map[1],
749             map->body.map[2], map->body.map[3]);
750     print_info_link_data(out, (const uint32_t *)map->body.mem, head.length);
751 }
752 
print_info_write_wait_wrapper(FILE * out,void * link)753 static void print_info_write_wait_wrapper(FILE *out, void *link)
754 {
755     regdma_link_write_wait_t *ww = CONTAINER_OF(link, regdma_link_write_wait_t, head);
756     fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:%p, backup:%p, value:%lx, mask:%lx\n",
757             ww->stat.module, ww->stat.id, link, *(uint32_t *)&ww->head, ww->body.next,
758             ww->body.backup, ww->body.value, ww->body.mask);
759 }
760 
print_info_branch_continuous_wrapper(FILE * out,void * link)761 static void print_info_branch_continuous_wrapper(FILE *out, void *link)
762 {
763     regdma_link_head_t head = REGDMA_LINK_HEAD(link);
764     regdma_link_branch_continuous_t *cons = CONTAINER_OF(link, regdma_link_branch_continuous_t, head);
765     fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:{%p,%p,%p,%p}, backup:%p, restore:%p, buff:%p\n",
766             cons->stat.module, cons->stat.id, link, *(uint32_t *)&cons->head, cons->body.next[0], cons->body.next[1],
767             cons->body.next[2], cons->body.next[3], cons->body.backup, cons->body.restore,
768             cons->body.mem);
769     print_info_link_data(out, (const uint32_t *)cons->body.mem, head.length);
770 }
771 
print_info_branch_addr_map_wrapper(FILE * out,void * link)772 static void print_info_branch_addr_map_wrapper(FILE *out, void *link)
773 {
774     regdma_link_head_t head = REGDMA_LINK_HEAD(link);
775     regdma_link_branch_addr_map_t *map = CONTAINER_OF(link, regdma_link_branch_addr_map_t, head);
776     fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:{%p,%p,%p,%p}, backup:%p, restore:%p, buff:%p, map:{%lx,%lx,%lx,%lx}\n",
777             map->stat.module, map->stat.id, link, *(uint32_t *)&map->head, map->body.next[0], map->body.next[1], map->body.next[2],
778             map->body.next[3], map->body.backup, map->body.restore, map->body.mem, map->body.map[0],
779             map->body.map[1], map->body.map[2], map->body.map[3]);
780     print_info_link_data(out, (const uint32_t *)map->body.mem, head.length);
781 }
782 
print_info_branch_write_wait_wrapper(FILE * out,void * link)783 static void print_info_branch_write_wait_wrapper(FILE *out, void *link)
784 {
785     regdma_link_branch_write_wait_t *ww = CONTAINER_OF(link, regdma_link_branch_write_wait_t, head);
786     fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:{%p,%p,%p,%p}, backup:%p, value:%lx, mask:%lx\n",
787             ww->stat.module, ww->stat.id, link, *(uint32_t *)&ww->head, ww->body.next[0], ww->body.next[1],
788             ww->body.next[2], ww->body.next[3], ww->body.backup, ww->body.value,
789             ww->body.mask);
790 }
791 
print_link_info(FILE * out,void * args,int entry,int depth)792 static void print_link_info(FILE *out, void *args, int entry, int depth)
793 {
794     typedef void (*prinf_fn_t)(FILE *, void *);
795 
796     const static prinf_fn_t prinf_fn[] = {
797         [0] = (prinf_fn_t)print_info_continuous_wrapper,
798         [1] = (prinf_fn_t)print_info_addr_map_wrapper,
799         [2] = (prinf_fn_t)print_info_write_wait_wrapper,
800         [3] = (prinf_fn_t)print_info_write_wait_wrapper,
801         [4] = (prinf_fn_t)print_info_branch_continuous_wrapper,
802         [5] = (prinf_fn_t)print_info_branch_addr_map_wrapper,
803         [6] = (prinf_fn_t)print_info_branch_write_wait_wrapper,
804         [7] = (prinf_fn_t)print_info_branch_write_wait_wrapper
805     };
806 
807     regdma_link_head_t head = REGDMA_LINK_HEAD(args);
808     int it = (head.branch << 2) | head.mode;
809     assert(it < ARRAY_SIZE(prinf_fn));
810 
811     (*prinf_fn[it])(out, args);
812 }
813 
regdma_link_dump(FILE * out,void * link,int entry)814 void regdma_link_dump(FILE *out, void *link, int entry)
815 {
816     assert(entry < REGDMA_LINK_ENTRY_NUM);
817 
818     void *next = link;
819     if (link) {
820         do {
821             print_link_info(out, next, entry, 0);
822         } while ((next = regdma_link_get_next(next, entry)) != NULL);
823     } else {
824         fprintf(out, "This REGDMA linked list is empty!\n");
825     }
826 }
827 #endif
828