Commit 2e956fb3 authored by Stefani Seibold's avatar Stefani Seibold Committed by Linus Torvalds

kfifo: replace the old non generic API

Simply replace the whole kfifo.c and kfifo.h files with the new generic
version and fix the kerneldoc API template file.
Signed-off-by: default avatarStefani Seibold <stefani@seibold.net>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 4201d9a8
...@@ -132,7 +132,6 @@ X!Ilib/string.c ...@@ -132,7 +132,6 @@ X!Ilib/string.c
<title>FIFO Buffer</title> <title>FIFO Buffer</title>
<sect1><title>kfifo interface</title> <sect1><title>kfifo interface</title>
!Iinclude/linux/kfifo.h !Iinclude/linux/kfifo.h
!Ekernel/kfifo.c
</sect1> </sect1>
</chapter> </chapter>
......
/*
* A generic kernel FIFO implementation
*
* Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.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_spinlocked and kfifo_get
* into kfifo_out_spinlocked
* Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc
* must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked
* 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;
unsigned int esize;
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);
/*
* helper macro to distinguish between real in place fifo where the fifo
* array is a part of the structure and the fifo type where the array is
* outside of the fifo structure.
*/
#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo))
/**
* DECLARE_KFIFO_PTR - macro to declare a fifo pointer object
* @fifo: name of the declared fifo
* @type: type of the fifo elements
*/
#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) 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
/**
* INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO
* @fifo: name of the declared fifo datatype
*/
#define INIT_KFIFO(fifo) \
(void)({ \
typeof(&(fifo)) __tmp = &(fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__kfifo->in = 0; \
__kfifo->out = 0; \
__kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\
__kfifo->esize = sizeof(*__tmp->buf); \
__kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \
})
/**
* 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) = \
(typeof(fifo)) { \
{ \
{ \
.in = 0, \
.out = 0, \
.mask = __is_kfifo_ptr(&(fifo)) ? \
0 : \
ARRAY_SIZE((fifo).buf) - 1, \
.esize = sizeof(*(fifo).buf), \
.data = __is_kfifo_ptr(&(fifo)) ? \
NULL : \
(fifo).buf, \
} \
} \
}
static inline unsigned int __must_check
__kfifo_must_check_helper(unsigned int val)
{
return val;
}
/**
* kfifo_initialized - Check if the fifo is initialized
* @fifo: address of the fifo to check
*
* Return %true if fifo is initialized, otherwise %false.
* Assumes the fifo was 0 before.
*/
#define kfifo_initialized(fifo) ((fifo)->kfifo.mask)
/**
* kfifo_esize - returns the size of the element managed by the fifo
* @fifo: address of the fifo to be used
*/
#define kfifo_esize(fifo) ((fifo)->kfifo.esize)
/**
* kfifo_recsize - returns the size of the record length field
* @fifo: address of the fifo to be used
*/
#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype))
/**
* kfifo_size - returns the size of the fifo in elements
* @fifo: address of the fifo to be used
*/
#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1)
/**
* kfifo_reset - removes the entire fifo content
* @fifo: address of 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: address of 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: address of 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: address of 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: address of 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 unused elements in the fifo
* @fifo: address of the fifo to be used
*/
#define kfifo_avail(fifo) \
__kfifo_must_check_helper( \
({ \
typeof(fifo + 1) __tmpq = (fifo); \
const size_t __recsize = sizeof(*__tmpq->rectype); \
unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \
(__recsize) ? ((__avail <= __recsize) ? 0 : \
__kfifo_max_r(__avail - __recsize, __recsize)) : \
__avail; \
}) \
)
/**
* kfifo_skip - skip output data
* @fifo: address of 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_r(__kfifo, __recsize); \
else \
__kfifo->out++; \
})
/**
* kfifo_peek_len - gets the size of the next fifo record
* @fifo: address of the fifo to be used
*
* This function returns the size of the next fifo record in number of bytes.
*/
#define kfifo_peek_len(fifo) \
__kfifo_must_check_helper( \
({ \
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_len_r(__kfifo, __recsize); \
}) \
)
/**
* kfifo_alloc - dynamically allocates a new fifo buffer
* @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 buffer.
*
* 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_must_check_helper( \
({ \
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
*
* This macro initialize a fifo using a preallocated buffer.
*
* The numer of elements will be rounded-up to a power of 2.
* Return 0 if no error, otherwise an error code.
*/
#define kfifo_init(fifo, buffer, size) \
({ \
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: address of the fifo to be used
* @val: the data to be added
*
* This macro copies the given value into the fifo.
* It returns 0 if the fifo was full. Otherwise it returns the number
* processed elements.
*
* 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_r(__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: address of the fifo to be used
* @val: the var where to store the data to be added
*
* This macro reads the data from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* 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) \
__kfifo_must_check_helper( \
({ \
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_r(__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: address of the fifo to be used
* @val: the var where to store the data to be added
*
* This reads the data from the fifo without removing it from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* 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) \
__kfifo_must_check_helper( \
({ \
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))NULL; \
if (__recsize) \
__ret = __kfifo_out_peek_r(__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 - put data into the fifo
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
*
* This macro copies the given 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); \
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; \
} \
(__recsize) ?\
__kfifo_in_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_in(__kfifo, __buf, __n); \
})
/**
* kfifo_in_spinlocked - put data into the fifo using a spinlock for locking
* @fifo: address of 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_spinlocked(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; \
})
/* alias for kfifo_in_spinlocked, will be removed in a future release */
#define kfifo_in_locked(fifo, buf, n, lock) \
kfifo_in_spinlocked(fifo, buf, n, lock)
/**
* kfifo_out - get data from the fifo
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
*
* This macro get some 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_must_check_helper( \
({ \
typeof(fifo + 1) __tmp = (fifo); \
typeof(buf + 1) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (0) { \
typeof(__tmp->ptr) __dummy = NULL; \
__buf = __dummy; \
} \
(__recsize) ?\
__kfifo_out_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out(__kfifo, __buf, __n); \
}) \
)
/**
* kfifo_out_spinlocked - get data from the fifo using a spinlock for locking
* @fifo: address of 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_spinlocked(fifo, buf, n, lock) \
__kfifo_must_check_helper( \
({ \
unsigned long __flags; \
unsigned int __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_out(fifo, buf, n); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
}) \
)
/* alias for kfifo_out_spinlocked, will be removed in a future release */
#define kfifo_out_locked(fifo, buf, n, lock) \
kfifo_out_spinlocked(fifo, buf, n, lock)
/**
* kfifo_from_user - puts some data from user space into the fifo
* @fifo: address of 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_must_check_helper( \
({ \
typeof(fifo + 1) __tmp = (fifo); \
const void __user *__from = (from); \
unsigned int __len = (len); \
unsigned int *__copied = (copied); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \
__kfifo_from_user(__kfifo, __from, __len, __copied); \
}) \
)
/**
* kfifo_to_user - copies data from the fifo into user space
* @fifo: address of 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_must_check_helper( \
({ \
typeof(fifo + 1) __tmp = (fifo); \
void __user *__to = (to); \
unsigned int __len = (len); \
unsigned int *__copied = (copied); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \
__kfifo_to_user(__kfifo, __to, __len, __copied); \
}) \
)
/**
* kfifo_dma_in_prepare - setup a scatterlist for DMA input
* @fifo: address of the fifo to be used
* @sgl: pointer to the scatterlist array
* @nents: number of entries in the scatterlist array
* @len: number of elements to transfer
*
* This macro fills a scatterlist for DMA input.
* It returns the number entries in the scatterlist array.
*
* 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); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \
__kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len); \
})
/**
* kfifo_dma_in_finish - finish a DMA IN operation
* @fifo: address of 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_r(__kfifo, __len, __recsize); \
else \
__kfifo->in += __len / sizeof(*__tmp->type); \
})
/**
* kfifo_dma_out_prepare - setup a scatterlist for DMA output
* @fifo: address of the fifo to be used
* @sgl: pointer to the scatterlist array
* @nents: number of entries in the scatterlist array
* @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 entries in the scatterlist array.
* 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); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \
__kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len); \
})
/**
* kfifo_dma_out_finish - finish a DMA OUT operation
* @fifo: address of 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_r(__kfifo, __recsize); \
else \
__kfifo->out += __len / sizeof(*__tmp->type); \
})
/**
* kfifo_out_peek - gets some data from the fifo
* @fifo: address of 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_must_check_helper( \
({ \
typeof(fifo + 1) __tmp = (fifo); \
typeof(buf + 1) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (0) { \
typeof(__tmp->ptr) __dummy __attribute__ ((unused)) = NULL; \
__buf = __dummy; \
} \
(__recsize) ? \
__kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out_peek(__kfifo, __buf, __n); \
}) \
)
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,
const void *buf, unsigned int len);
extern unsigned int __kfifo_out(struct __kfifo *fifo,
void *buf, unsigned int len);
extern int __kfifo_from_user(struct __kfifo *fifo,
const void __user *from, unsigned long len, unsigned int *copied);
extern int __kfifo_to_user(struct __kfifo *fifo,
void __user *to, unsigned long len, unsigned int *copied);
extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len);
extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len);
extern unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void *buf, unsigned int len);
extern unsigned int __kfifo_in_r(struct __kfifo *fifo,
const void *buf, unsigned int len, size_t recsize);
extern unsigned int __kfifo_out_r(struct __kfifo *fifo,
void *buf, unsigned int len, size_t recsize);
extern int __kfifo_from_user_r(struct __kfifo *fifo,
const void __user *from, unsigned long len, unsigned int *copied,
size_t recsize);
extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
unsigned long len, unsigned int *copied, size_t recsize);
extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
unsigned int len, size_t recsize);
extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize);
extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize);
extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo,
void *buf, unsigned int len, size_t recsize);
extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize);
#endif
/* /*
* A generic kernel FIFO implementation. * A generic kernel FIFO implementation
* *
* Copyright (C) 2009 Stefani Seibold <stefani@seibold.net> * Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
* Copyright (C) 2004 Stelian Pop <stelian@popies.net>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -20,8 +19,11 @@ ...@@ -20,8 +19,11 @@
* *
*/ */
#ifndef _LINUX_KFIFO_H
#define _LINUX_KFIFO_H
/* /*
* Howto porting drivers to the new generic fifo API: * How to porting drivers to the new generic FIFO API:
* *
* - Modify the declaration of the "struct kfifo *" object into a * - Modify the declaration of the "struct kfifo *" object into a
* in-place "struct kfifo" object * in-place "struct kfifo" object
...@@ -30,586 +32,813 @@ ...@@ -30,586 +32,813 @@
* passed as the first argument to this functions * passed as the first argument to this functions
* - Replace the use of __kfifo_put into kfifo_in and __kfifo_get * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get
* into kfifo_out * into kfifo_out
* - Replace the use of kfifo_put into kfifo_in_locked and kfifo_get * - Replace the use of kfifo_put into kfifo_in_spinlocked and kfifo_get
* into kfifo_out_locked * into kfifo_out_spinlocked
* Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc
* must be passed now to the kfifo_in_locked and kfifo_out_locked * must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked
* as the last parameter. * as the last parameter
* - All formerly name __kfifo_* functions has been renamed into kfifo_* * - The formerly __kfifo_* functions are renamed into kfifo_*
*/ */
#ifndef _LINUX_KFIFO_H /*
#define _LINUX_KFIFO_H * 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/kernel.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/stddef.h>
struct kfifo { #include <linux/scatterlist.h>
unsigned char *buffer; /* the buffer holding the data */
unsigned int size; /* the size of the allocated buffer */ struct __kfifo {
unsigned int in; /* data is added at offset (in % size) */ unsigned int in;
unsigned int out; /* data is extracted from off. (out % size) */ unsigned int out;
unsigned int mask;
unsigned int esize;
void *data;
}; };
/* #define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \
* Macros for declaration and initialization of the kfifo datatype union { \
*/ struct __kfifo kfifo; \
datatype *type; \
/* helper macro */ char (*rectype)[recsize]; \
#define __kfifo_initializer(s, b) \ ptrtype *ptr; \
(struct kfifo) { \ const ptrtype *ptr_const; \
.size = s, \
.in = 0, \
.out = 0, \
.buffer = b \
} }
/** #define __STRUCT_KFIFO(type, size, recsize, ptrtype) \
* DECLARE_KFIFO - macro to declare a kfifo and the associated buffer { \
* @name: name of the declared kfifo datatype __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
* @size: size of the fifo buffer. Must be a power of two. type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
*
* 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)]; \
} }
/** #define STRUCT_KFIFO(type, size) \
* INIT_KFIFO - Initialize a kfifo declared by DECLARE_KFIFO struct __STRUCT_KFIFO(type, size, 0, type)
* @name: name of the declared kfifo datatype
#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
*/ */
#define INIT_KFIFO(name) \ struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);
name = __kfifo_initializer(sizeof(name##kfifo_buffer) - \
sizeof(struct kfifo), \
name##kfifo_buffer + sizeof(struct kfifo))
/** #define STRUCT_KFIFO_REC_1(size) \
* DEFINE_KFIFO - macro to define and initialize a kfifo struct __STRUCT_KFIFO(unsigned char, size, 1, void)
* @name: name of the declared kfifo datatype
* @size: size of the fifo buffer. Must be a power of two. #define STRUCT_KFIFO_REC_2(size) \
* struct __STRUCT_KFIFO(unsigned char, size, 2, void)
* 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 * define kfifo_rec types
* object named name##kfifo_buffer
*/ */
#define DEFINE_KFIFO(name, size) \ struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void);
unsigned char name##kfifo_buffer[size]; \ struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void);
struct kfifo name = __kfifo_initializer(size, name##kfifo_buffer)
extern void kfifo_init(struct kfifo *fifo, void *buffer, /*
unsigned int size); * helper macro to distinguish between real in place fifo where the fifo
extern __must_check int kfifo_alloc(struct kfifo *fifo, unsigned int size, * array is a part of the structure and the fifo type where the array is
gfp_t gfp_mask); * outside of the fifo structure.
extern void kfifo_free(struct kfifo *fifo); */
extern unsigned int kfifo_in(struct kfifo *fifo, #define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo))
const void *from, unsigned int len);
extern __must_check unsigned int kfifo_out(struct kfifo *fifo,
void *to, unsigned int len);
extern __must_check unsigned int kfifo_out_peek(struct kfifo *fifo,
void *to, unsigned int len, unsigned offset);
/** /**
* kfifo_initialized - Check if kfifo is initialized. * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object
* @fifo: fifo to check * @fifo: name of the declared fifo
* Return %true if FIFO is initialized, otherwise %false. * @type: type of the fifo elements
* Assumes the fifo was 0 before.
*/ */
static inline bool kfifo_initialized(struct kfifo *fifo) #define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo
{
return fifo->buffer != NULL;
}
/** /**
* kfifo_reset - removes the entire FIFO contents * DECLARE_KFIFO - macro to declare a fifo object
* @fifo: the fifo to be emptied. * @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
*/ */
static inline void kfifo_reset(struct kfifo *fifo) #define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo
{
fifo->in = fifo->out = 0;
}
/** /**
* kfifo_reset_out - skip FIFO contents * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO
* @fifo: the fifo to be emptied. * @fifo: name of the declared fifo datatype
*/ */
static inline void kfifo_reset_out(struct kfifo *fifo) #define INIT_KFIFO(fifo) \
{ (void)({ \
smp_mb(); typeof(&(fifo)) __tmp = &(fifo); \
fifo->out = fifo->in; struct __kfifo *__kfifo = &__tmp->kfifo; \
} __kfifo->in = 0; \
__kfifo->out = 0; \
__kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\
__kfifo->esize = sizeof(*__tmp->buf); \
__kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \
})
/** /**
* kfifo_size - returns the size of the fifo in bytes * DEFINE_KFIFO - macro to define and initialize a fifo
* @fifo: the fifo to be used. * @fifo: name of the declared fifo datatype
*/ * @type: type of the fifo elements
static inline __must_check unsigned int kfifo_size(struct kfifo *fifo) * @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) = \
(typeof(fifo)) { \
{ \
{ \
.in = 0, \
.out = 0, \
.mask = __is_kfifo_ptr(&(fifo)) ? \
0 : \
ARRAY_SIZE((fifo).buf) - 1, \
.esize = sizeof(*(fifo).buf), \
.data = __is_kfifo_ptr(&(fifo)) ? \
NULL : \
(fifo).buf, \
} \
} \
}
static inline unsigned int __must_check
__kfifo_must_check_helper(unsigned int val)
{ {
return fifo->size; return val;
} }
/** /**
* kfifo_len - returns the number of used bytes in the FIFO * kfifo_initialized - Check if the fifo is initialized
* @fifo: the fifo to be used. * @fifo: address of the fifo to check
*
* Return %true if fifo is initialized, otherwise %false.
* Assumes the fifo was 0 before.
*/ */
static inline unsigned int kfifo_len(struct kfifo *fifo) #define kfifo_initialized(fifo) ((fifo)->kfifo.mask)
{
register unsigned int out;
out = fifo->out;
smp_rmb();
return fifo->in - out;
}
/** /**
* kfifo_is_empty - returns true if the fifo is empty * kfifo_esize - returns the size of the element managed by the fifo
* @fifo: the fifo to be used. * @fifo: address of the fifo to be used
*/ */
static inline __must_check bool kfifo_is_empty(struct kfifo *fifo) #define kfifo_esize(fifo) ((fifo)->kfifo.esize)
{
return fifo->in == fifo->out;
}
/** /**
* kfifo_is_full - returns true if the fifo is full * kfifo_recsize - returns the size of the record length field
* @fifo: the fifo to be used. * @fifo: address of the fifo to be used
*/ */
static inline __must_check bool kfifo_is_full(struct kfifo *fifo) #define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype))
{
return kfifo_len(fifo) == kfifo_size(fifo);
}
/** /**
* kfifo_avail - returns the number of bytes available in the FIFO * kfifo_size - returns the size of the fifo in elements
* @fifo: the fifo to be used. * @fifo: address of the fifo to be used
*/ */
static inline __must_check unsigned int kfifo_avail(struct kfifo *fifo) #define kfifo_size(fifo) ((fifo)->kfifo.mask + 1)
{
return kfifo_size(fifo) - kfifo_len(fifo);
}
/** /**
* kfifo_in_locked - puts some data into the FIFO using a spinlock for locking * kfifo_reset - removes the entire fifo content
* @fifo: the fifo to be used. * @fifo: address of 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 @n bytes from the @from buffer into * Note: usage of kfifo_reset() is dangerous. It should be only called when the
* the FIFO depending on the free space, and returns the number of * fifo is exclusived locked or when it is secured that no other thread is
* bytes copied. * accessing the fifo.
*/ */
static inline unsigned int kfifo_in_locked(struct kfifo *fifo, #define kfifo_reset(fifo) \
const void *from, unsigned int n, spinlock_t *lock) (void)({ \
{ typeof(fifo + 1) __tmp = (fifo); \
unsigned long flags; __tmp->kfifo.in = __tmp->kfifo.out = 0; \
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 * kfifo_reset_out - skip fifo content
* @fifo: the fifo to be used. * @fifo: address of 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 @n bytes from the FIFO into the * Note: The usage of kfifo_reset_out() is safe until it will be only called
* @to buffer and returns the number of copied bytes. * 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().
static inline __must_check unsigned int kfifo_out_locked(struct kfifo *fifo,
void *to, unsigned int n, spinlock_t *lock)
{
unsigned long flags;
unsigned int ret;
spin_lock_irqsave(lock, flags);
ret = kfifo_out(fifo, to, n);
spin_unlock_irqrestore(lock, flags);
return ret;
}
extern void kfifo_skip(struct kfifo *fifo, unsigned int len);
extern __must_check int kfifo_from_user(struct kfifo *fifo,
const void __user *from, unsigned int n, unsigned *lenout);
extern __must_check int kfifo_to_user(struct kfifo *fifo,
void __user *to, unsigned int n, unsigned *lenout);
/*
* __kfifo_add_out internal helper function for updating the out offset
*/ */
static inline void __kfifo_add_out(struct kfifo *fifo, #define kfifo_reset_out(fifo) \
unsigned int off) (void)({ \
{ typeof(fifo + 1) __tmp = (fifo); \
smp_mb(); __tmp->kfifo.out = __tmp->kfifo.in; \
fifo->out += off; })
}
/* /**
* __kfifo_add_in internal helper function for updating the in offset * kfifo_len - returns the number of used elements in the fifo
* @fifo: address of the fifo to be used
*/ */
static inline void __kfifo_add_in(struct kfifo *fifo, #define kfifo_len(fifo) \
unsigned int off) ({ \
{ typeof(fifo + 1) __tmpl = (fifo); \
smp_wmb(); __tmpl->kfifo.in - __tmpl->kfifo.out; \
fifo->in += off; })
}
/* /**
* __kfifo_off internal helper function for calculating the index of a * kfifo_is_empty - returns true if the fifo is empty
* given offeset * @fifo: address of the fifo to be used
*/ */
static inline unsigned int __kfifo_off(struct kfifo *fifo, unsigned int off) #define kfifo_is_empty(fifo) \
{ ({ \
return off & (fifo->size - 1); typeof(fifo + 1) __tmpq = (fifo); \
} __tmpq->kfifo.in == __tmpq->kfifo.out; \
})
/* /**
* __kfifo_peek_n internal helper function for determinate the length of * kfifo_is_full - returns true if the fifo is full
* the next record in the fifo * @fifo: address of the fifo to be used
*/ */
static inline unsigned int __kfifo_peek_n(struct kfifo *fifo, #define kfifo_is_full(fifo) \
unsigned int recsize) ({ \
{ typeof(fifo + 1) __tmpq = (fifo); \
#define __KFIFO_GET(fifo, off, shift) \ kfifo_len(__tmpq) > __tmpq->kfifo.mask; \
((fifo)->buffer[__kfifo_off((fifo), (fifo)->out+(off))] << (shift)) })
unsigned int l; /**
* kfifo_avail - returns the number of unused elements in the fifo
* @fifo: address of the fifo to be used
*/
#define kfifo_avail(fifo) \
__kfifo_must_check_helper( \
({ \
typeof(fifo + 1) __tmpq = (fifo); \
const size_t __recsize = sizeof(*__tmpq->rectype); \
unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \
(__recsize) ? ((__avail <= __recsize) ? 0 : \
__kfifo_max_r(__avail - __recsize, __recsize)) : \
__avail; \
}) \
)
l = __KFIFO_GET(fifo, 0, 0); /**
* kfifo_skip - skip output data
* @fifo: address of 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_r(__kfifo, __recsize); \
else \
__kfifo->out++; \
})
if (--recsize) /**
l |= __KFIFO_GET(fifo, 1, 8); * kfifo_peek_len - gets the size of the next fifo record
* @fifo: address of the fifo to be used
*
* This function returns the size of the next fifo record in number of bytes.
*/
#define kfifo_peek_len(fifo) \
__kfifo_must_check_helper( \
({ \
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_len_r(__kfifo, __recsize); \
}) \
)
return l; /**
#undef __KFIFO_GET * kfifo_alloc - dynamically allocates a new fifo buffer
} * @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 buffer.
*
* 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_must_check_helper( \
({ \
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_poke_n internal helper function for storing the length of * kfifo_free - frees the fifo
* the next record into the fifo * @fifo: the fifo to be freed
*/ */
static inline void __kfifo_poke_n(struct kfifo *fifo, #define kfifo_free(fifo) \
unsigned int recsize, unsigned int n) ({ \
{ typeof(fifo + 1) __tmp = (fifo); \
#define __KFIFO_PUT(fifo, off, val, shift) \ struct __kfifo *__kfifo = &__tmp->kfifo; \
( \ if (__is_kfifo_ptr(__tmp)) \
(fifo)->buffer[__kfifo_off((fifo), (fifo)->in+(off))] = \ __kfifo_free(__kfifo); \
(unsigned char)((val) >> (shift)) \ })
)
__KFIFO_PUT(fifo, 0, n, 0); /**
* 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
*
* This macro initialize a fifo using a preallocated buffer.
*
* The numer of elements will be rounded-up to a power of 2.
* Return 0 if no error, otherwise an error code.
*/
#define kfifo_init(fifo, buffer, size) \
({ \
typeof(fifo + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__is_kfifo_ptr(__tmp) ? \
__kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \
-EINVAL; \
})
if (--recsize) /**
__KFIFO_PUT(fifo, 1, n, 8); * kfifo_put - put data into the fifo
#undef __KFIFO_PUT * @fifo: address of the fifo to be used
} * @val: the data to be added
*
* This macro copies the given value into the fifo.
* It returns 0 if the fifo was full. Otherwise it returns the number
* processed elements.
*
* 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_r(__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_in_... internal functions for put date into the fifo * kfifo_get - get data from the fifo
* do not call it directly, use kfifo_in_rec() instead * @fifo: address of the fifo to be used
*/ * @val: the var where to store the data to be added
extern unsigned int __kfifo_in_n(struct kfifo *fifo, *
const void *from, unsigned int n, unsigned int recsize); * This macro reads the data from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* 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) \
__kfifo_must_check_helper( \
({ \
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_r(__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; \
}) \
)
extern unsigned int __kfifo_in_generic(struct kfifo *fifo, /**
const void *from, unsigned int n, unsigned int recsize); * kfifo_peek - get data from the fifo without removing
* @fifo: address of the fifo to be used
* @val: the var where to store the data to be added
*
* This reads the data from the fifo without removing it from the fifo.
* It returns 0 if the fifo was empty. Otherwise it returns the number
* processed elements.
*
* 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) \
__kfifo_must_check_helper( \
({ \
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))NULL; \
if (__recsize) \
__ret = __kfifo_out_peek_r(__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; \
}) \
)
static inline unsigned int __kfifo_in_rec(struct kfifo *fifo, /**
const void *from, unsigned int n, unsigned int recsize) * kfifo_in - put data into the fifo
{ * @fifo: address of the fifo to be used
unsigned int ret; * @buf: the data to be added
* @n: number of elements to be added
*
* This macro copies the given 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); \
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; \
} \
(__recsize) ?\
__kfifo_in_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_in(__kfifo, __buf, __n); \
})
ret = __kfifo_in_n(fifo, from, n, recsize); /**
* kfifo_in_spinlocked - put data into the fifo using a spinlock for locking
* @fifo: address of 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_spinlocked(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; \
})
/* alias for kfifo_in_spinlocked, will be removed in a future release */
#define kfifo_in_locked(fifo, buf, n, lock) \
kfifo_in_spinlocked(fifo, buf, n, lock)
if (likely(ret == 0)) { /**
if (recsize) * kfifo_out - get data from the fifo
__kfifo_poke_n(fifo, recsize, n); * @fifo: address of the fifo to be used
__kfifo_add_in(fifo, n + recsize); * @buf: pointer to the storage buffer
} * @n: max. number of elements to get
return ret; *
} * This macro get some 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_must_check_helper( \
({ \
typeof(fifo + 1) __tmp = (fifo); \
typeof(buf + 1) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (0) { \
typeof(__tmp->ptr) __dummy = NULL; \
__buf = __dummy; \
} \
(__recsize) ?\
__kfifo_out_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out(__kfifo, __buf, __n); \
}) \
)
/**
* kfifo_out_spinlocked - get data from the fifo using a spinlock for locking
* @fifo: address of 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_spinlocked(fifo, buf, n, lock) \
__kfifo_must_check_helper( \
({ \
unsigned long __flags; \
unsigned int __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_out(fifo, buf, n); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
}) \
)
/* alias for kfifo_out_spinlocked, will be removed in a future release */
#define kfifo_out_locked(fifo, buf, n, lock) \
kfifo_out_spinlocked(fifo, buf, n, lock)
/** /**
* kfifo_in_rec - puts some record data into the FIFO * kfifo_from_user - puts some data from user space into the fifo
* @fifo: the fifo to be used. * @fifo: address of the fifo to be used
* @from: the data to be added. * @from: pointer to the data to be added
* @n: the length of the data to be added. * @len: the length of the data to be added
* @recsize: size of record field * @copied: pointer to output variable to store the number of copied bytes
* *
* This function copies @n bytes from the @from into the FIFO and returns * This macro copies at most @len bytes from the @from into the
* the number of bytes which cannot be copied. * fifo, depending of the available space and returns -EFAULT/0.
* 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 * Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions. * writer, you don't need extra locking to use these macro.
*/ */
static inline __must_check unsigned int kfifo_in_rec(struct kfifo *fifo, #define kfifo_from_user(fifo, from, len, copied) \
void *from, unsigned int n, unsigned int recsize) __kfifo_must_check_helper( \
{ ({ \
if (!__builtin_constant_p(recsize)) typeof(fifo + 1) __tmp = (fifo); \
return __kfifo_in_generic(fifo, from, n, recsize); const void __user *__from = (from); \
return __kfifo_in_rec(fifo, from, n, recsize); unsigned int __len = (len); \
} unsigned int *__copied = (copied); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \
__kfifo_from_user(__kfifo, __from, __len, __copied); \
}) \
)
/* /**
* __kfifo_out_... internal functions for get date from the fifo * kfifo_to_user - copies data from the fifo into user space
* do not call it directly, use kfifo_out_rec() instead * @fifo: address of the fifo to be used
*/ * @to: where the data must be copied
extern unsigned int __kfifo_out_n(struct kfifo *fifo, * @len: the size of the destination buffer
void *to, unsigned int reclen, unsigned int recsize); * @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_must_check_helper( \
({ \
typeof(fifo + 1) __tmp = (fifo); \
void __user *__to = (to); \
unsigned int __len = (len); \
unsigned int *__copied = (copied); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \
__kfifo_to_user(__kfifo, __to, __len, __copied); \
}) \
)
/**
* kfifo_dma_in_prepare - setup a scatterlist for DMA input
* @fifo: address of the fifo to be used
* @sgl: pointer to the scatterlist array
* @nents: number of entries in the scatterlist array
* @len: number of elements to transfer
*
* This macro fills a scatterlist for DMA input.
* It returns the number entries in the scatterlist array.
*
* 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); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \
__kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len); \
})
extern unsigned int __kfifo_out_generic(struct kfifo *fifo, /**
void *to, unsigned int n, * kfifo_dma_in_finish - finish a DMA IN operation
unsigned int recsize, unsigned int *total); * @fifo: address of 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_r(__kfifo, __len, __recsize); \
else \
__kfifo->in += __len / sizeof(*__tmp->type); \
})
static inline unsigned int __kfifo_out_rec(struct kfifo *fifo, /**
void *to, unsigned int n, unsigned int recsize, * kfifo_dma_out_prepare - setup a scatterlist for DMA output
unsigned int *total) * @fifo: address of the fifo to be used
{ * @sgl: pointer to the scatterlist array
unsigned int l; * @nents: number of entries in the scatterlist array
* @len: number of elements to transfer
if (!recsize) { *
l = n; * This macro fills a scatterlist for DMA output which at most @len bytes
if (total) * to transfer.
*total = l; * It returns the number entries in the scatterlist array.
} else { * A zero means there is no space available and the scatterlist is not filled.
l = __kfifo_peek_n(fifo, recsize); *
if (total) * Note that with only one concurrent reader and one concurrent
*total = l; * writer, you don't need extra locking to use these macros.
if (n < l) */
return l; #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); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ? \
__kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \
__kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len); \
})
return __kfifo_out_n(fifo, to, l, recsize); /**
} * kfifo_dma_out_finish - finish a DMA OUT operation
* @fifo: address of 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_r(__kfifo, __recsize); \
else \
__kfifo->out += __len / sizeof(*__tmp->type); \
})
/** /**
* kfifo_out_rec - gets some record data from the FIFO * kfifo_out_peek - gets some data from the fifo
* @fifo: the fifo to be used. * @fifo: address of the fifo to be used
* @to: where the data must be copied. * @buf: pointer to the storage buffer
* @n: the size of the destination buffer. * @n: max. number of elements to get
* @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 * This macro get the data from the fifo and return the numbers of elements
* number of bytes which cannot be copied. * copied. The data is not removed from the fifo.
* 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 * Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions. * writer, you don't need extra locking to use these macro.
*/ */
static inline __must_check unsigned int kfifo_out_rec(struct kfifo *fifo, #define kfifo_out_peek(fifo, buf, n) \
void *to, unsigned int n, unsigned int recsize, __kfifo_must_check_helper( \
unsigned int *total) ({ \
typeof(fifo + 1) __tmp = (fifo); \
typeof(buf + 1) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (0) { \
typeof(__tmp->ptr) __dummy __attribute__ ((unused)) = NULL; \
__buf = __dummy; \
} \
(__recsize) ? \
__kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out_peek(__kfifo, __buf, __n); \
}) \
)
{ extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
if (!__builtin_constant_p(recsize)) size_t esize, gfp_t gfp_mask);
return __kfifo_out_generic(fifo, to, n, recsize, total);
return __kfifo_out_rec(fifo, to, n, recsize, total);
}
/* extern void __kfifo_free(struct __kfifo *fifo);
* __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, extern int __kfifo_init(struct __kfifo *fifo, void *buffer,
const void __user *from, unsigned int n, unsigned int recsize); unsigned int size, size_t esize);
static inline unsigned int __kfifo_from_user_rec(struct kfifo *fifo, extern unsigned int __kfifo_in(struct __kfifo *fifo,
const void __user *from, unsigned int n, unsigned int recsize) const void *buf, unsigned int len);
{
unsigned int ret;
ret = __kfifo_from_user_n(fifo, from, n, recsize); extern unsigned int __kfifo_out(struct __kfifo *fifo,
void *buf, unsigned int len);
if (likely(ret == 0)) { extern int __kfifo_from_user(struct __kfifo *fifo,
if (recsize) const void __user *from, unsigned long len, unsigned int *copied);
__kfifo_poke_n(fifo, recsize, n);
__kfifo_add_in(fifo, n + recsize);
}
return ret;
}
/** extern int __kfifo_to_user(struct __kfifo *fifo,
* kfifo_from_user_rec - puts some data from user space into the FIFO void __user *to, unsigned long len, unsigned int *copied);
* @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);
}
/* extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
* __kfifo_to_user_... internal functions for transfer fifo data into user space struct scatterlist *sgl, int nents, unsigned int len);
* 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, extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
void __user *to, unsigned int n, unsigned int recsize, struct scatterlist *sgl, int nents, unsigned int len);
unsigned int *total);
static inline unsigned int __kfifo_to_user_rec(struct kfifo *fifo, extern unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void __user *to, unsigned int n, void *buf, unsigned int len);
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); extern unsigned int __kfifo_in_r(struct __kfifo *fifo,
} const void *buf, unsigned int len, size_t recsize);
/** extern unsigned int __kfifo_out_r(struct __kfifo *fifo,
* kfifo_to_user_rec - gets data from the FIFO and write it to user space void *buf, unsigned int len, size_t recsize);
* @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);
}
/* extern int __kfifo_from_user_r(struct __kfifo *fifo,
* __kfifo_peek_... internal functions for peek into the next fifo record const void __user *from, unsigned long len, unsigned int *copied,
* do not call it directly, use kfifo_peek_rec() instead size_t recsize);
*/
extern unsigned int __kfifo_peek_generic(struct kfifo *fifo,
unsigned int recsize);
/** extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
* kfifo_peek_rec - gets the size of the next FIFO record data unsigned long len, unsigned int *copied, size_t recsize);
* @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);
}
/* extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
* __kfifo_skip_... internal functions for skip the next fifo record struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
* 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, extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
unsigned int recsize) unsigned int len, size_t recsize);
{
unsigned int l;
if (recsize) { extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
l = __kfifo_peek_n(fifo, recsize); struct scatterlist *sgl, int nents, unsigned int len, size_t recsize);
if (l + recsize <= kfifo_len(fifo)) { extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize);
__kfifo_add_out(fifo, l + recsize);
return;
}
}
kfifo_reset_out(fifo);
}
/** extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize);
* 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);
}
/** extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo,
* kfifo_avail_rec - returns the number of bytes available in a record FIFO void *buf, unsigned int len, size_t recsize);
* @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; extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize);
}
#endif #endif
/*
* A generic kernel FIFO implementation
*
* Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.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/log2.h>
#include <linux/uaccess.h>
#include <linux/kfifo.h>
/*
* internal helper to calculate the unused elements in a fifo
*/
static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{
return (fifo->mask + 1) - (fifo->in - fifo->out);
}
int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
size_t esize, gfp_t gfp_mask)
{
/*
* round down 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);
fifo->in = 0;
fifo->out = 0;
fifo->esize = esize;
if (size < 2) {
fifo->data = NULL;
fifo->mask = 0;
return -EINVAL;
}
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->data);
fifo->in = 0;
fifo->out = 0;
fifo->esize = 0;
fifo->data = NULL;
fifo->mask = 0;
}
EXPORT_SYMBOL(__kfifo_free);
int __kfifo_init(struct __kfifo *fifo, void *buffer,
unsigned int size, size_t esize)
{
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;
}
fifo->mask = size - 1;
return 0;
}
EXPORT_SYMBOL(__kfifo_init);
static void kfifo_copy_in(struct __kfifo *fifo, const void *src,
unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
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);
/*
* make sure that the data in the fifo is up to date before
* incrementing the fifo->in index counter
*/
smp_wmb();
}
unsigned int __kfifo_in(struct __kfifo *fifo,
const void *buf, unsigned int len)
{
unsigned int l;
l = kfifo_unused(fifo);
if (len > l)
len = l;
kfifo_copy_in(fifo, buf, len, fifo->in);
fifo->in += len;
return len;
}
EXPORT_SYMBOL(__kfifo_in);
static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
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);
/*
* make sure that the data is copied before
* incrementing the fifo->out index counter
*/
smp_wmb();
}
unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void *buf, unsigned int len)
{
unsigned int l;
l = fifo->in - fifo->out;
if (len > l)
len = l;
kfifo_copy_out(fifo, buf, len, fifo->out);
return len;
}
EXPORT_SYMBOL(__kfifo_out_peek);
unsigned int __kfifo_out(struct __kfifo *fifo,
void *buf, unsigned int len)
{
len = __kfifo_out_peek(fifo, buf, len);
fifo->out += len;
return len;
}
EXPORT_SYMBOL(__kfifo_out);
static unsigned long kfifo_copy_from_user(struct __kfifo *fifo,
const void __user *from, unsigned int len, unsigned int off,
unsigned int *copied)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
unsigned long ret;
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);
}
/*
* make sure that the data in the fifo is up to date before
* incrementing the fifo->in index counter
*/
smp_wmb();
*copied = len - ret;
/* return the number of elements which are not copied */
return ret;
}
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;
if (esize != 1)
len /= esize;
l = kfifo_unused(fifo);
if (len > l)
len = l;
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;
}
EXPORT_SYMBOL(__kfifo_from_user);
static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to,
unsigned int len, unsigned int off, unsigned int *copied)
{
unsigned int l;
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);
}
/*
* make sure that the data is copied before
* incrementing the fifo->out index counter
*/
smp_wmb();
*copied = len - ret;
/* return the number of elements which are not copied */
return ret;
}
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;
if (esize != 1)
len /= esize;
l = fifo->in - fifo->out;
if (len > l)
len = l;
ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied);
if (unlikely(ret)) {
len -= ret;
err = -EFAULT;
} else
err = 0;
fifo->out += len;
return err;
}
EXPORT_SYMBOL(__kfifo_to_user);
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) {
sgl->page_link = 0;
sg_set_page(sgl++, page, l - off, off);
if (++n == nents)
return n;
page = npage;
len -= l - off;
l = off = 0;
}
}
sgl->page_link = 0;
sg_set_page(sgl++, page, len, off);
return n + 1;
}
static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
int nents, unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
unsigned int n;
off &= fifo->mask;
if (esize != 1) {
off *= esize;
size *= esize;
len *= esize;
}
l = min(len, size - off);
n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
if (n)
sg_mark_end(sgl + n - 1);
return n;
}
unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len)
{
unsigned int l;
l = kfifo_unused(fifo);
if (len > l)
len = l;
return setup_sgl(fifo, sgl, nents, len, fifo->in);
}
EXPORT_SYMBOL(__kfifo_dma_in_prepare);
unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len)
{
unsigned int l;
l = fifo->in - fifo->out;
if (len > l)
len = l;
return setup_sgl(fifo, sgl, nents, len, fifo->out);
}
EXPORT_SYMBOL(__kfifo_dma_out_prepare);
unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
{
unsigned int max = (1 << (recsize << 3)) - 1;
if (len > max)
return max;
return len;
}
#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 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 > 1)
__KFIFO_POKE(data, fifo->in + 1, mask, n >> 8);
}
unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize)
{
return __kfifo_peek_n(fifo, recsize);
}
EXPORT_SYMBOL(__kfifo_len_r);
unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf,
unsigned int len, size_t recsize)
{
if (len + recsize > kfifo_unused(fifo))
return 0;
__kfifo_poke_n(fifo, len, recsize);
kfifo_copy_in(fifo, buf, len, fifo->in + recsize);
fifo->in += len + recsize;
return len;
}
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)
{
*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);
}
EXPORT_SYMBOL(__kfifo_out_peek_r);
unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf,
unsigned int len, size_t recsize)
{
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;
}
EXPORT_SYMBOL(__kfifo_out_r);
int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from,
unsigned long len, unsigned int *copied, size_t recsize)
{
unsigned long ret;
len = __kfifo_max_r(len, recsize);
if (len + recsize > kfifo_unused(fifo)) {
*copied = 0;
return 0;
}
__kfifo_poke_n(fifo, len, recsize);
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;
}
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)
{
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;
}
EXPORT_SYMBOL(__kfifo_to_user_r);
unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
{
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);
}
EXPORT_SYMBOL(__kfifo_dma_in_prepare_r);
void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
unsigned int len, size_t recsize)
{
len = __kfifo_max_r(len, recsize);
__kfifo_poke_n(fifo, len, recsize);
fifo->in += len + recsize;
}
EXPORT_SYMBOL(__kfifo_dma_in_finish_r);
unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
{
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);
}
EXPORT_SYMBOL(__kfifo_dma_out_prepare_r);
void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize)
{
unsigned int len;
len = __kfifo_peek_n(fifo, recsize);
fifo->out += len + recsize;
}
EXPORT_SYMBOL(__kfifo_dma_out_finish_r);
/* /*
* A generic kernel FIFO implementation. * A generic kernel FIFO implementation
* *
* Copyright (C) 2009 Stefani Seibold <stefani@seibold.net> * Copyright (C) 2009/2010 Stefani Seibold <stefani@seibold.net>
* Copyright (C) 2004 Stelian Pop <stelian@popies.net>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -24,422 +23,580 @@ ...@@ -24,422 +23,580 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/kfifo.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kfifo.h>
static void _kfifo_init(struct kfifo *fifo, void *buffer, /*
unsigned int size) * internal helper to calculate the unused elements in a fifo
{
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 has to be a power of 2.
*
*/ */
void kfifo_init(struct kfifo *fifo, void *buffer, unsigned int size) static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{ {
/* size must be a power of 2 */ return (fifo->mask + 1) - (fifo->in - fifo->out);
BUG_ON(!is_power_of_2(size));
_kfifo_init(fifo, buffer, size);
} }
EXPORT_SYMBOL(kfifo_init);
/** int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
* kfifo_alloc - allocates a new FIFO internal buffer size_t esize, gfp_t gfp_mask)
* @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 * round down to the next power of 2, since our 'let the indices
* wrap' technique works only in this case. * wrap' technique works only in this case.
*/ */
if (!is_power_of_2(size)) { if (!is_power_of_2(size))
BUG_ON(size > 0x80000000); size = rounddown_pow_of_two(size);
size = roundup_pow_of_two(size);
fifo->in = 0;
fifo->out = 0;
fifo->esize = esize;
if (size < 2) {
fifo->data = NULL;
fifo->mask = 0;
return -EINVAL;
} }
buffer = kmalloc(size, gfp_mask); fifo->data = kmalloc(size * esize, gfp_mask);
if (!buffer) {
_kfifo_init(fifo, NULL, 0); if (!fifo->data) {
fifo->mask = 0;
return -ENOMEM; return -ENOMEM;
} }
fifo->mask = size - 1;
_kfifo_init(fifo, buffer, size);
return 0; return 0;
} }
EXPORT_SYMBOL(kfifo_alloc); EXPORT_SYMBOL(__kfifo_alloc);
/** void __kfifo_free(struct __kfifo *fifo)
* kfifo_free - frees the FIFO internal buffer
* @fifo: the fifo to be freed.
*/
void kfifo_free(struct kfifo *fifo)
{ {
kfree(fifo->buffer); kfree(fifo->data);
_kfifo_init(fifo, NULL, 0); fifo->in = 0;
fifo->out = 0;
fifo->esize = 0;
fifo->data = NULL;
fifo->mask = 0;
} }
EXPORT_SYMBOL(kfifo_free); EXPORT_SYMBOL(__kfifo_free);
/** int __kfifo_init(struct __kfifo *fifo, void *buffer,
* kfifo_skip - skip output data unsigned int size, size_t esize)
* @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)) { size /= esize;
__kfifo_add_out(fifo, len);
return; 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;
} }
kfifo_reset_out(fifo); fifo->mask = size - 1;
return 0;
} }
EXPORT_SYMBOL(kfifo_skip); EXPORT_SYMBOL(__kfifo_init);
static inline void __kfifo_in_data(struct kfifo *fifo, static void kfifo_copy_in(struct __kfifo *fifo, const void *src,
const void *from, unsigned int len, unsigned int off) unsigned int len, unsigned int off)
{ {
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l; unsigned int l;
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);
/* /*
* Ensure that we sample the fifo->out index -before- we * make sure that the data in the fifo is up to date before
* start putting bytes into the kfifo. * incrementing the fifo->in index counter
*/ */
smp_wmb();
}
smp_mb(); unsigned int __kfifo_in(struct __kfifo *fifo,
const void *buf, unsigned int len)
off = __kfifo_off(fifo, fifo->in + off); {
unsigned int l;
/* first put the data starting from fifo->in to buffer end */ l = kfifo_unused(fifo);
l = min(len, fifo->size - off); if (len > l)
memcpy(fifo->buffer + off, from, l); len = l;
/* then put the rest (if any) at the beginning of the buffer */ kfifo_copy_in(fifo, buf, len, fifo->in);
memcpy(fifo->buffer, from + l, len - l); fifo->in += len;
return len;
} }
EXPORT_SYMBOL(__kfifo_in);
static inline void __kfifo_out_data(struct kfifo *fifo, static void kfifo_copy_out(struct __kfifo *fifo, void *dst,
void *to, unsigned int len, unsigned int off) unsigned int len, unsigned int off)
{ {
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l; unsigned int l;
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);
/* /*
* Ensure that we sample the fifo->in index -before- we * make sure that the data is copied before
* start removing bytes from the kfifo. * incrementing the fifo->out index counter
*/ */
smp_wmb();
}
smp_rmb(); unsigned int __kfifo_out_peek(struct __kfifo *fifo,
void *buf, unsigned int len)
{
unsigned int l;
off = __kfifo_off(fifo, fifo->out + off); l = fifo->in - fifo->out;
if (len > l)
len = l;
/* first get the data from fifo->out until the end of the buffer */ kfifo_copy_out(fifo, buf, len, fifo->out);
l = min(len, fifo->size - off); return len;
memcpy(to, fifo->buffer + off, l); }
EXPORT_SYMBOL(__kfifo_out_peek);
/* then get the rest (if any) from the beginning of the buffer */ unsigned int __kfifo_out(struct __kfifo *fifo,
memcpy(to + l, fifo->buffer, len - l); void *buf, unsigned int len)
{
len = __kfifo_out_peek(fifo, buf, len);
fifo->out += len;
return len;
} }
EXPORT_SYMBOL(__kfifo_out);
static inline int __kfifo_from_user_data(struct kfifo *fifo, static unsigned long kfifo_copy_from_user(struct __kfifo *fifo,
const void __user *from, unsigned int len, unsigned int off, const void __user *from, unsigned int len, unsigned int off,
unsigned *lenout) unsigned int *copied)
{ {
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l; unsigned int l;
int ret; unsigned long ret;
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);
}
/* /*
* Ensure that we sample the fifo->out index -before- we * make sure that the data in the fifo is up to date before
* start putting bytes into the kfifo. * incrementing the fifo->in index counter
*/ */
smp_wmb();
*copied = len - ret;
/* return the number of elements which are not copied */
return ret;
}
smp_mb(); 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;
off = __kfifo_off(fifo, fifo->in + off); if (esize != 1)
len /= esize;
/* first put the data starting from fifo->in to buffer end */ l = kfifo_unused(fifo);
l = min(len, fifo->size - off); if (len > l)
ret = copy_from_user(fifo->buffer + off, from, l); len = l;
if (unlikely(ret)) {
*lenout = ret;
return -EFAULT;
}
*lenout = l;
/* then put the rest (if any) at the beginning of the buffer */ ret = kfifo_copy_from_user(fifo, from, len, fifo->in, copied);
ret = copy_from_user(fifo->buffer, from + l, len - l); if (unlikely(ret)) {
*lenout += ret ? ret : len - l; len -= ret;
return ret ? -EFAULT : 0; err = -EFAULT;
} else
err = 0;
fifo->in += len;
return err;
} }
EXPORT_SYMBOL(__kfifo_from_user);
static inline int __kfifo_to_user_data(struct kfifo *fifo, static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to,
void __user *to, unsigned int len, unsigned int off, unsigned *lenout) unsigned int len, unsigned int off, unsigned int *copied)
{ {
unsigned int l; unsigned int l;
int ret; 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);
}
/* /*
* Ensure that we sample the fifo->in index -before- we * make sure that the data is copied before
* start removing bytes from the kfifo. * incrementing the fifo->out index counter
*/ */
smp_wmb();
*copied = len - ret;
/* return the number of elements which are not copied */
return ret;
}
smp_rmb(); 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;
off = __kfifo_off(fifo, fifo->out + off); if (esize != 1)
len /= esize;
/* first get the data from fifo->out until the end of the buffer */ l = fifo->in - fifo->out;
l = min(len, fifo->size - off); if (len > l)
ret = copy_to_user(to, fifo->buffer + off, l); len = l;
*lenout = l; ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied);
if (unlikely(ret)) { if (unlikely(ret)) {
*lenout -= ret; len -= ret;
return -EFAULT; err = -EFAULT;
} } else
err = 0;
fifo->out += len;
return err;
}
EXPORT_SYMBOL(__kfifo_to_user);
/* then get the rest (if any) from the beginning of the buffer */ static int setup_sgl_buf(struct scatterlist *sgl, void *buf,
len -= l; int nents, unsigned int len)
ret = copy_to_user(to + l, fifo->buffer, len); {
if (unlikely(ret)) { int n;
*lenout += len - ret; unsigned int l;
return -EFAULT; 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) {
sgl->page_link = 0;
sg_set_page(sgl++, page, l - off, off);
if (++n == nents)
return n;
page = npage;
len -= l - off;
l = off = 0;
}
} }
*lenout += len; sgl->page_link = 0;
return 0; sg_set_page(sgl++, page, len, off);
return n + 1;
} }
unsigned int __kfifo_in_n(struct kfifo *fifo, static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl,
const void *from, unsigned int len, unsigned int recsize) int nents, unsigned int len, unsigned int off)
{ {
if (kfifo_avail(fifo) < len + recsize) unsigned int size = fifo->mask + 1;
return len + 1; unsigned int esize = fifo->esize;
unsigned int l;
unsigned int n;
__kfifo_in_data(fifo, from, len, recsize); off &= fifo->mask;
return 0; if (esize != 1) {
off *= esize;
size *= esize;
len *= esize;
}
l = min(len, size - off);
n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
if (n)
sg_mark_end(sgl + n - 1);
return n;
} }
EXPORT_SYMBOL(__kfifo_in_n);
/** unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo,
* kfifo_in - puts some data into the FIFO struct scatterlist *sgl, int nents, unsigned int len)
* @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 void *from,
unsigned int len)
{ {
len = min(kfifo_avail(fifo), len); unsigned int l;
__kfifo_in_data(fifo, from, len, 0); l = kfifo_unused(fifo);
__kfifo_add_in(fifo, len); if (len > l)
return len; len = l;
return setup_sgl(fifo, sgl, nents, len, fifo->in);
} }
EXPORT_SYMBOL(kfifo_in); EXPORT_SYMBOL(__kfifo_dma_in_prepare);
unsigned int __kfifo_in_generic(struct kfifo *fifo, unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo,
const void *from, unsigned int len, unsigned int recsize) struct scatterlist *sgl, int nents, unsigned int len)
{ {
return __kfifo_in_rec(fifo, from, len, recsize); unsigned int l;
l = fifo->in - fifo->out;
if (len > l)
len = l;
return setup_sgl(fifo, sgl, nents, len, fifo->out);
} }
EXPORT_SYMBOL(__kfifo_in_generic); EXPORT_SYMBOL(__kfifo_dma_out_prepare);
unsigned int __kfifo_out_n(struct kfifo *fifo, unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
void *to, unsigned int len, unsigned int recsize)
{ {
if (kfifo_len(fifo) < len + recsize) unsigned int max = (1 << (recsize << 3)) - 1;
return len;
__kfifo_out_data(fifo, to, len, recsize); if (len > max)
__kfifo_add_out(fifo, len + recsize); return max;
return 0; return len;
} }
EXPORT_SYMBOL(__kfifo_out_n);
/** #define __KFIFO_PEEK(data, out, mask) \
* kfifo_out - gets some data from the FIFO ((data)[(out) & (mask)])
* @fifo: the fifo to be used. /*
* @to: where the data must be copied. * __kfifo_peek_n internal helper function for determinate the length of
* @len: the size of the destination buffer. * the next record in the fifo
*
* 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, void *to, unsigned int len) static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize)
{ {
len = min(kfifo_len(fifo), len); unsigned int l;
unsigned int mask = fifo->mask;
unsigned char *data = fifo->data;
__kfifo_out_data(fifo, to, len, 0); l = __KFIFO_PEEK(data, fifo->out, mask);
__kfifo_add_out(fifo, len);
return len; if (--recsize)
l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8;
return l;
} }
EXPORT_SYMBOL(kfifo_out);
#define __KFIFO_POKE(data, in, mask, val) \
/** ( \
* kfifo_out_peek - copy some data from the FIFO, but do not remove it (data)[(in) & (mask)] = (unsigned char)(val) \
* @fifo: the fifo to be used. )
* @to: where the data must be copied.
* @len: the size of the destination buffer. /*
* @offset: offset into the fifo * __kfifo_poke_n internal helper function for storeing the length of
* * the record into the fifo
* This function copies at most @len bytes at @offset from the FIFO
* into the @to buffer and returns the number of copied bytes.
* The data is not removed from the FIFO.
*/ */
unsigned int kfifo_out_peek(struct kfifo *fifo, void *to, unsigned int len, static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize)
unsigned offset)
{ {
len = min(kfifo_len(fifo), len + offset); unsigned int mask = fifo->mask;
unsigned char *data = fifo->data;
__kfifo_out_data(fifo, to, len, offset); __KFIFO_POKE(data, fifo->in, mask, n);
return len;
if (recsize > 1)
__KFIFO_POKE(data, fifo->in + 1, mask, n >> 8);
} }
EXPORT_SYMBOL(kfifo_out_peek);
unsigned int __kfifo_out_generic(struct kfifo *fifo, unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize)
void *to, unsigned int len, unsigned int recsize,
unsigned int *total)
{ {
return __kfifo_out_rec(fifo, to, len, recsize, total); return __kfifo_peek_n(fifo, recsize);
} }
EXPORT_SYMBOL(__kfifo_out_generic); EXPORT_SYMBOL(__kfifo_len_r);
unsigned int __kfifo_from_user_n(struct kfifo *fifo, unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf,
const void __user *from, unsigned int len, unsigned int recsize) unsigned int len, size_t recsize)
{ {
unsigned total; if (len + recsize > kfifo_unused(fifo))
return 0;
if (kfifo_avail(fifo) < len + recsize) __kfifo_poke_n(fifo, len, recsize);
return len + 1;
__kfifo_from_user_data(fifo, from, len, recsize, &total); kfifo_copy_in(fifo, buf, len, fifo->in + recsize);
return total; fifo->in += len + recsize;
return len;
} }
EXPORT_SYMBOL(__kfifo_from_user_n); EXPORT_SYMBOL(__kfifo_in_r);
/** static unsigned int kfifo_out_copy_r(struct __kfifo *fifo,
* kfifo_from_user - puts some data from user space into the FIFO void *buf, unsigned int len, size_t recsize, unsigned int *n)
* @fifo: the fifo to be used.
* @from: pointer to the data to be added.
* @len: the length of the data to be added.
* @total: the actual returned data length.
*
* This function copies at most @len bytes from the @from into the
* FIFO depending and returns -EFAULT/0.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/
int kfifo_from_user(struct kfifo *fifo,
const void __user *from, unsigned int len, unsigned *total)
{ {
int ret; *n = __kfifo_peek_n(fifo, recsize);
len = min(kfifo_avail(fifo), len);
ret = __kfifo_from_user_data(fifo, from, len, 0, total); if (len > *n)
if (ret) len = *n;
return ret;
__kfifo_add_in(fifo, len); kfifo_copy_out(fifo, buf, len, fifo->out + recsize);
return 0; 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);
} }
EXPORT_SYMBOL(kfifo_from_user); EXPORT_SYMBOL(__kfifo_out_peek_r);
unsigned int __kfifo_from_user_generic(struct kfifo *fifo, unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf,
const void __user *from, unsigned int len, unsigned int recsize) unsigned int len, size_t recsize)
{ {
return __kfifo_from_user_rec(fifo, from, len, recsize); 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;
} }
EXPORT_SYMBOL(__kfifo_from_user_generic); EXPORT_SYMBOL(__kfifo_out_r);
unsigned int __kfifo_to_user_n(struct kfifo *fifo, int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from,
void __user *to, unsigned int len, unsigned int reclen, unsigned long len, unsigned int *copied, size_t recsize)
unsigned int recsize)
{ {
unsigned int ret, total; unsigned long ret;
if (kfifo_len(fifo) < reclen + recsize) len = __kfifo_max_r(len, recsize);
return len;
ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total); if (len + recsize > kfifo_unused(fifo)) {
*copied = 0;
return 0;
}
if (likely(ret == 0)) __kfifo_poke_n(fifo, len, recsize);
__kfifo_add_out(fifo, reclen + recsize);
return total; 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;
} }
EXPORT_SYMBOL(__kfifo_to_user_n); EXPORT_SYMBOL(__kfifo_from_user_r);
/** int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to,
* kfifo_to_user - gets data from the FIFO and write it to user space unsigned long len, unsigned int *copied, size_t recsize)
* @fifo: the fifo to be used.
* @to: where the data must be copied.
* @len: the size of the destination buffer.
* @lenout: pointer to output variable with copied data
*
* This function copies at most @len bytes from the FIFO into the
* @to buffer and 0 or -EFAULT.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these functions.
*/
int kfifo_to_user(struct kfifo *fifo,
void __user *to, unsigned int len, unsigned *lenout)
{ {
int ret; unsigned long ret;
len = min(kfifo_len(fifo), len); unsigned int n;
ret = __kfifo_to_user_data(fifo, to, len, 0, lenout);
__kfifo_add_out(fifo, *lenout); if (fifo->in == fifo->out) {
return ret; *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;
} }
EXPORT_SYMBOL(kfifo_to_user); EXPORT_SYMBOL(__kfifo_to_user_r);
unsigned int __kfifo_to_user_generic(struct kfifo *fifo, unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo,
void __user *to, unsigned int len, unsigned int recsize, struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
unsigned int *total)
{ {
return __kfifo_to_user_rec(fifo, to, len, recsize, total); 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);
} }
EXPORT_SYMBOL(__kfifo_to_user_generic); EXPORT_SYMBOL(__kfifo_dma_in_prepare_r);
unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize) void __kfifo_dma_in_finish_r(struct __kfifo *fifo,
unsigned int len, size_t recsize)
{ {
if (recsize == 0) len = __kfifo_max_r(len, recsize);
return kfifo_avail(fifo); __kfifo_poke_n(fifo, len, recsize);
fifo->in += len + recsize;
return __kfifo_peek_n(fifo, recsize);
} }
EXPORT_SYMBOL(__kfifo_peek_generic); EXPORT_SYMBOL(__kfifo_dma_in_finish_r);
void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize) unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo,
struct scatterlist *sgl, int nents, unsigned int len, size_t recsize)
{ {
__kfifo_skip_rec(fifo, recsize); 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);
} }
EXPORT_SYMBOL(__kfifo_skip_generic); EXPORT_SYMBOL(__kfifo_dma_out_prepare_r);
void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize)
{
unsigned int len;
len = __kfifo_peek_n(fifo, recsize);
fifo->out += len + recsize;
}
EXPORT_SYMBOL(__kfifo_dma_out_finish_r);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment