1 // Copyright (C) 2022 Beken Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #pragma once
16
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20
21 #include <common/bk_include.h>
22 #include <common/bk_generic.h>
23 #include <common/bk_compiler.h>
24 #include <os/mem.h>
25 #include <os/os.h>
26
27 typedef struct kfifo
28 {
29 unsigned int in;
30 unsigned int out;
31
32 unsigned int mask;
33
34 unsigned int size;
35 unsigned char *buffer;
36 } kfifo_t, *kfifo_ptr_t;
37
38 /**
39 * kfifo_init - allocates a new FIFO using a preallocated buffer
40 * @buffer: the preallocated buffer to be used.
41 * @size: the size of the internal buffer, this have to be a power of 2.
42 * @gfp_mask: get_free_pages mask, passed to ke_malloc()
43 * @lock: the lock to be used to protect the fifo buffer
44 *
45 * Do NOT pass the kfifo to kfifo_free() after use ! Simply free the
46 * struct kfifo with ke_free().
47 */
kfifo_init(unsigned char * buffer,unsigned int size)48 __BK_INLINE struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size)
49 {
50 struct kfifo *fifo;
51
52 /* size must be a power of 2 */
53 //BK_ASSERT(size & (size - 1));
54
55 fifo = os_malloc(sizeof(struct kfifo));
56 if (!fifo)
57 return NULLPTR;
58
59 fifo->buffer = buffer;
60 fifo->size = size;
61 fifo->in = 0;
62 fifo->out = 0;
63 fifo->mask = fifo->size - 1;
64
65 return fifo;
66 }
67
68 /**
69 * kfifo_alloc - allocates a new FIFO and its internal buffer
70 * @size: the size of the internal buffer to be allocated.
71 * @gfp_mask: get_free_pages mask, passed to ke_malloc()
72 * @lock: the lock to be used to protect the fifo buffer
73 *
74 * The size will be rounded-up to a power of 2.
75 */
kfifo_alloc(unsigned int size)76 __BK_INLINE struct kfifo *kfifo_alloc(unsigned int size)
77 {
78 unsigned char *buffer;
79 struct kfifo *ret;
80
81 buffer = os_malloc(size);
82 if (!buffer)
83 return 0;
84 os_memset(buffer, 0, size);
85
86 ret = kfifo_init(buffer, size);
87
88 if (!(ret))
89 os_free(buffer);
90
91 return ret;
92 }
93
94 /**
95 * kfifo_free - frees the FIFO
96 * @fifo: the fifo to be freed.
97 */
kfifo_free(struct kfifo * fifo)98 __BK_INLINE void kfifo_free(struct kfifo *fifo)
99 {
100 os_free(fifo->buffer);
101 fifo->buffer = 0;
102
103 os_free(fifo);
104 }
105
106 /**
107 * __kfifo_put - puts some data into the FIFO, no locking version
108 * @fifo: the fifo to be used.
109 * @buffer: the data to be added.
110 * @len: the length of the data to be added.
111 *
112 * This function copies at most 'len' bytes from the 'buffer' into
113 * the FIFO depending on the free space, and returns the number of
114 * bytes copied.
115 *
116 * Note that with only one concurrent reader and one concurrent
117 * writer, you don't need extra locking to use these functions.
118 */
kfifo_put(struct kfifo * fifo,unsigned char * buffer,unsigned int len)119 __BK_INLINE unsigned int kfifo_put(struct kfifo *fifo,
120 unsigned char *buffer, unsigned int len)
121 {
122 unsigned int l;
123 GLOBAL_INT_DECLARATION();
124
125 GLOBAL_INT_DISABLE();
126 len = min(len, fifo->size - fifo->in + fifo->out);
127
128 /* first put the data starting from fifo->in to buffer end */
129 l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
130 os_memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
131
132 /* then put the rest (if any) at the beginning of the buffer */
133 os_memcpy(fifo->buffer, buffer + l, len - l);
134
135 fifo->in += len;
136 GLOBAL_INT_RESTORE();
137
138 return len;
139 }
140
141 /**
142 * __kfifo_get - gets some data from the FIFO, no locking version
143 * @fifo: the fifo to be used.
144 * @buffer: where the data must be copied.
145 * @len: the size of the destination buffer.
146 *
147 * This function copies at most 'len' bytes from the FIFO into the
148 * 'buffer' and returns the number of copied bytes.
149 *
150 * Note that with only one concurrent reader and one concurrent
151 * writer, you don't need extra locking to use these functions.
152 */
kfifo_get(struct kfifo * fifo,unsigned char * buffer,unsigned int len)153 __BK_INLINE unsigned int kfifo_get(struct kfifo *fifo,
154 unsigned char *buffer, unsigned int len)
155 {
156 unsigned int l;
157 GLOBAL_INT_DECLARATION();
158
159 GLOBAL_INT_DISABLE();
160 len = min(len, fifo->in - fifo->out);
161
162 /* first get the data from fifo->out until the end of the buffer */
163 l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
164 os_memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
165
166 /* then get the rest (if any) from the beginning of the buffer */
167 os_memcpy(buffer + l, fifo->buffer, len - l);
168
169 fifo->out += len;
170
171 if (fifo->out == fifo->in) {
172 fifo->in = 0;
173 fifo->out = 0;
174 }
175 GLOBAL_INT_RESTORE();
176
177 return len;
178 }
179
kfifo_data_size(struct kfifo * fifo)180 __BK_INLINE unsigned int kfifo_data_size(struct kfifo *fifo)
181 {
182 return (fifo->in - fifo->out);
183 }
184
kfifo_unused(struct kfifo * fifo)185 __BK_INLINE unsigned int kfifo_unused(struct kfifo *fifo)
186 {
187 return (fifo->mask + 1) - (fifo->in - fifo->out);
188 }
189
kfifo_copy_out(struct kfifo * fifo,void * dst,unsigned int len,unsigned int off)190 __BK_INLINE void kfifo_copy_out(struct kfifo *fifo, void *dst,
191 unsigned int len, unsigned int off)
192 {
193 unsigned int size = fifo->mask + 1;
194 unsigned int l;
195
196 off &= fifo->mask;
197
198 l = min(len, size - off);
199
200 os_memcpy(dst, (void *)(fifo->buffer + off), l);
201 os_memcpy((void *)((unsigned int)dst + l), (void *)fifo->buffer, len - l);
202 /*
203 * make sure that the data is copied before
204 * incrementing the fifo->out index counter
205 */
206 }
207
kfifo_out_peek(struct kfifo * fifo,unsigned char * buffer,unsigned int len)208 __BK_INLINE unsigned int kfifo_out_peek(struct kfifo *fifo,
209 unsigned char *buffer, unsigned int len)
210 {
211 unsigned int l;
212
213 l = fifo->in - fifo->out;
214 if (len > l)
215 len = l;
216
217 kfifo_copy_out(fifo, buffer, len, fifo->out);
218
219 return len;
220 }
221
222 #ifdef __cplusplus
223 }
224 #endif
225