xref: /dflybsd-src/sys/dev/drm/include/linux/kfifo.h (revision 789731325bde747251c28a37e0a00ed4efb88c46)
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