Blame view

kernel/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
  	 */
2e956fb32   Stefani Seibold   kfifo: replace th...
45
46
47
48
49
50
51
52
53
54
55
  	if (!is_power_of_2(size))
  		size = rounddown_pow_of_two(size);
  
  	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
56
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
57
58
59
60
  	fifo->data = kmalloc(size * esize, gfp_mask);
  
  	if (!fifo->data) {
  		fifo->mask = 0;
454654878   Stefani Seibold   kfifo: move struc...
61
62
  		return -ENOMEM;
  	}
2e956fb32   Stefani Seibold   kfifo: replace th...
63
  	fifo->mask = size - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2e956fb32   Stefani Seibold   kfifo: replace th...
222
223
224
225
226
227
228
  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...
229

2e956fb32   Stefani Seibold   kfifo: replace th...
230
231
  	if (esize != 1)
  		len /= esize;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
232

2e956fb32   Stefani Seibold   kfifo: replace th...
233
234
235
  	l = kfifo_unused(fifo);
  	if (len > l)
  		len = l;
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
236

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

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

2e956fb32   Stefani Seibold   kfifo: replace th...
282
283
284
285
286
287
288
  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...
289

2e956fb32   Stefani Seibold   kfifo: replace th...
290
291
  	if (esize != 1)
  		len /= esize;
86d488031   Stefani Seibold   kfifo: add record...
292

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

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

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

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

2e956fb32   Stefani Seibold   kfifo: replace th...
366
367
  unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
  		struct scatterlist *sgl, int nents, unsigned int len)
86d488031   Stefani Seibold   kfifo: add record...
368
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
369
  	unsigned int l;
86d488031   Stefani Seibold   kfifo: add record...
370

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

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

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

2e956fb32   Stefani Seibold   kfifo: replace th...
396
397
398
  	if (len > max)
  		return max;
  	return len;
86d488031   Stefani Seibold   kfifo: add record...
399
  }
a121f24ac   Stefani Seibold   kfifo: add kfifo_...
400

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

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

2e956fb32   Stefani Seibold   kfifo: replace th...
415
416
417
418
  	if (--recsize)
  		l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8;
  
  	return l;
86d488031   Stefani Seibold   kfifo: add record...
419
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
420
421
422
423
424
425
426
427
428
  
  #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_...
429
   */
2e956fb32   Stefani Seibold   kfifo: replace th...
430
  static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize)
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
431
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
432
433
  	unsigned int mask = fifo->mask;
  	unsigned char *data = fifo->data;
a5b9e2c10   Andi Kleen   kfifo: add kfifo_...
434

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

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

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

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

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

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

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

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

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

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

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

2e956fb32   Stefani Seibold   kfifo: replace th...
556
557
  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...
558
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
559
560
561
562
563
564
565
566
567
  	if (!nents)
  		BUG();
  
  	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...
568
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
569
  EXPORT_SYMBOL(__kfifo_dma_in_prepare_r);
86d488031   Stefani Seibold   kfifo: add record...
570

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

2e956fb32   Stefani Seibold   kfifo: replace th...
580
581
  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...
582
  {
2e956fb32   Stefani Seibold   kfifo: replace th...
583
584
585
586
587
588
589
590
591
  	if (!nents)
  		BUG();
  
  	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...
592
  }
2e956fb32   Stefani Seibold   kfifo: replace th...
593
594
595
596
597
  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...
598

2e956fb32   Stefani Seibold   kfifo: replace th...
599
600
601
602
  	len = __kfifo_peek_n(fifo, recsize);
  	fifo->out += len + recsize;
  }
  EXPORT_SYMBOL(__kfifo_dma_out_finish_r);