[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20100115192029.GC10591@ovro.caltech.edu>
Date: Fri, 15 Jan 2010 11:20:29 -0800
From: "Ira W. Snyder" <iws@...o.caltech.edu>
To: Stefani Seibold <stefani@...bold.net>
Cc: linux-kernel <linux-kernel@...r.kernel.org>,
Andrew Morton <akpm@...ux-foundation.org>,
Andi Kleen <andi@...stfloor.org>,
Greg Kroah-Hartman <gregkh@...e.de>,
Alan Cox <alan@...rguk.ukuu.org.uk>,
Theodore Tso <tytso@....edu>
Subject: Re: [PATCH] enhanced reimplemented of the kfifo API
On Fri, Jan 15, 2010 at 10:06:58AM +0100, Stefani Seibold wrote:
> This is a complete reimplementation of the new kfifo API, which is now
> really generic, type save and type definable.
>
> The API is still stable, no code which use the current kfifo API must
> be modified!
>
> ChangeLog:
>
> 15.01.2010 fix kfifo_dma_*() bugs
> add a DMA usage exmaple
> fix kfifo_free()
> prevent creation of fifo with less then 2 entries
> prevent a real in place fifo manipulation with kfifo_alloc(),
> kfifo_init() or kfifo_free()
> make INIT_KFIFO save with a dynamic allocated fifo
> 14.01.2010 Change the size field of the fifo structure into a mask field, which
> is size - 1. This will save some instructions
> Make the basic structure mode generic. Add a data pointer and mask
> field, also for real in place fifo, because the extra function parameter
> passing of the data pointer and and the fifo size was to costly
> Change all internal functions to work with the generic base structure
> Optimized the kfifo_put and kfifo_get macros to prevent an indirection
> Code cleanup
> Bug fixes in kfifo_dma_* macros
> Update examples
> Sync with kernel 2.6.33-rc4
> 06.01.2010 Add a note about locking: clarify when locking is needed
> Fix byte stream example
> Remove unnecessary typedefs
> Make checkpatch.pl clean: one error left, but there is no way to
> solve this...
> 28.12.2009 Sanitize kfifo_*_user() error handling (suggested by Andi Kleen)
> kfifo_from_user() and kfifo_to_user() will now return an error
> code and the number of copied bytes will be stored in a variable
> passed as pointer
> Make patch readable
> Update examples
> Fix a typo
> 27.12.2009 Sync with kernel 2.6.33-rc2
> Introduce new kfifo_initialized macro (suggested by Andi Kleen)
> Renamed kfifo_peek into kfifo_peek_len
> Introduce new kfifo_peek macro (suggest by Andi Kleen)
> Introduce new kfifo_out_peek macro (suggested by Andi Kleen)
> Fix broken kernel-doc notation
> Fix samples
> 21.12.2009 Fix checkpatch.pl, fix samples
> 20.12.2009 Bug fixing
> Fix samples
> 19.12.2009 First draft
> 13.12.2009 First implementation of a type safe fifo implementation, called kqueue
>
> There are different types of a fifo which can not handled in C without a
> lot of overhead. So i decided to write the API as a set of macros, which
> is the only way to do a kind of template meta programming without C++.
> This macros handles the different types of fifos in a transparent way.
>
> There are a lot of benefits:
>
> - Compile time handling of the different fifo types
> - Better performance (a save put or get of an integer does only generate
> 9 assembly instructions on a x86)
> - Type save
> - Cleaner interface, the additional kfifo_..._rec() functions are gone
> - Easier to use
> - Less error prone
> - Different types of fifos: it is now possible to define a int fifo or
> any other type. See below for an example.
> - Smaller footprint for none byte type fifos
> - The size of the record field will be now detected at compile time
> - No need of creating a second hidden variable, like in the old DEFINE_KFIFO
>
> The API was not changed.
>
> There are now real in place fifos where the data space is a part of the
> structure. There is no need for an extra indirection to access the data.
>
> The dynamic assigned or allocated fifos still needs 16 byte plus the
> fifo space and does also create more code.
>
> Most of the macros code will be optimized away and simple generate a
> function call. Only the really small ones generates inline code.
>
> Additional you can now create fifos for any data type, not only the
> "unsigned char" byte streamed fifos.
>
> There is also a new kfifo_put and kfifo_get function, to handle a single
> element in a fifo.
>
>
> Here are the examples how to use it:
>
> Example 1: an integer fifo
>
> #include "kfifo.h"
>
> #define FIFO_SIZE 32
>
> #define DYNAMIC
> #ifdef DYNAMIC
> static DECLARE_KFIFO_PTR(test, int);
> #else
> static DECLARE_KFIFO(test, int, FIFO_SIZE);
> #endif
>
> int testfunc(void)
> {
> int i;
> int buf[6];
> unsigned int ret;
> unsigned int copied;
>
> #ifdef DYNAMIC
> if (kfifo_alloc(&test, FIFO_SIZE, 0)) {
> printk("error kfifo_alloc\n");
> return 1;
> }
> #else
> INIT_KFIFO(test);
> #endif
>
> printk("int fifo test start\n");
>
> if (kfifo_initialized(&test))
> printk("fifo is initalized\n");
>
> for(i = 0; i != 10; i++)
> kfifo_put(&test, &i);
>
> printk("queue peek: %u\n", kfifo_peek_len(&test));
>
> ret = kfifo_to_user(&test, buf, kfifo_sizeof(&test) * 2, &copied);
> printk("ret: %d %u\n", ret, copied);
> ret = kfifo_from_user(&test, buf, copied, &copied);
> printk("ret: %d %u\n", ret, copied);
> ret = kfifo_out(&test, buf, 1);
> printk("ret: %d\n", ret);
> ret = kfifo_in(&test, buf, 1);
> printk("ret: %d\n", ret);
>
> for(i = 20; i != 30; i++)
> kfifo_put(&test, &i);
>
> printk("queue len: %u\n", kfifo_len(&test));
>
> if (kfifo_peek(&test, &i))
> printk("%d\n", i);
>
> while(kfifo_get(&test, &i))
> printk("%d ", i);
> printk("\n");
>
> return 0;
> }
>
> Example 2: a dynamic record size fifo
>
> #include "kfifo.h"
>
> #define FIFO_SIZE 128
>
> #define DYNAMIC
> #ifdef DYNAMIC
> struct kfifo_rec_ptr_1 test[1];
>
> #else
> typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) mytest;
>
> static mytest test[1];
> #endif
>
> int testfunc(void)
> {
> const struct { unsigned char buf[6]; } hello = { "hello" };
> unsigned int i;
> char buf[100];
> unsigned int ret;
> unsigned int copied;
>
> printk("record fifo test start\n");
>
> #ifdef DYNAMIC
> if (kfifo_alloc(test, FIFO_SIZE, 0)) {
> printk("error kfifo_alloc\n");
> return 1;
> }
> #else
> INIT_KFIFO(test[0]);
> #endif
> printk("queue size: %u\n", kfifo_size(test));
>
> kfifo_put(test, &hello);
>
> printk("queue peek: %u\n", kfifo_peek_len(test));
>
> for(i = 0; i < 10; i++) {
> memset(buf,'a' + i, i + 1);
> kfifo_in(test, buf, i + 1);
> }
>
> ret = kfifo_to_user(test, buf, sizeof(buf), &copied);
> printk("ret: %d %u\n", ret, copied);
> ret = kfifo_from_user(test, buf, copied, &copied);
> printk("ret: %d %u\n", ret, copied);
>
> printk("queue len: %u\n", kfifo_len(test));
>
> ret = kfifo_peek(test, buf);
> if (ret)
> printk("%.*s\n", ret, buf);
>
> while(!kfifo_is_empty(test)) {
> ret = kfifo_out(test, buf, sizeof(buf));
> printk("%.*s\n", ret, buf);
> }
>
> return 0;
> }
>
> Example 3: a bytes stream fifo
>
> #include "kfifo.h"
>
> #define FIFO_SIZE 32
>
> //#define DYNAMIC
> #ifdef DYNAMIC
> static struct kfifo test[1];
> #else
> static DECLARE_KFIFO(test[1], unsigned char, FIFO_SIZE);
> #endif
>
> int testfunc(void)
> {
> unsigned char buf[6];
> unsigned char i;
> unsigned int ret;
> unsigned int copied;
>
> printk("byte stream fifo test start\n");
>
> #ifdef DYNAMIC
> if (kfifo_alloc(test, FIFO_SIZE, 0)) {
> printk("error kfifo_alloc\n");
> return 1;
> }
> #else
> INIT_KFIFO(test[0]);
> #endif
>
> printk("queue size: %u\n", kfifo_size(test));
>
> kfifo_in(test, "hello", 5);
>
> for(i = 0; i != 9; i++)
> kfifo_put(test, &i);
>
> printk("queue peek: %u\n", kfifo_peek_len(test));
>
> i = kfifo_out(test, buf, 5);
> printk("buf: %.*s\n", i, buf);
>
> ret = kfifo_to_user(test, buf, sizeof(int), &copied);
> printk("ret: %d %u\n", ret, copied);
> ret = kfifo_from_user(test, buf, copied, &copied);
> printk("ret: %d %u\n", ret, copied);
>
> ret = kfifo_out(test, buf, 2);
> printk("ret: %d\n", ret);
> ret = kfifo_in(test, buf, ret);
> printk("ret: %d\n", ret);
>
> printk("queue len: %u\n", kfifo_len(test));
>
> for(i = 20; kfifo_put(test, &i); i++)
> ;
>
> while(kfifo_get(test, &i))
> printk("%d ", i);
> printk("\n");
>
> return 0;
> }
>
> Example 4: DMA usage
>
> #include "kfifo.h"
>
> #define FIFO_SIZE 32
>
> static struct kfifo fifo;
>
> int testfunc(void)
> {
> int i;
> unsigned int ret;
> /* kfifo_dma_* will never return more than two sgl entries */
> struct scatterlist sg[2];
>
I'm glad to see this example, it really illustrates how to use the new
DMA functionality of the kfifo API.
Is there any reason why a very large scatterlist could not be used? I
have a driver that uses a large scatterlist (~4000 entries, allocated as
a struct sg_table). I implemented my own copy_from_user() functionality
into this scatterlist, but I'd love to use the kfifo DMA API instead.
After filling the scatterlist, I use the usual DMA API's to transfer it
to my device.
Ira
> printk("DMA fifo test start\n");
>
> if (kfifo_alloc(&fifo, FIFO_SIZE, 0)) {
> printk("error kfifo_alloc\n");
> return 1;
> }
>
> printk("queue size: %u\n", kfifo_size(&fifo));
>
> kfifo_in(&fifo, "test", 4);
>
> for(i = 0; i != 9; i++)
> kfifo_put(&fifo, &i);
>
> /* kick away first byte */
> kfifo_get(&fifo, &i);
>
> printk("queue peek: %u\n", kfifo_peek_len(&fifo));
>
> ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE);
> printk("DMA in byte count: %d\n", ret);
>
> /* if 0 was returned, fifo is full and no sgl was created */
> if (ret) {
> printk("scatterlist for receive:\n");
> for (i = 0; i < ARRAY_SIZE(sg); i++) {
> printk("sg[%d] -> page_link 0x%.8lx offset 0x%.8x len 0x%.8x\n",
> i, sg[i].page_link, sg[i].offset, sg[i].length);
>
> if (sg_is_last(&sg[i]))
> break;
> }
>
> /* but here your code to setup and exectute the dma operation */
> /* ... */
>
> /* example: zero bytes received */
> ret = 0;
>
> /* finish the dma operation and update the received data */
> kfifo_dma_in_finish(&fifo, ret);
> }
>
> ret = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8);
> printk("DMA out byte count: %d\n", ret);
>
> /* if 0 was returned, no data was available and no sgl was created */
> if (ret) {
> printk("scatterlist:\n");
> for (i = 0; i < ARRAY_SIZE(sg); i++) {
> printk("sg[%d] -> page_link 0x%.8lx offset 0x%.8x len 0x%.8x\n",
> i, sg[i].page_link, sg[i].offset, sg[i].length);
>
> if (sg_is_last(&sg[i]))
> break;
> }
>
> /* but here your code to setup and exectute the dma operation */
> /* ... */
>
> /* example: 5 bytes transmitted */
> ret = 5;
>
> /* finish the dma operation and update the transmitted data */
> kfifo_dma_out_finish(&fifo, ret);
> }
>
> printk("queue peek: %u\n", kfifo_peek_len(&fifo));
>
> return 0;
> }
>
>
> I know that this kind of macros are very sophisticated and not easy to
> maintain. But i have all tested and it works as expected. I analyzed the
> output of the compiler and for the x86 the code is as good as hand
> written assembler code. For the byte stream fifo the generate code is exact
> the same as with the current kfifo implementation. For all other types of
> fifos the code is smaller before, because the interface is easier to use.
>
> The main goal was to provide an API which is very intuitive, save and easy
> to use. So linux will get now a powerful fifo API which provides all what
> a developer needs. This will save in the future a lot of kernel space, since
> there is no need to write an own implementation. Most of the device driver
> developers need a fifo, and also deep kernel development will gain benefit
> from this API.
>
> You can download the test code at www.seibold.net/kfifo.tgz
>
> The patch-set is against linux 2.6.33-rc4. This code is ready to merge into
> the mm tree or linux next. Please review it and merge.
>
> Stefani
>
> Signed-off-by: Stefani Seibold <stefani@...bold.net>
> ---
> linux-2.6.33-rc4.dummy/include/linux/kfifo.h | 610 ------------------
> linux-2.6.33-rc4.dummy/kernel/kfifo.c | 400 -----------
> linux-2.6.33-rc4.new/include/linux/kfifo.h | 901 +++++++++++++++++++++++++++
> linux-2.6.33-rc4.new/kernel/kfifo.c | 781 +++++++++++++++++++++++
> 4 files changed, 1682 insertions(+), 1010 deletions(-)
>
> diff -u -N -r -p linux-2.6.33-rc4.orig/include/linux/kfifo.h linux-2.6.33-rc4.dummy/include/linux/kfifo.h
> --- linux-2.6.33-rc4.orig/include/linux/kfifo.h 2010-01-14 17:08:28.275654594 +0100
> +++ linux-2.6.33-rc4.dummy/include/linux/kfifo.h 1970-01-01 01:00:00.000000000 +0100
> @@ -1,610 +0,0 @@
> -/*
> - * A generic kernel FIFO implementation.
> - *
> - * Copyright (C) 2009 Stefani Seibold <stefani@...bold.net>
> - * Copyright (C) 2004 Stelian Pop <stelian@...ies.net>
> - *
> - * 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
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * 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.
> - *
> - */
> -
> -/*
> - * Howto porting drivers to the new generic fifo API:
> - *
> - * - Modify the declaration of the "struct kfifo *" object into a
> - * in-place "struct kfifo" object
> - * - Init the in-place object with kfifo_alloc() or kfifo_init()
> - * Note: The address of the in-place "struct kfifo" object must be
> - * passed as the first argument to this functions
> - * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get
> - * into kfifo_out
> - * - Replace the use of kfifo_put into kfifo_in_locked and kfifo_get
> - * into kfifo_out_locked
> - * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc
> - * must be passed now to the kfifo_in_locked and kfifo_out_locked
> - * as the last parameter.
> - * - All formerly name __kfifo_* functions has been renamed into kfifo_*
> - */
> -
> -#ifndef _LINUX_KFIFO_H
> -#define _LINUX_KFIFO_H
> -
> -#include <linux/kernel.h>
> -#include <linux/spinlock.h>
> -
> -struct kfifo {
> - unsigned char *buffer; /* the buffer holding the data */
> - unsigned int size; /* the size of the allocated buffer */
> - unsigned int in; /* data is added at offset (in % size) */
> - unsigned int out; /* data is extracted from off. (out % size) */
> -};
> -
> -/*
> - * Macros for declaration and initialization of the kfifo datatype
> - */
> -
> -/* helper macro */
> -#define __kfifo_initializer(s, b) \
> - (struct kfifo) { \
> - .size = s, \
> - .in = 0, \
> - .out = 0, \
> - .buffer = b \
> - }
> -
> -/**
> - * DECLARE_KFIFO - macro to declare a kfifo and the associated buffer
> - * @name: name of the declared kfifo datatype
> - * @size: size of the fifo buffer
> - *
> - * Note1: the macro can be used inside struct or union declaration
> - * Note2: the macro creates two objects:
> - * A kfifo object with the given name and a buffer for the kfifo
> - * object named name##kfifo_buffer
> - */
> -#define DECLARE_KFIFO(name, size) \
> -union { \
> - struct kfifo name; \
> - unsigned char name##kfifo_buffer[size + sizeof(struct kfifo)]; \
> -}
> -
> -/**
> - * INIT_KFIFO - Initialize a kfifo declared by DECLARE_KFIFO
> - * @name: name of the declared kfifo datatype
> - */
> -#define INIT_KFIFO(name) \
> - name = __kfifo_initializer(sizeof(name##kfifo_buffer) - \
> - sizeof(struct kfifo), name##kfifo_buffer)
> -
> -/**
> - * DEFINE_KFIFO - macro to define and initialize a kfifo
> - * @name: name of the declared kfifo datatype
> - * @size: size of the fifo buffer
> - *
> - * Note1: the macro can be used for global and local kfifo data type variables
> - * Note2: the macro creates two objects:
> - * A kfifo object with the given name and a buffer for the kfifo
> - * object named name##kfifo_buffer
> - */
> -#define DEFINE_KFIFO(name, size) \
> - unsigned char name##kfifo_buffer[size]; \
> - struct kfifo name = __kfifo_initializer(size, name##kfifo_buffer)
> -
> -#undef __kfifo_initializer
> -
> -extern void kfifo_init(struct kfifo *fifo, unsigned char *buffer,
> - unsigned int size);
> -extern __must_check int kfifo_alloc(struct kfifo *fifo, unsigned int size,
> - gfp_t gfp_mask);
> -extern void kfifo_free(struct kfifo *fifo);
> -extern unsigned int kfifo_in(struct kfifo *fifo,
> - const unsigned char *from, unsigned int len);
> -extern __must_check unsigned int kfifo_out(struct kfifo *fifo,
> - unsigned char *to, unsigned int len);
> -
> -/**
> - * kfifo_reset - removes the entire FIFO contents
> - * @fifo: the fifo to be emptied.
> - */
> -static inline void kfifo_reset(struct kfifo *fifo)
> -{
> - fifo->in = fifo->out = 0;
> -}
> -
> -/**
> - * kfifo_reset_out - skip FIFO contents
> - * @fifo: the fifo to be emptied.
> - */
> -static inline void kfifo_reset_out(struct kfifo *fifo)
> -{
> - smp_mb();
> - fifo->out = fifo->in;
> -}
> -
> -/**
> - * kfifo_size - returns the size of the fifo in bytes
> - * @fifo: the fifo to be used.
> - */
> -static inline __must_check unsigned int kfifo_size(struct kfifo *fifo)
> -{
> - return fifo->size;
> -}
> -
> -/**
> - * kfifo_len - returns the number of used bytes in the FIFO
> - * @fifo: the fifo to be used.
> - */
> -static inline unsigned int kfifo_len(struct kfifo *fifo)
> -{
> - register unsigned int out;
> -
> - out = fifo->out;
> - smp_rmb();
> - return fifo->in - out;
> -}
> -
> -/**
> - * kfifo_is_empty - returns true if the fifo is empty
> - * @fifo: the fifo to be used.
> - */
> -static inline __must_check int kfifo_is_empty(struct kfifo *fifo)
> -{
> - return fifo->in == fifo->out;
> -}
> -
> -/**
> - * kfifo_is_full - returns true if the fifo is full
> - * @fifo: the fifo to be used.
> - */
> -static inline __must_check int kfifo_is_full(struct kfifo *fifo)
> -{
> - return kfifo_len(fifo) == kfifo_size(fifo);
> -}
> -
> -/**
> - * kfifo_avail - returns the number of bytes available in the FIFO
> - * @fifo: the fifo to be used.
> - */
> -static inline __must_check unsigned int kfifo_avail(struct kfifo *fifo)
> -{
> - return kfifo_size(fifo) - kfifo_len(fifo);
> -}
> -
> -/**
> - * kfifo_in_locked - puts some data into the FIFO using a spinlock for locking
> - * @fifo: the fifo to be used.
> - * @from: the data to be added.
> - * @n: the length of the data to be added.
> - * @lock: pointer to the spinlock to use for locking.
> - *
> - * This function copies at most @len bytes from the @from buffer into
> - * the FIFO depending on the free space, and returns the number of
> - * bytes copied.
> - */
> -static inline unsigned int kfifo_in_locked(struct kfifo *fifo,
> - const unsigned char *from, unsigned int n, spinlock_t *lock)
> -{
> - unsigned long flags;
> - unsigned int ret;
> -
> - spin_lock_irqsave(lock, flags);
> -
> - ret = kfifo_in(fifo, from, n);
> -
> - spin_unlock_irqrestore(lock, flags);
> -
> - return ret;
> -}
> -
> -/**
> - * kfifo_out_locked - gets some data from the FIFO using a spinlock for locking
> - * @fifo: the fifo to be used.
> - * @to: where the data must be copied.
> - * @n: the size of the destination buffer.
> - * @lock: pointer to the spinlock to use for locking.
> - *
> - * This function copies at most @len bytes from the FIFO into the
> - * @to buffer and returns the number of copied bytes.
> - */
> -static inline __must_check unsigned int kfifo_out_locked(struct kfifo *fifo,
> - unsigned char *to, unsigned int n, spinlock_t *lock)
> -{
> - unsigned long flags;
> - unsigned int ret;
> -
> - spin_lock_irqsave(lock, flags);
> -
> - ret = kfifo_out(fifo, to, n);
> -
> - /*
> - * optimization: if the FIFO is empty, set the indices to 0
> - * so we don't wrap the next time
> - */
> - if (kfifo_is_empty(fifo))
> - kfifo_reset(fifo);
> -
> - spin_unlock_irqrestore(lock, flags);
> -
> - return ret;
> -}
> -
> -extern void kfifo_skip(struct kfifo *fifo, unsigned int len);
> -
> -extern __must_check unsigned int kfifo_from_user(struct kfifo *fifo,
> - const void __user *from, unsigned int n);
> -
> -extern __must_check unsigned int kfifo_to_user(struct kfifo *fifo,
> - void __user *to, unsigned int n);
> -
> -/*
> - * __kfifo_add_out internal helper function for updating the out offset
> - */
> -static inline void __kfifo_add_out(struct kfifo *fifo,
> - unsigned int off)
> -{
> - smp_mb();
> - fifo->out += off;
> -}
> -
> -/*
> - * __kfifo_add_in internal helper function for updating the in offset
> - */
> -static inline void __kfifo_add_in(struct kfifo *fifo,
> - unsigned int off)
> -{
> - smp_wmb();
> - fifo->in += off;
> -}
> -
> -/*
> - * __kfifo_off internal helper function for calculating the index of a
> - * given offeset
> - */
> -static inline unsigned int __kfifo_off(struct kfifo *fifo, unsigned int off)
> -{
> - return off & (fifo->size - 1);
> -}
> -
> -/*
> - * __kfifo_peek_n internal helper function for determinate the length of
> - * the next record in the fifo
> - */
> -static inline unsigned int __kfifo_peek_n(struct kfifo *fifo,
> - unsigned int recsize)
> -{
> -#define __KFIFO_GET(fifo, off, shift) \
> - ((fifo)->buffer[__kfifo_off((fifo), (fifo)->out+(off))] << (shift))
> -
> - unsigned int l;
> -
> - l = __KFIFO_GET(fifo, 0, 0);
> -
> - if (--recsize)
> - l |= __KFIFO_GET(fifo, 1, 8);
> -
> - return l;
> -#undef __KFIFO_GET
> -}
> -
> -/*
> - * __kfifo_poke_n internal helper function for storing the length of
> - * the next record into the fifo
> - */
> -static inline void __kfifo_poke_n(struct kfifo *fifo,
> - unsigned int recsize, unsigned int n)
> -{
> -#define __KFIFO_PUT(fifo, off, val, shift) \
> - ( \
> - (fifo)->buffer[__kfifo_off((fifo), (fifo)->in+(off))] = \
> - (unsigned char)((val) >> (shift)) \
> - )
> -
> - __KFIFO_PUT(fifo, 0, n, 0);
> -
> - if (--recsize)
> - __KFIFO_PUT(fifo, 1, n, 8);
> -#undef __KFIFO_PUT
> -}
> -
> -/*
> - * __kfifo_in_... internal functions for put date into the fifo
> - * do not call it directly, use kfifo_in_rec() instead
> - */
> -extern unsigned int __kfifo_in_n(struct kfifo *fifo,
> - const void *from, unsigned int n, unsigned int recsize);
> -
> -extern unsigned int __kfifo_in_generic(struct kfifo *fifo,
> - const void *from, unsigned int n, unsigned int recsize);
> -
> -static inline unsigned int __kfifo_in_rec(struct kfifo *fifo,
> - const void *from, unsigned int n, unsigned int recsize)
> -{
> - unsigned int ret;
> -
> - ret = __kfifo_in_n(fifo, from, n, recsize);
> -
> - if (likely(ret == 0)) {
> - if (recsize)
> - __kfifo_poke_n(fifo, recsize, n);
> - __kfifo_add_in(fifo, n + recsize);
> - }
> - return ret;
> -}
> -
> -/**
> - * kfifo_in_rec - puts some record data into the FIFO
> - * @fifo: the fifo to be used.
> - * @from: the data to be added.
> - * @n: the length of the data to be added.
> - * @recsize: size of record field
> - *
> - * This function copies @n bytes from the @from into the FIFO and returns
> - * the number of bytes which cannot be copied.
> - * A returned value greater than the @n value means that the record doesn't
> - * fit into the buffer.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -static inline __must_check unsigned int kfifo_in_rec(struct kfifo *fifo,
> - void *from, unsigned int n, unsigned int recsize)
> -{
> - if (!__builtin_constant_p(recsize))
> - return __kfifo_in_generic(fifo, from, n, recsize);
> - return __kfifo_in_rec(fifo, from, n, recsize);
> -}
> -
> -/*
> - * __kfifo_out_... internal functions for get date from the fifo
> - * do not call it directly, use kfifo_out_rec() instead
> - */
> -extern unsigned int __kfifo_out_n(struct kfifo *fifo,
> - void *to, unsigned int reclen, unsigned int recsize);
> -
> -extern unsigned int __kfifo_out_generic(struct kfifo *fifo,
> - void *to, unsigned int n,
> - unsigned int recsize, unsigned int *total);
> -
> -static inline unsigned int __kfifo_out_rec(struct kfifo *fifo,
> - void *to, unsigned int n, unsigned int recsize,
> - unsigned int *total)
> -{
> - unsigned int l;
> -
> - if (!recsize) {
> - l = n;
> - if (total)
> - *total = l;
> - } else {
> - l = __kfifo_peek_n(fifo, recsize);
> - if (total)
> - *total = l;
> - if (n < l)
> - return l;
> - }
> -
> - return __kfifo_out_n(fifo, to, l, recsize);
> -}
> -
> -/**
> - * kfifo_out_rec - gets some record data from the FIFO
> - * @fifo: the fifo to be used.
> - * @to: where the data must be copied.
> - * @n: the size of the destination buffer.
> - * @recsize: size of record field
> - * @total: pointer where the total number of to copied bytes should stored
> - *
> - * This function copies at most @n bytes from the FIFO to @to and returns the
> - * number of bytes which cannot be copied.
> - * A returned value greater than the @n value means that the record doesn't
> - * fit into the @to buffer.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -static inline __must_check unsigned int kfifo_out_rec(struct kfifo *fifo,
> - void *to, unsigned int n, unsigned int recsize,
> - unsigned int *total)
> -
> -{
> - if (!__builtin_constant_p(recsize))
> - return __kfifo_out_generic(fifo, to, n, recsize, total);
> - return __kfifo_out_rec(fifo, to, n, recsize, total);
> -}
> -
> -/*
> - * __kfifo_from_user_... internal functions for transfer from user space into
> - * the fifo. do not call it directly, use kfifo_from_user_rec() instead
> - */
> -extern unsigned int __kfifo_from_user_n(struct kfifo *fifo,
> - const void __user *from, unsigned int n, unsigned int recsize);
> -
> -extern unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
> - const void __user *from, unsigned int n, unsigned int recsize);
> -
> -static inline unsigned int __kfifo_from_user_rec(struct kfifo *fifo,
> - const void __user *from, unsigned int n, unsigned int recsize)
> -{
> - unsigned int ret;
> -
> - ret = __kfifo_from_user_n(fifo, from, n, recsize);
> -
> - if (likely(ret == 0)) {
> - if (recsize)
> - __kfifo_poke_n(fifo, recsize, n);
> - __kfifo_add_in(fifo, n + recsize);
> - }
> - return ret;
> -}
> -
> -/**
> - * kfifo_from_user_rec - puts some data from user space into the FIFO
> - * @fifo: the fifo to be used.
> - * @from: pointer to the data to be added.
> - * @n: the length of the data to be added.
> - * @recsize: size of record field
> - *
> - * This function copies @n bytes from the @from into the
> - * FIFO and returns the number of bytes which cannot be copied.
> - *
> - * If the returned value is equal or less the @n value, the copy_from_user()
> - * functions has failed. Otherwise the record doesn't fit into the buffer.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -static inline __must_check unsigned int kfifo_from_user_rec(struct kfifo *fifo,
> - const void __user *from, unsigned int n, unsigned int recsize)
> -{
> - if (!__builtin_constant_p(recsize))
> - return __kfifo_from_user_generic(fifo, from, n, recsize);
> - return __kfifo_from_user_rec(fifo, from, n, recsize);
> -}
> -
> -/*
> - * __kfifo_to_user_... internal functions for transfer fifo data into user space
> - * do not call it directly, use kfifo_to_user_rec() instead
> - */
> -extern unsigned int __kfifo_to_user_n(struct kfifo *fifo,
> - void __user *to, unsigned int n, unsigned int reclen,
> - unsigned int recsize);
> -
> -extern unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
> - void __user *to, unsigned int n, unsigned int recsize,
> - unsigned int *total);
> -
> -static inline unsigned int __kfifo_to_user_rec(struct kfifo *fifo,
> - void __user *to, unsigned int n,
> - unsigned int recsize, unsigned int *total)
> -{
> - unsigned int l;
> -
> - if (!recsize) {
> - l = n;
> - if (total)
> - *total = l;
> - } else {
> - l = __kfifo_peek_n(fifo, recsize);
> - if (total)
> - *total = l;
> - if (n < l)
> - return l;
> - }
> -
> - return __kfifo_to_user_n(fifo, to, n, l, recsize);
> -}
> -
> -/**
> - * kfifo_to_user_rec - gets data from the FIFO and write it to user space
> - * @fifo: the fifo to be used.
> - * @to: where the data must be copied.
> - * @n: the size of the destination buffer.
> - * @recsize: size of record field
> - * @total: pointer where the total number of to copied bytes should stored
> - *
> - * This function copies at most @n bytes from the FIFO to the @to.
> - * In case of an error, the function returns the number of bytes which cannot
> - * be copied.
> - * If the returned value is equal or less the @n value, the copy_to_user()
> - * functions has failed. Otherwise the record doesn't fit into the @to buffer.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -static inline __must_check unsigned int kfifo_to_user_rec(struct kfifo *fifo,
> - void __user *to, unsigned int n, unsigned int recsize,
> - unsigned int *total)
> -{
> - if (!__builtin_constant_p(recsize))
> - return __kfifo_to_user_generic(fifo, to, n, recsize, total);
> - return __kfifo_to_user_rec(fifo, to, n, recsize, total);
> -}
> -
> -/*
> - * __kfifo_peek_... internal functions for peek into the next fifo record
> - * do not call it directly, use kfifo_peek_rec() instead
> - */
> -extern unsigned int __kfifo_peek_generic(struct kfifo *fifo,
> - unsigned int recsize);
> -
> -/**
> - * kfifo_peek_rec - gets the size of the next FIFO record data
> - * @fifo: the fifo to be used.
> - * @recsize: size of record field
> - *
> - * This function returns the size of the next FIFO record in number of bytes
> - */
> -static inline __must_check unsigned int kfifo_peek_rec(struct kfifo *fifo,
> - unsigned int recsize)
> -{
> - if (!__builtin_constant_p(recsize))
> - return __kfifo_peek_generic(fifo, recsize);
> - if (!recsize)
> - return kfifo_len(fifo);
> - return __kfifo_peek_n(fifo, recsize);
> -}
> -
> -/*
> - * __kfifo_skip_... internal functions for skip the next fifo record
> - * do not call it directly, use kfifo_skip_rec() instead
> - */
> -extern void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize);
> -
> -static inline void __kfifo_skip_rec(struct kfifo *fifo,
> - unsigned int recsize)
> -{
> - unsigned int l;
> -
> - if (recsize) {
> - l = __kfifo_peek_n(fifo, recsize);
> -
> - if (l + recsize <= kfifo_len(fifo)) {
> - __kfifo_add_out(fifo, l + recsize);
> - return;
> - }
> - }
> - kfifo_reset_out(fifo);
> -}
> -
> -/**
> - * kfifo_skip_rec - skip the next fifo out record
> - * @fifo: the fifo to be used.
> - * @recsize: size of record field
> - *
> - * This function skips the next FIFO record
> - */
> -static inline void kfifo_skip_rec(struct kfifo *fifo,
> - unsigned int recsize)
> -{
> - if (!__builtin_constant_p(recsize))
> - __kfifo_skip_generic(fifo, recsize);
> - else
> - __kfifo_skip_rec(fifo, recsize);
> -}
> -
> -/**
> - * kfifo_avail_rec - returns the number of bytes available in a record FIFO
> - * @fifo: the fifo to be used.
> - * @recsize: size of record field
> - */
> -static inline __must_check unsigned int kfifo_avail_rec(struct kfifo *fifo,
> - unsigned int recsize)
> -{
> - unsigned int l = kfifo_size(fifo) - kfifo_len(fifo);
> -
> - return (l > recsize) ? l - recsize : 0;
> -}
> -
> -#endif
> diff -u -N -r -p linux-2.6.33-rc4.orig/kernel/kfifo.c linux-2.6.33-rc4.dummy/kernel/kfifo.c
> --- linux-2.6.33-rc4.orig/kernel/kfifo.c 2010-01-14 17:08:28.851544315 +0100
> +++ linux-2.6.33-rc4.dummy/kernel/kfifo.c 1970-01-01 01:00:00.000000000 +0100
> @@ -1,400 +0,0 @@
> -/*
> - * A generic kernel FIFO implementation.
> - *
> - * Copyright (C) 2009 Stefani Seibold <stefani@...bold.net>
> - * Copyright (C) 2004 Stelian Pop <stelian@...ies.net>
> - *
> - * 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
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * 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>
> -#include <linux/module.h>
> -#include <linux/slab.h>
> -#include <linux/err.h>
> -#include <linux/kfifo.h>
> -#include <linux/log2.h>
> -#include <linux/uaccess.h>
> -
> -static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer,
> - unsigned int size)
> -{
> - fifo->buffer = buffer;
> - fifo->size = size;
> -
> - kfifo_reset(fifo);
> -}
> -
> -/**
> - * kfifo_init - initialize a FIFO using a preallocated buffer
> - * @fifo: the fifo to assign the buffer
> - * @buffer: the preallocated buffer to be used.
> - * @size: the size of the internal buffer, this have to be a power of 2.
> - *
> - */
> -void kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size)
> -{
> - /* size must be a power of 2 */
> - BUG_ON(!is_power_of_2(size));
> -
> - _kfifo_init(fifo, buffer, size);
> -}
> -EXPORT_SYMBOL(kfifo_init);
> -
> -/**
> - * kfifo_alloc - allocates a new FIFO internal buffer
> - * @fifo: the fifo to assign then new buffer
> - * @size: the size of the buffer to be allocated, this have to be a power of 2.
> - * @gfp_mask: get_free_pages mask, passed to kmalloc()
> - *
> - * This function dynamically allocates a new fifo internal buffer
> - *
> - * The size will be rounded-up to a power of 2.
> - * The buffer will be release with kfifo_free().
> - * Return 0 if no error, otherwise the an error code
> - */
> -int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask)
> -{
> - unsigned char *buffer;
> -
> - /*
> - * round up to the next power of 2, since our 'let the indices
> - * wrap' technique works only in this case.
> - */
> - if (!is_power_of_2(size)) {
> - BUG_ON(size > 0x80000000);
> - size = roundup_pow_of_two(size);
> - }
> -
> - buffer = kmalloc(size, gfp_mask);
> - if (!buffer) {
> - _kfifo_init(fifo, 0, 0);
> - return -ENOMEM;
> - }
> -
> - _kfifo_init(fifo, buffer, size);
> -
> - return 0;
> -}
> -EXPORT_SYMBOL(kfifo_alloc);
> -
> -/**
> - * kfifo_free - frees the FIFO internal buffer
> - * @fifo: the fifo to be freed.
> - */
> -void kfifo_free(struct kfifo *fifo)
> -{
> - kfree(fifo->buffer);
> -}
> -EXPORT_SYMBOL(kfifo_free);
> -
> -/**
> - * kfifo_skip - skip output data
> - * @fifo: the fifo to be used.
> - * @len: number of bytes to skip
> - */
> -void kfifo_skip(struct kfifo *fifo, unsigned int len)
> -{
> - if (len < kfifo_len(fifo)) {
> - __kfifo_add_out(fifo, len);
> - return;
> - }
> - kfifo_reset_out(fifo);
> -}
> -EXPORT_SYMBOL(kfifo_skip);
> -
> -static inline void __kfifo_in_data(struct kfifo *fifo,
> - const void *from, unsigned int len, unsigned int off)
> -{
> - unsigned int l;
> -
> - /*
> - * Ensure that we sample the fifo->out index -before- we
> - * start putting bytes into the kfifo.
> - */
> -
> - smp_mb();
> -
> - off = __kfifo_off(fifo, fifo->in + off);
> -
> - /* first put the data starting from fifo->in to buffer end */
> - l = min(len, fifo->size - off);
> - memcpy(fifo->buffer + off, from, l);
> -
> - /* then put the rest (if any) at the beginning of the buffer */
> - memcpy(fifo->buffer, from + l, len - l);
> -}
> -
> -static inline void __kfifo_out_data(struct kfifo *fifo,
> - void *to, unsigned int len, unsigned int off)
> -{
> - unsigned int l;
> -
> - /*
> - * Ensure that we sample the fifo->in index -before- we
> - * start removing bytes from the kfifo.
> - */
> -
> - smp_rmb();
> -
> - off = __kfifo_off(fifo, fifo->out + off);
> -
> - /* first get the data from fifo->out until the end of the buffer */
> - l = min(len, fifo->size - off);
> - memcpy(to, fifo->buffer + off, l);
> -
> - /* then get the rest (if any) from the beginning of the buffer */
> - memcpy(to + l, fifo->buffer, len - l);
> -}
> -
> -static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
> - const void __user *from, unsigned int len, unsigned int off)
> -{
> - unsigned int l;
> - int ret;
> -
> - /*
> - * Ensure that we sample the fifo->out index -before- we
> - * start putting bytes into the kfifo.
> - */
> -
> - smp_mb();
> -
> - off = __kfifo_off(fifo, fifo->in + off);
> -
> - /* first put the data starting from fifo->in to buffer end */
> - l = min(len, fifo->size - off);
> - ret = copy_from_user(fifo->buffer + off, from, l);
> -
> - if (unlikely(ret))
> - return ret + len - l;
> -
> - /* then put the rest (if any) at the beginning of the buffer */
> - return copy_from_user(fifo->buffer, from + l, len - l);
> -}
> -
> -static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
> - void __user *to, unsigned int len, unsigned int off)
> -{
> - unsigned int l;
> - int ret;
> -
> - /*
> - * Ensure that we sample the fifo->in index -before- we
> - * start removing bytes from the kfifo.
> - */
> -
> - smp_rmb();
> -
> - off = __kfifo_off(fifo, fifo->out + off);
> -
> - /* first get the data from fifo->out until the end of the buffer */
> - l = min(len, fifo->size - off);
> - ret = copy_to_user(to, fifo->buffer + off, l);
> -
> - if (unlikely(ret))
> - return ret + len - l;
> -
> - /* then get the rest (if any) from the beginning of the buffer */
> - return copy_to_user(to + l, fifo->buffer, len - l);
> -}
> -
> -unsigned int __kfifo_in_n(struct kfifo *fifo,
> - const void *from, unsigned int len, unsigned int recsize)
> -{
> - if (kfifo_avail(fifo) < len + recsize)
> - return len + 1;
> -
> - __kfifo_in_data(fifo, from, len, recsize);
> - return 0;
> -}
> -EXPORT_SYMBOL(__kfifo_in_n);
> -
> -/**
> - * kfifo_in - puts some data into the FIFO
> - * @fifo: the fifo to be used.
> - * @from: the data to be added.
> - * @len: the length of the data to be added.
> - *
> - * This function copies at most @len bytes from the @from buffer into
> - * the FIFO depending on the free space, and returns the number of
> - * bytes copied.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from,
> - unsigned int len)
> -{
> - len = min(kfifo_avail(fifo), len);
> -
> - __kfifo_in_data(fifo, from, len, 0);
> - __kfifo_add_in(fifo, len);
> - return len;
> -}
> -EXPORT_SYMBOL(kfifo_in);
> -
> -unsigned int __kfifo_in_generic(struct kfifo *fifo,
> - const void *from, unsigned int len, unsigned int recsize)
> -{
> - return __kfifo_in_rec(fifo, from, len, recsize);
> -}
> -EXPORT_SYMBOL(__kfifo_in_generic);
> -
> -unsigned int __kfifo_out_n(struct kfifo *fifo,
> - void *to, unsigned int len, unsigned int recsize)
> -{
> - if (kfifo_len(fifo) < len + recsize)
> - return len;
> -
> - __kfifo_out_data(fifo, to, len, recsize);
> - __kfifo_add_out(fifo, len + recsize);
> - return 0;
> -}
> -EXPORT_SYMBOL(__kfifo_out_n);
> -
> -/**
> - * kfifo_out - gets some data from the FIFO
> - * @fifo: the fifo to be used.
> - * @to: where the data must be copied.
> - * @len: the size of the destination buffer.
> - *
> - * This function copies at most @len bytes from the FIFO into the
> - * @to buffer and returns the number of copied bytes.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len)
> -{
> - len = min(kfifo_len(fifo), len);
> -
> - __kfifo_out_data(fifo, to, len, 0);
> - __kfifo_add_out(fifo, len);
> -
> - return len;
> -}
> -EXPORT_SYMBOL(kfifo_out);
> -
> -unsigned int __kfifo_out_generic(struct kfifo *fifo,
> - void *to, unsigned int len, unsigned int recsize,
> - unsigned int *total)
> -{
> - return __kfifo_out_rec(fifo, to, len, recsize, total);
> -}
> -EXPORT_SYMBOL(__kfifo_out_generic);
> -
> -unsigned int __kfifo_from_user_n(struct kfifo *fifo,
> - const void __user *from, unsigned int len, unsigned int recsize)
> -{
> - if (kfifo_avail(fifo) < len + recsize)
> - return len + 1;
> -
> - return __kfifo_from_user_data(fifo, from, len, recsize);
> -}
> -EXPORT_SYMBOL(__kfifo_from_user_n);
> -
> -/**
> - * kfifo_from_user - puts some data from user space into the FIFO
> - * @fifo: the fifo to be used.
> - * @from: pointer to the data to be added.
> - * @len: the length of the data to be added.
> - *
> - * This function copies at most @len bytes from the @from into the
> - * FIFO depending and returns the number of copied bytes.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -unsigned int kfifo_from_user(struct kfifo *fifo,
> - const void __user *from, unsigned int len)
> -{
> - len = min(kfifo_avail(fifo), len);
> - len -= __kfifo_from_user_data(fifo, from, len, 0);
> - __kfifo_add_in(fifo, len);
> - return len;
> -}
> -EXPORT_SYMBOL(kfifo_from_user);
> -
> -unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
> - const void __user *from, unsigned int len, unsigned int recsize)
> -{
> - return __kfifo_from_user_rec(fifo, from, len, recsize);
> -}
> -EXPORT_SYMBOL(__kfifo_from_user_generic);
> -
> -unsigned int __kfifo_to_user_n(struct kfifo *fifo,
> - void __user *to, unsigned int len, unsigned int reclen,
> - unsigned int recsize)
> -{
> - unsigned int ret;
> -
> - if (kfifo_len(fifo) < reclen + recsize)
> - return len;
> -
> - ret = __kfifo_to_user_data(fifo, to, reclen, recsize);
> -
> - if (likely(ret == 0))
> - __kfifo_add_out(fifo, reclen + recsize);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL(__kfifo_to_user_n);
> -
> -/**
> - * kfifo_to_user - gets data from the FIFO and write it to user space
> - * @fifo: the fifo to be used.
> - * @to: where the data must be copied.
> - * @len: the size of the destination buffer.
> - *
> - * This function copies at most @len bytes from the FIFO into the
> - * @to buffer and returns the number of copied bytes.
> - *
> - * Note that with only one concurrent reader and one concurrent
> - * writer, you don't need extra locking to use these functions.
> - */
> -unsigned int kfifo_to_user(struct kfifo *fifo,
> - void __user *to, unsigned int len)
> -{
> - len = min(kfifo_len(fifo), len);
> - len -= __kfifo_to_user_data(fifo, to, len, 0);
> - __kfifo_add_out(fifo, len);
> - return len;
> -}
> -EXPORT_SYMBOL(kfifo_to_user);
> -
> -unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
> - void __user *to, unsigned int len, unsigned int recsize,
> - unsigned int *total)
> -{
> - return __kfifo_to_user_rec(fifo, to, len, recsize, total);
> -}
> -EXPORT_SYMBOL(__kfifo_to_user_generic);
> -
> -unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize)
> -{
> - if (recsize == 0)
> - return kfifo_avail(fifo);
> -
> - return __kfifo_peek_n(fifo, recsize);
> -}
> -EXPORT_SYMBOL(__kfifo_peek_generic);
> -
> -void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize)
> -{
> - __kfifo_skip_rec(fifo, recsize);
> -}
> -EXPORT_SYMBOL(__kfifo_skip_generic);
> -
> diff -u -N -r -p linux-2.6.33-rc4.dummy/include/linux/kfifo.h linux-2.6.33-rc4.new/include/linux/kfifo.h
> --- linux-2.6.33-rc4.dummy/include/linux/kfifo.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.33-rc4.new/include/linux/kfifo.h 2010-01-15 09:55:02.154635012 +0100
> @@ -0,0 +1,901 @@
> +/*
> + * A generic kernel FIFO implementation
> + *
> + * Copyright (C) 2009/2010 Stefani Seibold <stefani@...bold.net>
> + *
> + * 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
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * 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.
> + *
> + */
> +
> +#ifndef _LINUX_KFIFO_H
> +#define _LINUX_KFIFO_H
> +
> +/*
> + * How to porting drivers to the new generic FIFO API:
> + *
> + * - Modify the declaration of the "struct kfifo *" object into a
> + * in-place "struct kfifo" object
> + * - Init the in-place object with kfifo_alloc() or kfifo_init()
> + * Note: The address of the in-place "struct kfifo" object must be
> + * passed as the first argument to this functions
> + * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get
> + * into kfifo_out
> + * - Replace the use of kfifo_put into kfifo_in_locked and kfifo_get
> + * into kfifo_out_locked
> + * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc
> + * must be passed now to the kfifo_in_locked and kfifo_out_locked
> + * as the last parameter.
> + * - The formerly __kfifo_* functions are renamed into kfifo_*
> + */
> +
> +/*
> + * Note about locking : There is no locking required until only * one reader
> + * and one writer is using the fifo and no kfifo_reset() will be * called.
> + * kfifo_reset_out() can be safely used, until it will be only called
> + * in the reader thread.
> + * For multiple writer and one reader there is only a need to lock the writer.
> + * And vice versa for only one writer and multiple reader there is only a need
> + * to lock the reader.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/spinlock.h>
> +#include <linux/stddef.h>
> +#include <linux/scatterlist.h>
> +
> +struct __kfifo {
> + unsigned int in;
> + unsigned int out;
> + unsigned int mask;
> + void *data;
> +};
> +
> +#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \
> + union { \
> + struct __kfifo kfifo; \
> + datatype *type; \
> + char (*rectype)[recsize]; \
> + ptrtype *ptr; \
> + const ptrtype *ptr_const; \
> + }
> +
> +#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \
> +{ \
> + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
> + type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
> +}
> +
> +#define STRUCT_KFIFO(type, size) \
> + struct __STRUCT_KFIFO(type, size, 0, type)
> +
> +#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \
> +{ \
> + __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
> + type buf[0]; \
> +}
> +
> +#define STRUCT_KFIFO_PTR(type) \
> + struct __STRUCT_KFIFO_PTR(type, 0, type)
> +
> +/*
> + * define compatibility "struct kfifo" for dynamic allocated fifos
> + */
> +struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);
> +
> +#define STRUCT_KFIFO_REC_1(size) \
> + struct __STRUCT_KFIFO(unsigned char, size, 1, void)
> +
> +#define STRUCT_KFIFO_REC_2(size) \
> + struct __STRUCT_KFIFO(unsigned char, size, 2, void)
> +
> +/*
> + * define kfifo_rec types
> + */
> +struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void);
> +struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
> +
> +/*
> + * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object
> + * @fifo: name of the declared fifo
> + * @type: type of the fifo elements
> + * @size: the number of elements in the fifo, this must be a power of 2.
> + */
> +#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo
> +
> +/* helper macro */
> +#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo))
> +
> +#define __kfifo_initializer(fifo) \
> + (typeof(fifo)) { \
> + { \
> + { \
> + .in = 0, \
> + .out = 0, \
> + .mask = __is_kfifo_ptr(&fifo) ? \
> + 0 : \
> + sizeof((fifo).buf)/sizeof(*(fifo).buf) - 1, \
> + .data = __is_kfifo_ptr(&fifo) ? \
> + 0 : \
> + (fifo).buf, \
> + } \
> + } \
> + }
> +
> +/*
> + * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO
> + * @fifo: name of the declared fifo datatype
> + */
> +#define INIT_KFIFO(fifo) fifo = __kfifo_initializer(fifo)
> +
> +/*
> + * DECLARE_KFIFO - macro to declare a fifo object
> + * @fifo: name of the declared fifo
> + * @type: type of the fifo elements
> + * @size: the number of elements in the fifo, this must be a power of 2.
> + */
> +#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo
> +
> +/*
> + * DEFINE_KFIFO - macro to define and initialize a fifo
> + * @fifo: name of the declared fifo datatype
> + * @type: type of the fifo elements
> + * @size: the number of elements in the fifo, this must be a power of 2.
> + *
> + * Note: the macro can be used for global and local fifo data type variables
> + */
> +#define DEFINE_KFIFO(fifo, type, size) \
> + DECLARE_KFIFO(fifo, type, size) = __kfifo_initializer(fifo)
> +
> +static inline unsigned int __must_check __kfifo_check(unsigned int val)
> +{
> + return val;
> +}
> +
> +/*
> + * kfifo_initialized - Check if kfifo is initialized.
> + * @fifo: fifo to check
> + * Return %true if FIFO is initialized, otherwise %false.
> + * Assumes the fifo was 0 before.
> + *
> + * Note: for in place fifo's this macro returns alway true
> + */
> +#define kfifo_initialized(fifo) ((fifo)->kfifo.data != 0)
> +
> +/*
> + * kfifo_sizeof - returns the size of a fifo element
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_sizeof(fifo) (sizeof(*(fifo)->type))
> +
> +/*
> + * kfifo_recsize - returns the size of the record length field
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype))
> +
> +/*
> + * kfifo_size - returns the size of the fifo in elements
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1)
> +
> +/*
> + * kfifo_reset - removes the entire fifo content
> + * @fifo: the fifo to be used.
> + *
> + * Note: usage of kfifo_reset() is dangerous. It should be only called when the
> + * fifo is exclusived locked or when it is secured that no other thread is
> + * accessing the fifo.
> + */
> +#define kfifo_reset(fifo) \
> +(void)({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + __tmp->kfifo.in = __tmp->kfifo.out = 0; \
> +})
> +
> +/*
> + * kfifo_reset_out - skip fifo content
> + * @fifo: the fifo to be used.
> + *
> + * Note: The usage of kfifo_reset_out() is safe until it will be only called
> + * from the reader thread and there is only one concurrent reader. Otherwise
> + * it is dangerous and must be handled in the same way as kfifo_reset().
> + */
> +#define kfifo_reset_out(fifo) \
> +(void)({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + __tmp->kfifo.out = __tmp->kfifo.in; \
> +})
> +
> +/*
> + * kfifo_len - returns the number of used elements in the fifo
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_len(fifo) \
> +({ \
> + typeof(fifo + 1) __tmpl = (fifo); \
> + __tmpl->kfifo.in - __tmpl->kfifo.out; \
> +})
> +
> +/*
> + * kfifo_is_empty - returns true if the fifo is empty
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_is_empty(fifo) \
> +({ \
> + typeof(fifo + 1) __tmpq = (fifo); \
> + __tmpq->kfifo.in == __tmpq->kfifo.out; \
> +})
> +
> +/*
> + * kfifo_is_full - returns true if the fifo is full
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_is_full(fifo) \
> +({ \
> + typeof(fifo + 1) __tmpq = (fifo); \
> + kfifo_len(__tmpq) > __tmpq->kfifo.mask; \
> +})
> +
> +/*
> + * kfifo_avail - returns the number of elements available in the fifo
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_avail(fifo) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmpq = (fifo); \
> + const size_t __recsize = sizeof(*__tmpq->rectype); \
> + unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \
> + (__avail <= recsize) ? 0 __avail - __recsize; \
> +}) \
> +)
> +
> +/*
> + * kfifo_skip - skip output data
> + * @fifo: the fifo to be used.
> + */
> +#define kfifo_skip(fifo) \
> +(void)({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __kfifo_skip_rec(__kfifo, __recsize); \
> + else \
> + __kfifo->out++; \
> +})
> +
> +/*
> + * kfifo_peek_len - gets the size of the next FIFO record
> + * @fifo: the fifo to be used.
> + * @recsize: size of record field
> + *
> + * This function returns the size of the next FIFO record in number of bytes
> + */
> +#define kfifo_peek_len(fifo) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + (!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \
> + __kfifo_peek_reclen(__kfifo, __recsize); \
> +}) \
> +)
> +
> +/*
> + * kfifo_alloc - dynamically allocates a new fifo
> + * @fifo: pointer to the fifo
> + * @size: the number of elements in the fifo, this must be a power of 2.
> + * @gfp_mask: get_free_pages mask, passed to kmalloc()
> + *
> + * This macro dynamically allocates a new fifo.
> + *
> + * The numer of elements will be rounded-up to a power of 2.
> + * The fifo will be release with kfifo_free().
> + * Return 0 if no error, otherwise an error code
> + */
> +#define kfifo_alloc(fifo, size, gfp_mask) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + __is_kfifo_ptr(__tmp) ? \
> + __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \
> + -EINVAL; \
> +}) \
> +)
> +
> +/*
> + * kfifo_free - frees the fifo
> + * @fifo: the fifo to be freed.
> + */
> +#define kfifo_free(fifo) \
> +({\ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__is_kfifo_ptr(__tmp)) \
> + __kfifo_free(__kfifo); \
> +})
> +
> +/*
> + * kfifo_init - initialize a FIFO using a preallocated buffer
> + * @fifo: the fifo to assign the buffer
> + * @buffer: the preallocated buffer to be used.
> + * @size: the size of the internal buffer, this have to be a power of 2.
> + */
> +#define kfifo_init(fifo, buffer, size) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + __is_kfifo_ptr(__tmp) ? \
> + __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \
> + -EINVAL; \
> +}) \
> +)
> +
> +/*
> + * kfifo_put - put data into the fifo
> + * @fifo: the fifo to be used.
> + * @val: the data to be added.
> + *
> + * This macro copies the given value into the fifo.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_put(fifo, val) \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + typeof(val + 1) __val = (val); \
> + unsigned int __ret; \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (0) { \
> + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \
> + __dummy = (typeof(__val))NULL; \
> + } \
> + if (__recsize) \
> + __ret = __kfifo_in_rec(__kfifo, __val, sizeof(*__val), \
> + __recsize); \
> + else { \
> + __ret = !kfifo_is_full(__tmp); \
> + if (__ret) { \
> + (__is_kfifo_ptr(__tmp) ? \
> + ((typeof(__tmp->type))__kfifo->data) : \
> + (__tmp->buf) \
> + )[__kfifo->in & __tmp->kfifo.mask] = \
> + *(typeof(__tmp->type))__val; \
> + smp_wmb(); \
> + __kfifo->in++; \
> + } \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_get - get data from the fifo
> + * @fifo: the fifo to be used.
> + * @val: the var where to store the data to be added.
> + *
> + * This macro returns the data from the fifo
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_get(fifo, val) \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + typeof(val + 1) __val = (val); \
> + unsigned int __ret; \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (0) \
> + __val = (typeof(__tmp->ptr))0; \
> + if (__recsize) \
> + __ret = __kfifo_out_rec(__kfifo, __val, sizeof(*__val), \
> + __recsize); \
> + else { \
> + __ret = !kfifo_is_empty(__tmp); \
> + if (__ret) { \
> + *(typeof(__tmp->type))__val = \
> + (__is_kfifo_ptr(__tmp) ? \
> + ((typeof(__tmp->type))__kfifo->data) : \
> + (__tmp->buf) \
> + )[__kfifo->out & __tmp->kfifo.mask]; \
> + smp_wmb(); \
> + __kfifo->out++; \
> + } \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_peek - get data from the fifo without removing
> + * @fifo: the fifo to be used.
> + * @val: the var where to store the data to be added.
> + *
> + * This macro returns the data from the fifo without removing it from the fifo
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_peek(fifo, val) \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + typeof(val + 1) __val = (val); \
> + unsigned int __ret; \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (0) \
> + __val = (typeof(__tmp->ptr))0; \
> + if (__recsize) \
> + __ret = __kfifo_out_peek_rec(__kfifo, __val, sizeof(*__val), \
> + __recsize); \
> + else { \
> + __ret = !kfifo_is_empty(__tmp); \
> + if (__ret) { \
> + *(typeof(__tmp->type))__val = \
> + (__is_kfifo_ptr(__tmp) ? \
> + ((typeof(__tmp->type))__kfifo->data) : \
> + (__tmp->buf) \
> + )[__kfifo->out & __tmp->kfifo.mask]; \
> + smp_wmb(); \
> + } \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_in - puts some data into the fifo
> + * @fifo: the fifo to be used.
> + * @buf: the data to be added.
> + * @n: number of elements to be added
> + *
> + * This macro copies the given values buffer into the fifo and returns the
> + * number of copied elements.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_in(fifo, buf, n) \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + typeof(buf + 1) __buf = (buf); \
> + unsigned long __n = (n); \
> + unsigned int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (0) { \
> + typeof(__tmp->ptr_const) __dummy __attribute__ ((unused)); \
> + __dummy = (typeof(__buf))NULL; \
> + } \
> + if (__recsize) \
> + __ret = __kfifo_in_rec(__kfifo, __buf, __n, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_in_1(__kfifo, __buf, __n) : \
> + __kfifo_in(__kfifo, __esize, __buf, __n); \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_in_locked - puts some data into the fifo using a spinlock for locking
> + * @fifo: the fifo to be used.
> + * @buf: the data to be added.
> + * @n: number of elements to be added
> + * @lock: pointer to the spinlock to use for locking.
> + *
> + * This macro copies the given values buffer into the fifo and returns the
> + * number of copied elements.
> + */
> +#define kfifo_in_locked(fifo, buf, n, lock) \
> +({ \
> + unsigned long __flags; \
> + unsigned int __ret; \
> + spin_lock_irqsave(lock, __flags); \
> + __ret = kfifo_in(fifo, buf, n); \
> + spin_unlock_irqrestore(lock, __flags); \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_out - gets some data from the fifo
> + * @fifo: the fifo to be used.
> + * @buf: pointer to the storage buffer
> + * @n: max. number of elements to get
> + *
> + * This macro get the data from the fifo and return the numbers of elements
> + * copied.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_out(fifo, buf, n) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + typeof(buf + 1) __buf = (buf); \
> + unsigned long __n = (n); \
> + unsigned int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (0) { \
> + typeof(__tmp->ptr) __dummy = 0; \
> + __buf = __dummy; \
> + } \
> + if (__recsize) \
> + __ret = __kfifo_out_rec(__kfifo, __buf, __n, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_out_1(__kfifo, __buf, __n) : \
> + __kfifo_out(__kfifo, __esize, __buf, __n); \
> + } \
> + __ret; \
> +}) \
> +)
> +
> +/*
> + * kfifo_out_locked - gets some data from the fifo using a spinlock for locking
> + * @fifo: the fifo to be used.
> + * @buf: pointer to the storage buffer
> + * @n: max. number of elements to get
> + * @lock: pointer to the spinlock to use for locking.
> + *
> + * This macro get the data from the fifo and return the numbers of elements
> + * copied.
> + */
> +#define kfifo_out_locked(fifo, buf, n, lock) \
> +__kfifo_check( \
> +({ \
> + unsigned long __flags; \
> + unsigned int __ret; \
> + spin_lock_irqsave(lock, __flags); \
> + __ret = kfifo_out(fifo, buf, n); \
> + spin_unlock_irqrestore(lock, __flags); \
> + __ret; \
> +}) \
> +)
> +
> +/*
> + * kfifo_from_user - puts some data from user space into the fifo
> + * @fifo: the fifo to be used.
> + * @from: pointer to the data to be added.
> + * @len: the length of the data to be added.
> + * @copied: pointer to output variable to store the number of copied bytes.
> + *
> + * This macro copies at most @len bytes from the @from into the
> + * fifo, depending of the available space and returns -EFAULT/0
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_from_user(fifo, from, len, copied) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + const void __user *__from = (from); \
> + unsigned int __len = (len); \
> + unsigned int *__copied = (copied); \
> + int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __ret = __kfifo_from_user_rec(__kfifo, __from, __len, \
> + __copied, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_from_user_1(__kfifo, __from, __len, \
> + __copied) : \
> + __kfifo_from_user(__kfifo, __esize, __from, __len, \
> + __copied); \
> + } \
> + __ret; \
> +}) \
> +)
> +
> +/*
> + * kfifo_to_user - copies data from the fifo into user space
> + * @fifo: the fifo to be used.
> + * @to: where the data must be copied.
> + * @len: the size of the destination buffer.
> + * @copied: pointer to output variable to store the number of copied bytes.
> + *
> + * This macro copies at most @len bytes from the fifo into the
> + * @to buffer and returns -EFAULT/0.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_to_user(fifo, to, len, copied) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + void __user *__to = (to); \
> + unsigned int __len = (len); \
> + unsigned int *__copied = (copied); \
> + int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __ret = __kfifo_to_user_rec(__kfifo, __to, __len, \
> + __copied, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_to_user_1(__kfifo, __to, __len, __copied) : \
> + __kfifo_to_user(__kfifo, __esize, __to, __len, \
> + __copied); \
> + } \
> + __ret; \
> +}) \
> +)
> +
> +/*
> + * kfifo_dma_in_prepare - setup a scatterlist for DMA input
> + * @fifo: the fifo to be used.
> + * @sgl: pointer to the scatterlist array.
> + * @nents: number of entries in the scatterlist array (should be 1 or 2).
> + * @len: number of elements to transfer.
> + *
> + * This macro fills a scatterlist for DMA input.
> + * It returns the number of bytes which are available for the transfer.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macros.
> + */
> +#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + struct scatterlist *__sgl = (sgl); \
> + int __nents = (nents); \
> + unsigned int __len = (len); \
> + int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __ret = __kfifo_dma_in_prepare_rec(__kfifo, __sgl, \
> + __nents, __len, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_dma_in_prepare_1(__kfifo, __sgl, \
> + __nents, __len) : \
> + __kfifo_dma_in_prepare(__kfifo, __esize, __sgl, \
> + __nents, __len); \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_dma_in_finish - finish a DMA IN operation
> + * @fifo: the fifo to be used.
> + * @len: number of bytes to received.
> + *
> + * This macro finish a DMA IN operation. The in counter will be updated by
> + * the len parameter. No error checking will be done.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macros.
> + */
> +#define kfifo_dma_in_finish(fifo, len) \
> +(void)({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + unsigned int __len = (len); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __kfifo_dma_in_finish_rec(__kfifo, __len, __recsize); \
> + else \
> + __kfifo->in += __len / sizeof(*__tmp->type); \
> +})
> +
> +/*
> + * kfifo_dma_out_prepare - setup a scatterlist for DMA output
> + * @fifo: the fifo to be used.
> + * @sgl: pointer to the scatterlist array.
> + * @nents: number of entries in the scatterlist array (should be 1 or 2).
> + * @len: number of elements to transfer.
> + *
> + * This macro fills a scatterlist for DMA output which at most @len bytes
> + * to transfer.
> + * It returns the number of bytes which are available for the transfer.
> + * A zero means there is no space available and the scatterlist is not filled
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macros.
> + */
> +#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + struct scatterlist *__sgl = (sgl); \
> + int __nents = (nents); \
> + unsigned int __len = (len); \
> + int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __ret = __kfifo_dma_out_prepare_rec(__kfifo, __sgl, \
> + __nents, __len, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_dma_out_prepare_1(__kfifo, __sgl, \
> + __nents, __len) : \
> + __kfifo_dma_out_prepare(__kfifo, __esize, \
> + __sgl, __nents, __len); \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * kfifo_dma_out_finish - finish a DMA OUT operation
> + * @fifo: the fifo to be used.
> + * @len: number of bytes transferd.
> + *
> + * This macro finish a DMA OUT operation. The out counter will be updated by
> + * the len parameter. No error checking will be done.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macros.
> + */
> +#define kfifo_dma_out_finish(fifo, len) \
> +(void)({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + unsigned int __len = (len); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (__recsize) \
> + __kfifo_dma_out_finish_rec(__kfifo, __len, __recsize); \
> + else \
> + __kfifo->out += __len / sizeof(*__tmp->type); \
> +})
> +
> +/*
> + * kfifo_out_peek - gets some data from the fifo
> + * @fifo: the fifo to be used.
> + * @buf: pointer to the storage buffer
> + * @n: max. number of elements to get
> + *
> + * This macro get the data from the fifo and return the numbers of elements
> + * copied. The data is not removed from the FIFO.
> + *
> + * Note that with only one concurrent reader and one concurrent
> + * writer, you don't need extra locking to use these macro.
> + */
> +#define kfifo_out_peek(fifo, buf, n) \
> +__kfifo_check( \
> +({ \
> + typeof(fifo + 1) __tmp = (fifo); \
> + typeof(buf + 1) __buf = (buf); \
> + unsigned long __n = (n); \
> + unsigned int __ret; \
> + const size_t __esize = sizeof(*__tmp->type); \
> + const size_t __recsize = sizeof(*__tmp->rectype); \
> + struct __kfifo *__kfifo = &__tmp->kfifo; \
> + if (0) { \
> + typeof(__tmp->ptr) __dummy __attribute__ ((unused)) = 0; \
> + __buf = __dummy; \
> + } \
> + if (__recsize) \
> + __ret = __kfifo_out_peek_rec(__kfifo, __buf, __n, __recsize); \
> + else { \
> + __ret = (__esize == 1) ? \
> + __kfifo_out_peek_1(__kfifo, __buf, __n) :\
> + __kfifo_out_peek(__kfifo, __esize, __buf, __n); \
> + } \
> + __ret; \
> +}) \
> +)
> +
> +extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
> + size_t esize, gfp_t gfp_mask);
> +
> +extern void __kfifo_free(struct __kfifo *fifo);
> +
> +extern int __kfifo_init(struct __kfifo *fifo, void *buffer,
> + unsigned int size, size_t esize);
> +
> +
> +extern unsigned int __kfifo_in(struct __kfifo *fifo,
> + size_t esize, const void *buf, unsigned int len);
> +
> +extern unsigned int __kfifo_in_1(struct __kfifo *fifo,
> + const void *buf, unsigned int len);
> +
> +extern unsigned int __kfifo_in_rec(struct __kfifo *fifo,
> + const void *buf, unsigned int len, size_t recsize);
> +
> +
> +extern unsigned int __kfifo_out(struct __kfifo *fifo,
> + size_t esize, void *buf, unsigned int len);
> +
> +extern unsigned int __kfifo_out_1(struct __kfifo *fifo,
> + void *buf, unsigned int len);
> +
> +extern unsigned int __kfifo_out_rec(struct __kfifo *fifo,
> + void *buf, unsigned int len, size_t recsize);
> +
> +
> +extern int __kfifo_from_user(struct __kfifo *fifo, size_t esize,
> + const void __user *from, unsigned long len, unsigned int *copied);
> +
> +extern int __kfifo_from_user_1(struct __kfifo *fifo,
> + const void __user *from, unsigned long len, unsigned int *copied);
> +
> +extern int __kfifo_from_user_rec(struct __kfifo *fifo,
> + const void __user *from, unsigned long len, unsigned int *copied,
> + size_t recsize);
> +
> +
> +extern int __kfifo_to_user(struct __kfifo *fifo, size_t esize,
> + void __user *to, unsigned long len, unsigned int *copied);
> +
> +extern int __kfifo_to_user_1(struct __kfifo *fifo,
> + void __user *to, unsigned long len, unsigned int *copied);
> +
> +extern int __kfifo_to_user_rec(struct __kfifo *fifo, void __user *to,
> + unsigned long len, unsigned int *copied, size_t recsize);
> +
> +
> +extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
> + size_t esize, struct scatterlist *sgl, int nents, unsigned int len);
> +
> +extern unsigned int __kfifo_dma_in_prepare_1(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len);
> +
> +extern unsigned int __kfifo_dma_in_prepare_rec(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
> +
> +
> +extern void __kfifo_dma_in_finish_rec(struct __kfifo *fifo,
> + unsigned int len, size_t recsize);
> +
> +
> +extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
> + size_t esize, struct scatterlist *sgl, int nents, unsigned int len);
> +
> +extern unsigned int __kfifo_dma_out_prepare_1(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len);
> +
> +extern unsigned int __kfifo_dma_out_prepare_rec(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
> +
> +
> +extern void __kfifo_dma_out_finish_rec(struct __kfifo *fifo,
> + unsigned int len, size_t recsize);
> +
> +
> +extern unsigned int __kfifo_peek_reclen(struct __kfifo *fifo,
> + size_t recsize);
> +
> +
> +extern unsigned int __kfifo_out_peek(struct __kfifo *fifo,
> + size_t esize, void *buf, unsigned int len);
> +
> +extern unsigned int __kfifo_out_peek_1(struct __kfifo *fifo,
> + void *buf, unsigned int len);
> +
> +extern unsigned int __kfifo_out_peek_rec(struct __kfifo *fifo,
> + void *buf, unsigned int len, size_t recsize);
> +
> +#endif
> +
> diff -u -N -r -p linux-2.6.33-rc4.dummy/kernel/kfifo.c linux-2.6.33-rc4.new/kernel/kfifo.c
> --- linux-2.6.33-rc4.dummy/kernel/kfifo.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.33-rc4.new/kernel/kfifo.c 2010-01-15 09:55:10.898054325 +0100
> @@ -0,0 +1,781 @@
> +/*
> + * A generic kernel FIFO implementation
> + *
> + * Copyright (C) 2009 Stefani Seibold <stefani@...bold.net>
> + *
> + * 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
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * 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>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/kfifo.h>
> +#include <linux/log2.h>
> +#include <linux/uaccess.h>
> +
> +#define roundup_diff(val, size) (((val) + (size - 1)) / size)
> +
> +int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
> + size_t esize, gfp_t gfp_mask)
> +{
> + /*
> + * round up to the next power of 2, since our 'let the indices
> + * wrap' technique works only in this case.
> + */
> + if (!is_power_of_2(size))
> + size = rounddown_pow_of_two(size);
> +
> + if (size < 2)
> + return -EINVAL;
> +
> + fifo->in = fifo->out = 0;
> + fifo->data = kmalloc(size * esize, gfp_mask);
> +
> + if (!fifo->data) {
> + fifo->mask = 0;
> + return -ENOMEM;
> + }
> +
> + fifo->mask = size - 1;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(__kfifo_alloc);
> +
> +void __kfifo_free(struct __kfifo *fifo)
> +{
> + kfree(fifo);
> + fifo->data = 0;
> + fifo->mask = 0;
> + fifo->in = fifo->out = 0;
> +}
> +EXPORT_SYMBOL(__kfifo_free);
> +
> +int __kfifo_init(struct __kfifo *fifo, void *buffer,
> + unsigned int size, size_t esize)
> +{
> + size /= esize;
> +
> + if (size)
> + size = rounddown_pow_of_two(size);
> +
> + if (size < 2)
> + return -EINVAL;
> +
> + fifo->data = buffer;
> + fifo->in = fifo->out = 0;
> + fifo->mask = size - 1;
> + return 0;
> +}
> +EXPORT_SYMBOL(__kfifo_init);
> +
> +unsigned int __kfifo_in(struct __kfifo *fifo, size_t esize,
> + const void *buf, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = size - (fifo->in - fifo->out);
> + if (len > l)
> + len = l;
> +
> + off = fifo->in & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(data + off * esize, buf, l * esize);
> + memcpy(data, buf + l * esize, (len - l) * esize);
> +
> + smp_wmb();
> + fifo->in += len;
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_in);
> +
> +unsigned int __kfifo_out(struct __kfifo *fifo,
> + size_t esize, void *buf, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(buf, data + off * esize, l * esize);
> + memcpy(buf + l * esize, data, (len - l) * esize);
> +
> + smp_wmb();
> + fifo->out += len;
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_out);
> +
> +unsigned int __kfifo_out_peek(struct __kfifo *fifo,
> + size_t esize, void *buf, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(buf, data + off * esize, l * esize);
> + memcpy(buf + l * esize, data, (len - l) * esize);
> +
> + smp_wmb();
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_out_peek);
> +
> +int __kfifo_from_user(struct __kfifo *fifo, size_t esize,
> + const void __user *from, unsigned long len, unsigned int *copied)
> +{
> + unsigned int l;
> + unsigned long ret;
> + unsigned long off;
> + int err = 0;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + len /= esize;
> + l = size - (fifo->in - fifo->out);
> + if (len > l)
> + len = l;
> +
> + off = fifo->in & fifo->mask;
> +
> + l = min(len, size - off);
> + ret = copy_from_user(data + off * esize, from, l * esize);
> +
> + if (unlikely(ret)) {
> + len = l - roundup_diff(ret, esize);
> + err = -EFAULT;
> + } else {
> + ret = copy_from_user(data, from + l * esize, (len - l) * esize);
> +
> + if (unlikely(ret)) {
> + len -= roundup_diff(ret, esize);
> + err = -EFAULT;
> + }
> + }
> +
> + smp_wmb();
> + fifo->in += len;
> + if (copied)
> + *copied = len * esize;
> + return err;
> +}
> +EXPORT_SYMBOL(__kfifo_from_user);
> +
> +int __kfifo_to_user(struct __kfifo *fifo, size_t esize, void __user *to,
> + unsigned long len, unsigned int *copied)
> +{
> + unsigned int l;
> + unsigned long ret;
> + unsigned long off;
> + int err = 0;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + len /= esize;
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> + ret = copy_to_user(to, data + off * esize, l * esize);
> +
> + if (unlikely(ret)) {
> + len = l - roundup_diff(ret, esize);
> + err = -EFAULT;
> + } else {
> + ret = copy_to_user(to + l * esize, data, (len - l) * esize);
> +
> + if (unlikely(ret)) {
> + len -= roundup_diff(ret, esize);
> + err = -EFAULT;
> + }
> + }
> +
> + smp_wmb();
> + fifo->out += len;
> + if (copied)
> + *copied = len * esize;
> + return err;
> +}
> +EXPORT_SYMBOL(__kfifo_to_user);
> +
> +static unsigned int setup_sgl(void *data, unsigned int size,
> + struct scatterlist *sgl, int nents, unsigned int len, unsigned int off)
> +{
> + unsigned int l;
> +
> + l = min(len, size - off);
> + if (l != len) {
> + if (nents > 1) {
> + sg_set_buf(sgl, data + off, l);
> + sgl++;
> +
> + off = 0;
> + l = len - l;
> + } else
> + len = l;
> + }
> + sg_set_buf(sgl, data + off, l);
> + sg_mark_end(sgl);
> +
> + return len;
> +}
> +
> +unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, size_t esize,
> + struct scatterlist *sgl, int nents, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (!nents)
> + BUG();
> +
> + l = size - (fifo->in - fifo->out);
> + if (len > l)
> + len = l;
> + if (!len)
> + return 0;
> +
> + off = fifo->in & fifo->mask;
> +
> + return setup_sgl(data, size, sgl, nents, len * esize, off * esize);
> +}
> +EXPORT_SYMBOL(__kfifo_dma_in_prepare);
> +
> +unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, size_t esize,
> + struct scatterlist *sgl, int nents, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (!nents)
> + BUG();
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> + if (!len)
> + return 0;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> +
> + return setup_sgl(data, size, sgl, nents, len * esize, off * esize);
> +}
> +EXPORT_SYMBOL(__kfifo_dma_out_prepare);
> +
> +unsigned int __kfifo_in_1(struct __kfifo *fifo, const void *buf,
> + unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = size - (fifo->in - fifo->out);
> + if (len > l)
> + len = l;
> +
> + off = fifo->in & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(data + off, buf, l);
> + memcpy(data, buf + l, len - l);
> +
> + smp_wmb();
> + fifo->in += len;
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_in_1);
> +
> +unsigned int __kfifo_out_1(struct __kfifo *fifo, void *buf, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(buf, data + off, l);
> + memcpy(buf + l, data, len - l);
> +
> + smp_wmb();
> + fifo->out += len;
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_out_1);
> +
> +unsigned int __kfifo_out_peek_1(struct __kfifo *fifo, void *buf,
> + unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(buf, data + off, l);
> + memcpy(buf + l, data, len - l);
> +
> + smp_wmb();
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_out_peek_1);
> +
> +int __kfifo_from_user_1(struct __kfifo *fifo, const void __user *from,
> + unsigned long len, unsigned int *copied)
> +{
> + unsigned int l;
> + unsigned long ret;
> + unsigned long off;
> + int err = 0;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = size - (fifo->in - fifo->out);
> + if (len > l)
> + len = l;
> +
> + off = fifo->in & fifo->mask;
> +
> + l = min(len, size - off);
> + ret = copy_from_user(data + off, from, l);
> +
> + if (unlikely(ret)) {
> + ret = l - ret;
> + err = -EFAULT;
> + } else {
> + ret = copy_from_user(data, from + l, len - l);
> + if (unlikely(ret))
> + err = -EFAULT;
> + ret = len - ret;
> + }
> +
> + smp_wmb();
> + fifo->in += ret;
> + if (copied)
> + *copied = ret;
> + return err;
> +}
> +EXPORT_SYMBOL(__kfifo_from_user_1);
> +
> +int __kfifo_to_user_1(struct __kfifo *fifo, void __user *to,
> + unsigned long len, unsigned int *copied)
> +{
> + unsigned int l;
> + unsigned long ret;
> + unsigned long off;
> + int err = 0;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> +
> + off = fifo->out & fifo->mask;
> +
> + l = min(len, size - off);
> + ret = copy_to_user(to, data + off, l);
> +
> + if (unlikely(ret)) {
> + ret = l - ret;
> + err = -EFAULT;
> + } else {
> + ret = copy_to_user(to + l, data, len - l);
> + if (unlikely(ret))
> + err = -EFAULT;
> + ret = len - ret;
> + }
> + smp_wmb();
> + fifo->out += ret;
> + if (copied)
> + *copied = ret;
> + return err;
> +}
> +EXPORT_SYMBOL(__kfifo_to_user_1);
> +
> +unsigned int __kfifo_dma_in_prepare_1(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (!nents)
> + BUG();
> +
> + l = size - (fifo->in - fifo->out);
> + if (len > l)
> + len = l;
> + if (!len)
> + return 0;
> +
> + off = fifo->in & fifo->mask;
> +
> + return setup_sgl(data, size, sgl, nents, len, off);
> +}
> +EXPORT_SYMBOL(__kfifo_dma_in_prepare_1);
> +
> +unsigned int __kfifo_dma_out_prepare_1(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (!nents)
> + BUG();
> +
> + l = fifo->in - fifo->out;
> + if (len > l)
> + len = l;
> + if (!len)
> + return 0;
> +
> + off = fifo->out & fifo->mask;
> +
> + return setup_sgl(data, size, sgl, nents, len, off);
> +}
> +EXPORT_SYMBOL(__kfifo_dma_out_prepare_1);
> +
> +#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
> + */
> +static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize)
> +{
> + unsigned int l;
> + unsigned int mask = fifo->mask;
> + unsigned char *data = fifo->data;
> +
> + l = __KFIFO_PEEK(data, fifo->out, mask);
> +
> + if (--recsize)
> + l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8;
> +
> + return l;
> +}
> +
> +#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 next record into the fifo
> + */
> +static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize)
> +{
> + unsigned int mask = fifo->mask;
> + unsigned char *data = fifo->data;
> +
> + __KFIFO_POKE(data, fifo->in, mask, n);
> +
> + if (--recsize)
> + __KFIFO_POKE(data, fifo->in + 1, mask, n >> 8);
> +}
> +
> +unsigned int __kfifo_peek_reclen(struct __kfifo *fifo, size_t recsize)
> +{
> + return __kfifo_peek_n(fifo, recsize);
> +}
> +EXPORT_SYMBOL(__kfifo_peek_reclen);
> +
> +unsigned int __kfifo_in_rec(struct __kfifo *fifo, const void *buf,
> + unsigned int len, size_t recsize)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = size - (fifo->in - fifo->out);
> + if (len + recsize > l)
> + return 0;
> +
> + __kfifo_poke_n(fifo, len, recsize);
> +
> + off = (fifo->in + recsize) & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(data + off, buf, l);
> + memcpy(data, buf + l, len - l);
> +
> + smp_wmb();
> + fifo->in += len + recsize;
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_in_rec);
> +
> +unsigned int __kfifo_out_rec(struct __kfifo *fifo, void *buf,
> + unsigned int len, size_t recsize)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int n;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (fifo->in == fifo->out)
> + return 0;
> +
> + n = __kfifo_peek_n(fifo, recsize);
> + if (len > n)
> + len = n;
> +
> + off = (fifo->out + recsize) & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(buf, data + off, l);
> + memcpy(buf + l, data, len - l);
> +
> + smp_wmb();
> + fifo->out += n + recsize;
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_out_rec);
> +
> +unsigned int __kfifo_out_peek_rec(struct __kfifo *fifo, void *buf,
> + unsigned int len, size_t recsize)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int n;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (fifo->in == fifo->out)
> + return 0;
> +
> + n = __kfifo_peek_n(fifo, recsize);
> + if (len > n)
> + len = n;
> +
> + off = (fifo->out + recsize) & fifo->mask;
> +
> + l = min(len, size - off);
> + memcpy(buf, data + off, l);
> + memcpy(buf + l, data, len - l);
> +
> + smp_wmb();
> + return len;
> +}
> +EXPORT_SYMBOL(__kfifo_out_peek_rec);
> +
> +int __kfifo_from_user_rec(struct __kfifo *fifo, const void __user *from,
> + unsigned long len, unsigned int *copied, size_t recsize)
> +{
> + unsigned int l;
> + unsigned long ret;
> + unsigned long off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + l = size - (fifo->in - fifo->out);
> + if (len + recsize > l) {
> + *copied = 0;
> + return 0;
> + }
> +
> + __kfifo_poke_n(fifo, len, recsize);
> +
> + off = (fifo->in + recsize) & fifo->mask;
> +
> + l = min(len, size - off);
> + ret = copy_from_user(data + off, from, l);
> +
> + if (unlikely(ret))
> + return -EFAULT;
> +
> + ret = copy_from_user(data, from + l, len - l);
> + if (unlikely(ret))
> + return -EFAULT;
> +
> + smp_wmb();
> + fifo->in += len + recsize;
> + if (copied)
> + *copied = len;
> + return 0;
> +}
> +EXPORT_SYMBOL(__kfifo_from_user_rec);
> +
> +int __kfifo_to_user_rec(struct __kfifo *fifo, void __user *to,
> + unsigned long len, unsigned int *copied, size_t recsize)
> +{
> + unsigned int l;
> + unsigned long ret;
> + unsigned long off;
> + unsigned int n;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (fifo->in == fifo->out) {
> + *copied = 0;
> + return 0;
> + }
> +
> + n = __kfifo_peek_n(fifo, recsize);
> + if (len > n)
> + len = n;
> +
> + off = (fifo->out + recsize) & fifo->mask;
> +
> + l = min(len, size - off);
> + ret = copy_to_user(to, data + off, l);
> +
> + if (unlikely(ret))
> + return -EFAULT;
> +
> + ret = copy_to_user(to + l, data, len - l);
> + if (unlikely(ret))
> + return -EFAULT;
> +
> + smp_wmb();
> + fifo->out += n + recsize;
> + if (copied)
> + *copied = len;
> + return 0;
> +}
> +EXPORT_SYMBOL(__kfifo_to_user_rec);
> +
> +unsigned int __kfifo_dma_in_prepare_rec(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (!nents)
> + BUG();
> +
> + switch (recsize) {
> + case 1:
> + if (len > 255)
> + len = 255;
> + break;
> + case 2:
> + if (len > 65535)
> + len = 65535;
> + }
> +
> + l = size - (fifo->in - fifo->out);
> + if (len + recsize > l)
> + return 0;
> +
> + off = (fifo->in + recsize) & fifo->mask;
> +
> + return setup_sgl(data, size, sgl, nents, len, off);
> +}
> +EXPORT_SYMBOL(__kfifo_dma_in_prepare_rec);
> +
> +void __kfifo_dma_in_finish_rec(struct __kfifo *fifo,
> + unsigned int len, size_t recsize)
> +{
> + void *data = fifo->data;
> +
> + __kfifo_poke_n(fifo, len, recsize);
> + fifo->in += len + recsize;
> +}
> +EXPORT_SYMBOL(__kfifo_dma_in_finish_rec);
> +
> +unsigned int __kfifo_dma_out_prepare_rec(struct __kfifo *fifo,
> + struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
> +{
> + unsigned int l;
> + unsigned int off;
> + unsigned int size = fifo->mask + 1;
> + void *data = fifo->data;
> +
> + if (!nents)
> + BUG();
> +
> + switch (recsize) {
> + case 1:
> + if (len > 255)
> + len = 255;
> + break;
> + case 2:
> + if (len > 65535)
> + len = 65535;
> + }
> +
> + l = fifo->in - fifo->out;
> + if (len + recsize > l)
> + return 0;
> +
> + off = (fifo->out + recsize) & fifo->mask;
> +
> + return setup_sgl(data, size, sgl, nents, len, off);
> +}
> +EXPORT_SYMBOL(__kfifo_dma_out_prepare_rec);
> +
> +
> +void __kfifo_dma_out_finish_rec(struct __kfifo *fifo,
> + unsigned int len, size_t recsize)
> +{
> + void *data = fifo->data;
> +
> + len = __kfifo_peek_n(fifo, recsize);
> + fifo->out += len + recsize;
> +}
> +EXPORT_SYMBOL(__kfifo_dma_out_finish_rec);
> +
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists