Blame view

lib/kfifo.c 12.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
2e956fb32   Stefani Seibold   kfifo: replace th...
2
   * A generic kernel FIFO implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
2e956fb32   Stefani Seibold   kfifo: replace th...
4
   * Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
12
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
d78a3eda6   Stefani Seibold   kernel/kfifo.c: a...
13
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   */
  
  #include <linux/kernel.h>
9984de1a5   Paul Gortmaker   kernel: Map most ...
23
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  #include <linux/slab.h>
  #include <linux/err.h>
f84d5a76c   vignesh babu   is_power_of_2: ke...
26
  #include <linux/log2.h>
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
27
  #include <linux/uaccess.h>
2e956fb32   Stefani Seibold   kfifo: replace th...
28
  #include <linux/kfifo.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

2e956fb32   Stefani Seibold   kfifo: replace th...
30
31
  /*
   * internal helper to calculate the unused elements in a fifo
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
33
  static inline unsigned int kfifo_unused(struct __kfifo *fifo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
35
  	return (fifo->mask + 1) - (fifo->in - fifo->out);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

2e956fb32   Stefani Seibold   kfifo: replace th...
38
39
  int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
  		size_t esize, gfp_t gfp_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
42
  	 * round down to the next power of 2, since our 'let the indices
b33112d1c   Robert P. J. Day   kernel/kfifo.c: r...
43
  	 * wrap' technique works only in this case.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  	 */
dfe2a77fd   Stefani Seibold   kfifo: fix kfifo_...
45
  	size = roundup_pow_of_two(size);
2e956fb32   Stefani Seibold   kfifo: replace th...
46
47
48
49
50
51
52
53
54
  
  	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
