d094af73da1fcf65c51efec95807d5bc52fc6b3e
[dragonfly.git] / sys / dev / drm / include / linux / kfifo.h
1 /*      $NetBSD: kfifo.h,v 1.3 2018/08/27 14:41:53 riastradh Exp $      */
2
3 /*-
4  * Copyright (c) 2018 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Taylor R. Campbell.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #ifndef _LINUX_KFIFO_H_
33 #define _LINUX_KFIFO_H_
34
35 #include <sys/types.h>
36 #include <sys/errno.h>
37 #include <sys/mutex.h>
38
39 #include <linux/gfp.h>
40 #include <linux/slab.h>
41
42 struct kfifo_meta {
43         kmutex_t        kfm_lock;
44         size_t          kfm_head;
45         size_t          kfm_tail;
46         size_t          kfm_nbytes;
47 };
48
49 #define _KFIFO_PTR_TYPE(TAG, TYPE)                                            \
50         struct TAG {                                                          \
51                 struct kfifo_meta       kf_meta;                              \
52                 TYPE                    *kf_buf;                              \
53         }
54
55 #define DECLARE_KFIFO_PTR(FIFO, TYPE)   _KFIFO_PTR_TYPE(, TYPE) FIFO
56
57 _KFIFO_PTR_TYPE(kfifo, void);
58
59 #define kfifo_alloc(FIFO, SIZE, GFP)                                          \
60         _kfifo_alloc(&(FIFO)->kf_meta, &(FIFO)->kf_buf, (SIZE), (GFP))
61
62 static inline int
63 _kfifo_alloc(struct kfifo_meta *meta, void *bufp, size_t nbytes, gfp_t gfp)
64 {
65         void *buf;
66
67         buf = kmalloc(nbytes, gfp);
68         if (buf == NULL)
69                 return -ENOMEM;
70
71         /* Type pun!  Hope void * == struct whatever *.  */
72         memcpy(bufp, &buf, sizeof(void *));
73
74         mutex_init(&meta->kfm_lock, MUTEX_DEFAULT, IPL_VM);
75         meta->kfm_head = 0;
76         meta->kfm_tail = 0;
77         meta->kfm_nbytes = nbytes;
78
79         return 0;
80 }
81
82 #define kfifo_free(FIFO)                                                      \
83         _kfifo_free(&(FIFO)->kf_meta, &(FIFO)->kf_buf)
84
85 static inline void
86 _kfifo_free(struct kfifo_meta *meta, void *bufp)
87 {
88         void *buf;
89
90         mutex_destroy(&meta->kfm_lock);
91
92         memcpy(&buf, bufp, sizeof(void *));
93         kfree(buf);
94
95         /* Paranoia.  */
96         buf = NULL;
97         memcpy(bufp, &buf, sizeof(void *));
98 }
99
100 #define kfifo_is_empty(FIFO)    (kfifo_len(FIFO) == 0)
101 #define kfifo_len(FIFO)         _kfifo_len(&(FIFO)->kf_meta)
102
103 static inline size_t
104 _kfifo_len(struct kfifo_meta *meta)
105 {
106         const size_t head = meta->kfm_head;
107         const size_t tail = meta->kfm_tail;
108         const size_t nbytes = meta->kfm_nbytes;
109
110         return (head <= tail ? tail - head : nbytes + tail - head);
111 }
112
113 #define kfifo_out_peek(FIFO, PTR, SIZE)                                       \
114         _kfifo_out_peek(&(FIFO)->kf_meta, (FIFO)->kf_buf, (PTR), (SIZE))
115
116 static inline size_t
117 _kfifo_out_peek(struct kfifo_meta *meta, void *buf, void *ptr, size_t size)
118 {
119         const char *src = buf;
120         char *dst = ptr;
121         size_t copied = 0;
122
123         mutex_spin_enter(&meta->kfm_lock);
124         const size_t head = meta->kfm_head;
125         const size_t tail = meta->kfm_tail;
126         const size_t nbytes = meta->kfm_nbytes;
127         if (head <= tail) {
128                 if (size <= tail - head) {
129                         memcpy(dst, src + head, size);
130                         copied = size;
131                 }
132         } else {
133                 if (size <= nbytes - head) {
134                         memcpy(dst, src + head, size);
135                         copied = size;
136                 } else if (size <= nbytes + tail - head) {
137                         memcpy(dst, src + head, nbytes - head);
138                         memcpy(dst + nbytes - head, src,
139                             size - (nbytes - head));
140                         copied = size;
141                 }
142         }
143         mutex_spin_exit(&meta->kfm_lock);
144
145         return copied;
146 }
147
148 #define kfifo_out(FIFO, PTR, SIZE)                                            \
149         _kfifo_out(&(FIFO)->kf_meta, (FIFO)->kf_buf, (PTR), (SIZE))
150
151 static inline size_t
152 _kfifo_out(struct kfifo_meta *meta, const void *buf, void *ptr, size_t size)
153 {
154         const char *src = buf;
155         char *dst = ptr;
156         size_t copied = 0;
157
158         mutex_spin_enter(&meta->kfm_lock);
159         const size_t head = meta->kfm_head;
160         const size_t tail = meta->kfm_tail;
161         const size_t nbytes = meta->kfm_nbytes;
162         if (head <= tail) {
163                 if (size <= tail - head) {
164                         memcpy(dst, src + head, size);
165                         meta->kfm_head = head + size;
166                         copied = size;
167                 }
168         } else {
169                 if (size <= nbytes - head) {
170                         memcpy(dst, src + head, size);
171                         meta->kfm_head = head + size;
172                         copied = size;
173                 } else if (size <= nbytes + tail - head) {
174                         memcpy(dst, src + head, nbytes - head);
175                         memcpy(dst + nbytes - head, src,
176                             size - (nbytes - head));
177                         meta->kfm_head = size - (nbytes - head);
178                         copied = size;
179                 }
180         }
181         mutex_spin_exit(&meta->kfm_lock);
182
183         return copied;
184 }
185
186 #define kfifo_in(FIFO, PTR, SIZE)                                             \
187         _kfifo_in(&(FIFO)->kf_meta, (FIFO)->kf_buf, (PTR), (SIZE))
188
189 static inline size_t
190 _kfifo_in(struct kfifo_meta *meta, void *buf, const void *ptr, size_t size)
191 {
192         const char *src = ptr;
193         char *dst = buf;
194         size_t copied = 0;
195
196         mutex_spin_enter(&meta->kfm_lock);
197         const size_t head = meta->kfm_head;
198         const size_t tail = meta->kfm_tail;
199         const size_t nbytes = meta->kfm_nbytes;
200         if (tail <= head) {
201                 if (size <= head - tail) {
202                         memcpy(dst + tail, src, size);
203                         meta->kfm_tail = tail + size;
204                         copied = size;
205                 }
206         } else {
207                 if (size <= nbytes - tail) {
208                         memcpy(dst + tail, src, size);
209                         meta->kfm_tail = tail + size;
210                 } else if (size <= nbytes + tail - head) {
211                         memcpy(dst + tail, src, nbytes - tail);
212                         memcpy(dst, src + nbytes - tail,
213                             size - (nbytes - tail));
214                         meta->kfm_tail = size - (nbytes - tail);
215                         copied = size;
216                 }
217         }
218         mutex_spin_exit(&meta->kfm_lock);
219
220         return copied;
221 }
222
223 #endif  /* _LINUX_KFIFO_H_ */