2019-05-29 16:57:49 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2012-06-25 14:23:54 +03:00
/*
* OF helpers for IOMMU
*
* Copyright ( c ) 2012 , NVIDIA CORPORATION . All rights reserved .
*/
# include <linux/export.h>
2014-08-27 16:20:32 +01:00
# include <linux/iommu.h>
2012-06-25 14:23:54 +03:00
# include <linux/limits.h>
2019-12-19 12:03:42 +00:00
# include <linux/module.h>
2019-09-03 13:30:59 +02:00
# include <linux/msi.h>
2012-06-25 14:23:54 +03:00
# include <linux/of.h>
2013-12-04 17:22:53 -08:00
# include <linux/of_iommu.h>
2016-09-12 17:13:41 +01:00
# include <linux/of_pci.h>
2019-12-19 12:03:42 +00:00
# include <linux/pci.h>
2014-12-05 13:41:02 +00:00
# include <linux/slab.h>
2018-09-10 19:19:17 +05:30
# include <linux/fsl/mc.h>
2012-06-25 14:23:54 +03:00
2017-08-04 17:29:06 +01:00
# define NO_IOMMU 1
2012-06-25 14:23:54 +03:00
/**
* of_get_dma_window - Parse * dma - window property and returns 0 if found .
*
* @ dn : device node
* @ prefix : prefix for property name if any
* @ index : index to start to parse
* @ busno : Returns busno if supported . Otherwise pass NULL
* @ addr : Returns address that DMA starts
* @ size : Returns the range that DMA can handle
*
* This supports different formats flexibly . " prefix " can be
* configured if any . " busno " and " index " are optionally
* specified . Set 0 ( or NULL ) if not used .
*/
int of_get_dma_window ( struct device_node * dn , const char * prefix , int index ,
unsigned long * busno , dma_addr_t * addr , size_t * size )
{
const __be32 * dma_window , * end ;
int bytes , cur_index = 0 ;
char propname [ NAME_MAX ] , addrname [ NAME_MAX ] , sizename [ NAME_MAX ] ;
if ( ! dn | | ! addr | | ! size )
return - EINVAL ;
if ( ! prefix )
prefix = " " ;
snprintf ( propname , sizeof ( propname ) , " %sdma-window " , prefix ) ;
snprintf ( addrname , sizeof ( addrname ) , " %s#dma-address-cells " , prefix ) ;
snprintf ( sizename , sizeof ( sizename ) , " %s#dma-size-cells " , prefix ) ;
dma_window = of_get_property ( dn , propname , & bytes ) ;
if ( ! dma_window )
return - ENODEV ;
end = dma_window + bytes / sizeof ( * dma_window ) ;
while ( dma_window < end ) {
u32 cells ;
const void * prop ;
/* busno is one cell if supported */
if ( busno )
* busno = be32_to_cpup ( dma_window + + ) ;
prop = of_get_property ( dn , addrname , NULL ) ;
if ( ! prop )
prop = of_get_property ( dn , " #address-cells " , NULL ) ;
cells = prop ? be32_to_cpup ( prop ) : of_n_addr_cells ( dn ) ;
if ( ! cells )
return - EINVAL ;
* addr = of_read_number ( dma_window , cells ) ;
dma_window + = cells ;
prop = of_get_property ( dn , sizename , NULL ) ;
cells = prop ? be32_to_cpup ( prop ) : of_n_size_cells ( dn ) ;
if ( ! cells )
return - EINVAL ;
* size = of_read_number ( dma_window , cells ) ;
dma_window + = cells ;
if ( cur_index + + = = index )
break ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( of_get_dma_window ) ;
2014-08-27 14:40:58 +01:00
2017-08-04 17:29:06 +01:00
static int of_iommu_xlate ( struct device * dev ,
struct of_phandle_args * iommu_spec )
2017-04-10 16:50:56 +05:30
{
const struct iommu_ops * ops ;
struct fwnode_handle * fwnode = & iommu_spec - > np - > fwnode ;
2019-12-19 12:03:42 +00:00
int ret ;
2017-04-10 16:50:56 +05:30
ops = iommu_ops_from_fwnode ( fwnode ) ;
2017-04-10 16:50:57 +05:30
if ( ( ops & & ! ops - > of_xlate ) | |
2018-07-09 09:41:52 -06:00
! of_device_is_available ( iommu_spec - > np ) )
2017-08-04 17:29:06 +01:00
return NO_IOMMU ;
2017-04-10 16:50:56 +05:30
2019-12-19 12:03:42 +00:00
ret = iommu_fwspec_init ( dev , & iommu_spec - > np - > fwnode , ops ) ;
if ( ret )
return ret ;
2017-04-10 16:50:57 +05:30
/*
* The otherwise - empty fwspec handily serves to indicate the specific
* IOMMU device we ' re waiting for , which will be useful if we ever get
* a proper probe - ordering dependency mechanism in future .
*/
if ( ! ops )
2018-07-09 09:41:51 -06:00
return driver_deferred_probe_check_state ( dev ) ;
2017-04-10 16:50:56 +05:30
2019-12-19 12:03:42 +00:00
if ( ! try_module_get ( ops - > owner ) )
return - ENODEV ;
ret = ops - > of_xlate ( dev , iommu_spec ) ;
module_put ( ops - > owner ) ;
return ret ;
2017-04-10 16:50:56 +05:30
}
2020-06-19 09:20:08 +01:00
static int of_iommu_configure_dev_id ( struct device_node * master_np ,
struct device * dev ,
const u32 * id )
2016-09-12 17:13:41 +01:00
{
2017-05-31 18:52:29 +01:00
struct of_phandle_args iommu_spec = { . args_count = 1 } ;
2017-04-10 16:50:56 +05:30
int err ;
2016-09-12 17:13:41 +01:00
2020-06-19 09:20:08 +01:00
err = of_map_id ( master_np , * id , " iommu-map " ,
" iommu-map-mask " , & iommu_spec . np ,
iommu_spec . args ) ;
2017-04-10 16:50:56 +05:30
if ( err )
2017-08-04 17:29:06 +01:00
return err = = - ENODEV ? NO_IOMMU : err ;
2016-09-12 17:13:41 +01:00
2020-06-19 09:20:08 +01:00
err = of_iommu_xlate ( dev , & iommu_spec ) ;
2016-09-12 17:13:41 +01:00
of_node_put ( iommu_spec . np ) ;
2017-09-21 11:20:58 +01:00
return err ;
2017-04-10 16:50:56 +05:30
}
2020-06-19 09:20:08 +01:00
static int of_iommu_configure_dev ( struct device_node * master_np ,
struct device * dev )
2018-09-10 19:19:17 +05:30
{
2020-06-19 09:20:08 +01:00
struct of_phandle_args iommu_spec ;
int err = NO_IOMMU , idx = 0 ;
while ( ! of_parse_phandle_with_args ( master_np , " iommus " ,
" #iommu-cells " ,
idx , & iommu_spec ) ) {
err = of_iommu_xlate ( dev , & iommu_spec ) ;
of_node_put ( iommu_spec . np ) ;
idx + + ;
if ( err )
break ;
}
2018-09-10 19:19:17 +05:30
return err ;
}
2020-06-19 09:20:08 +01:00
struct of_pci_iommu_alias_info {
struct device * dev ;
struct device_node * np ;
} ;
static int of_pci_iommu_init ( struct pci_dev * pdev , u16 alias , void * data )
{
struct of_pci_iommu_alias_info * info = data ;
u32 input_id = alias ;
return of_iommu_configure_dev_id ( info - > np , info - > dev , & input_id ) ;
}
static int of_iommu_configure_device ( struct device_node * master_np ,
struct device * dev , const u32 * id )
{
return ( id ) ? of_iommu_configure_dev_id ( master_np , dev , id ) :
of_iommu_configure_dev ( master_np , dev ) ;
}
2017-04-10 16:50:56 +05:30
const struct iommu_ops * of_iommu_configure ( struct device * dev ,
2020-06-19 09:20:08 +01:00
struct device_node * master_np ,
const u32 * id )
2017-04-10 16:50:56 +05:30
{
2017-05-31 18:52:29 +01:00
const struct iommu_ops * ops = NULL ;
2018-11-29 14:01:00 +01:00
struct iommu_fwspec * fwspec = dev_iommu_fwspec_get ( dev ) ;
2017-08-04 17:29:06 +01:00
int err = NO_IOMMU ;
2017-04-10 16:50:56 +05:30
if ( ! master_np )
return NULL ;
2017-04-10 16:50:57 +05:30
if ( fwspec ) {
if ( fwspec - > ops )
return fwspec - > ops ;
/* In the deferred case, start again from scratch */
iommu_fwspec_free ( dev ) ;
}
2017-05-31 18:52:29 +01:00
/*
* We don ' t currently walk up the tree looking for a parent IOMMU .
* See the ` Notes : ' section of
* Documentation / devicetree / bindings / iommu / iommu . txt
*/
if ( dev_is_pci ( dev ) ) {
struct of_pci_iommu_alias_info info = {
. dev = dev ,
. np = master_np ,
} ;
2019-12-19 12:03:38 +00:00
pci_request_acs ( ) ;
2017-05-31 18:52:29 +01:00
err = pci_for_each_dma_alias ( to_pci_dev ( dev ) ,
of_pci_iommu_init , & info ) ;
} else {
2020-06-19 09:20:08 +01:00
err = of_iommu_configure_device ( master_np , dev , id ) ;
2017-08-04 17:29:06 +01:00
2020-01-15 13:52:29 +01:00
fwspec = dev_iommu_fwspec_get ( dev ) ;
if ( ! err & & fwspec )
of_property_read_u32 ( master_np , " pasid-num-bits " ,
& fwspec - > num_pasid_bits ) ;
}
2018-11-29 14:01:00 +01:00
2017-08-04 17:29:06 +01:00
/*
* Two success conditions can be represented by non - negative err here :
* > 0 : there is no IOMMU , or one was unavailable for non - fatal reasons
* 0 : we found an IOMMU , and dev - > fwspec is initialised appropriately
* < 0 : any actual error
*/
2018-11-29 14:01:00 +01:00
if ( ! err ) {
/* The fwspec pointer changed, read it again */
fwspec = dev_iommu_fwspec_get ( dev ) ;
ops = fwspec - > ops ;
}
2017-04-10 16:50:57 +05:30
/*
* If we have reason to believe the IOMMU driver missed the initial
2018-12-05 14:39:45 +01:00
* probe for dev , replay it to get things in order .
2017-04-10 16:50:57 +05:30
*/
2019-01-07 17:04:50 +00:00
if ( ! err & & dev - > bus & & ! device_iommu_mapped ( dev ) )
2018-12-05 14:39:45 +01:00
err = iommu_probe_device ( dev ) ;
2014-08-27 16:20:32 +01:00
2017-05-27 19:17:41 +05:30
/* Ignore all other errors apart from EPROBE_DEFER */
2017-08-04 17:29:06 +01:00
if ( err = = - EPROBE_DEFER ) {
ops = ERR_PTR ( err ) ;
} else if ( err < 0 ) {
dev_dbg ( dev , " Adding to IOMMU failed: %d \n " , err ) ;
2017-05-27 19:17:41 +05:30
ops = NULL ;
}
2017-04-10 16:51:02 +05:30
return ops ;
2014-08-27 16:20:32 +01:00
}