2018-01-17 19:36:44 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-01-07 01:03:22 +03:00
/*
* Freescale Management Complex ( MC ) bus driver MSI support
*
2016-10-26 19:20:33 +03:00
* Copyright ( C ) 2015 - 2016 Freescale Semiconductor , Inc .
2016-01-07 01:03:22 +03:00
* Author : German Rivera < German . Rivera @ freescale . com >
*
*/
# include <linux/of_device.h>
# include <linux/of_address.h>
# include <linux/irq.h>
# include <linux/msi.h>
# include <linux/of.h>
# include <linux/of_irq.h>
2018-02-05 17:07:42 +03:00
# include <linux/fsl/mc.h>
2016-01-07 01:03:22 +03:00
static struct irq_chip its_msi_irq_chip = {
2016-10-17 21:42:53 +03:00
. name = " ITS-fMSI " ,
2016-01-07 01:03:22 +03:00
. irq_mask = irq_chip_mask_parent ,
. irq_unmask = irq_chip_unmask_parent ,
. irq_eoi = irq_chip_eoi_parent ,
. irq_set_affinity = msi_domain_set_affinity
} ;
static int its_fsl_mc_msi_prepare ( struct irq_domain * msi_domain ,
struct device * dev ,
int nvec , msi_alloc_info_t * info )
{
struct fsl_mc_device * mc_bus_dev ;
struct msi_domain_info * msi_info ;
2017-11-17 16:38:32 +03:00
if ( ! dev_is_fsl_mc ( dev ) )
2016-01-07 01:03:22 +03:00
return - EINVAL ;
mc_bus_dev = to_fsl_mc_device ( dev ) ;
2017-11-17 16:38:32 +03:00
if ( ! ( mc_bus_dev - > flags & FSL_MC_IS_DPRC ) )
2016-01-07 01:03:22 +03:00
return - EINVAL ;
/*
* Set the device Id to be passed to the GIC - ITS :
*
* NOTE : This device id corresponds to the IOMMU stream ID
* associated with the DPRC object ( ICID ) .
*/
info - > scratchpad [ 0 ] . ul = mc_bus_dev - > icid ;
msi_info = msi_get_domain_info ( msi_domain - > parent ) ;
2018-05-27 18:39:55 +03:00
/* Allocate at least 32 MSIs, and always as a power of 2 */
nvec = max_t ( int , 32 , roundup_pow_of_two ( nvec ) ) ;
2016-01-07 01:03:22 +03:00
return msi_info - > ops - > msi_prepare ( msi_domain - > parent , dev , nvec , info ) ;
}
2017-02-11 04:37:57 +03:00
static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = {
2016-01-07 01:03:22 +03:00
. msi_prepare = its_fsl_mc_msi_prepare ,
} ;
static struct msi_domain_info its_fsl_mc_msi_domain_info = {
. flags = ( MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS ) ,
. ops = & its_fsl_mc_msi_ops ,
. chip = & its_msi_irq_chip ,
} ;
static const struct of_device_id its_device_id [ ] = {
{ . compatible = " arm,gic-v3-its " , } ,
{ } ,
} ;
2018-01-17 14:14:04 +03:00
static int __init its_fsl_mc_msi_init ( void )
2016-01-07 01:03:22 +03:00
{
struct device_node * np ;
struct irq_domain * parent ;
struct irq_domain * mc_msi_domain ;
for ( np = of_find_matching_node ( NULL , its_device_id ) ; np ;
np = of_find_matching_node ( np , its_device_id ) ) {
2018-02-01 20:03:29 +03:00
if ( ! of_device_is_available ( np ) )
continue ;
2016-01-07 01:03:22 +03:00
if ( ! of_property_read_bool ( np , " msi-controller " ) )
continue ;
parent = irq_find_matching_host ( np , DOMAIN_BUS_NEXUS ) ;
if ( ! parent | | ! msi_get_domain_info ( parent ) ) {
2017-07-19 00:43:33 +03:00
pr_err ( " %pOF: unable to locate ITS domain \n " , np ) ;
2016-01-07 01:03:22 +03:00
continue ;
}
mc_msi_domain = fsl_mc_msi_create_irq_domain (
of_node_to_fwnode ( np ) ,
& its_fsl_mc_msi_domain_info ,
parent ) ;
if ( ! mc_msi_domain ) {
2017-07-19 00:43:33 +03:00
pr_err ( " %pOF: unable to create fsl-mc domain \n " , np ) ;
2016-01-07 01:03:22 +03:00
continue ;
}
2017-07-19 00:43:33 +03:00
pr_info ( " fsl-mc MSI: %pOF domain created \n " , np ) ;
2016-01-07 01:03:22 +03:00
}
return 0 ;
}
2018-01-16 16:19:07 +03:00
early_initcall ( its_fsl_mc_msi_init ) ;