1bfe2b6fbSFrançois Tigeot /* $NetBSD: kfifo.h,v 1.3 2018/08/27 14:41:53 riastradh Exp $ */
2bfe2b6fbSFrançois Tigeot
3bfe2b6fbSFrançois Tigeot /*-
4bfe2b6fbSFrançois Tigeot * Copyright (c) 2018 The NetBSD Foundation, Inc.
5bfe2b6fbSFrançois Tigeot * All rights reserved.
6bfe2b6fbSFrançois Tigeot *
7bfe2b6fbSFrançois Tigeot * This code is derived from software contributed to The NetBSD Foundation
8bfe2b6fbSFrançois Tigeot * by Taylor R. Campbell.
9bfe2b6fbSFrançois Tigeot *
10bfe2b6fbSFrançois Tigeot * Redistribution and use in source and binary forms, with or without
11bfe2b6fbSFrançois Tigeot * modification, are permitted provided that the following conditions
12bfe2b6fbSFrançois Tigeot * are met:
13bfe2b6fbSFrançois Tigeot * 1. Redistributions of source code must retain the above copyright
14bfe2b6fbSFrançois Tigeot * notice, this list of conditions and the following disclaimer.
15bfe2b6fbSFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
16bfe2b6fbSFrançois Tigeot * notice, this list of conditions and the following disclaimer in the
17bfe2b6fbSFrançois Tigeot * documentation and/or other materials provided with the distribution.
18bfe2b6fbSFrançois Tigeot *
19bfe2b6fbSFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20bfe2b6fbSFrançois Tigeot * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21bfe2b6fbSFrançois Tigeot * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22bfe2b6fbSFrançois Tigeot * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23bfe2b6fbSFrançois Tigeot * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24bfe2b6fbSFrançois Tigeot * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25bfe2b6fbSFrançois Tigeot * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26bfe2b6fbSFrançois Tigeot * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27bfe2b6fbSFrançois Tigeot * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28bfe2b6fbSFrançois Tigeot * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29bfe2b6fbSFrançois Tigeot * POSSIBILITY OF SUCH DAMAGE.
30bfe2b6fbSFrançois Tigeot */
31bfe2b6fbSFrançois Tigeot
32bfe2b6fbSFrançois Tigeot #ifndef _LINUX_KFIFO_H_
33bfe2b6fbSFrançois Tigeot #define _LINUX_KFIFO_H_
34bfe2b6fbSFrançois Tigeot
35bfe2b6fbSFrançois Tigeot #include <sys/types.h>
36bfe2b6fbSFrançois Tigeot #include <sys/errno.h>
3711125cdbSSascha Wildner #include <sys/lock.h>
38bfe2b6fbSFrançois Tigeot
39bfe2b6fbSFrançois Tigeot #include <linux/gfp.h>
40bfe2b6fbSFrançois Tigeot #include <linux/slab.h>
41bfe2b6fbSFrançois Tigeot
42bfe2b6fbSFrançois Tigeot struct kfifo_meta {
4345aa70c6SFrançois Tigeot struct lock kfm_lock;
44bfe2b6fbSFrançois Tigeot size_t kfm_head;
45bfe2b6fbSFrançois Tigeot size_t kfm_tail;
46bfe2b6fbSFrançois Tigeot size_t kfm_nbytes;
47bfe2b6fbSFrançois Tigeot };
48bfe2b6fbSFrançois Tigeot
49bfe2b6fbSFrançois Tigeot #define _KFIFO_PTR_TYPE(TAG, TYPE) \
50bfe2b6fbSFrançois Tigeot struct TAG { \
51bfe2b6fbSFrançois Tigeot struct kfifo_meta kf_meta; \
52bfe2b6fbSFrançois Tigeot TYPE *kf_buf; \
53bfe2b6fbSFrançois Tigeot }
54bfe2b6fbSFrançois Tigeot
55bfe2b6fbSFrançois Tigeot #define DECLARE_KFIFO_PTR(FIFO, TYPE) _KFIFO_PTR_TYPE(, TYPE) FIFO
56bfe2b6fbSFrançois Tigeot
57bfe2b6fbSFrançois Tigeot _KFIFO_PTR_TYPE(kfifo, void);
58bfe2b6fbSFrançois Tigeot
59bfe2b6fbSFrançois Tigeot #define kfifo_alloc(FIFO, SIZE, GFP) \
60bfe2b6fbSFrançois Tigeot _kfifo_alloc(&(FIFO)->kf_meta, &(FIFO)->kf_buf, (SIZE), (GFP))
61bfe2b6fbSFrançois Tigeot
62bfe2b6fbSFrançois Tigeot static inline int
_kfifo_alloc(struct kfifo_meta * meta,void * bufp,size_t nbytes,gfp_t gfp)63bfe2b6fbSFrançois Tigeot _kfifo_alloc(struct kfifo_meta *meta, void *bufp, size_t nbytes, gfp_t gfp)
64bfe2b6fbSFrançois Tigeot {
65bfe2b6fbSFrançois Tigeot void *buf;
66bfe2b6fbSFrançois Tigeot
6745aa70c6SFrançois Tigeot buf = kmalloc(nbytes, M_DRM, gfp);
68bfe2b6fbSFrançois Tigeot if (buf == NULL)
69bfe2b6fbSFrançois Tigeot return -ENOMEM;
70bfe2b6fbSFrançois Tigeot
71bfe2b6fbSFrançois Tigeot /* Type pun! Hope void * == struct whatever *. */
72bfe2b6fbSFrançois Tigeot memcpy(bufp, &buf, sizeof(void *));
73bfe2b6fbSFrançois Tigeot
7445aa70c6SFrançois Tigeot lockinit(&meta->kfm_lock, "lkfl", 0, LK_CANRECURSE);
75bfe2b6fbSFrançois Tigeot meta->kfm_head = 0;
76bfe2b6fbSFrançois Tigeot meta->kfm_tail = 0;
77bfe2b6fbSFrançois Tigeot meta->kfm_nbytes = nbytes;
78bfe2b6fbSFrançois Tigeot
79bfe2b6fbSFrançois Tigeot return 0;
80bfe2b6fbSFrançois Tigeot }
81bfe2b6fbSFrançois Tigeot
82bfe2b6fbSFrançois Tigeot #define kfifo_free(FIFO) \
83bfe2b6fbSFrançois Tigeot _kfifo_free(&(FIFO)->kf_meta, &(FIFO)->kf_buf)
84bfe2b6fbSFrançois Tigeot
85bfe2b6fbSFrançois Tigeot static inline void
_kfifo_free(struct kfifo_meta * meta,void * bufp)86bfe2b6fbSFrançois Tigeot _kfifo_free(struct kfifo_meta *meta, void *bufp)
87bfe2b6fbSFrançois Tigeot {
88bfe2b6fbSFrançois Tigeot void *buf;
89bfe2b6fbSFrançois Tigeot
90bfe2b6fbSFrançois Tigeot mutex_destroy(&meta->kfm_lock);
91bfe2b6fbSFrançois Tigeot
92bfe2b6fbSFrançois Tigeot memcpy(&buf, bufp, sizeof(void *));
93bfe2b6fbSFrançois Tigeot kfree(buf);
94bfe2b6fbSFrançois Tigeot
95bfe2b6fbSFrançois Tigeot /* Paranoia. */
96bfe2b6fbSFrançois Tigeot buf = NULL;
97bfe2b6fbSFrançois Tigeot memcpy(bufp, &buf, sizeof(void *));
98bfe2b6fbSFrançois Tigeot }
99bfe2b6fbSFrançois Tigeot
100bfe2b6fbSFrançois Tigeot #define kfifo_is_empty(FIFO) (kfifo_len(FIFO) == 0)
101bfe2b6fbSFrançois Tigeot #define kfifo_len(FIFO) _kfifo_len(&(FIFO)->kf_meta)
102bfe2b6fbSFrançois Tigeot
103bfe2b6fbSFrançois Tigeot static inline size_t
_kfifo_len(struct kfifo_meta * meta)104bfe2b6fbSFrançois Tigeot _kfifo_len(struct kfifo_meta *meta)
105bfe2b6fbSFrançois Tigeot {
106bfe2b6fbSFrançois Tigeot const size_t head = meta->kfm_head;
107bfe2b6fbSFrançois Tigeot const size_t tail = meta->kfm_tail;
108bfe2b6fbSFrançois Tigeot const size_t nbytes = meta->kfm_nbytes;
109bfe2b6fbSFrançois Tigeot
110bfe2b6fbSFrançois Tigeot return (head <= tail ? tail - head : nbytes + tail - head);
111bfe2b6fbSFrançois Tigeot }
112bfe2b6fbSFrançois Tigeot
113bfe2b6fbSFrançois Tigeot #define kfifo_out_peek(FIFO, PTR, SIZE) \
114bfe2b6fbSFrançois Tigeot _kfifo_out_peek(&(FIFO)->kf_meta, (FIFO)->kf_buf, (PTR), (SIZE))
115bfe2b6fbSFrançois Tigeot
116bfe2b6fbSFrançois Tigeot static inline size_t
_kfifo_out_peek(struct kfifo_meta * meta,void * buf,void * ptr,size_t size)117bfe2b6fbSFrançois Tigeot _kfifo_out_peek(struct kfifo_meta *meta, void *buf, void *ptr, size_t size)
118bfe2b6fbSFrançois Tigeot {
119bfe2b6fbSFrançois Tigeot const char *src = buf;
120bfe2b6fbSFrançois Tigeot char *dst = ptr;
121bfe2b6fbSFrançois Tigeot size_t copied = 0;
122bfe2b6fbSFrançois Tigeot
12345aa70c6SFrançois Tigeot lockmgr(&meta->kfm_lock, LK_EXCLUSIVE);
124bfe2b6fbSFrançois Tigeot const size_t head = meta->kfm_head;
125bfe2b6fbSFrançois Tigeot const size_t tail = meta->kfm_tail;
126bfe2b6fbSFrançois Tigeot const size_t nbytes = meta->kfm_nbytes;
127bfe2b6fbSFrançois Tigeot if (head <= tail) {
128bfe2b6fbSFrançois Tigeot if (size <= tail - head) {
129bfe2b6fbSFrançois Tigeot memcpy(dst, src + head, size);
130bfe2b6fbSFrançois Tigeot copied = size;
131bfe2b6fbSFrançois Tigeot }
132bfe2b6fbSFrançois Tigeot } else {
133bfe2b6fbSFrançois Tigeot if (size <= nbytes - head) {
134bfe2b6fbSFrançois Tigeot memcpy(dst, src + head, size);
135bfe2b6fbSFrançois Tigeot copied = size;
136bfe2b6fbSFrançois Tigeot } else if (size <= nbytes + tail - head) {
137bfe2b6fbSFrançois Tigeot memcpy(dst, src + head, nbytes - head);
138bfe2b6fbSFrançois Tigeot memcpy(dst + nbytes - head, src,
139bfe2b6fbSFrançois Tigeot size - (nbytes - head));
140bfe2b6fbSFrançois Tigeot copied = size;
141bfe2b6fbSFrançois Tigeot }
142bfe2b6fbSFrançois Tigeot }
14345aa70c6SFrançois Tigeot lockmgr(&meta->kfm_lock, LK_RELEASE);
144bfe2b6fbSFrançois Tigeot
145bfe2b6fbSFrançois Tigeot return copied;
146bfe2b6fbSFrançois Tigeot }
147bfe2b6fbSFrançois Tigeot
148bfe2b6fbSFrançois Tigeot #define kfifo_out(FIFO, PTR, SIZE) \
149bfe2b6fbSFrançois Tigeot _kfifo_out(&(FIFO)->kf_meta, (FIFO)->kf_buf, (PTR), (SIZE))
150bfe2b6fbSFrançois Tigeot
151bfe2b6fbSFrançois Tigeot static inline size_t
_kfifo_out(struct kfifo_meta * meta,const void * buf,void * ptr,size_t size)152bfe2b6fbSFrançois Tigeot _kfifo_out(struct kfifo_meta *meta, const void *buf, void *ptr, size_t size)
153bfe2b6fbSFrançois Tigeot {
154bfe2b6fbSFrançois Tigeot const char *src = buf;
155bfe2b6fbSFrançois Tigeot char *dst = ptr;
156bfe2b6fbSFrançois Tigeot size_t copied = 0;
157bfe2b6fbSFrançois Tigeot
15845aa70c6SFrançois Tigeot lockmgr(&meta->kfm_lock, LK_EXCLUSIVE);
159bfe2b6fbSFrançois Tigeot const size_t head = meta->kfm_head;
160bfe2b6fbSFrançois Tigeot const size_t tail = meta->kfm_tail;
161bfe2b6fbSFrançois Tigeot const size_t nbytes = meta->kfm_nbytes;
162bfe2b6fbSFrançois Tigeot if (head <= tail) {
163bfe2b6fbSFrançois Tigeot if (size <= tail - head) {
164bfe2b6fbSFrançois Tigeot memcpy(dst, src + head, size);
165bfe2b6fbSFrançois Tigeot meta->kfm_head = head + size;
166bfe2b6fbSFrançois Tigeot copied = size;
167bfe2b6fbSFrançois Tigeot }
168bfe2b6fbSFrançois Tigeot } else {
169bfe2b6fbSFrançois Tigeot if (size <= nbytes - head) {
170bfe2b6fbSFrançois Tigeot memcpy(dst, src + head, size);
171bfe2b6fbSFrançois Tigeot meta->kfm_head = head + size;
172bfe2b6fbSFrançois Tigeot copied = size;
173bfe2b6fbSFrançois Tigeot } else if (size <= nbytes + tail - head) {
174bfe2b6fbSFrançois Tigeot memcpy(dst, src + head, nbytes - head);
175bfe2b6fbSFrançois Tigeot memcpy(dst + nbytes - head, src,
176bfe2b6fbSFrançois Tigeot size - (nbytes - head));
177bfe2b6fbSFrançois Tigeot meta->kfm_head = size - (nbytes - head);
178bfe2b6fbSFrançois Tigeot copied = size;
179bfe2b6fbSFrançois Tigeot }
180bfe2b6fbSFrançois Tigeot }
18145aa70c6SFrançois Tigeot lockmgr(&meta->kfm_lock, LK_RELEASE);
182bfe2b6fbSFrançois Tigeot
183bfe2b6fbSFrançois Tigeot return copied;
184bfe2b6fbSFrançois Tigeot }
185bfe2b6fbSFrançois Tigeot
186bfe2b6fbSFrançois Tigeot #define kfifo_in(FIFO, PTR, SIZE) \
187bfe2b6fbSFrançois Tigeot _kfifo_in(&(FIFO)->kf_meta, (FIFO)->kf_buf, (PTR), (SIZE))
188bfe2b6fbSFrançois Tigeot
189bfe2b6fbSFrançois Tigeot static inline size_t
_kfifo_in(struct kfifo_meta * meta,void * buf,const void * ptr,size_t size)190bfe2b6fbSFrançois Tigeot _kfifo_in(struct kfifo_meta *meta, void *buf, const void *ptr, size_t size)
191bfe2b6fbSFrançois Tigeot {
192bfe2b6fbSFrançois Tigeot const char *src = ptr;
193bfe2b6fbSFrançois Tigeot char *dst = buf;
194bfe2b6fbSFrançois Tigeot size_t copied = 0;
195bfe2b6fbSFrançois Tigeot
19645aa70c6SFrançois Tigeot lockmgr(&meta->kfm_lock, LK_EXCLUSIVE);
197bfe2b6fbSFrançois Tigeot const size_t head = meta->kfm_head;
198bfe2b6fbSFrançois Tigeot const size_t tail = meta->kfm_tail;
199bfe2b6fbSFrançois Tigeot const size_t nbytes = meta->kfm_nbytes;
200bfe2b6fbSFrançois Tigeot if (tail <= head) {
201bfe2b6fbSFrançois Tigeot if (size <= head - tail) {
202bfe2b6fbSFrançois Tigeot memcpy(dst + tail, src, size);
203bfe2b6fbSFrançois Tigeot meta->kfm_tail = tail + size;
204bfe2b6fbSFrançois Tigeot copied = size;
205bfe2b6fbSFrançois Tigeot }
206bfe2b6fbSFrançois Tigeot } else {
207bfe2b6fbSFrançois Tigeot if (size <= nbytes - tail) {
208bfe2b6fbSFrançois Tigeot memcpy(dst + tail, src, size);
209bfe2b6fbSFrançois Tigeot meta->kfm_tail = tail + size;
210bfe2b6fbSFrançois Tigeot } else if (size <= nbytes + tail - head) {
211bfe2b6fbSFrançois Tigeot memcpy(dst + tail, src, nbytes - tail);
212bfe2b6fbSFrançois Tigeot memcpy(dst, src + nbytes - tail,
213bfe2b6fbSFrançois Tigeot size - (nbytes - tail));
214bfe2b6fbSFrançois Tigeot meta->kfm_tail = size - (nbytes - tail);
215bfe2b6fbSFrançois Tigeot copied = size;
216bfe2b6fbSFrançois Tigeot }
217bfe2b6fbSFrançois Tigeot }
21845aa70c6SFrançois Tigeot lockmgr(&meta->kfm_lock, LK_RELEASE);
219bfe2b6fbSFrançois Tigeot
220bfe2b6fbSFrançois Tigeot return copied;
221bfe2b6fbSFrançois Tigeot }
222bfe2b6fbSFrançois Tigeot
223*78973132SSergey Zigachev struct __kfifo {
224*78973132SSergey Zigachev unsigned int in;
225*78973132SSergey Zigachev unsigned int out;
226*78973132SSergey Zigachev unsigned int mask;
227*78973132SSergey Zigachev unsigned int esize;
228*78973132SSergey Zigachev void *data;
229*78973132SSergey Zigachev };
230*78973132SSergey Zigachev
231*78973132SSergey Zigachev #define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \
232*78973132SSergey Zigachev union { \
233*78973132SSergey Zigachev struct __kfifo kfifo; \
234*78973132SSergey Zigachev datatype *type; \
235*78973132SSergey Zigachev const datatype *const_type; \
236*78973132SSergey Zigachev char (*rectype)[recsize]; \
237*78973132SSergey Zigachev ptrtype *ptr; \
238*78973132SSergey Zigachev ptrtype const *ptr_const; \
239*78973132SSergey Zigachev }
240*78973132SSergey Zigachev
241*78973132SSergey Zigachev #define __STRUCT_KFIFO(type, size, recsize, ptrtype) \
242*78973132SSergey Zigachev { \
243*78973132SSergey Zigachev __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
244*78973132SSergey Zigachev type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
245*78973132SSergey Zigachev }
246*78973132SSergey Zigachev
247*78973132SSergey Zigachev #define _KFIFO_TYPE(TYPE, SIZE) \
248*78973132SSergey Zigachev struct __STRUCT_KFIFO(TYPE, SIZE, 0, TYPE)
249*78973132SSergey Zigachev /**
250*78973132SSergey Zigachev * DECLARE_KFIFO - macro to declare a fifo object
251*78973132SSergey Zigachev * @fifo: name of the declared fifo
252*78973132SSergey Zigachev * @type: type of the fifo elements
253*78973132SSergey Zigachev * @size: the number of elements in the fifo, this must be a power of 2
254*78973132SSergey Zigachev */
255*78973132SSergey Zigachev #define DECLARE_KFIFO(FIFO, TYPE, SIZE) _KFIFO_TYPE(TYPE, SIZE) FIFO
256*78973132SSergey Zigachev
257bfe2b6fbSFrançois Tigeot #endif /* _LINUX_KFIFO_H_ */
258