2005-04-17 02:20:36 +04:00
/*
* Dynamic DMA mapping support .
*
2005-09-30 01:45:24 +04:00
* This implementation is for IA - 64 and EM64T platforms that do not support
2005-04-17 02:20:36 +04:00
* I / O TLBs ( aka DMA address translation hardware ) .
* Copyright ( C ) 2000 Asit Mallick < Asit . K . Mallick @ intel . com >
* Copyright ( C ) 2000 Goutham Rao < goutham . rao @ intel . com >
* Copyright ( C ) 2000 , 2003 Hewlett - Packard Co
* David Mosberger - Tang < davidm @ hpl . hp . com >
*
* 03 / 05 / 07 davidm Switch from PCI - DMA to generic device DMA API .
* 00 / 12 / 13 davidm Rename to swiotlb . c and add mark_clean ( ) to avoid
* unnecessary i - cache flushing .
2005-09-30 01:45:24 +04:00
* 04 / 07 / . . ak Better overflow handling . Assorted fixes .
* 05 / 09 / 10 linville Add support for syncing ranges , support syncing for
* DMA_BIDIRECTIONAL mappings , miscellaneous cleanup .
2005-04-17 02:20:36 +04:00
*/
# include <linux/cache.h>
2005-09-30 02:52:13 +04:00
# include <linux/dma-mapping.h>
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/string.h>
# include <linux/types.h>
# include <linux/ctype.h>
# include <asm/io.h>
# include <asm/dma.h>
2005-09-30 02:52:13 +04:00
# include <asm/scatterlist.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/bootmem.h>
# define OFFSET(val,align) ((unsigned long) \
( ( val ) & ( ( align ) - 1 ) ) )
# define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset)
# define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
/*
* Maximum allowable number of contiguous slabs to map ,
* must be a power of 2. What is the appropriate value ?
* The complexity of { map , unmap } _single is linearly dependent on this value .
*/
# define IO_TLB_SEGSIZE 128
/*
* log of the size of each IO TLB slab . The number of slabs is command line
* controllable .
*/
# define IO_TLB_SHIFT 11
2005-09-06 21:20:49 +04:00
# define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
/*
* Minimum IO TLB size to bother booting with . Systems with mainly
* 64 bit capable cards will only lightly use the swiotlb . If we can ' t
* allocate a contiguous 1 MB , we ' re probably in trouble anyway .
*/
# define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
2005-09-30 01:44:57 +04:00
/*
* Enumeration for sync targets
*/
enum dma_sync_target {
SYNC_FOR_CPU = 0 ,
SYNC_FOR_DEVICE = 1 ,
} ;
2005-04-17 02:20:36 +04:00
int swiotlb_force ;
/*
* Used to do a quick range check in swiotlb_unmap_single and
* swiotlb_sync_single_ * , to see if the memory was in fact allocated by this
* API .
*/
static char * io_tlb_start , * io_tlb_end ;
/*
* The number of IO TLB blocks ( in groups of 64 ) betweeen io_tlb_start and
* io_tlb_end . This is command line adjustable via setup_io_tlb_npages .
*/
static unsigned long io_tlb_nslabs ;
/*
* When the IOMMU overflows we return a fallback buffer . This sets the size .
*/
static unsigned long io_tlb_overflow = 32 * 1024 ;
void * io_tlb_overflow_buffer ;
/*
* This is a free list describing the number of free entries available from
* each index
*/
static unsigned int * io_tlb_list ;
static unsigned int io_tlb_index ;
/*
* We need to save away the original address corresponding to a mapped entry
* for the sync operations .
*/
static unsigned char * * io_tlb_orig_addr ;
/*
* Protect the above data structures in the map and unmap calls
*/
static DEFINE_SPINLOCK ( io_tlb_lock ) ;
static int __init
setup_io_tlb_npages ( char * str )
{
if ( isdigit ( * str ) ) {
2005-08-05 00:06:00 +04:00
io_tlb_nslabs = simple_strtoul ( str , & str , 0 ) ;
2005-04-17 02:20:36 +04:00
/* avoid tail segment of size < IO_TLB_SEGSIZE */
io_tlb_nslabs = ALIGN ( io_tlb_nslabs , IO_TLB_SEGSIZE ) ;
}
if ( * str = = ' , ' )
+ + str ;
if ( ! strcmp ( str , " force " ) )
swiotlb_force = 1 ;
return 1 ;
}
__setup ( " swiotlb= " , setup_io_tlb_npages ) ;
/* make io_tlb_overflow tunable too? */
/*
* Statically reserve bounce buffer space and initialize bounce buffer data
2005-09-30 02:52:13 +04:00
* structures for the software IO TLB used to implement the DMA API .
2005-04-17 02:20:36 +04:00
*/
void
swiotlb_init_with_default_size ( size_t default_size )
{
unsigned long i ;
if ( ! io_tlb_nslabs ) {
2005-08-05 00:06:00 +04:00
io_tlb_nslabs = ( default_size > > IO_TLB_SHIFT ) ;
2005-04-17 02:20:36 +04:00
io_tlb_nslabs = ALIGN ( io_tlb_nslabs , IO_TLB_SEGSIZE ) ;
}
/*
* Get IO TLB memory from the low pages
*/
2006-01-06 11:11:01 +03:00
io_tlb_start = alloc_bootmem_low_pages ( io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! io_tlb_start )
panic ( " Cannot allocate SWIOTLB buffer " ) ;
io_tlb_end = io_tlb_start + io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ;
/*
* Allocate and initialize the free list array . This array is used
* to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
* between io_tlb_start and io_tlb_end .
*/
io_tlb_list = alloc_bootmem ( io_tlb_nslabs * sizeof ( int ) ) ;
for ( i = 0 ; i < io_tlb_nslabs ; i + + )
io_tlb_list [ i ] = IO_TLB_SEGSIZE - OFFSET ( i , IO_TLB_SEGSIZE ) ;
io_tlb_index = 0 ;
io_tlb_orig_addr = alloc_bootmem ( io_tlb_nslabs * sizeof ( char * ) ) ;
/*
* Get the overflow emergency buffer
*/
io_tlb_overflow_buffer = alloc_bootmem_low ( io_tlb_overflow ) ;
printk ( KERN_INFO " Placing software IO TLB between 0x%lx - 0x%lx \n " ,
virt_to_phys ( io_tlb_start ) , virt_to_phys ( io_tlb_end ) ) ;
}
void
swiotlb_init ( void )
{
swiotlb_init_with_default_size ( 64 * ( 1 < < 20 ) ) ; /* default to 64MB */
}
2005-09-06 21:20:49 +04:00
/*
* Systems with larger DMA zones ( those that don ' t support ISA ) can
* initialize the swiotlb later using the slab allocator if needed .
* This should be just like above , but with some error catching .
*/
int
swiotlb_late_init_with_default_size ( size_t default_size )
{
unsigned long i , req_nslabs = io_tlb_nslabs ;
unsigned int order ;
if ( ! io_tlb_nslabs ) {
io_tlb_nslabs = ( default_size > > IO_TLB_SHIFT ) ;
io_tlb_nslabs = ALIGN ( io_tlb_nslabs , IO_TLB_SEGSIZE ) ;
}
/*
* Get IO TLB memory from the low pages
*/
order = get_order ( io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ) ;
io_tlb_nslabs = SLABS_PER_PAGE < < order ;
while ( ( SLABS_PER_PAGE < < order ) > IO_TLB_MIN_SLABS ) {
io_tlb_start = ( char * ) __get_free_pages ( GFP_DMA | __GFP_NOWARN ,
order ) ;
if ( io_tlb_start )
break ;
order - - ;
}
if ( ! io_tlb_start )
goto cleanup1 ;
if ( order ! = get_order ( io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ) ) {
printk ( KERN_WARNING " Warning: only able to allocate %ld MB "
" for software IO TLB \n " , ( PAGE_SIZE < < order ) > > 20 ) ;
io_tlb_nslabs = SLABS_PER_PAGE < < order ;
}
io_tlb_end = io_tlb_start + io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ;
memset ( io_tlb_start , 0 , io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ) ;
/*
* Allocate and initialize the free list array . This array is used
* to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
* between io_tlb_start and io_tlb_end .
*/
io_tlb_list = ( unsigned int * ) __get_free_pages ( GFP_KERNEL ,
get_order ( io_tlb_nslabs * sizeof ( int ) ) ) ;
if ( ! io_tlb_list )
goto cleanup2 ;
for ( i = 0 ; i < io_tlb_nslabs ; i + + )
io_tlb_list [ i ] = IO_TLB_SEGSIZE - OFFSET ( i , IO_TLB_SEGSIZE ) ;
io_tlb_index = 0 ;
io_tlb_orig_addr = ( unsigned char * * ) __get_free_pages ( GFP_KERNEL ,
get_order ( io_tlb_nslabs * sizeof ( char * ) ) ) ;
if ( ! io_tlb_orig_addr )
goto cleanup3 ;
memset ( io_tlb_orig_addr , 0 , io_tlb_nslabs * sizeof ( char * ) ) ;
/*
* Get the overflow emergency buffer
*/
io_tlb_overflow_buffer = ( void * ) __get_free_pages ( GFP_DMA ,
get_order ( io_tlb_overflow ) ) ;
if ( ! io_tlb_overflow_buffer )
goto cleanup4 ;
printk ( KERN_INFO " Placing %ldMB software IO TLB between 0x%lx - "
" 0x%lx \n " , ( io_tlb_nslabs * ( 1 < < IO_TLB_SHIFT ) ) > > 20 ,
virt_to_phys ( io_tlb_start ) , virt_to_phys ( io_tlb_end ) ) ;
return 0 ;
cleanup4 :
free_pages ( ( unsigned long ) io_tlb_orig_addr , get_order ( io_tlb_nslabs *
sizeof ( char * ) ) ) ;
io_tlb_orig_addr = NULL ;
cleanup3 :
free_pages ( ( unsigned long ) io_tlb_list , get_order ( io_tlb_nslabs *
sizeof ( int ) ) ) ;
io_tlb_list = NULL ;
io_tlb_end = NULL ;
cleanup2 :
free_pages ( ( unsigned long ) io_tlb_start , order ) ;
io_tlb_start = NULL ;
cleanup1 :
io_tlb_nslabs = req_nslabs ;
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
static inline int
address_needs_mapping ( struct device * hwdev , dma_addr_t addr )
{
dma_addr_t mask = 0xffffffff ;
/* If the device has a mask, use it, otherwise default to 32 bits */
if ( hwdev & & hwdev - > dma_mask )
mask = * hwdev - > dma_mask ;
return ( addr & ~ mask ) ! = 0 ;
}
/*
* Allocates bounce buffer and returns its kernel virtual address .
*/
static void *
map_single ( struct device * hwdev , char * buffer , size_t size , int dir )
{
unsigned long flags ;
char * dma_addr ;
unsigned int nslots , stride , index , wrap ;
int i ;
/*
* For mappings greater than a page , we limit the stride ( and
* hence alignment ) to a page size .
*/
nslots = ALIGN ( size , 1 < < IO_TLB_SHIFT ) > > IO_TLB_SHIFT ;
if ( size > PAGE_SIZE )
stride = ( 1 < < ( PAGE_SHIFT - IO_TLB_SHIFT ) ) ;
else
stride = 1 ;
2006-03-24 20:47:11 +03:00
BUG_ON ( ! nslots ) ;
2005-04-17 02:20:36 +04:00
/*
* Find suitable number of IO TLB entries size that will fit this
* request and allocate a buffer from that IO TLB pool .
*/
spin_lock_irqsave ( & io_tlb_lock , flags ) ;
{
wrap = index = ALIGN ( io_tlb_index , stride ) ;
if ( index > = io_tlb_nslabs )
wrap = index = 0 ;
do {
/*
* If we find a slot that indicates we have ' nslots '
* number of contiguous buffers , we allocate the
* buffers from that slot and mark the entries as ' 0 '
* indicating unavailable .
*/
if ( io_tlb_list [ index ] > = nslots ) {
int count = 0 ;
for ( i = index ; i < ( int ) ( index + nslots ) ; i + + )
io_tlb_list [ i ] = 0 ;
for ( i = index - 1 ; ( OFFSET ( i , IO_TLB_SEGSIZE ) ! = IO_TLB_SEGSIZE - 1 ) & & io_tlb_list [ i ] ; i - - )
io_tlb_list [ i ] = + + count ;
dma_addr = io_tlb_start + ( index < < IO_TLB_SHIFT ) ;
/*
* Update the indices to avoid searching in
* the next round .
*/
io_tlb_index = ( ( index + nslots ) < io_tlb_nslabs
? ( index + nslots ) : 0 ) ;
goto found ;
}
index + = stride ;
if ( index > = io_tlb_nslabs )
index = 0 ;
} while ( index ! = wrap ) ;
spin_unlock_irqrestore ( & io_tlb_lock , flags ) ;
return NULL ;
}
found :
spin_unlock_irqrestore ( & io_tlb_lock , flags ) ;
/*
* Save away the mapping from the original address to the DMA address .
* This is needed when we sync the memory . Then we sync the buffer if
* needed .
*/
io_tlb_orig_addr [ index ] = buffer ;
if ( dir = = DMA_TO_DEVICE | | dir = = DMA_BIDIRECTIONAL )
memcpy ( dma_addr , buffer , size ) ;
return dma_addr ;
}
/*
* dma_addr is the kernel virtual address of the bounce buffer to unmap .
*/
static void
unmap_single ( struct device * hwdev , char * dma_addr , size_t size , int dir )
{
unsigned long flags ;
int i , count , nslots = ALIGN ( size , 1 < < IO_TLB_SHIFT ) > > IO_TLB_SHIFT ;
int index = ( dma_addr - io_tlb_start ) > > IO_TLB_SHIFT ;
char * buffer = io_tlb_orig_addr [ index ] ;
/*
* First , sync the memory before unmapping the entry
*/
if ( buffer & & ( ( dir = = DMA_FROM_DEVICE ) | | ( dir = = DMA_BIDIRECTIONAL ) ) )
/*
* bounce . . . copy the data back into the original buffer * and
* delete the bounce buffer .
*/
memcpy ( buffer , dma_addr , size ) ;
/*
* Return the buffer to the free list by setting the corresponding
* entries to indicate the number of contigous entries available .
* While returning the entries to the free list , we merge the entries
* with slots below and above the pool being returned .
*/
spin_lock_irqsave ( & io_tlb_lock , flags ) ;
{
count = ( ( index + nslots ) < ALIGN ( index + 1 , IO_TLB_SEGSIZE ) ?
io_tlb_list [ index + nslots ] : 0 ) ;
/*
* Step 1 : return the slots to the free list , merging the
* slots with superceeding slots
*/
for ( i = index + nslots - 1 ; i > = index ; i - - )
io_tlb_list [ i ] = + + count ;
/*
* Step 2 : merge the returned slots with the preceding slots ,
* if available ( non zero )
*/
for ( i = index - 1 ; ( OFFSET ( i , IO_TLB_SEGSIZE ) ! = IO_TLB_SEGSIZE - 1 ) & & io_tlb_list [ i ] ; i - - )
io_tlb_list [ i ] = + + count ;
}
spin_unlock_irqrestore ( & io_tlb_lock , flags ) ;
}
static void
2005-09-30 01:44:57 +04:00
sync_single ( struct device * hwdev , char * dma_addr , size_t size ,
int dir , int target )
2005-04-17 02:20:36 +04:00
{
int index = ( dma_addr - io_tlb_start ) > > IO_TLB_SHIFT ;
char * buffer = io_tlb_orig_addr [ index ] ;
2005-09-30 01:44:57 +04:00
switch ( target ) {
case SYNC_FOR_CPU :
if ( likely ( dir = = DMA_FROM_DEVICE | | dir = = DMA_BIDIRECTIONAL ) )
memcpy ( buffer , dma_addr , size ) ;
2006-03-24 20:47:11 +03:00
else
BUG_ON ( dir ! = DMA_TO_DEVICE ) ;
2005-09-30 01:44:57 +04:00
break ;
case SYNC_FOR_DEVICE :
if ( likely ( dir = = DMA_TO_DEVICE | | dir = = DMA_BIDIRECTIONAL ) )
memcpy ( dma_addr , buffer , size ) ;
2006-03-24 20:47:11 +03:00
else
BUG_ON ( dir ! = DMA_FROM_DEVICE ) ;
2005-09-30 01:44:57 +04:00
break ;
default :
2005-04-17 02:20:36 +04:00
BUG ( ) ;
2005-09-30 01:44:57 +04:00
}
2005-04-17 02:20:36 +04:00
}
void *
swiotlb_alloc_coherent ( struct device * hwdev , size_t size ,
2005-10-21 11:21:03 +04:00
dma_addr_t * dma_handle , gfp_t flags )
2005-04-17 02:20:36 +04:00
{
unsigned long dev_addr ;
void * ret ;
int order = get_order ( size ) ;
/*
* XXX fix me : the DMA API should pass us an explicit DMA mask
* instead , or use ZONE_DMA32 ( ia64 overloads ZONE_DMA to be a ~ 32
* bit range instead of a 16 MB one ) .
*/
flags | = GFP_DMA ;
ret = ( void * ) __get_free_pages ( flags , order ) ;
if ( ret & & address_needs_mapping ( hwdev , virt_to_phys ( ret ) ) ) {
/*
* The allocated memory isn ' t reachable by the device .
* Fall back on swiotlb_map_single ( ) .
*/
free_pages ( ( unsigned long ) ret , order ) ;
ret = NULL ;
}
if ( ! ret ) {
/*
* We are either out of memory or the device can ' t DMA
* to GFP_DMA memory ; fall back on
* swiotlb_map_single ( ) , which will grab memory from
* the lowest available address range .
*/
dma_addr_t handle ;
handle = swiotlb_map_single ( NULL , NULL , size , DMA_FROM_DEVICE ) ;
2006-01-12 00:44:42 +03:00
if ( swiotlb_dma_mapping_error ( handle ) )
2005-04-17 02:20:36 +04:00
return NULL ;
ret = phys_to_virt ( handle ) ;
}
memset ( ret , 0 , size ) ;
dev_addr = virt_to_phys ( ret ) ;
/* Confirm address can be DMA'd by device */
if ( address_needs_mapping ( hwdev , dev_addr ) ) {
printk ( " hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016lx \n " ,
( unsigned long long ) * hwdev - > dma_mask , dev_addr ) ;
panic ( " swiotlb_alloc_coherent: allocated memory is out of "
" range for device " ) ;
}
* dma_handle = dev_addr ;
return ret ;
}
void
swiotlb_free_coherent ( struct device * hwdev , size_t size , void * vaddr ,
dma_addr_t dma_handle )
{
if ( ! ( vaddr > = ( void * ) io_tlb_start
& & vaddr < ( void * ) io_tlb_end ) )
free_pages ( ( unsigned long ) vaddr , get_order ( size ) ) ;
else
/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
swiotlb_unmap_single ( hwdev , dma_handle , size , DMA_TO_DEVICE ) ;
}
static void
swiotlb_full ( struct device * dev , size_t size , int dir , int do_panic )
{
/*
* Ran out of IOMMU space for this operation . This is very bad .
* Unfortunately the drivers cannot handle this operation properly .
2005-09-30 02:52:13 +04:00
* unless they check for dma_mapping_error ( most don ' t )
2005-04-17 02:20:36 +04:00
* When the mapping is small enough return a static buffer to limit
* the damage , or panic when the transfer is too big .
*/
2005-09-30 02:52:13 +04:00
printk ( KERN_ERR " DMA: Out of SW-IOMMU space for %lu bytes at "
2005-04-17 02:20:36 +04:00
" device %s \n " , size , dev ? dev - > bus_id : " ? " ) ;
if ( size > io_tlb_overflow & & do_panic ) {
2005-09-30 02:52:13 +04:00
if ( dir = = DMA_FROM_DEVICE | | dir = = DMA_BIDIRECTIONAL )
panic ( " DMA: Memory would be corrupted \n " ) ;
if ( dir = = DMA_TO_DEVICE | | dir = = DMA_BIDIRECTIONAL )
panic ( " DMA: Random memory would be DMAed \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
/*
* Map a single buffer of the indicated size for DMA in streaming mode . The
2005-09-30 02:52:13 +04:00
* physical address to use is returned .
2005-04-17 02:20:36 +04:00
*
* Once the device is given the dma address , the device owns this memory until
* either swiotlb_unmap_single or swiotlb_dma_sync_single is performed .
*/
dma_addr_t
swiotlb_map_single ( struct device * hwdev , void * ptr , size_t size , int dir )
{
unsigned long dev_addr = virt_to_phys ( ptr ) ;
void * map ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
/*
* If the pointer passed in happens to be in the device ' s DMA window ,
* we can safely return the device addr and not worry about bounce
* buffering it .
*/
if ( ! address_needs_mapping ( hwdev , dev_addr ) & & ! swiotlb_force )
return dev_addr ;
/*
* Oh well , have to allocate and map a bounce buffer .
*/
map = map_single ( hwdev , ptr , size , dir ) ;
if ( ! map ) {
swiotlb_full ( hwdev , size , dir , 1 ) ;
map = io_tlb_overflow_buffer ;
}
dev_addr = virt_to_phys ( map ) ;
/*
* Ensure that the address returned is DMA ' ble
*/
if ( address_needs_mapping ( hwdev , dev_addr ) )
panic ( " map_single: bounce buffer is not DMA'ble " ) ;
return dev_addr ;
}
/*
* Since DMA is i - cache coherent , any ( complete ) pages that were written via
* DMA can be marked as " clean " so that lazy_mmu_prot_update ( ) doesn ' t have to
* flush them when they get mapped into an executable vm - area .
*/
static void
mark_clean ( void * addr , size_t size )
{
unsigned long pg_addr , end ;
pg_addr = PAGE_ALIGN ( ( unsigned long ) addr ) ;
end = ( unsigned long ) addr + size ;
while ( pg_addr + PAGE_SIZE < = end ) {
struct page * page = virt_to_page ( pg_addr ) ;
set_bit ( PG_arch_1 , & page - > flags ) ;
pg_addr + = PAGE_SIZE ;
}
}
/*
* Unmap a single streaming mode DMA translation . The dma_addr and size must
* match what was provided for in a previous swiotlb_map_single call . All
* other usages are undefined .
*
* After this call , reads by the cpu to the buffer are guaranteed to see
* whatever the device wrote there .
*/
void
swiotlb_unmap_single ( struct device * hwdev , dma_addr_t dev_addr , size_t size ,
int dir )
{
char * dma_addr = phys_to_virt ( dev_addr ) ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
if ( dma_addr > = io_tlb_start & & dma_addr < io_tlb_end )
unmap_single ( hwdev , dma_addr , size , dir ) ;
else if ( dir = = DMA_FROM_DEVICE )
mark_clean ( dma_addr , size ) ;
}
/*
* Make physical memory consistent for a single streaming mode DMA translation
* after a transfer .
*
* If you perform a swiotlb_map_single ( ) but wish to interrogate the buffer
2005-09-30 02:52:13 +04:00
* using the cpu , yet do not wish to teardown the dma mapping , you must
* call this function before doing so . At the next point you give the dma
2005-04-17 02:20:36 +04:00
* address back to the card , you must first perform a
* swiotlb_dma_sync_for_device , and then the device again owns the buffer
*/
2005-09-30 01:43:32 +04:00
static inline void
swiotlb_sync_single ( struct device * hwdev , dma_addr_t dev_addr ,
2005-09-30 01:44:57 +04:00
size_t size , int dir , int target )
2005-04-17 02:20:36 +04:00
{
char * dma_addr = phys_to_virt ( dev_addr ) ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
if ( dma_addr > = io_tlb_start & & dma_addr < io_tlb_end )
2005-09-30 01:44:57 +04:00
sync_single ( hwdev , dma_addr , size , dir , target ) ;
2005-04-17 02:20:36 +04:00
else if ( dir = = DMA_FROM_DEVICE )
mark_clean ( dma_addr , size ) ;
}
2005-09-30 01:43:32 +04:00
void
swiotlb_sync_single_for_cpu ( struct device * hwdev , dma_addr_t dev_addr ,
size_t size , int dir )
{
2005-09-30 01:44:57 +04:00
swiotlb_sync_single ( hwdev , dev_addr , size , dir , SYNC_FOR_CPU ) ;
2005-09-30 01:43:32 +04:00
}
2005-04-17 02:20:36 +04:00
void
swiotlb_sync_single_for_device ( struct device * hwdev , dma_addr_t dev_addr ,
size_t size , int dir )
{
2005-09-30 01:44:57 +04:00
swiotlb_sync_single ( hwdev , dev_addr , size , dir , SYNC_FOR_DEVICE ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-30 01:44:23 +04:00
/*
* Same as above , but for a sub - range of the mapping .
*/
static inline void
swiotlb_sync_single_range ( struct device * hwdev , dma_addr_t dev_addr ,
2005-09-30 01:44:57 +04:00
unsigned long offset , size_t size ,
int dir , int target )
2005-09-30 01:44:23 +04:00
{
char * dma_addr = phys_to_virt ( dev_addr ) + offset ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-09-30 01:44:23 +04:00
if ( dma_addr > = io_tlb_start & & dma_addr < io_tlb_end )
2005-09-30 01:44:57 +04:00
sync_single ( hwdev , dma_addr , size , dir , target ) ;
2005-09-30 01:44:23 +04:00
else if ( dir = = DMA_FROM_DEVICE )
mark_clean ( dma_addr , size ) ;
}
void
swiotlb_sync_single_range_for_cpu ( struct device * hwdev , dma_addr_t dev_addr ,
unsigned long offset , size_t size , int dir )
{
2005-09-30 01:44:57 +04:00
swiotlb_sync_single_range ( hwdev , dev_addr , offset , size , dir ,
SYNC_FOR_CPU ) ;
2005-09-30 01:44:23 +04:00
}
void
swiotlb_sync_single_range_for_device ( struct device * hwdev , dma_addr_t dev_addr ,
unsigned long offset , size_t size , int dir )
{
2005-09-30 01:44:57 +04:00
swiotlb_sync_single_range ( hwdev , dev_addr , offset , size , dir ,
SYNC_FOR_DEVICE ) ;
2005-09-30 01:44:23 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Map a set of buffers described by scatterlist in streaming mode for DMA .
* This is the scatter - gather version of the above swiotlb_map_single
* interface . Here the scatter gather list elements are each tagged with the
* appropriate dma address and length . They are obtained via
* sg_dma_ { address , length } ( SG ) .
*
* NOTE : An implementation may be able to use a smaller number of
* DMA address / length pairs than there are SG table elements .
* ( for example via virtual mapping capabilities )
* The routine returns the number of addr / length pairs actually
* used , at most nents .
*
* Device ownership issues as mentioned above for swiotlb_map_single are the
* same here .
*/
int
swiotlb_map_sg ( struct device * hwdev , struct scatterlist * sg , int nelems ,
int dir )
{
void * addr ;
unsigned long dev_addr ;
int i ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < nelems ; i + + , sg + + ) {
addr = SG_ENT_VIRT_ADDRESS ( sg ) ;
dev_addr = virt_to_phys ( addr ) ;
if ( swiotlb_force | | address_needs_mapping ( hwdev , dev_addr ) ) {
2005-12-20 16:45:19 +03:00
void * map = map_single ( hwdev , addr , sg - > length , dir ) ;
sg - > dma_address = virt_to_bus ( map ) ;
if ( ! map ) {
2005-04-17 02:20:36 +04:00
/* Don't panic here, we expect map_sg users
to do proper error handling . */
swiotlb_full ( hwdev , sg - > length , dir , 0 ) ;
swiotlb_unmap_sg ( hwdev , sg - i , i , dir ) ;
sg [ 0 ] . dma_length = 0 ;
return 0 ;
}
} else
sg - > dma_address = dev_addr ;
sg - > dma_length = sg - > length ;
}
return nelems ;
}
/*
* Unmap a set of streaming mode DMA translations . Again , cpu read rules
* concerning calls here are the same as for swiotlb_unmap_single ( ) above .
*/
void
swiotlb_unmap_sg ( struct device * hwdev , struct scatterlist * sg , int nelems ,
int dir )
{
int i ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < nelems ; i + + , sg + + )
if ( sg - > dma_address ! = SG_ENT_PHYS_ADDRESS ( sg ) )
unmap_single ( hwdev , ( void * ) phys_to_virt ( sg - > dma_address ) , sg - > dma_length , dir ) ;
else if ( dir = = DMA_FROM_DEVICE )
mark_clean ( SG_ENT_VIRT_ADDRESS ( sg ) , sg - > dma_length ) ;
}
/*
* Make physical memory consistent for a set of streaming mode DMA translations
* after a transfer .
*
* The same as swiotlb_sync_single_ * but for a scatter - gather list , same rules
* and usage .
*/
2005-09-30 01:43:32 +04:00
static inline void
swiotlb_sync_sg ( struct device * hwdev , struct scatterlist * sg ,
2005-09-30 01:44:57 +04:00
int nelems , int dir , int target )
2005-04-17 02:20:36 +04:00
{
int i ;
2006-03-24 20:47:11 +03:00
BUG_ON ( dir = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < nelems ; i + + , sg + + )
if ( sg - > dma_address ! = SG_ENT_PHYS_ADDRESS ( sg ) )
sync_single ( hwdev , ( void * ) sg - > dma_address ,
2005-09-30 01:44:57 +04:00
sg - > dma_length , dir , target ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-30 01:43:32 +04:00
void
swiotlb_sync_sg_for_cpu ( struct device * hwdev , struct scatterlist * sg ,
int nelems , int dir )
{
2005-09-30 01:44:57 +04:00
swiotlb_sync_sg ( hwdev , sg , nelems , dir , SYNC_FOR_CPU ) ;
2005-09-30 01:43:32 +04:00
}
2005-04-17 02:20:36 +04:00
void
swiotlb_sync_sg_for_device ( struct device * hwdev , struct scatterlist * sg ,
int nelems , int dir )
{
2005-09-30 01:44:57 +04:00
swiotlb_sync_sg ( hwdev , sg , nelems , dir , SYNC_FOR_DEVICE ) ;
2005-04-17 02:20:36 +04:00
}
int
swiotlb_dma_mapping_error ( dma_addr_t dma_addr )
{
return ( dma_addr = = virt_to_phys ( io_tlb_overflow_buffer ) ) ;
}
/*
2005-09-30 02:52:13 +04:00
* Return whether the given device DMA address mask can be supported
2005-04-17 02:20:36 +04:00
* properly . For example , if your device can only drive the low 24 - bits
2005-09-30 02:52:13 +04:00
* during bus mastering , then you would pass 0x00ffffff as the mask to
2005-04-17 02:20:36 +04:00
* this function .
*/
int
swiotlb_dma_supported ( struct device * hwdev , u64 mask )
{
return ( virt_to_phys ( io_tlb_end ) - 1 ) < = mask ;
}
EXPORT_SYMBOL ( swiotlb_init ) ;
EXPORT_SYMBOL ( swiotlb_map_single ) ;
EXPORT_SYMBOL ( swiotlb_unmap_single ) ;
EXPORT_SYMBOL ( swiotlb_map_sg ) ;
EXPORT_SYMBOL ( swiotlb_unmap_sg ) ;
EXPORT_SYMBOL ( swiotlb_sync_single_for_cpu ) ;
EXPORT_SYMBOL ( swiotlb_sync_single_for_device ) ;
2005-09-30 01:44:23 +04:00
EXPORT_SYMBOL_GPL ( swiotlb_sync_single_range_for_cpu ) ;
EXPORT_SYMBOL_GPL ( swiotlb_sync_single_range_for_device ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( swiotlb_sync_sg_for_cpu ) ;
EXPORT_SYMBOL ( swiotlb_sync_sg_for_device ) ;
EXPORT_SYMBOL ( swiotlb_dma_mapping_error ) ;
EXPORT_SYMBOL ( swiotlb_alloc_coherent ) ;
EXPORT_SYMBOL ( swiotlb_free_coherent ) ;
EXPORT_SYMBOL ( swiotlb_dma_supported ) ;