55
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
56
57
58
59
  	fifo->data = kmalloc(size * esize, gfp_mask);
  
  	if (!fifo->data) {
  		fifo->mask = 0;
454654878   Stefani Seibold   kfifo: move struc...
60
61
  		return -ENOMEM;
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
62
  	fifo->mask = size - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

454654878   Stefani Seibold   kfifo: move struc...
64
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
66
  EXPORT_SYMBOL(__kfifo_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

2e956fb32   Stefani Seibold   kfifo: replace th...
68
  void __kfifo_free(struct __kfifo *fifo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
70
71
72
73
74
75
  	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
76
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
77
  EXPORT_SYMBOL(__kfifo_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

2e956fb32   Stefani Seibold   kfifo: replace th...
79
80
  int __kfifo_init(struct __kfifo *fifo, void *buffer,
  		unsigned int size, size_t esize)
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
81
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
82
  	size /= esize;
dfe2a77fd   Stefani Seibold   kfifo: fix kfifo_...
83
  	size = roundup_pow_of_two(size);
2e956fb32   Stefani Seibold   kfifo: replace th...
84
85
86
87
88
89
90
91
92
  
  	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_...
93
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
94
95
96
  	fifo->mask = size - 1;
  
  	return 0;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
97
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
98
  EXPORT_SYMBOL(__kfifo_init);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
99

2e956fb32   Stefani Seibold   kfifo: replace th...
100
101
  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
102
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
103
104
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
106
107
108
109
110
111
112
113
114
115
  	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...
116
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
117
118
  	 * 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...
119
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
120
121
  	smp_wmb();
  }
a45bce495   Paul E. McKenney   [PATCH] memory or...
122

2e956fb32   Stefani Seibold   kfifo: replace th...
123
124
125
126
  unsigned int __kfifo_in(struct __kfifo *fifo,
  		const void *buf, unsigned int len)
  {
  	unsigned int l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
127

2e956fb32   Stefani Seibold   kfifo: replace th...
128
129
130
  	l = kfifo_unused(fifo);
  	if (len > l)
  		len = l;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131

2e956fb32   Stefani Seibold   kfifo: replace th...
132
133
134
  	kfifo_copy_in(fifo, buf, len, fifo->in);
  	fifo->in += len;
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
136
  EXPORT_SYMBOL(__kfifo_in);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137

2e956fb32   Stefani Seibold   kfifo: replace th...
138
139
  static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
  		unsigned int len, unsigned int off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
141
142
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
144
145
146
147
148
149
150
151
152
153
  	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...
154
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
155
156
  	 * make sure that the data is copied before
  	 * incrementing the fifo->out index counter
a45bce495   Paul E. McKenney   [PATCH] memory or...
157
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
158
159
  	smp_wmb();
  }
a45bce495   Paul E. McKenney   [PATCH] memory or...
160

2e956fb32   Stefani Seibold   kfifo: replace th...
161
162
163
164
  unsigned int __kfifo_out_peek(struct __kfifo *fifo,
  		void *buf, unsigned int len)
  {
  	unsigned int l;
a45bce495   Paul E. McKenney   [PATCH] memory or...
165

2e956fb32   Stefani Seibold   kfifo: replace th...
166
167
168
  	l = fifo->in - fifo->out;
  	if (len > l)
  		len = l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
169

2e956fb32   Stefani Seibold   kfifo: replace th...
170
171
172
173
  	kfifo_copy_out(fifo, buf, len, fifo->out);
  	return len;
  }
  EXPORT_SYMBOL(__kfifo_out_peek);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174

2e956fb32   Stefani Seibold   kfifo: replace th...
175
176
177
178
179
180
  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_...
181
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
182
  EXPORT_SYMBOL(__kfifo_out);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
183

2e956fb32   Stefani Seibold   kfifo: replace th...
184
185
186
  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_...
187
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
188
189
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
190
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
191
  	unsigned long ret;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
192

2e956fb32   Stefani Seibold   kfifo: replace th...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  	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...
209
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
210
211
  	 * 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...
212
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
213
  	smp_wmb();
a019e48cf   Lars-Peter Clausen   kfifo: kfifo_copy...
214
  	*copied = len - ret * esize;
2e956fb32   Stefani Seibold   kfifo: replace th...
215
216
217
  	/* return the number of elements which are not copied */
  	return ret;
  }
a45bce495   Paul E. McKenney   [PATCH] memory or...
218

2e956fb32   Stefani Seibold   kfifo: replace th...
219
220
221
222
223
224
225
  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...
226

2e956fb32   Stefani Seibold   kfifo: replace th...
227
228
  	if (esize != 1)
  		len /= esize;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
229

2e956fb32   Stefani Seibold   kfifo: replace th...
230
231
232
  	l = kfifo_unused(fifo);
  	if (len > l)
  		len = l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
233

2e956fb32   Stefani Seibold   kfifo: replace th...
234
235
236
237
238
239
240
241
  	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...
242
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
243
  EXPORT_SYMBOL(__kfifo_from_user);
86d488031   Stefani Seibold   kfifo: add record...
244

2e956fb32   Stefani Seibold   kfifo: replace th...
245
246
  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...
247
248
  {
  	unsigned int l;
2e956fb32   Stefani Seibold   kfifo: replace th...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  	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...
269
  	/*
2e956fb32   Stefani Seibold   kfifo: replace th...
270
271
  	 * make sure that the data is copied before
  	 * incrementing the fifo->out index counter
86d488031   Stefani Seibold   kfifo: add record...
272
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
273
  	smp_wmb();
a019e48cf   Lars-Peter Clausen   kfifo: kfifo_copy...
274
  	*copied = len - ret * esize;
2e956fb32   Stefani Seibold   kfifo: replace th...
275
276
277
  	/* return the number of elements which are not copied */
  	return ret;
  }
86d488031   Stefani Seibold   kfifo: add record...
278

2e956fb32   Stefani Seibold   kfifo: replace th...
279
280
281
282
283
284
285
  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...
286

2e956fb32   Stefani Seibold   kfifo: replace th...
287
288
  	if (esize != 1)
  		len /= esize;
86d488031   Stefani Seibold   kfifo: add record...
289

2e956fb32   Stefani Seibold   kfifo: replace th...
290
291
292
293
  	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 *...
294
  	if (unlikely(ret)) {
2e956fb32   Stefani Seibold   kfifo: replace th...
295
296
297
298
299
300
301
302
  		len -= ret;
  		err = -EFAULT;
  	} else
  		err = 0;
  	fifo->out += len;
  	return err;
  }
  EXPORT_SYMBOL(__kfifo_to_user);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
303

2e956fb32   Stefani Seibold   kfifo: replace th...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  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...
330
331
332
  			sg_set_page(sgl, page, l - off, off);
  			sgl = sg_next(sgl);
  			if (++n == nents || sgl == NULL)
2e956fb32   Stefani Seibold   kfifo: replace th...
333
334
335
336
337
  				return n;
  			page = npage;
  			len -= l - off;
  			l = off = 0;
  		}
