2008-11-26 17:21:24 +01:00
/*
* Copyright ( C ) 2007 - 2008 Advanced Micro Devices , Inc .
* Author : Joerg Roedel < joerg . roedel @ amd . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2011-09-06 16:03:26 +02:00
# include <linux/device.h>
2011-09-02 13:32:32 -04:00
# include <linux/kernel.h>
2008-11-26 17:21:24 +01:00
# include <linux/bug.h>
# include <linux/types.h>
2009-05-06 16:03:07 -07:00
# include <linux/module.h>
# include <linux/slab.h>
2008-11-26 17:21:24 +01:00
# include <linux/errno.h>
# include <linux/iommu.h>
static struct iommu_ops * iommu_ops ;
void register_iommu ( struct iommu_ops * ops )
{
if ( iommu_ops )
BUG ( ) ;
iommu_ops = ops ;
}
2011-08-26 16:48:26 +02:00
static void iommu_bus_init ( struct bus_type * bus , struct iommu_ops * ops )
{
}
/**
* bus_set_iommu - set iommu - callbacks for the bus
* @ bus : bus .
* @ ops : the callbacks provided by the iommu - driver
*
* This function is called by an iommu driver to set the iommu methods
* used for a particular bus . Drivers for devices on that bus can use
* the iommu - api after these ops are registered .
* This special function is needed because IOMMUs are usually devices on
* the bus itself , so the iommu drivers are not initialized when the bus
* is set up . With this function the iommu - driver can set the iommu - ops
* afterwards .
*/
int bus_set_iommu ( struct bus_type * bus , struct iommu_ops * ops )
{
if ( bus - > iommu_ops ! = NULL )
return - EBUSY ;
bus - > iommu_ops = ops ;
/* Do IOMMU specific setup for this bus-type */
iommu_bus_init ( bus , ops ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( bus_set_iommu ) ;
2009-03-05 12:12:44 +01:00
bool iommu_found ( void )
2008-11-26 17:21:24 +01:00
{
return iommu_ops ! = NULL ;
}
EXPORT_SYMBOL_GPL ( iommu_found ) ;
2011-09-06 16:03:26 +02:00
struct iommu_domain * iommu_domain_alloc ( struct bus_type * bus )
2008-11-26 17:21:24 +01:00
{
struct iommu_domain * domain ;
2011-09-06 16:03:26 +02:00
struct iommu_ops * ops ;
2008-11-26 17:21:24 +01:00
int ret ;
2011-09-06 16:03:26 +02:00
if ( bus - > iommu_ops )
ops = bus - > iommu_ops ;
else
ops = iommu_ops ;
if ( ops = = NULL )
return NULL ;
2008-11-26 17:21:24 +01:00
domain = kmalloc ( sizeof ( * domain ) , GFP_KERNEL ) ;
if ( ! domain )
return NULL ;
2011-09-06 16:03:26 +02:00
domain - > ops = ops ;
2008-11-26 17:21:24 +01:00
ret = iommu_ops - > domain_init ( domain ) ;
if ( ret )
goto out_free ;
return domain ;
out_free :
kfree ( domain ) ;
return NULL ;
}
EXPORT_SYMBOL_GPL ( iommu_domain_alloc ) ;
void iommu_domain_free ( struct iommu_domain * domain )
{
iommu_ops - > domain_destroy ( domain ) ;
kfree ( domain ) ;
}
EXPORT_SYMBOL_GPL ( iommu_domain_free ) ;
int iommu_attach_device ( struct iommu_domain * domain , struct device * dev )
{
return iommu_ops - > attach_dev ( domain , dev ) ;
}
EXPORT_SYMBOL_GPL ( iommu_attach_device ) ;
void iommu_detach_device ( struct iommu_domain * domain , struct device * dev )
{
iommu_ops - > detach_dev ( domain , dev ) ;
}
EXPORT_SYMBOL_GPL ( iommu_detach_device ) ;
phys_addr_t iommu_iova_to_phys ( struct iommu_domain * domain ,
unsigned long iova )
{
return iommu_ops - > iova_to_phys ( domain , iova ) ;
}
EXPORT_SYMBOL_GPL ( iommu_iova_to_phys ) ;
2009-03-18 15:33:06 +08:00
int iommu_domain_has_cap ( struct iommu_domain * domain ,
unsigned long cap )
{
return iommu_ops - > domain_has_cap ( domain , cap ) ;
}
EXPORT_SYMBOL_GPL ( iommu_domain_has_cap ) ;
2010-01-08 13:35:09 +01:00
int iommu_map ( struct iommu_domain * domain , unsigned long iova ,
phys_addr_t paddr , int gfp_order , int prot )
{
size_t size ;
2011-09-06 14:36:17 +02:00
size = PAGE_SIZE < < gfp_order ;
2010-01-08 13:35:09 +01:00
2011-09-02 13:32:32 -04:00
BUG_ON ( ! IS_ALIGNED ( iova | paddr , size ) ) ;
2010-01-08 13:35:09 +01:00
2010-01-21 11:50:28 +01:00
return iommu_ops - > map ( domain , iova , paddr , gfp_order , prot ) ;
2010-01-08 13:35:09 +01:00
}
EXPORT_SYMBOL_GPL ( iommu_map ) ;
int iommu_unmap ( struct iommu_domain * domain , unsigned long iova , int gfp_order )
{
size_t size ;
2011-09-06 14:36:17 +02:00
size = PAGE_SIZE < < gfp_order ;
2010-01-08 13:35:09 +01:00
2011-09-02 13:32:32 -04:00
BUG_ON ( ! IS_ALIGNED ( iova , size ) ) ;
2010-01-08 13:35:09 +01:00
2010-01-21 11:50:28 +01:00
return iommu_ops - > unmap ( domain , iova , gfp_order ) ;
2010-01-08 13:35:09 +01:00
}
EXPORT_SYMBOL_GPL ( iommu_unmap ) ;