2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
2010-08-11 05:03:38 +04:00
* A generic kernel FIFO implementation
2005-04-17 02:20:36 +04:00
*
2010-08-11 05:03:38 +04:00
* Copyright ( C ) 2009 / 2010 Stefani Seibold < stefani @ seibold . net >
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
2011-05-23 22:51:41 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/err.h>
2007-07-16 10:41:34 +04:00
# include <linux/log2.h>
2009-12-22 01:37:31 +03:00
# include <linux/uaccess.h>
2010-08-11 05:03:38 +04:00
# include <linux/kfifo.h>
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
/*
* internal helper to calculate the unused elements in a fifo
2005-04-17 02:20:36 +04:00
*/
2010-08-11 05:03:38 +04:00
static inline unsigned int kfifo_unused ( struct __kfifo * fifo )
2005-04-17 02:20:36 +04:00
{
2010-08-11 05:03:38 +04:00
return ( fifo - > mask + 1 ) - ( fifo - > in - fifo - > out ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-11 05:03:38 +04:00
int __kfifo_alloc ( struct __kfifo * fifo , unsigned int size ,
size_t esize , gfp_t gfp_mask )
2005-04-17 02:20:36 +04:00
{
/*
2018-03-26 21:18:23 +03:00
* round up to the next power of 2 , since our ' let the indices
2009-06-17 02:33:34 +04:00
* wrap ' technique works only in this case .
2005-04-17 02:20:36 +04:00
*/
2013-02-28 05:05:51 +04:00
size = roundup_pow_of_two ( size ) ;
2010-08-11 05:03:38 +04:00
fifo - > in = 0 ;
fifo - > out = 0 ;
fifo - > esize = esize ;
if ( size < 2 ) {
fifo - > data = NULL ;
fifo - > mask = 0 ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
fifo - > data = kmalloc_array ( esize , size , gfp_mask ) ;
2010-08-11 05:03:38 +04:00
if ( ! fifo - > data ) {
fifo - > mask = 0 ;
kfifo: move struct kfifo in place
This is a new generic kernel FIFO implementation.
The current kernel fifo API is not very widely used, because it has to
many constrains. Only 17 files in the current 2.6.31-rc5 used it.
FIFO's are like list's a very basic thing and a kfifo API which handles
the most use case would save a lot of development time and memory
resources.
I think this are the reasons why kfifo is not in use:
- The API is to simple, important functions are missing
- A fifo can be only allocated dynamically
- There is a requirement of a spinlock whether you need it or not
- There is no support for data records inside a fifo
So I decided to extend the kfifo in a more generic way without blowing up
the API to much. The new API has the following benefits:
- Generic usage: For kernel internal use and/or device driver.
- Provide an API for the most use case.
- Slim API: The whole API provides 25 functions.
- Linux style habit.
- DECLARE_KFIFO, DEFINE_KFIFO and INIT_KFIFO Macros
- Direct copy_to_user from the fifo and copy_from_user into the fifo.
- The kfifo itself is an in place member of the using data structure, this save an
indirection access and does not waste the kernel allocator.
- Lockless access: if only one reader and one writer is active on the fifo,
which is the common use case, no additional locking is necessary.
- Remove spinlock - give the user the freedom of choice what kind of locking to use if
one is required.
- Ability to handle records. Three type of records are supported:
- Variable length records between 0-255 bytes, with a record size
field of 1 bytes.
- Variable length records between 0-65535 bytes, with a record size
field of 2 bytes.
- Fixed size records, which no record size field.
- Preserve memory resource.
- Performance!
- Easy to use!
This patch:
Since most users want to have the kfifo as part of another object,
reorganize the code to allow including struct kfifo in another data
structure. This requires changing the kfifo_alloc and kfifo_init
prototypes so that we pass an existing kfifo pointer into them. This
patch changes the implementation and all existing users.
[akpm@linux-foundation.org: fix warning]
Signed-off-by: Stefani Seibold <stefani@seibold.net>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-12-22 01:37:26 +03:00
return - ENOMEM ;
}
2010-08-11 05:03:38 +04:00
fifo - > mask = size - 1 ;
2005-04-17 02:20:36 +04:00
kfifo: move struct kfifo in place
This is a new generic kernel FIFO implementation.
The current kernel fifo API is not very widely used, because it has to
many constrains. Only 17 files in the current 2.6.31-rc5 used it.
FIFO's are like list's a very basic thing and a kfifo API which handles
the most use case would save a lot of development time and memory
resources.
I think this are the reasons why kfifo is not in use:
- The API is to simple, important functions are missing
- A fifo can be only allocated dynamically
- There is a requirement of a spinlock whether you need it or not
- There is no support for data records inside a fifo
So I decided to extend the kfifo in a more generic way without blowing up
the API to much. The new API has the following benefits:
- Generic usage: For kernel internal use and/or device driver.
- Provide an API for the most use case.
- Slim API: The whole API provides 25 functions.
- Linux style habit.
- DECLARE_KFIFO, DEFINE_KFIFO and INIT_KFIFO Macros
- Direct copy_to_user from the fifo and copy_from_user into the fifo.
- The kfifo itself is an in place member of the using data structure, this save an
indirection access and does not waste the kernel allocator.
- Lockless access: if only one reader and one writer is active on the fifo,
which is the common use case, no additional locking is necessary.
- Remove spinlock - give the user the freedom of choice what kind of locking to use if
one is required.
- Ability to handle records. Three type of records are supported:
- Variable length records between 0-255 bytes, with a record size
field of 1 bytes.
- Variable length records between 0-65535 bytes, with a record size
field of 2 bytes.
- Fixed size records, which no record size field.
- Preserve memory resource.
- Performance!
- Easy to use!
This patch:
Since most users want to have the kfifo as part of another object,
reorganize the code to allow including struct kfifo in another data
structure. This requires changing the kfifo_alloc and kfifo_init
prototypes so that we pass an existing kfifo pointer into them. This
patch changes the implementation and all existing users.
[akpm@linux-foundation.org: fix warning]
Signed-off-by: Stefani Seibold <stefani@seibold.net>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-12-22 01:37:26 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_alloc ) ;
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
void __kfifo_free ( struct __kfifo * fifo )
2005-04-17 02:20:36 +04:00
{
2010-08-11 05:03:38 +04:00
kfree ( fifo - > data ) ;
fifo - > in = 0 ;
fifo - > out = 0 ;
fifo - > esize = 0 ;
fifo - > data = NULL ;
fifo - > mask = 0 ;
2005-04-17 02:20:36 +04:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_free ) ;
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
int __kfifo_init ( struct __kfifo * fifo , void * buffer ,
unsigned int size , size_t esize )
2009-12-22 01:37:31 +03:00
{
2010-08-11 05:03:38 +04:00
size / = esize ;
2019-08-31 04:47:15 +03:00
if ( ! is_power_of_2 ( size ) )
size = rounddown_pow_of_two ( size ) ;
2010-08-11 05:03:38 +04:00
fifo - > in = 0 ;
fifo - > out = 0 ;
fifo - > esize = esize ;
fifo - > data = buffer ;
if ( size < 2 ) {
fifo - > mask = 0 ;
return - EINVAL ;
2009-12-22 01:37:31 +03:00
}
2010-08-11 05:03:38 +04:00
fifo - > mask = size - 1 ;
return 0 ;
2009-12-22 01:37:31 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_init ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
static void kfifo_copy_in ( struct __kfifo * fifo , const void * src ,
unsigned int len , unsigned int off )
2005-04-17 02:20:36 +04:00
{
2010-08-11 05:03:38 +04:00
unsigned int size = fifo - > mask + 1 ;
unsigned int esize = fifo - > esize ;
2005-04-17 02:20:36 +04:00
unsigned int l ;
2010-08-11 05:03:38 +04:00
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 ) ;
2006-09-29 13:00:11 +04:00
/*
2010-08-11 05:03:38 +04:00
* make sure that the data in the fifo is up to date before
* incrementing the fifo - > in index counter
2006-09-29 13:00:11 +04:00
*/
2010-08-11 05:03:38 +04:00
smp_wmb ( ) ;
}
2006-09-29 13:00:11 +04:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_in ( struct __kfifo * fifo ,
const void * buf , unsigned int len )
{
unsigned int l ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
l = kfifo_unused ( fifo ) ;
if ( len > l )
len = l ;
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
kfifo_copy_in ( fifo , buf , len , fifo - > in ) ;
fifo - > in + = len ;
return len ;
2005-04-17 02:20:36 +04:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_in ) ;
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
static void kfifo_copy_out ( struct __kfifo * fifo , void * dst ,
unsigned int len , unsigned int off )
2005-04-17 02:20:36 +04:00
{
2010-08-11 05:03:38 +04:00
unsigned int size = fifo - > mask + 1 ;
unsigned int esize = fifo - > esize ;
2005-04-17 02:20:36 +04:00
unsigned int l ;
2010-08-11 05:03:38 +04:00
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 ) ;
2006-09-29 13:00:11 +04:00
/*
2010-08-11 05:03:38 +04:00
* make sure that the data is copied before
* incrementing the fifo - > out index counter
2006-09-29 13:00:11 +04:00
*/
2010-08-11 05:03:38 +04:00
smp_wmb ( ) ;
}
2006-09-29 13:00:11 +04:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_out_peek ( struct __kfifo * fifo ,
void * buf , unsigned int len )
{
unsigned int l ;
2006-09-29 13:00:11 +04:00
2010-08-11 05:03:38 +04:00
l = fifo - > in - fifo - > out ;
if ( len > l )
len = l ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
kfifo_copy_out ( fifo , buf , len , fifo - > out ) ;
return len ;
}
EXPORT_SYMBOL ( __kfifo_out_peek ) ;
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_out ( struct __kfifo * fifo ,
void * buf , unsigned int len )
{
len = __kfifo_out_peek ( fifo , buf , len ) ;
fifo - > out + = len ;
return len ;
2009-12-22 01:37:31 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_out ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
static unsigned long kfifo_copy_from_user ( struct __kfifo * fifo ,
const void __user * from , unsigned int len , unsigned int off ,
unsigned int * copied )
2009-12-22 01:37:31 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int size = fifo - > mask + 1 ;
unsigned int esize = fifo - > esize ;
2009-12-22 01:37:31 +03:00
unsigned int l ;
2010-08-11 05:03:38 +04:00
unsigned long ret ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
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 ) ;
}
2006-09-29 13:00:11 +04:00
/*
2010-08-11 05:03:38 +04:00
* make sure that the data in the fifo is up to date before
* incrementing the fifo - > in index counter
2006-09-29 13:00:11 +04:00
*/
2010-08-11 05:03:38 +04:00
smp_wmb ( ) ;
2013-11-15 02:32:16 +04:00
* copied = len - ret * esize ;
2010-08-11 05:03:38 +04:00
/* return the number of elements which are not copied */
return ret ;
}
2006-09-29 13:00:11 +04:00
2010-08-11 05:03:38 +04:00
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 ;
2006-09-29 13:00:11 +04:00
2010-08-11 05:03:38 +04:00
if ( esize ! = 1 )
len / = esize ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
l = kfifo_unused ( fifo ) ;
if ( len > l )
len = l ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
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 ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_from_user ) ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
static unsigned long kfifo_copy_to_user ( struct __kfifo * fifo , void __user * to ,
unsigned int len , unsigned int off , unsigned int * copied )
2009-12-22 01:37:32 +03:00
{
unsigned int l ;
2010-08-11 05:03:38 +04:00
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 ) ;
}
2009-12-22 01:37:32 +03:00
/*
2010-08-11 05:03:38 +04:00
* make sure that the data is copied before
* incrementing the fifo - > out index counter
2009-12-22 01:37:32 +03:00
*/
2010-08-11 05:03:38 +04:00
smp_wmb ( ) ;
2013-11-15 02:32:16 +04:00
* copied = len - ret * esize ;
2010-08-11 05:03:38 +04:00
/* return the number of elements which are not copied */
return ret ;
}
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
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 ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
if ( esize ! = 1 )
len / = esize ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
l = fifo - > in - fifo - > out ;
if ( len > l )
len = l ;
ret = kfifo_copy_to_user ( fifo , to , len , fifo - > out , copied ) ;
2010-01-16 04:01:15 +03:00
if ( unlikely ( ret ) ) {
2010-08-11 05:03:38 +04:00
len - = ret ;
err = - EFAULT ;
} else
err = 0 ;
fifo - > out + = len ;
return err ;
}
EXPORT_SYMBOL ( __kfifo_to_user ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
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 ) {
2010-08-12 01:17:27 +04:00
sg_set_page ( sgl , page , l - off , off ) ;
sgl = sg_next ( sgl ) ;
if ( + + n = = nents | | sgl = = NULL )
2010-08-11 05:03:38 +04:00
return n ;
page = npage ;
len - = l - off ;
l = off = 0 ;
}
2010-01-16 04:01:15 +03:00
}
2010-08-12 01:17:27 +04:00
sg_set_page ( sgl , page , len , off ) ;
2010-08-11 05:03:38 +04:00
return n + 1 ;
2009-12-22 01:37:32 +03:00
}
2005-04-17 02:20:36 +04:00
2010-08-11 05:03:38 +04:00
static unsigned int setup_sgl ( struct __kfifo * fifo , struct scatterlist * sgl ,
int nents , unsigned int len , unsigned int off )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int size = fifo - > mask + 1 ;
unsigned int esize = fifo - > esize ;
unsigned int l ;
unsigned int n ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
off & = fifo - > mask ;
if ( esize ! = 1 ) {
off * = esize ;
size * = esize ;
len * = esize ;
}
l = min ( len , size - off ) ;
2010-08-12 01:17:27 +04:00
n = setup_sgl_buf ( sgl , fifo - > data + off , nents , l ) ;
2010-08-11 05:03:38 +04:00
n + = setup_sgl_buf ( sgl + n , fifo - > data , nents - n , len - l ) ;
return n ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_dma_in_prepare ( struct __kfifo * fifo ,
struct scatterlist * sgl , int nents , unsigned int len )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int l ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
l = kfifo_unused ( fifo ) ;
if ( len > l )
len = l ;
return setup_sgl ( fifo , sgl , nents , len , fifo - > in ) ;
2005-04-17 02:20:36 +04:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_dma_in_prepare ) ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_dma_out_prepare ( struct __kfifo * fifo ,
struct scatterlist * sgl , int nents , unsigned int len )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int l ;
l = fifo - > in - fifo - > out ;
if ( len > l )
len = l ;
return setup_sgl ( fifo , sgl , nents , len , fifo - > out ) ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_dma_out_prepare ) ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_max_r ( unsigned int len , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int max = ( 1 < < ( recsize < < 3 ) ) - 1 ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
if ( len > max )
return max ;
return len ;
2009-12-22 01:37:32 +03:00
}
2012-04-11 12:01:56 +04:00
EXPORT_SYMBOL ( __kfifo_max_r ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
# 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
2009-12-22 01:37:31 +03:00
*/
2010-08-11 05:03:38 +04:00
static unsigned int __kfifo_peek_n ( struct __kfifo * fifo , size_t recsize )
2009-12-22 01:37:31 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int l ;
unsigned int mask = fifo - > mask ;
unsigned char * data = fifo - > data ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
l = __KFIFO_PEEK ( data , fifo - > out , mask ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
if ( - - recsize )
l | = __KFIFO_PEEK ( data , fifo - > out + 1 , mask ) < < 8 ;
return l ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
# define __KFIFO_POKE(data, in, mask, val) \
( \
( data ) [ ( in ) & ( mask ) ] = ( unsigned char ) ( val ) \
)
/*
2021-07-08 04:07:31 +03:00
* __kfifo_poke_n internal helper function for storing the length of
2010-08-11 05:03:38 +04:00
* the record into the fifo
2010-01-16 04:01:16 +03:00
*/
2010-08-11 05:03:38 +04:00
static void __kfifo_poke_n ( struct __kfifo * fifo , unsigned int n , size_t recsize )
2010-01-16 04:01:16 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned int mask = fifo - > mask ;
unsigned char * data = fifo - > data ;
2010-01-16 04:01:16 +03:00
2010-08-11 05:03:38 +04:00
__KFIFO_POKE ( data , fifo - > in , mask , n ) ;
if ( recsize > 1 )
__KFIFO_POKE ( data , fifo - > in + 1 , mask , n > > 8 ) ;
2010-01-16 04:01:16 +03:00
}
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_len_r ( struct __kfifo * fifo , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
return __kfifo_peek_n ( fifo , recsize ) ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_len_r ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_in_r ( struct __kfifo * fifo , const void * buf ,
unsigned int len , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
if ( len + recsize > kfifo_unused ( fifo ) )
return 0 ;
2010-01-16 04:01:15 +03:00
2010-08-11 05:03:38 +04:00
__kfifo_poke_n ( fifo , len , recsize ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
kfifo_copy_in ( fifo , buf , len , fifo - > in + recsize ) ;
fifo - > in + = len + recsize ;
return len ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
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 )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
* 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 ) ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_out_peek_r ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_out_r ( struct __kfifo * fifo , void * buf ,
unsigned int len , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
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 ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_out_r ) ;
2009-12-22 01:37:31 +03:00
2010-08-20 01:13:27 +04:00
void __kfifo_skip_r ( struct __kfifo * fifo , size_t recsize )
{
unsigned int n ;
n = __kfifo_peek_n ( fifo , recsize ) ;
fifo - > out + = n + recsize ;
}
EXPORT_SYMBOL ( __kfifo_skip_r ) ;
2010-08-11 05:03:38 +04:00
int __kfifo_from_user_r ( struct __kfifo * fifo , const void __user * from ,
unsigned long len , unsigned int * copied , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
unsigned long ret ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
len = __kfifo_max_r ( len , recsize ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
if ( len + recsize > kfifo_unused ( fifo ) ) {
* copied = 0 ;
return 0 ;
}
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
__kfifo_poke_n ( fifo , len , recsize ) ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
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 ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
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 )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
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 ;
2009-12-22 01:37:31 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_to_user_r ) ;
2009-12-22 01:37:31 +03:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_dma_in_prepare_r ( struct __kfifo * fifo ,
struct scatterlist * sgl , int nents , unsigned int len , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2014-08-09 01:22:44 +04:00
BUG_ON ( ! nents ) ;
2010-08-11 05:03:38 +04:00
len = __kfifo_max_r ( len , recsize ) ;
if ( len + recsize > kfifo_unused ( fifo ) )
return 0 ;
return setup_sgl ( fifo , sgl , nents , len , fifo - > in + recsize ) ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_dma_in_prepare_r ) ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
void __kfifo_dma_in_finish_r ( struct __kfifo * fifo ,
unsigned int len , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2010-08-11 05:03:38 +04:00
len = __kfifo_max_r ( len , recsize ) ;
__kfifo_poke_n ( fifo , len , recsize ) ;
fifo - > in + = len + recsize ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_dma_in_finish_r ) ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
unsigned int __kfifo_dma_out_prepare_r ( struct __kfifo * fifo ,
struct scatterlist * sgl , int nents , unsigned int len , size_t recsize )
2009-12-22 01:37:32 +03:00
{
2014-08-09 01:22:44 +04:00
BUG_ON ( ! nents ) ;
2010-08-11 05:03:38 +04:00
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 ) ;
2009-12-22 01:37:32 +03:00
}
2010-08-11 05:03:38 +04:00
EXPORT_SYMBOL ( __kfifo_dma_out_prepare_r ) ;
void __kfifo_dma_out_finish_r ( struct __kfifo * fifo , size_t recsize )
{
unsigned int len ;
2009-12-22 01:37:32 +03:00
2010-08-11 05:03:38 +04:00
len = __kfifo_peek_n ( fifo , recsize ) ;
fifo - > out + = len + recsize ;
}
EXPORT_SYMBOL ( __kfifo_dma_out_finish_r ) ;