64ce1037c   Andi Kleen   kfifo: sanitize *...
338
  	}
d78a3eda6   Stefani Seibold   kernel/kfifo.c: a...
339
  	sg_set_page(sgl, page, len, off);
2e956fb32   Stefani Seibold   kfifo: replace th...
340
  	return n + 1;
86d488031   Stefani Seibold   kfifo: add record...
341
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342

2e956fb32   Stefani Seibold   kfifo: replace th...
343
344
  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...
345
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
346
347
348
349
  	unsigned int size = fifo->mask + 1;
  	unsigned int esize = fifo->esize;
  	unsigned int l;
  	unsigned int n;
86d488031   Stefani Seibold   kfifo: add record...
350

2e956fb32   Stefani Seibold   kfifo: replace th...
351
352
353
354
355
356
357
  	off &= fifo->mask;
  	if (esize != 1) {
  		off *= esize;
  		size *= esize;
  		len *= esize;
  	}
  	l = min(len, size - off);
d78a3eda6   Stefani Seibold   kernel/kfifo.c: a...
358
  	n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
2e956fb32   Stefani Seibold   kfifo: replace th...
359
  	n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
2e956fb32   Stefani Seibold   kfifo: replace th...
360
  	return n;
86d488031   Stefani Seibold   kfifo: add record...
361
  }
86d488031   Stefani Seibold   kfifo: add record...
362

2e956fb32   Stefani Seibold   kfifo: replace th...
363
364
  unsigned int __kfifo_dma_in_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
  	unsigned int l;
86d488031   Stefani Seibold   kfifo: add record...
367

2e956fb32   Stefani Seibold   kfifo: replace th...
368
369
370
371
372
  	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
373
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
374
  EXPORT_SYMBOL(__kfifo_dma_in_prepare);
86d488031   Stefani Seibold   kfifo: add record...
375

2e956fb32   Stefani Seibold   kfifo: replace th...
376
377
  unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
  		struct scatterlist *sgl, int nents, unsigned int len)
86d488031   Stefani Seibold   kfifo: add record...
378
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
379
380
381
382
383
384
385
  	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...
386
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
387
  EXPORT_SYMBOL(__kfifo_dma_out_prepare);
86d488031   Stefani Seibold   kfifo: add record...
388

2e956fb32   Stefani Seibold   kfifo: replace th...
389
  unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
390
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
391
  	unsigned int max = (1 << (recsize << 3)) - 1;
86d488031   Stefani Seibold   kfifo: add record...
392

2e956fb32   Stefani Seibold   kfifo: replace th...
393
394
395
  	if (len > max)
  		return max;
  	return len;
86d488031   Stefani Seibold   kfifo: add record...
396
  }
30059d93b   Srinivas Kandagatla   [media] kernel:kf...
397
  EXPORT_SYMBOL(__kfifo_max_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
398

2e956fb32   Stefani Seibold   kfifo: replace th...
399
400
401
402
403
  #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_...
404
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
405
  static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize)
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
406
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
407
408
409
  	unsigned int l;
  	unsigned int mask = fifo->mask;
  	unsigned char *data = fifo->data;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
410

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

2e956fb32   Stefani Seibold   kfifo: replace th...
413
414
415
416
  	if (--recsize)
  		l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8;
  
  	return l;
