2005-04-17 02:20:36 +04:00
/* Fallback functions when the main IOMMU code is not compiled in. This
code is roughly equivalent to i386 . */
2006-06-26 15:59:05 +04:00
# include <linux/dma-mapping.h>
2007-07-24 14:39:27 +04:00
# include <linux/scatterlist.h>
2009-03-21 14:31:25 +03:00
# include <linux/string.h>
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/mm.h>
2006-06-26 15:59:05 +04:00
2005-04-17 02:20:36 +04:00
# include <asm/processor.h>
2009-03-21 14:31:25 +03:00
# include <asm/iommu.h>
2006-01-12 00:44:42 +03:00
# include <asm/dma.h>
2005-04-17 02:20:36 +04:00
2006-01-12 00:44:42 +03:00
static int
check_addr ( char * name , struct device * hwdev , dma_addr_t bus , size_t size )
2005-04-17 02:20:36 +04:00
{
2009-07-10 05:04:55 +04:00
if ( hwdev & & ! dma_capable ( hwdev , bus , size ) ) {
2009-04-07 06:01:15 +04:00
if ( * hwdev - > dma_mask > = DMA_BIT_MASK ( 32 ) )
2006-05-15 20:19:38 +04:00
printk ( KERN_ERR
2006-06-26 15:59:05 +04:00
" nommu_%s: overflow %Lx+%zu of device mask %Lx \n " ,
name , ( long long ) bus , size ,
( long long ) * hwdev - > dma_mask ) ;
2006-01-12 00:44:42 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-01-12 00:44:42 +03:00
return 1 ;
}
2005-04-17 02:20:36 +04:00
2009-01-05 17:47:27 +03:00
static dma_addr_t nommu_map_page ( struct device * dev , struct page * page ,
unsigned long offset , size_t size ,
enum dma_data_direction dir ,
struct dma_attrs * attrs )
2006-01-12 00:44:42 +03:00
{
2009-01-05 17:47:27 +03:00
dma_addr_t bus = page_to_phys ( page ) + offset ;
2008-04-08 20:20:49 +04:00
WARN_ON ( size = = 0 ) ;
2009-01-05 17:47:27 +03:00
if ( ! check_addr ( " map_single " , dev , bus , size ) )
2009-11-15 15:19:53 +03:00
return DMA_ERROR_CODE ;
2008-04-08 20:20:46 +04:00
flush_write_buffers ( ) ;
2006-01-12 00:44:42 +03:00
return bus ;
2005-04-17 02:20:36 +04:00
}
2006-01-12 00:44:42 +03:00
/* Map a set of buffers described by scatterlist in streaming
* mode for DMA . This is the scatter - gather version of the
* above pci_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 pci_map_single are
* the same here .
*/
2007-07-21 19:11:23 +04:00
static int nommu_map_sg ( struct device * hwdev , struct scatterlist * sg ,
2009-01-05 17:59:02 +03:00
int nents , enum dma_data_direction dir ,
struct dma_attrs * attrs )
2005-04-17 02:20:36 +04:00
{
2007-07-24 14:39:27 +04:00
struct scatterlist * s ;
2006-01-12 00:44:42 +03:00
int i ;
2005-04-17 02:20:36 +04:00
2008-04-08 20:20:49 +04:00
WARN_ON ( nents = = 0 | | sg [ 0 ] . length = = 0 ) ;
2007-07-24 14:39:27 +04:00
for_each_sg ( sg , s , nents , i ) {
2007-10-22 22:02:46 +04:00
BUG_ON ( ! sg_page ( s ) ) ;
2008-04-08 20:20:47 +04:00
s - > dma_address = sg_phys ( s ) ;
2006-01-12 00:44:42 +03:00
if ( ! check_addr ( " map_sg " , hwdev , s - > dma_address , s - > length ) )
return 0 ;
s - > dma_length = s - > length ;
}
2008-04-08 20:20:46 +04:00
flush_write_buffers ( ) ;
2006-01-12 00:44:42 +03:00
return nents ;
}
2005-04-17 02:20:36 +04:00
2008-08-19 18:32:43 +04:00
static void nommu_free_coherent ( struct device * dev , size_t size , void * vaddr ,
dma_addr_t dma_addr )
{
free_pages ( ( unsigned long ) vaddr , get_order ( size ) ) ;
}
2009-08-10 06:53:10 +04:00
static void nommu_sync_single_for_device ( struct device * dev ,
dma_addr_t addr , size_t size ,
enum dma_data_direction dir )
{
flush_write_buffers ( ) ;
}
static void nommu_sync_sg_for_device ( struct device * dev ,
struct scatterlist * sg , int nelems ,
enum dma_data_direction dir )
{
flush_write_buffers ( ) ;
}
2009-01-05 17:59:02 +03:00
struct dma_map_ops nommu_dma_ops = {
2009-08-10 06:53:10 +04:00
. alloc_coherent = dma_generic_alloc_coherent ,
. free_coherent = nommu_free_coherent ,
. map_sg = nommu_map_sg ,
. map_page = nommu_map_page ,
. sync_single_for_device = nommu_sync_single_for_device ,
. sync_sg_for_device = nommu_sync_sg_for_device ,
. is_phys = 1 ,
2006-01-12 00:44:42 +03:00
} ;