2008-11-26 19:21:24 +03: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 18:03:26 +04:00
# include <linux/device.h>
2011-09-02 21:32:32 +04:00
# include <linux/kernel.h>
2008-11-26 19:21:24 +03:00
# include <linux/bug.h>
# include <linux/types.h>
2009-05-07 03:03:07 +04:00
# include <linux/module.h>
# include <linux/slab.h>
2008-11-26 19:21:24 +03:00
# include <linux/errno.h>
# include <linux/iommu.h>
2011-08-26 18:48:26 +04:00
static void iommu_bus_init ( struct bus_type * bus , struct iommu_ops * ops )
{
}
2008-11-26 19:21:24 +03:00
2011-08-26 18:48:26 +04:00
/**
* 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 )
2008-11-26 19:21:24 +03:00
{
2011-08-26 18:48:26 +04:00
if ( bus - > iommu_ops ! = NULL )
return - EBUSY ;
2008-11-26 19:21:24 +03:00
2011-08-26 18:48:26 +04:00
bus - > iommu_ops = ops ;
/* Do IOMMU specific setup for this bus-type */
iommu_bus_init ( bus , ops ) ;
2008-11-26 19:21:24 +03:00
2011-08-26 18:48:26 +04:00
return 0 ;
2008-11-26 19:21:24 +03:00
}
2011-08-26 18:48:26 +04:00
EXPORT_SYMBOL_GPL ( bus_set_iommu ) ;
2008-11-26 19:21:24 +03:00
2011-09-06 20:46:34 +04:00
bool iommu_present ( struct bus_type * bus )
2008-11-26 19:21:24 +03:00
{
2011-09-06 20:58:54 +04:00
return bus - > iommu_ops ! = NULL ;
2008-11-26 19:21:24 +03:00
}
2011-09-06 20:46:34 +04:00
EXPORT_SYMBOL_GPL ( iommu_present ) ;
2008-11-26 19:21:24 +03:00
2011-09-13 23:25:23 +04:00
/**
* iommu_set_fault_handler ( ) - set a fault handler for an iommu domain
* @ domain : iommu domain
* @ handler : fault handler
2011-09-27 15:36:40 +04:00
*
* This function should be used by IOMMU users which want to be notified
* whenever an IOMMU fault happens .
*
* The fault handler itself should return 0 on success , and an appropriate
* error code otherwise .
2011-09-13 23:25:23 +04:00
*/
void iommu_set_fault_handler ( struct iommu_domain * domain ,
iommu_fault_handler_t handler )
{
BUG_ON ( ! domain ) ;
domain - > handler = handler ;
}
2011-09-26 17:11:46 +04:00
EXPORT_SYMBOL_GPL ( iommu_set_fault_handler ) ;
2011-09-13 23:25:23 +04:00
2011-09-06 18:03:26 +04:00
struct iommu_domain * iommu_domain_alloc ( struct bus_type * bus )
2008-11-26 19:21:24 +03:00
{
struct iommu_domain * domain ;
int ret ;
2011-09-06 20:58:54 +04:00
if ( bus = = NULL | | bus - > iommu_ops = = NULL )
2011-09-06 18:03:26 +04:00
return NULL ;
2008-11-26 19:21:24 +03:00
domain = kmalloc ( sizeof ( * domain ) , GFP_KERNEL ) ;
if ( ! domain )
return NULL ;
2011-09-06 20:58:54 +04:00
domain - > ops = bus - > iommu_ops ;
2011-09-06 18:03:26 +04:00
2011-09-06 20:58:54 +04:00
ret = domain - > ops - > domain_init ( domain ) ;
2008-11-26 19:21:24 +03:00
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 )
{
2011-09-06 18:44:29 +04:00
if ( likely ( domain - > ops - > domain_destroy ! = NULL ) )
domain - > ops - > domain_destroy ( domain ) ;
2008-11-26 19:21:24 +03:00
kfree ( domain ) ;
}
EXPORT_SYMBOL_GPL ( iommu_domain_free ) ;
int iommu_attach_device ( struct iommu_domain * domain , struct device * dev )
{
2011-09-06 18:44:29 +04:00
if ( unlikely ( domain - > ops - > attach_dev = = NULL ) )
return - ENODEV ;
return domain - > ops - > attach_dev ( domain , dev ) ;
2008-11-26 19:21:24 +03:00
}
EXPORT_SYMBOL_GPL ( iommu_attach_device ) ;
void iommu_detach_device ( struct iommu_domain * domain , struct device * dev )
{
2011-09-06 18:44:29 +04:00
if ( unlikely ( domain - > ops - > detach_dev = = NULL ) )
return ;
domain - > ops - > detach_dev ( domain , dev ) ;
2008-11-26 19:21:24 +03:00
}
EXPORT_SYMBOL_GPL ( iommu_detach_device ) ;
phys_addr_t iommu_iova_to_phys ( struct iommu_domain * domain ,
unsigned long iova )
{
2011-09-06 18:44:29 +04:00
if ( unlikely ( domain - > ops - > iova_to_phys = = NULL ) )
return 0 ;
return domain - > ops - > iova_to_phys ( domain , iova ) ;
2008-11-26 19:21:24 +03:00
}
EXPORT_SYMBOL_GPL ( iommu_iova_to_phys ) ;
2009-03-18 10:33:06 +03:00
int iommu_domain_has_cap ( struct iommu_domain * domain ,
unsigned long cap )
{
2011-09-06 18:44:29 +04:00
if ( unlikely ( domain - > ops - > domain_has_cap = = NULL ) )
return 0 ;
return domain - > ops - > domain_has_cap ( domain , cap ) ;
2009-03-18 10:33:06 +03:00
}
EXPORT_SYMBOL_GPL ( iommu_domain_has_cap ) ;
2010-01-08 15:35:09 +03: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 18:44:29 +04:00
if ( unlikely ( domain - > ops - > map = = NULL ) )
return - ENODEV ;
2010-01-08 15:35:09 +03:00
2011-09-06 16:36:17 +04:00
size = PAGE_SIZE < < gfp_order ;
2010-01-08 15:35:09 +03:00
2011-09-02 21:32:32 +04:00
BUG_ON ( ! IS_ALIGNED ( iova | paddr , size ) ) ;
2010-01-08 15:35:09 +03:00
2011-09-06 18:44:29 +04:00
return domain - > ops - > map ( domain , iova , paddr , gfp_order , prot ) ;
2010-01-08 15:35:09 +03: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 18:44:29 +04:00
if ( unlikely ( domain - > ops - > unmap = = NULL ) )
return - ENODEV ;
2011-09-06 16:36:17 +04:00
size = PAGE_SIZE < < gfp_order ;
2010-01-08 15:35:09 +03:00
2011-09-02 21:32:32 +04:00
BUG_ON ( ! IS_ALIGNED ( iova , size ) ) ;
2010-01-08 15:35:09 +03:00
2011-09-06 18:44:29 +04:00
return domain - > ops - > unmap ( domain , iova , gfp_order ) ;
2010-01-08 15:35:09 +03:00
}
EXPORT_SYMBOL_GPL ( iommu_unmap ) ;