Blame view

lib/kfifo.c 12.1 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
2e956fb32   Stefani Seibold   kfifo: replace th...
3
   * A generic kernel FIFO implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
2e956fb32   Stefani Seibold   kfifo: replace th...
5
   * Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
   */
  
  #include <linux/kernel.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
9
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
  #include <linux/slab.h>
  #include <linux/err.h>
f84d5a76c   vignesh babu   is_power_of_2: ke...
12
  #include <linux/log2.h>
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
13
  #include <linux/uaccess.h>
2e956fb32   Stefani Seibold   kfifo: replace th...
14
  #include <linux/kfifo.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15

2e956fb32   Stefani Seibold   kfifo: replace th...
16
17
  /*
   * internal helper to calculate the unused elements in a fifo
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
19
  static inline unsigned int kfifo_unused(struct __kfifo *fifo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
21
  	return (fifo->mask + 1) - (fifo->in - fifo->out);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

2e956fb32   Stefani Seibold   kfifo: replace th...
24
25
  int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
  		size_t esize, gfp_t gfp_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  	/*
75a24b822   Martin Kelly   kfifo: fix inaccu...
28
  	 * round up to the next power of 2, since our 'let the indices
b33112d1c   Robert P. J. Day   kernel/kfifo.c: r...
29
  	 * wrap' technique works only in this case.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  	 */
dfe2a77fd   Stefani Seibold   kfifo: fix kfifo_...
31
  	size = roundup_pow_of_two(size);
2e956fb32   Stefani Seibold   kfifo: replace th...
32
33
34
35
36
37
38
39
40
  
  	fifo->in = 0;
  	fifo->out = 0;
  	fifo->esize = esize;
  
  	if (size < 2) {
  		fifo->data = NULL;
  		fifo->mask = 0;
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  	}
6da2ec560   Kees Cook   treewide: kmalloc...
42
  	fifo->data = kmalloc_array(esize, size, gfp_mask);
