2005-04-17 02:20:36 +04:00
/*
* Dynamic DMA mapping support .
*
* We never have any address translations to worry about , so this
* is just alloc / free .
*/
# include <linux/types.h>
# include <linux/mm.h>
2007-07-25 16:07:20 +04:00
# include <linux/device.h>
2009-01-28 10:29:35 +03:00
# include <linux/dma-mapping.h>
2009-04-17 17:11:38 +04:00
# include <asm/cacheflush.h>
2005-04-17 02:20:36 +04:00
void * dma_alloc_coherent ( struct device * dev , size_t size ,
2009-01-28 10:29:35 +03:00
dma_addr_t * dma_handle , gfp_t gfp )
2005-04-17 02:20:36 +04:00
{
void * ret ;
/* ignore region specifiers */
gfp & = ~ ( __GFP_DMA | __GFP_HIGHMEM ) ;
if ( dev = = NULL | | ( * dev - > dma_mask < 0xffffffff ) )
gfp | = GFP_DMA ;
ret = ( void * ) __get_free_pages ( gfp , get_order ( size ) ) ;
if ( ret ! = NULL ) {
memset ( ret , 0 , size ) ;
* dma_handle = virt_to_phys ( ret ) ;
}
return ret ;
}
void dma_free_coherent ( struct device * dev , size_t size ,
void * vaddr , dma_addr_t dma_handle )
{
free_pages ( ( unsigned long ) vaddr , get_order ( size ) ) ;
}
2009-01-28 10:29:35 +03:00
2009-04-17 17:11:38 +04:00
void dma_sync_single_for_device ( struct device * dev , dma_addr_t handle ,
size_t size , enum dma_data_direction dir )
2009-01-28 10:29:35 +03:00
{
2009-04-17 17:11:38 +04:00
switch ( dir ) {
case DMA_TO_DEVICE :
flush_dcache_range ( handle , size ) ;
break ;
case DMA_FROM_DEVICE :
/* Should be clear already */
break ;
default :
if ( printk_ratelimit ( ) )
printk ( " dma_sync_single_for_device: unsupported dir %u \n " , dir ) ;
break ;
}
}
EXPORT_SYMBOL ( dma_sync_single_for_device ) ;
dma_addr_t dma_map_single ( struct device * dev , void * addr , size_t size ,
enum dma_data_direction dir )
{
dma_addr_t handle = virt_to_phys ( addr ) ;
flush_dcache_range ( handle , size ) ;
return handle ;
2009-01-28 10:29:35 +03:00
}
2009-04-17 17:11:38 +04:00
EXPORT_SYMBOL ( dma_map_single ) ;
2009-01-28 10:29:35 +03:00
2009-04-17 17:11:38 +04:00
dma_addr_t dma_map_page ( struct device * dev , struct page * page ,
unsigned long offset , size_t size ,
enum dma_data_direction dir )
{
dma_addr_t handle = page_to_phys ( page ) + offset ;
dma_sync_single_for_device ( dev , handle , size , dir ) ;
return handle ;
}
EXPORT_SYMBOL ( dma_map_page ) ;