2005-04-17 02:20:36 +04:00
/*
* DMA memory management for framework level HCD code ( hc_driver )
*
* This implementation plugs in through generic " usb_bus " level methods ,
2014-01-04 09:54:41 +04:00
* and should work with all USB controllers , regardless of bus type .
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/device.h>
# include <linux/mm.h>
2010-12-25 13:17:01 +03:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
# include <linux/dma-mapping.h>
# include <linux/dmapool.h>
# include <linux/usb.h>
2010-04-25 01:21:52 +04:00
# include <linux/usb/hcd.h>
2005-04-17 02:20:36 +04:00
/*
* DMA - Coherent Buffers
*/
/* FIXME tune these based on pool statistics ... */
2014-12-05 17:13:54 +03:00
static size_t pool_max [ HCD_BUFFER_POOLS ] = {
32 , 128 , 512 , 2048 ,
2005-04-17 02:20:36 +04:00
} ;
2014-12-05 17:13:54 +03:00
void __init usb_init_pool_max ( void )
{
/*
* The pool_max values must never be smaller than
* ARCH_KMALLOC_MINALIGN .
*/
if ( ARCH_KMALLOC_MINALIGN < = 32 )
; /* Original value is okay */
else if ( ARCH_KMALLOC_MINALIGN < = 64 )
pool_max [ 0 ] = 64 ;
else if ( ARCH_KMALLOC_MINALIGN < = 128 )
pool_max [ 0 ] = 0 ; /* Don't use this pool */
else
BUILD_BUG ( ) ; /* We don't allow this */
}
2005-04-17 02:20:36 +04:00
/* SETUP primitives */
/**
* hcd_buffer_create - initialize buffer pools
* @ hcd : the bus whose buffer pools are to be initialized
* Context : ! in_interrupt ( )
*
* Call this as part of initializing a host controller that uses the dma
* memory allocators . It initializes some pools of dma - coherent memory that
2013-08-02 22:10:04 +04:00
* will be shared by all drivers using that controller .
2005-04-17 02:20:36 +04:00
*
* Call hcd_buffer_destroy ( ) to clean up after using those pools .
2013-08-02 22:10:04 +04:00
*
* Return : 0 if successful . A negative errno value otherwise .
2005-04-17 02:20:36 +04:00
*/
2007-01-25 13:17:41 +03:00
int hcd_buffer_create ( struct usb_hcd * hcd )
2005-04-17 02:20:36 +04:00
{
2007-01-25 13:17:41 +03:00
char name [ 16 ] ;
2010-12-25 13:17:01 +03:00
int i , size ;
2005-04-17 02:20:36 +04:00
2008-01-23 09:58:35 +03:00
if ( ! hcd - > self . controller - > dma_mask & &
! ( hcd - > driver - > flags & HCD_LOCAL_MEM ) )
2005-11-28 20:29:23 +03:00
return 0 ;
2008-01-31 02:21:33 +03:00
for ( i = 0 ; i < HCD_BUFFER_POOLS ; i + + ) {
size = pool_max [ i ] ;
if ( ! size )
2005-04-17 02:20:36 +04:00
continue ;
2015-04-29 13:49:33 +03:00
snprintf ( name , sizeof ( name ) , " buffer-%d " , size ) ;
2007-01-25 13:17:41 +03:00
hcd - > pool [ i ] = dma_pool_create ( name , hcd - > self . controller ,
2005-04-17 02:20:36 +04:00
size , size , 0 ) ;
2010-12-25 13:17:01 +03:00
if ( ! hcd - > pool [ i ] ) {
2007-01-25 13:17:41 +03:00
hcd_buffer_destroy ( hcd ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
}
return 0 ;
}
/**
* hcd_buffer_destroy - deallocate buffer pools
* @ hcd : the bus whose buffer pools are to be destroyed
* Context : ! in_interrupt ( )
*
* This frees the buffer pools created by hcd_buffer_create ( ) .
*/
2007-01-25 13:17:41 +03:00
void hcd_buffer_destroy ( struct usb_hcd * hcd )
2005-04-17 02:20:36 +04:00
{
2008-01-31 02:21:33 +03:00
int i ;
2005-04-17 02:20:36 +04:00
2008-01-31 02:21:33 +03:00
for ( i = 0 ; i < HCD_BUFFER_POOLS ; i + + ) {
struct dma_pool * pool = hcd - > pool [ i ] ;
2015-04-29 13:49:33 +03:00
2005-04-17 02:20:36 +04:00
if ( pool ) {
2007-01-25 13:17:41 +03:00
dma_pool_destroy ( pool ) ;
2005-04-17 02:20:36 +04:00
hcd - > pool [ i ] = NULL ;
}
}
}
2006-12-07 07:33:19 +03:00
/* sometimes alloc/free could use kmalloc with GFP_DMA, for
2005-04-17 02:20:36 +04:00
* better sharing and to leverage mm / slab . c intelligence .
*/
2007-01-25 13:17:41 +03:00
void * hcd_buffer_alloc (
2010-12-25 13:17:01 +03:00
struct usb_bus * bus ,
2005-04-17 02:20:36 +04:00
size_t size ,
2005-10-21 11:21:58 +04:00
gfp_t mem_flags ,
2005-04-17 02:20:36 +04:00
dma_addr_t * dma
)
{
2006-08-30 19:32:52 +04:00
struct usb_hcd * hcd = bus_to_hcd ( bus ) ;
2010-12-25 13:17:01 +03:00
int i ;
2005-04-17 02:20:36 +04:00
/* some USB hosts just use PIO */
2008-01-23 09:58:35 +03:00
if ( ! bus - > controller - > dma_mask & &
! ( hcd - > driver - > flags & HCD_LOCAL_MEM ) ) {
2005-04-17 02:20:36 +04:00
* dma = ~ ( dma_addr_t ) 0 ;
2007-01-25 13:17:41 +03:00
return kmalloc ( size , mem_flags ) ;
2005-04-17 02:20:36 +04:00
}
for ( i = 0 ; i < HCD_BUFFER_POOLS ; i + + ) {
2010-12-25 13:17:01 +03:00
if ( size < = pool_max [ i ] )
return dma_pool_alloc ( hcd - > pool [ i ] , mem_flags , dma ) ;
2005-04-17 02:20:36 +04:00
}
2009-04-18 13:00:39 +04:00
return dma_alloc_coherent ( hcd - > self . controller , size , dma , mem_flags ) ;
2005-04-17 02:20:36 +04:00
}
2007-01-25 13:17:41 +03:00
void hcd_buffer_free (
2010-12-25 13:17:01 +03:00
struct usb_bus * bus ,
2005-04-17 02:20:36 +04:00
size_t size ,
2010-12-25 13:17:01 +03:00
void * addr ,
2005-04-17 02:20:36 +04:00
dma_addr_t dma
)
{
2006-08-30 19:32:52 +04:00
struct usb_hcd * hcd = bus_to_hcd ( bus ) ;
2010-12-25 13:17:01 +03:00
int i ;
2005-04-17 02:20:36 +04:00
if ( ! addr )
return ;
2008-01-23 09:58:35 +03:00
if ( ! bus - > controller - > dma_mask & &
! ( hcd - > driver - > flags & HCD_LOCAL_MEM ) ) {
2007-01-25 13:17:41 +03:00
kfree ( addr ) ;
2005-04-17 02:20:36 +04:00
return ;
}
for ( i = 0 ; i < HCD_BUFFER_POOLS ; i + + ) {
2010-12-25 13:17:01 +03:00
if ( size < = pool_max [ i ] ) {
dma_pool_free ( hcd - > pool [ i ] , addr , dma ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
2007-01-25 13:17:41 +03:00
dma_free_coherent ( hcd - > self . controller , size , addr , dma ) ;
2005-04-17 02:20:36 +04:00
}