2e956fb32   Stefani Seibold   kfifo: replace th...
43
44
45
  
  	if (!fifo->data) {
  		fifo->mask = 0;
454654878   Stefani Seibold   kfifo: move struc...
46
47
  		return -ENOMEM;
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
48
  	fifo->mask = size - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49

454654878   Stefani Seibold   kfifo: move struc...
50
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
52
  EXPORT_SYMBOL(__kfifo_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53

2e956fb32   Stefani Seibold   kfifo: replace th...
54
  void __kfifo_free(struct __kfifo *fifo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
56
57
58
59
60
61
  	kfree(fifo->data);
  	fifo->in = 0;
  	fifo->out = 0;
  	fifo->esize = 0;
  	fifo->data = NULL;
  	fifo->mask = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
63
  EXPORT_SYMBOL(__kfifo_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

2e956fb32   Stefani Seibold   kfifo: replace th...
65
66
  int __kfifo_init(struct __kfifo *fifo, void *buffer,
  		unsigned int size, size_t esize)
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
67
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
68
  	size /= esize;
ab9bb6318   Linus Torvalds   Partially revert ...
69
70
  	if (!is_power_of_2(size))
  		size = rounddown_pow_of_two(size);
2e956fb32   Stefani Seibold   kfifo: replace th...
71
72
73
74
75
76
77
78
79
  
  	fifo->in = 0;
  	fifo->out = 0;
  	fifo->esize = esize;
  	fifo->data = buffer;
  
  	if (size < 2) {
  		fifo->mask = 0;
  		return -EINVAL;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
80
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
81
82
83
  	fifo->mask = size - 1;
  
  	return 0;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
84
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
85
  EXPORT_SYMBOL(__kfifo_init);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
86

2e956fb32   Stefani Seibold   kfifo: replace th...
87
88
  static void kfifo_copy_in(struct __kfifo *fifo, const void *src,
  		unsigned int len, unsigned int off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
90
91
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
93
94
95
96
97
98
99
100
101
102
  	off &= fifo->mask;
  	if (esize != 1) {
  		off *= esize;
  		size *= esize;
  		len *= esize;
  	}
  	l = min(len, size - off);
  
  	memcpy(fifo->data + off, src, l);
  	memcpy(fifo->data, src + l, len - l);
a45bce495   Paul E. McKenney   [PATCH] memory or...
103
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
104
105
  	 * make sure that the data in the fifo is up to date before
  	 * incrementing the fifo->in index counter
a45bce495   Paul E. McKenney   [PATCH] memory or...
106
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
107
108
  	smp_wmb();
  }
a45bce495   Paul E. McKenney   [PATCH] memory or...
109

2e956fb32   Stefani Seibold   kfifo: replace th...
110
111
112
113
  unsigned int __kfifo_in(struct __kfifo *fifo,
  		const void *buf, unsigned int len)
  {
  	unsigned int l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
114

2e956fb32   Stefani Seibold   kfifo: replace th...
115
116
117
  	l = kfifo_unused(fifo);
  	if (len > l)
  		len = l;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118

2e956fb32   Stefani Seibold   kfifo: replace th...
119
120
121
  	kfifo_copy_in(fifo, buf, len, fifo->in);
  	fifo->in += len;
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
123
  EXPORT_SYMBOL(__kfifo_in);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124

2e956fb32   Stefani Seibold   kfifo: replace th...
125
126
  static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
  		unsigned int len, unsigned int off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
128
129
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
131
132
133
134
135
136
137
138
139
140
  	off &= fifo->mask;
  	if (esize != 1) {
  		off *= esize;
  		size *= esize;
  		len *= esize;
  	}
  	l = min(len, size - off);
  
  	memcpy(dst, fifo->data + off, l);
  	memcpy(dst + l, fifo->data, len - l);
a45bce495   Paul E. McKenney   [PATCH] memory or...
141
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
142
143
  	 * make sure that the data is copied before
  	 * incrementing the fifo->out index counter
a45bce495   Paul E. McKenney   [PATCH] memory or...
144
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
145
146
  	smp_wmb();
  }
a45bce495   Paul E. McKenney   [PATCH] memory or...
147

2e956fb32   Stefani Seibold   kfifo: replace th...
148
149
150
151
  unsigned int __kfifo_out_peek(struct __kfifo *fifo,
  		void *buf, unsigned int len)
  {
  	unsigned int l;
a45bce495   Paul E. McKenney   [PATCH] memory or...
152

2e956fb32   Stefani Seibold   kfifo: replace th...
153
154
155
  	l = fifo->in - fifo->out;
  	if (len > l)
  		len = l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
156

2e956fb32   Stefani Seibold   kfifo: replace th...
157
158
159
160
  	kfifo_copy_out(fifo, buf, len, fifo->out);
  	return len;
  }
  EXPORT_SYMBOL(__kfifo_out_peek);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

2e956fb32   Stefani Seibold   kfifo: replace th...
162
163
164
165
166
167
  unsigned int __kfifo_out(struct __kfifo *fifo,
  		void *buf, unsigned int len)
  {
  	len = __kfifo_out_peek(fifo, buf, len);
  	fifo->out += len;
  	return len;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
168
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
169
  EXPORT_SYMBOL(__kfifo_out);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
170

2e956fb32   Stefani Seibold   kfifo: replace th...
171
172
173
  static unsigned long kfifo_copy_from_user(struct __kfifo *fifo,
  	const void __user *from, unsigned int len, unsigned int off,
  	unsigned int *copied)
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
174
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
175
176
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
177
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
178
  	unsigned long ret;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
179

2e956fb32   Stefani Seibold   kfifo: replace th...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  	off &= fifo->mask;
  	if (esize != 1) {
  		off *= esize;
  		size *= esize;
  		len *= esize;
  	}
  	l = min(len, size - off);
  
  	ret = copy_from_user(fifo->data + off, from, l);
  	if (unlikely(ret))
  		ret = DIV_ROUND_UP(ret + len - l, esize);
  	else {
  		ret = copy_from_user(fifo->data, from + l, len - l);
  		if (unlikely(ret))
  			ret = DIV_ROUND_UP(ret, esize);
  	}
a45bce495   Paul E. McKenney   [PATCH] memory or...
196
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
197
198
  	 * make sure that the data in the fifo is up to date before
  	 * incrementing the fifo->in index counter
a45bce495   Paul E. McKenney   [PATCH] memory or...
199
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
200
  	smp_wmb();
a019e48cf   Lars-Peter Clausen   kfifo: kfifo_copy...
201
  	*copied = len - ret * esize;
2e956fb32   Stefani Seibold   kfifo: replace th...
202
203
204
  	/* return the number of elements which are not copied */
  	return ret;
  }
a45bce495   Paul E. McKenney   [PATCH] memory or...
205

2e956fb32   Stefani Seibold   kfifo: replace th...
206
207
208
209
210
211
212
  int __kfifo_from_user(struct __kfifo *fifo, const void __user *from,
  		unsigned long len, unsigned int *copied)
  {
  	unsigned int l;
  	unsigned long ret;
  	unsigned int esize = fifo->esize;
  	int err;
a45bce495   Paul E. McKenney   [PATCH] memory or...
213

2e956fb32   Stefani Seibold   kfifo: replace th...
214
215
  	if (esize != 1)
  		len /= esize;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
216

2e956fb32   Stefani Seibold   kfifo: replace th...
217
218
219
  	l = kfifo_unused(fifo);
  	if (len > l)
  		len = l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
220

2e956fb32   Stefani Seibold   kfifo: replace th...
221
222
223
224
225
226
227
228
  	ret = kfifo_copy_from_user(fifo, from, len, fifo->in, copied);
  	if (unlikely(ret)) {
  		len -= ret;
  		err = -EFAULT;
  	} else
  		err = 0;
  	fifo->in += len;
  	return err;
86d488031   Stefani Seibold   kfifo: add record...
229
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
230
  EXPORT_SYMBOL(__kfifo_from_user);
86d488031   Stefani Seibold   kfifo: add record...
231

2e956fb32   Stefani Seibold   kfifo: replace th...
232
233
  static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to,
  		unsigned int len, unsigned int off, unsigned int *copied)
86d488031   Stefani Seibold   kfifo: add record...
234
235
  {
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  	unsigned long ret;
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
  
  	off &= fifo->mask;
  	if (esize != 1) {
  		off *= esize;
  		size *= esize;
  		len *= esize;
  	}
  	l = min(len, size - off);
  
  	ret = copy_to_user(to, fifo->data + off, l);
  	if (unlikely(ret))
  		ret = DIV_ROUND_UP(ret + len - l, esize);
  	else {
  		ret = copy_to_user(to + l, fifo->data, len - l);
  		if (unlikely(ret))
  			ret = DIV_ROUND_UP(ret, esize);
  	}
86d488031   Stefani Seibold   kfifo: add record...
256
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
257
258
  	 * make sure that the data is copied before
  	 * incrementing the fifo->out index counter
86d488031   Stefani Seibold   kfifo: add record...
259
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
260
  	smp_wmb();
a019e48cf   Lars-Peter Clausen   kfifo: kfifo_copy...
261
  	*copied = len - ret * esize;
2e956fb32   Stefani Seibold   kfifo: replace th...
262
263
264
  	/* return the number of elements which are not copied */
  	return ret;
  }
86d488031   Stefani Seibold   kfifo: add record...
265

2e956fb32   Stefani Seibold   kfifo: replace th...
266
267
268
269
270
271
272
  int __kfifo_to_user(struct __kfifo *fifo, void __user *to,
  		unsigned long len, unsigned int *copied)
  {
  	unsigned int l;
  	unsigned long ret;
  	unsigned int esize = fifo->esize;
  	int err;
86d488031   Stefani Seibold   kfifo: add record...
273

2e956fb32   Stefani Seibold   kfifo: replace th...
274
275
  	if (esize != 1)
  		len /= esize;
86d488031   Stefani Seibold   kfifo: add record...
276

2e956fb32   Stefani Seibold   kfifo: replace th...
277
278
279
280
  	l = fifo->in - fifo->out;
  	if (len > l)
  		len = l;
  	ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied);
64ce1037c   Andi Kleen   kfifo: sanitize *...
281
  	if (unlikely(ret)) {
2e956fb32   Stefani Seibold   kfifo: replace th...
282
283
284
285
286
287
288
289
  		len -= ret;
  		err = -EFAULT;
  	} else
  		err = 0;
  	fifo->out += len;
  	return err;
  }
  EXPORT_SYMBOL(__kfifo_to_user);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
290

2e956fb32   Stefani Seibold   kfifo: replace th...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  static int setup_sgl_buf(struct scatterlist *sgl, void *buf,
  		int nents, unsigned int len)
  {
  	int n;
  	unsigned int l;
  	unsigned int off;
  	struct page *page;
  
  	if (!nents)
  		return 0;
  
  	if (!len)
  		return 0;
  
  	n = 0;
  	page = virt_to_page(buf);
  	off = offset_in_page(buf);
  	l = 0;
  
  	while (len >= l + PAGE_SIZE - off) {
  		struct page *npage;
  
  		l += PAGE_SIZE;
  		buf += PAGE_SIZE;
  		npage = virt_to_page(buf);
  		if (page_to_phys(page) != page_to_phys(npage) - l) {
d78a3eda6   Stefani Seibold   kernel/kfifo.c: a...
317
318
319
  			sg_set_page(sgl, page, l - off, off);
  			sgl = sg_next(sgl);
  			if (++n == nents || sgl == NULL)
2e956fb32   Stefani Seibold   kfifo: replace th...
320
321
322
323
324
  				return n;
  			page = npage;
  			len -= l - off;
  			l = off = 0;
  		}
64ce1037c   Andi Kleen   kfifo: sanitize *...
325
  	}
d78a3eda6   Stefani Seibold   kernel/kfifo.c: a...
326
  	sg_set_page(sgl, page, len, off);
2e956fb32   Stefani Seibold   kfifo: replace th...
327
  	return n + 1;
86d488031   Stefani Seibold   kfifo: add record...
328
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329

2e956fb32   Stefani Seibold   kfifo: replace th...
330
331
  static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
  		int nents, unsigned int len, unsigned int off)
86d488031   Stefani Seibold   kfifo: add record...
332
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
333
334
335
336
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
  	unsigned int l;
  	unsigned int n;
86d488031   Stefani Seibold   kfifo: add record...
337

2e956fb32   Stefani Seibold   kfifo: replace th...
338
339
340
341
342
343
344
  	off &= fifo->mask;
  	if (esize != 1) {
  		off *= esize;
  		size *= esize;
  		len *= esize;
  	}
  	l = min(len, size - off);
d78a3eda6   Stefani Seibold   kernel/kfifo.c: a...
345
  	n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
2e956fb32   Stefani Seibold   kfifo: replace th...
346
  	n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
2e956fb32   Stefani Seibold   kfifo: replace th...
347
  	return n;
86d488031   Stefani Seibold   kfifo: add record...
348
  }
86d488031   Stefani Seibold   kfifo: add record...
349

2e956fb32   Stefani Seibold   kfifo: replace th...
350
351
  unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
  		struct scatterlist *sgl, int nents, unsigned int len)
86d488031   Stefani Seibold   kfifo: add record...
352
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
353
  	unsigned int l;
86d488031   Stefani Seibold   kfifo: add record...
354

2e956fb32   Stefani Seibold   kfifo: replace th...
355
356
357
358
359
  	l = kfifo_unused(fifo);
  	if (len > l)
  		len = l;
  
  	return setup_sgl(fifo, sgl, nents, len, fifo->in);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
361
  EXPORT_SYMBOL(__kfifo_dma_in_prepare);
86d488031   Stefani Seibold   kfifo: add record...
362

2e956fb32   Stefani Seibold   kfifo: replace th...
363
364
  unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
  		struct scatterlist *sgl, int nents, unsigned int len)
86d488031   Stefani Seibold   kfifo: add record...
365
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
366
367
368
369
370
371
372
  	unsigned int l;
  
  	l = fifo->in - fifo->out;
  	if (len > l)
  		len = l;
  
  	return setup_sgl(fifo, sgl, nents, len, fifo->out);
86d488031   Stefani Seibold   kfifo: add record...
373
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
374
  EXPORT_SYMBOL(__kfifo_dma_out_prepare);
86d488031   Stefani Seibold   kfifo: add record...
375

2e956fb32   Stefani Seibold   kfifo: replace th...
376
  unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
377
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
378
  	unsigned int max = (1 << (recsize << 3)) - 1;
86d488031   Stefani Seibold   kfifo: add record...
379

2e956fb32   Stefani Seibold   kfifo: replace th...
380
381
382
  	if (len > max)
  		return max;
  	return len;
86d488031   Stefani Seibold   kfifo: add record...
383
  }
