1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 #ifndef NV_CONTAINERS_RINGBUF_H
24 #define NV_CONTAINERS_RINGBUF_H
25 
26 #include "nvtypes.h"
27 #include "nvstatus.h"
28 #include "nvmisc.h"
29 #include "nvctassert.h"
30 #include "utils/nvassert.h"
31 #include "nvport/nvport.h"
32 #include "containers/type_safety.h"
33 
34 typedef struct RingBufBase
35 {
36     NvU64 head;
37     NvU64 tail;
38     NvU64 logSz;
39     NvU8 *arr;
40 } RingBufBase;
41 
42 #define RINGBUF_ARRAY_SIZE(pBuf) (1llu << ((pBuf)->logSz))
43 
44 #define RINGBUF_ARRAY_MASK(pBuf) (RINGBUF_ARRAY_SIZE(pBuf) - 1llu)
45 
46 #define MAKE_RINGBUF(containedType, outputType, logSz)                                                         \
47     typedef struct outputType {                                                                                \
48         union {                                                                                                \
49             RingBufBase base;                                                                                  \
50             PORT_MEM_ALLOCATOR *pAllocator;                                                                    \
51         };                                                                                                     \
52         union {                                                                                                \
53             containedType elem[1llu << (logSz)];                                                               \
54             NvU8 lgSz[((logSz) < 64) ? (logSz) : -1]; /* Ternary to ensure we get CT error when logSz >= 64 */ \
55         };                                                                                                     \
56     } outputType
57 
58 #define MAKE_RINGBUF_DYNAMIC(containedType, outputType) \
59     typedef union outputType {                          \
60         struct {                                        \
61             RingBufBase base;                           \
62             PORT_MEM_ALLOCATOR *pAllocator;             \
63         };                                              \
64         containedType *elem;                            \
65     } outputType
66 
67 #if NV_TYPEOF_SUPPORTED
68 
69 #define FOR_EACH_IN_RINGBUF(pBuf, idx, ptr)                                                                       \
70     {                                                                                                             \
71         (idx) = (pBuf)->base.tail;                                                                                \
72         while((idx) != (pBuf)->base.head)                                                                         \
73         {                                                                                                         \
74             (ptr) = (typeof(&((pBuf)->elem)[0])) &(pBuf)->base.arr[((idx) & RINGBUF_ARRAY_MASK(&((pBuf)->base))) * \
75                                                                   sizeof(*((pBuf)->elem))];                       \
76             (idx)++;
77 
78 #else
79 
80 #define FOR_EACH_IN_RINGBUF(pBuf, idx, ptr)                                                                       \
81     {                                                                                                             \
82         (idx) = (pBuf)->base.tail;                                                                                \
83         while((idx) != (pBuf)->base.head)                                                                         \
84         {                                                                                                         \
85             (ptr) = (void *)&(pBuf)->base.arr[((idx) & RINGBUF_ARRAY_MASK(&((pBuf)->base))) *                     \
86                                                                   sizeof(*((pBuf)->elem))];                       \
87             (idx)++;
88 
89 #endif // NV_TYPEOF_SUPPORTED
90 
91 #define FOR_EACH_END_RINGBUF() \
92         }                      \
93     }
94 
95 
96 #define ringbufConstructDynamic(pBuf, logSz, pAlloc) \
97     (pBuf->pAllocator = pAlloc, ringbufConstructDynamic_IMPL(&((pBuf)->base), logSz, sizeof(*((pBuf)->elem)), pAlloc))
98 
99 #define ringbufConstruct(pBuf) \
100     ringbufConstruct_IMPL(&((pBuf)->base), sizeof((pBuf)->lgSz),  (void*)((pBuf)->elem))
101 
102 #define ringbufDestruct(pBuf) \
103     ringbufDestruct_IMPL(&((pBuf)->base), ((void*)&((pBuf)->pAllocator)) == ((void*)&((pBuf)->base)) ? NULL : ((pBuf)->pAllocator) )
104 
105 #if NV_TYPEOF_SUPPORTED
106 
107 #define ringbufPopN(pBuf, pMax) \
108     (typeof(&((pBuf)->elem)[0])) ringbufPopN_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), pMax)
109 
110 #define ringbufPeekN(pBuf, pMax) \
111     (typeof(&((pBuf)->elem)[0])) ringbufPeekN_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), pMax)
112 
113 #define ringbufAppendN(pBuf, pEles, num, bOver) \
114     ringbufAppendN_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), (NvU8*)pEles, num, bOver)
115 
116 #define ringbufPop(pBuf) \
117     (typeof(&((pBuf)->elem)[0])) ringbufPop_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)))
118 
119 #define ringbufPeek(pBuf) \
120     (typeof(&((pBuf)->elem)[0])) ringbufPeek_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)))
121 
122 #else
123 
124 #define ringbufPopN(pBuf, pMax) \
125     (void *)ringbufPopN_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), pMax)
126 
127 #define ringbufPeekN(pBuf, pMax) \
128     (void *)ringbufPeekN_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), pMax)
129 
130 #define ringbufAppendN(pBuf, pEles, num, bOver) \
131     ringbufAppendN_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), (NvU8*)pEles, num, bOver)
132 
133 #define ringbufPop(pBuf) \
134     (void *)ringbufPop_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)))
135 
136 #define ringbufPeek(pBuf) \
137     (void *)ringbufPeek_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)))
138 
139 #endif // NV_TYPEOF_SUPPORTED
140 
141 #define ringbufAppend(pBuf, pEle, bOver) \
142     ringbufAppend_IMPL(&((pBuf)->base), sizeof(*((pBuf)->elem)), (NvU8*)pEle, bOver)
143 
144 #define ringbufCurrentSize(pBuf) \
145     ringbufCurrentSize_IMPL(&((pBuf)->base))
146 
147 NvBool ringbufConstructDynamic_IMPL(RingBufBase *pBase, NvU64 logSz, NvU64 eleSz, PORT_MEM_ALLOCATOR *pAlloc);
148 NvBool ringbufConstruct_IMPL(RingBufBase *pBase, NvU64 logSz, void *arr);
149 void ringbufDestruct_IMPL(RingBufBase *pBase, void *alloc);
150 void *ringbufPopN_IMPL(RingBufBase *pBase, NvU64 eleSz, NvU64 *pMax);
151 void *ringbufPeekN_IMPL(RingBufBase *pBase, NvU64 eleSz, NvU64 *pMax);
152 NvBool ringbufAppendN_IMPL(RingBufBase *pBase, NvU64 eleSz, NvU8 *pEle, NvU64 num, NvBool bOverwrite);
153 NvU64 ringbufCurrentSize_IMPL(RingBufBase *pBase);
154 
ringbufPeek_IMPL(RingBufBase * pBase,NvU64 eleSz)155 static inline void *ringbufPeek_IMPL(RingBufBase *pBase, NvU64 eleSz)
156 {
157     NvU64 max = 1;
158     return ringbufPeekN_IMPL(pBase, eleSz, &max);
159 }
ringbufPop_IMPL(RingBufBase * pBase,NvU64 eleSz)160 static inline void *ringbufPop_IMPL(RingBufBase *pBase, NvU64 eleSz)
161 {
162     NvU64 max = 1;
163     return ringbufPopN_IMPL(pBase, eleSz, &max);
164 }
ringbufAppend_IMPL(RingBufBase * pBase,NvU64 eleSz,NvU8 * pEle,NvBool bOverwrite)165 static inline NvBool ringbufAppend_IMPL(RingBufBase *pBase, NvU64 eleSz, NvU8 *pEle, NvBool bOverwrite)
166 {
167     return ringbufAppendN_IMPL(pBase, eleSz, pEle, 1, bOverwrite);
168 }
169 #endif
170