1 /*
2 * Copyright (c) 2021-2023, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * ======== RCL_Buffer.c ========
34 */
35
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39
40 #include <ti/drivers/rcl/RCL_Command.h>
41 #include <ti/drivers/rcl/RCL_Scheduler.h>
42 #include <ti/drivers/rcl/RCL_Buffer.h>
43 #include <ti/drivers/rcl/RCL_Debug.h>
44
45 #include <ti/log/Log.h>
46
47 #include <ti/devices/DeviceFamily.h>
48 #include DeviceFamily_constructPath(inc/hw_ints.h)
49
50 #include <ti/log/Log.h>
51
52 static bool RxEntry_isAtEnd(RCL_MultiBuffer *multiBuffer, uint16_t curIndex);
53 static void List_consumeAndStore(List_List *list, List_List *consumedBuffers);
54
55 /*
56 * ======== RCL_TxBuffer_put ========
57 */
RCL_TxBuffer_put(List_List * list,RCL_Buffer_TxBuffer * elem)58 void RCL_TxBuffer_put(List_List *list, RCL_Buffer_TxBuffer *elem)
59 {
60
61 List_put(list, (List_Elem *)elem);
62 /* Notify running command */
63 RCL_Scheduler_postEvent(rclSchedulerState.currCmd, RCL_EventTxBufferUpdate);
64 }
65
66 /*
67 * ======== RCL_TxBuffer_init ========
68 */
RCL_TxBuffer_init(RCL_Buffer_TxBuffer * buffer,uint32_t numPad,uint32_t hdrLen,uint32_t dataLen)69 uint8_t *RCL_TxBuffer_init(RCL_Buffer_TxBuffer *buffer, uint32_t numPad, uint32_t hdrLen,
70 uint32_t dataLen)
71 {
72 if (buffer == NULL)
73 {
74 return NULL;
75 }
76 else
77 {
78 buffer->state = RCL_BufferStatePending;
79 buffer->length = sizeof(buffer->numPad) + numPad + hdrLen + dataLen;
80 buffer->numPad = numPad;
81 /* Start writing at pad0, then continue into data field */
82 uint8_t *data = &buffer->pad0;
83 while (numPad > 0)
84 {
85 --numPad;
86 *data++ = numPad;
87 }
88 return data;
89 }
90 }
91
92 /*
93 * ======== RCL_MultiBuffer_clear ========
94 */
RCL_MultiBuffer_clear(RCL_MultiBuffer * buffer)95 void RCL_MultiBuffer_clear(RCL_MultiBuffer *buffer)
96 {
97 buffer->state = RCL_BufferStatePending;
98 buffer->headIndex = 0;
99 buffer->tailIndex = 0;
100 }
101
102 /*
103 * ======== RCL_MultiBuffer_init ========
104 */
RCL_MultiBuffer_init(RCL_MultiBuffer * buffer,size_t size)105 void RCL_MultiBuffer_init(RCL_MultiBuffer *buffer, size_t size)
106 {
107 size -= offsetof(RCL_MultiBuffer, data);
108 RCL_Debug_assert(size > 0 && size <= 0xFFFF);
109 buffer->length = size;
110 RCL_MultiBuffer_clear(buffer);
111
112 }
113
114 /*
115 * ======== RCL_MultiBuffer_put ========
116 */
RCL_MultiBuffer_put(List_List * list,RCL_MultiBuffer * elem)117 void RCL_MultiBuffer_put(List_List *list, RCL_MultiBuffer *elem)
118 {
119 List_put(list, (List_Elem *)elem);
120 /* Notify running command */
121 RCL_Scheduler_postEvent(rclSchedulerState.currCmd, RCL_EventRxBufferUpdate);
122 }
123
124 /*
125 * ======== RCL_MultiBuffer_RxEntry_get ========
126 */
RCL_MultiBuffer_RxEntry_get(List_List * list,List_List * consumedBuffers)127 RCL_Buffer_DataEntry *RCL_MultiBuffer_RxEntry_get(List_List *list, List_List *consumedBuffers)
128 {
129 RCL_Buffer_DataEntry *rxEntry = NULL;
130 RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)list->head;
131 if (multiBuffer != NULL)
132 {
133 int32_t headIndex = multiBuffer->headIndex;
134 int32_t tailIndex = multiBuffer->tailIndex;
135
136 RCL_Debug_assert(headIndex <= tailIndex);
137
138 if (headIndex >= tailIndex)
139 {
140 if (multiBuffer->state == RCL_BufferStateFinished)
141 {
142 List_consumeAndStore(list, consumedBuffers);
143 multiBuffer = (RCL_MultiBuffer *) List_head(list);
144 headIndex = 0;
145 tailIndex = multiBuffer->tailIndex;
146 RCL_Debug_assert(multiBuffer->headIndex == 0);
147
148 }
149 }
150
151 if (headIndex < tailIndex)
152 {
153 rxEntry = (RCL_Buffer_DataEntry *) &multiBuffer->data[headIndex];
154 headIndex += RCL_Buffer_DataEntry_paddedLen(rxEntry->length);
155 RCL_Debug_assert(headIndex <= tailIndex);
156 multiBuffer->headIndex = headIndex;
157 if (headIndex >= tailIndex)
158 {
159 if (multiBuffer->state == RCL_BufferStateFinished)
160 {
161 List_consumeAndStore(list, consumedBuffers);
162 }
163 }
164 }
165 }
166 return rxEntry;
167 }
168
169 /*
170 * ======== RCL_MultiBuffer_RxEntry_isEmpty ========
171 */
RCL_MultiBuffer_RxEntry_isEmpty(List_List * list)172 bool RCL_MultiBuffer_RxEntry_isEmpty(List_List *list)
173 {
174 RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)list->head;
175
176 if (multiBuffer != NULL)
177 {
178 return RxEntry_isAtEnd(multiBuffer, multiBuffer->headIndex);
179 }
180 else {
181 return true;
182 }
183 }
184
185 /*
186 * ======== RCL_MultiBuffer_ListInfo_init ========
187 */
RCL_MultiBuffer_ListInfo_init(RCL_MultiBuffer_ListInfo * listInfo,List_List * list)188 void RCL_MultiBuffer_ListInfo_init(RCL_MultiBuffer_ListInfo *listInfo, List_List *list)
189 {
190 RCL_Debug_assert(listInfo != NULL);
191 RCL_Debug_assert(list != NULL);
192
193 listInfo->multiBuffers = list;
194 listInfo->nextBuffer = (RCL_MultiBuffer *) List_head(list);
195 if (listInfo->nextBuffer != NULL)
196 {
197 listInfo->nextIndex = listInfo->nextBuffer->headIndex;
198 }
199 else
200 {
201 listInfo->nextIndex = 0;
202 }
203 }
204
205 /*
206 * ======== RCL_MultiBuffer_RxEntry_next ========
207 */
RCL_MultiBuffer_RxEntry_next(RCL_MultiBuffer_ListInfo * listInfo)208 RCL_Buffer_DataEntry *RCL_MultiBuffer_RxEntry_next(RCL_MultiBuffer_ListInfo *listInfo)
209 {
210 RCL_Buffer_DataEntry *rxEntry = NULL;
211
212 RCL_Debug_assert(listInfo != NULL);
213 RCL_MultiBuffer *nextBuffer = listInfo->nextBuffer;
214
215 if (nextBuffer == NULL)
216 {
217 RCL_Debug_assert(listInfo->multiBuffers != NULL);
218 nextBuffer = RCL_MultiBuffer_head(listInfo->multiBuffers);
219 }
220
221 if (nextBuffer != NULL)
222 {
223 int32_t nextIndex = listInfo->nextIndex;
224 int32_t tailIndex = nextBuffer->tailIndex;
225 if (nextIndex >= tailIndex)
226 {
227 if (nextBuffer->state == RCL_BufferStateFinished)
228 {
229 nextBuffer = (RCL_MultiBuffer *) List_next((List_Elem *) nextBuffer);
230 nextIndex = 0;
231 tailIndex = nextBuffer->tailIndex;
232 }
233 }
234
235 if (nextIndex < tailIndex)
236 {
237 rxEntry = (RCL_Buffer_DataEntry *) &nextBuffer->data[nextIndex];
238 nextIndex += RCL_Buffer_DataEntry_paddedLen(rxEntry->length);
239 RCL_Debug_assert(nextIndex <= tailIndex);
240 if (nextIndex >= tailIndex)
241 {
242 if (nextBuffer->state == RCL_BufferStateFinished)
243 {
244 nextBuffer = (RCL_MultiBuffer *) List_next((List_Elem *) nextBuffer);
245 nextIndex = 0;
246 }
247 }
248 }
249 listInfo->nextBuffer = nextBuffer;
250 listInfo->nextIndex = nextIndex;
251 }
252 return rxEntry;
253 }
254
255 /*
256 * ======== RCL_MultiBuffer_RxEntry_isLast ========
257 */
RCL_MultiBuffer_RxEntry_isLast(RCL_MultiBuffer_ListInfo * listInfo)258 bool RCL_MultiBuffer_RxEntry_isLast(RCL_MultiBuffer_ListInfo *listInfo)
259 {
260 RCL_Debug_assert(listInfo != NULL);
261
262 RCL_MultiBuffer *nextBuffer = listInfo->nextBuffer;
263
264 if (nextBuffer != NULL)
265 {
266 return RxEntry_isAtEnd(nextBuffer, listInfo->nextIndex);
267 }
268 else {
269 RCL_Debug_assert(listInfo->multiBuffers != NULL);
270 return RxEntry_isAtEnd((RCL_MultiBuffer *)List_head(listInfo->multiBuffers), 0);
271 }
272 }
273
274 /*
275 * ======== RCL_MultiBuffer_RxEntry_consume ========
276 */
RCL_MultiBuffer_RxEntry_consume(RCL_MultiBuffer_ListInfo * listInfo,List_List * consumedBuffers)277 void RCL_MultiBuffer_RxEntry_consume(RCL_MultiBuffer_ListInfo *listInfo, List_List *consumedBuffers)
278 {
279 RCL_Debug_assert(listInfo != NULL);
280
281 List_List *multiBuffers = listInfo->multiBuffers;
282 RCL_Debug_assert(multiBuffers != NULL);
283
284 RCL_MultiBuffer *nextBuffer = listInfo->nextBuffer;
285 RCL_MultiBuffer *head = RCL_MultiBuffer_head(multiBuffers);
286 if (head != NULL)
287 {
288 while (head != nextBuffer)
289 {
290 RCL_Debug_assert(head != NULL);
291 List_consumeAndStore(multiBuffers, consumedBuffers);
292 head = (RCL_MultiBuffer *) List_next((List_Elem *) head);
293 }
294 }
295 }
296
297 /*
298 * ======== RCL_MultiBuffer_findFirstWritableBuffer ========
299 */
RCL_MultiBuffer_findFirstWritableBuffer(RCL_MultiBuffer * head)300 RCL_MultiBuffer *RCL_MultiBuffer_findFirstWritableBuffer(RCL_MultiBuffer *head)
301 {
302 RCL_MultiBuffer *curBuffer = head;
303 while (curBuffer != NULL && curBuffer->state == RCL_BufferStateFinished)
304 {
305 curBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)curBuffer);
306 }
307 return curBuffer;
308 }
309
310 /*
311 * ======== RCL_MultiBuffer_getBuffer ========
312 */
RCL_MultiBuffer_getBuffer(RCL_MultiBuffer * curBuffer,uint32_t minLength)313 RCL_MultiBuffer *RCL_MultiBuffer_getBuffer(RCL_MultiBuffer *curBuffer,
314 uint32_t minLength)
315 {
316 /* Try to find a buffer with enough space */
317 if (curBuffer != NULL)
318 {
319 /* Check if first buffer in queue needs initialization */
320 if (curBuffer->state != RCL_BufferStateInUse)
321 {
322 /* Initialize buffer for use */
323 curBuffer->state = RCL_BufferStateInUse;
324 /* Initialize indeces */
325 curBuffer->headIndex = 0;
326 curBuffer->tailIndex = 0;
327 }
328 if (minLength + curBuffer->tailIndex > curBuffer->length)
329 {
330 /* Not room in this buffer. Need to go to next buffer - unless buffer is empty */
331 if (curBuffer->tailIndex == 0)
332 {
333 /* New buffer already - give up, as buffer is too small */
334 curBuffer = NULL;
335 }
336 else
337 {
338 curBuffer->state = RCL_BufferStateFinished;
339 curBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)curBuffer);
340 /* Check that buffer is available */
341 if (curBuffer != NULL) {
342 /* Make sure that length is enough */
343 if (minLength > curBuffer->length)
344 {
345 /* Buffer too short */
346 curBuffer = NULL;
347 }
348 else
349 {
350 /* Initialize buffer for use */
351 curBuffer->state = RCL_BufferStateInUse;
352 /* Initialize indeces */
353 curBuffer->headIndex = 0;
354 curBuffer->tailIndex = 0;
355 }
356 }
357 }
358 }
359 }
360
361 return curBuffer;
362 }
363
364 /*
365 * ======== RCL_MultiBuffer_findAvailableRxSpace ========
366 */
RCL_MultiBuffer_findAvailableRxSpace(const RCL_MultiBuffer * curBuffer)367 uint32_t RCL_MultiBuffer_findAvailableRxSpace(const RCL_MultiBuffer *curBuffer)
368 {
369 uint32_t space = 0;
370
371 if (curBuffer != NULL)
372 {
373 /* Find available space in current buffer */
374 if (curBuffer->state == RCL_BufferStateInUse)
375 {
376 const RCL_MultiBuffer *nextBuffer;
377 nextBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)curBuffer);
378 /* Check if there is another buffer available */
379 if (nextBuffer == NULL)
380 {
381 /* No - use remaining space in this buffer */
382 space = curBuffer->length - curBuffer->tailIndex;
383 }
384 else
385 {
386 /* Yes - use space in next buffer */
387 space = nextBuffer->length;
388 }
389 }
390 else
391 {
392 space = curBuffer->length;
393 }
394 }
395 return space;
396 }
397
398 /*
399 * ======== RxEntry_isAtEnd ========
400 */
RxEntry_isAtEnd(RCL_MultiBuffer * multiBuffer,uint16_t curIndex)401 static bool RxEntry_isAtEnd(RCL_MultiBuffer *multiBuffer, uint16_t curIndex)
402 {
403 bool isAtEnd = true;
404
405 if (multiBuffer != NULL)
406 {
407 if (curIndex < multiBuffer->tailIndex)
408 {
409 isAtEnd = false;
410 }
411 else
412 {
413 if (multiBuffer->state == RCL_BufferStateFinished)
414 {
415 /* Look in next MultiBuffer to see if there is data there */
416 multiBuffer = (RCL_MultiBuffer *) List_next((List_Elem *)multiBuffer);
417 if (multiBuffer != NULL && multiBuffer->tailIndex > 0)
418 {
419 isAtEnd = false;
420 }
421 }
422 }
423 }
424
425 return isAtEnd;
426 }
427
428 /*
429 * ======== List_consumeAndStore ========
430 */
List_consumeAndStore(List_List * list,List_List * consumedBuffers)431 static void List_consumeAndStore(List_List *list, List_List *consumedBuffers)
432 {
433 List_Elem *consumedBuffer = List_get(list);
434
435 if (consumedBuffers != NULL)
436 {
437 List_put(consumedBuffers, consumedBuffer);
438 }
439 }
440