30059d93b   Srinivas Kandagatla   [media] kernel:kf...
384
  EXPORT_SYMBOL(__kfifo_max_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
385

2e956fb32   Stefani Seibold   kfifo: replace th...
386
387
388
389
390
  #define	__KFIFO_PEEK(data, out, mask) \
  	((data)[(out) & (mask)])
  /*
   * __kfifo_peek_n internal helper function for determinate the length of
   * the next record in the fifo
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
391
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
392
  static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize)
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
393
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
394
395
396
  	unsigned int l;
  	unsigned int mask = fifo->mask;
  	unsigned char *data = fifo->data;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
397

2e956fb32   Stefani Seibold   kfifo: replace th...
398
  	l = __KFIFO_PEEK(data, fifo->out, mask);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
399

2e956fb32   Stefani Seibold   kfifo: replace th...
400
401
402
403
  	if (--recsize)
  		l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8;
  
  	return l;
86d488031   Stefani Seibold   kfifo: add record...
404
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
405
406
407
408
409
410
411
  
  #define	__KFIFO_POKE(data, in, mask, val) \
  	( \
  	(data)[(in) & (mask)] = (unsigned char)(val) \
  	)
  
  /*
9dbbc3b9d   Zhen Lei   lib: fix spelling...
412
   * __kfifo_poke_n internal helper function for storing the length of
2e956fb32   Stefani Seibold   kfifo: replace th...
413
   * the record into the fifo
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
414
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
415
  static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize)
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
416
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
417
418
  	unsigned int mask = fifo->mask;
  	unsigned char *data = fifo->data;
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
419

2e956fb32   Stefani Seibold   kfifo: replace th...
420
421
422
423
  	__KFIFO_POKE(data, fifo->in, mask, n);
  
  	if (recsize > 1)
  		__KFIFO_POKE(data, fifo->in + 1, mask, n >> 8);
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
424
  }
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
425

2e956fb32   Stefani Seibold   kfifo: replace th...
426
  unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
427
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
428
  	return __kfifo_peek_n(fifo, recsize);
86d488031   Stefani Seibold   kfifo: add record...
429
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
430
  EXPORT_SYMBOL(__kfifo_len_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
431

2e956fb32   Stefani Seibold   kfifo: replace th...
432
433
  unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf,
  		unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
434
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
435
436
  	if (len + recsize > kfifo_unused(fifo))
  		return 0;
64ce1037c   Andi Kleen   kfifo: sanitize *...
437

2e956fb32   Stefani Seibold   kfifo: replace th...
438
  	__kfifo_poke_n(fifo, len, recsize);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
439

2e956fb32   Stefani Seibold   kfifo: replace th...
440
441
442
  	kfifo_copy_in(fifo, buf, len, fifo->in + recsize);
  	fifo->in += len + recsize;
  	return len;
86d488031   Stefani Seibold   kfifo: add record...
443
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
444
445
446
447
  EXPORT_SYMBOL(__kfifo_in_r);
  
  static unsigned int kfifo_out_copy_r(struct __kfifo *fifo,
  	void *buf, unsigned int len, size_t recsize, unsigned int *n)
86d488031   Stefani Seibold   kfifo: add record...
448
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  	*n = __kfifo_peek_n(fifo, recsize);
  
  	if (len > *n)
  		len = *n;
  
  	kfifo_copy_out(fifo, buf, len, fifo->out + recsize);
  	return len;
  }
  
  unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf,
  		unsigned int len, size_t recsize)
  {
  	unsigned int n;
  
  	if (fifo->in == fifo->out)
  		return 0;
  
  	return kfifo_out_copy_r(fifo, buf, len, recsize, &n);
86d488031   Stefani Seibold   kfifo: add record...
467
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
468
  EXPORT_SYMBOL(__kfifo_out_peek_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
469

2e956fb32   Stefani Seibold   kfifo: replace th...
470
471
  unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf,
  		unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
472
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
473
474
475
476
477
478
479
480
  	unsigned int n;
  
  	if (fifo->in == fifo->out)
  		return 0;
  
  	len = kfifo_out_copy_r(fifo, buf, len, recsize, &n);
  	fifo->out += n + recsize;
  	return len;
86d488031   Stefani Seibold   kfifo: add record...
481
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
482
  EXPORT_SYMBOL(__kfifo_out_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
483

b35de43b3   Andrea Righi   kfifo: implement ...
484
485
486
487
488
489
490
491
  void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize)
  {
  	unsigned int n;
  
  	n = __kfifo_peek_n(fifo, recsize);
  	fifo->out += n + recsize;
  }
  EXPORT_SYMBOL(__kfifo_skip_r);
2e956fb32   Stefani Seibold   kfifo: replace th...
492
493
  int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from,
  	unsigned long len, unsigned int *copied, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
494
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
495
  	unsigned long ret;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
496

2e956fb32   Stefani Seibold   kfifo: replace th...
497
  	len = __kfifo_max_r(len, recsize);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
498

2e956fb32   Stefani Seibold   kfifo: replace th...
499
500
501
502
  	if (len + recsize > kfifo_unused(fifo)) {
  		*copied = 0;
  		return 0;
  	}
86d488031   Stefani Seibold   kfifo: add record...
503

2e956fb32   Stefani Seibold   kfifo: replace th...
504
  	__kfifo_poke_n(fifo, len, recsize);
86d488031   Stefani Seibold   kfifo: add record...
505

2e956fb32   Stefani Seibold   kfifo: replace th...
506
507
508
509
510
511
512
  	ret = kfifo_copy_from_user(fifo, from, len, fifo->in + recsize, copied);
  	if (unlikely(ret)) {
  		*copied = 0;
  		return -EFAULT;
  	}
  	fifo->in += len + recsize;
  	return 0;
86d488031   Stefani Seibold   kfifo: add record...
513
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
514
515
516
517
  EXPORT_SYMBOL(__kfifo_from_user_r);
  
  int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
  	unsigned long len, unsigned int *copied, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
518
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  	unsigned long ret;
  	unsigned int n;
  
  	if (fifo->in == fifo->out) {
  		*copied = 0;
  		return 0;
  	}
  
  	n = __kfifo_peek_n(fifo, recsize);
  	if (len > n)
  		len = n;
  
  	ret = kfifo_copy_to_user(fifo, to, len, fifo->out + recsize, copied);
  	if (unlikely(ret)) {
  		*copied = 0;
  		return -EFAULT;
  	}
  	fifo->out += n + recsize;
  	return 0;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
538
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
539
  EXPORT_SYMBOL(__kfifo_to_user_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
540

2e956fb32   Stefani Seibold   kfifo: replace th...
541
542
  unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
  	struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
543
  {
89b3ac630   Himangi Saraogi   kfifo: use BUG_ON
544
  	BUG_ON(!nents);
2e956fb32   Stefani Seibold   kfifo: replace th...
545
546
547
548
549
550
551
  
  	len = __kfifo_max_r(len, recsize);
  
  	if (len + recsize > kfifo_unused(fifo))
  		return 0;
  
  	return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize);
86d488031   Stefani Seibold   kfifo: add record...
552
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
553
  EXPORT_SYMBOL(__kfifo_dma_in_prepare_r);
86d488031   Stefani Seibold   kfifo: add record...
554

2e956fb32   Stefani Seibold   kfifo: replace th...
555
556
  void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
  	unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
557
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
558
559
560
  	len = __kfifo_max_r(len, recsize);
  	__kfifo_poke_n(fifo, len, recsize);
  	fifo->in += len + recsize;
86d488031   Stefani Seibold   kfifo: add record...
561
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
562
  EXPORT_SYMBOL(__kfifo_dma_in_finish_r);
86d488031   Stefani Seibold   kfifo: add record...
563

2e956fb32   Stefani Seibold   kfifo: replace th...
564
565
  unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
  	struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
566
  {
89b3ac630   Himangi Saraogi   kfifo: use BUG_ON
567
  	BUG_ON(!nents);
2e956fb32   Stefani Seibold   kfifo: replace th...
568
569
570
571
572
573
574
  
  	len = __kfifo_max_r(len, recsize);
  
  	if (len + recsize > fifo->in - fifo->out)
  		return 0;
  
  	return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize);
86d488031   Stefani Seibold   kfifo: add record...
575
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
576
577
578
579
580
  EXPORT_SYMBOL(__kfifo_dma_out_prepare_r);
  
  void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize)
  {
  	unsigned int len;
86d488031   Stefani Seibold   kfifo: add record...
581

2e956fb32   Stefani Seibold   kfifo: replace th...
582
583
584
585
  	len = __kfifo_peek_n(fifo, recsize);
  	fifo->out += len + recsize;
  }
  EXPORT_SYMBOL(__kfifo_dma_out_finish_r);