86d488031   Stefani Seibold   kfifo: add record...
417
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
418
419
420
421
422
423
424
425
426
  
  #define	__KFIFO_POKE(data, in, mask, val) \
  	( \
  	(data)[(in) & (mask)] = (unsigned char)(val) \
  	)
  
  /*
   * __kfifo_poke_n internal helper function for storeing the length of
   * the record into the fifo
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
427
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
428
  static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize)
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
429
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
430
431
  	unsigned int mask = fifo->mask;
  	unsigned char *data = fifo->data;
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
432

2e956fb32   Stefani Seibold   kfifo: replace th...
433
434
435
436
  	__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_...
437
  }
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
438

2e956fb32   Stefani Seibold   kfifo: replace th...
439
  unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
440
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
441
  	return __kfifo_peek_n(fifo, recsize);
86d488031   Stefani Seibold   kfifo: add record...
442
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
443
  EXPORT_SYMBOL(__kfifo_len_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
444

2e956fb32   Stefani Seibold   kfifo: replace th...
445
446
  unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf,
  		unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
447
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
448
449
  	if (len + recsize > kfifo_unused(fifo))
  		return 0;
64ce1037c   Andi Kleen   kfifo: sanitize *...
450

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

2e956fb32   Stefani Seibold   kfifo: replace th...
453
454
455
  	kfifo_copy_in(fifo, buf, len, fifo->in + recsize);
  	fifo->in += len + recsize;
  	return len;
86d488031   Stefani Seibold   kfifo: add record...
456
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
457
458
459
460
  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...
461
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  	*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...
480
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
481
  EXPORT_SYMBOL(__kfifo_out_peek_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
482

2e956fb32   Stefani Seibold   kfifo: replace th...
483
484
  unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf,
  		unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
485
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
486
487
488
489
490
491
492
493
  	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...
494
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
495
  EXPORT_SYMBOL(__kfifo_out_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
496

b35de43b3   Andrea Righi   kfifo: implement ...
497
498
499
500
501
502
503
504
  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...
505
506
  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...
507
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
508
  	unsigned long ret;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
509

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

2e956fb32   Stefani Seibold   kfifo: replace th...
512
513
514
515
  	if (len + recsize > kfifo_unused(fifo)) {
  		*copied = 0;
  		return 0;
  	}
86d488031   Stefani Seibold   kfifo: add record...
516

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

2e956fb32   Stefani Seibold   kfifo: replace th...
519
520
521
522
523
524
525
  	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...
526
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
527
528
529
530
  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...
531
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  	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_...
551
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
552
  EXPORT_SYMBOL(__kfifo_to_user_r);
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
553

2e956fb32   Stefani Seibold   kfifo: replace th...
554
555
  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...
556
  {
89b3ac630   Himangi Saraogi   kfifo: use BUG_ON
557
  	BUG_ON(!nents);
2e956fb32   Stefani Seibold   kfifo: replace th...
558
559
560
561
562
563
564
  
  	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...
565
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
566
  EXPORT_SYMBOL(__kfifo_dma_in_prepare_r);
86d488031   Stefani Seibold   kfifo: add record...
567

2e956fb32   Stefani Seibold   kfifo: replace th...
568
569
  void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
  	unsigned int len, size_t recsize)
86d488031   Stefani Seibold   kfifo: add record...
570
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
571
572
573
  	len = __kfifo_max_r(len, recsize);
  	__kfifo_poke_n(fifo, len, recsize);
  	fifo->in += len + recsize;
86d488031   Stefani Seibold   kfifo: add record...
574
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
575
  EXPORT_SYMBOL(__kfifo_dma_in_finish_r);
86d488031   Stefani Seibold   kfifo: add record...
576

2e956fb32   Stefani Seibold   kfifo: replace th...
577
578
  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...
579
  {
89b3ac630   Himangi Saraogi   kfifo: use BUG_ON
580
  	BUG_ON(!nents);
2e956fb32   Stefani Seibold   kfifo: replace th...
581
582
583
584
585
586
587
  
  	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...
588
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
589
590
591
592
593
  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...
594

2e956fb32   Stefani Seibold   kfifo: replace th...
595
596
597
598
  	len = __kfifo_peek_n(fifo, recsize);
  	fifo->out += len + recsize;
  }
  EXPORT_SYMBOL(__kfifo_dma_out_finish_r);