2017-11-07 19:30:07 +03:00
// SPDX-License-Identifier: GPL-2.0
2015-07-28 16:46:16 +03:00
/*
* MSI framework for platform devices
*
* Copyright ( C ) 2015 ARM Limited , All Rights Reserved .
* Author : Marc Zyngier < marc . zyngier @ arm . com >
*/
# include <linux/device.h>
# include <linux/idr.h>
# include <linux/irq.h>
# include <linux/irqdomain.h>
# include <linux/msi.h>
# include <linux/slab.h>
2015-12-22 05:47:22 +03:00
# define DEV_ID_SHIFT 21
2015-11-23 11:26:02 +03:00
# define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT))
2015-07-28 16:46:16 +03:00
/*
* Internal data structure containing a ( made up , but unique ) devid
* and the callback to write the MSI message .
*/
struct platform_msi_priv_data {
2021-08-13 06:56:28 +03:00
struct device * dev ;
void * host_data ;
msi_alloc_info_t arg ;
irq_write_msi_msg_t write_msg ;
int devid ;
2015-07-28 16:46:16 +03:00
} ;
/* The devid allocator */
static DEFINE_IDA ( platform_msi_devid_ida ) ;
# ifdef GENERIC_MSI_DOMAIN_OPS
/*
* Convert an msi_desc to a globaly unique identifier ( per - device
* devid + msi_desc position in the msi_list ) .
*/
static irq_hw_number_t platform_msi_calc_hwirq ( struct msi_desc * desc )
{
2021-12-11 01:19:11 +03:00
u32 devid = desc - > dev - > msi . data - > platform_data - > devid ;
2015-07-28 16:46:16 +03:00
2021-12-11 01:19:14 +03:00
return ( devid < < ( 32 - DEV_ID_SHIFT ) ) | desc - > msi_index ;
2015-07-28 16:46:16 +03:00
}
static void platform_msi_set_desc ( msi_alloc_info_t * arg , struct msi_desc * desc )
{
arg - > desc = desc ;
arg - > hwirq = platform_msi_calc_hwirq ( desc ) ;
}
static int platform_msi_init ( struct irq_domain * domain ,
struct msi_domain_info * info ,
unsigned int virq , irq_hw_number_t hwirq ,
msi_alloc_info_t * arg )
{
2015-09-13 15:37:03 +03:00
return irq_domain_set_hwirq_and_chip ( domain , virq , hwirq ,
info - > chip , info - > chip_data ) ;
2015-07-28 16:46:16 +03:00
}
2020-11-29 16:52:06 +03:00
static void platform_msi_set_proxy_dev ( msi_alloc_info_t * arg )
{
arg - > flags | = MSI_ALLOC_FLAGS_PROXY_DEVICE ;
}
2015-07-28 16:46:16 +03:00
# else
# define platform_msi_set_desc NULL
# define platform_msi_init NULL
2020-11-29 16:52:06 +03:00
# define platform_msi_set_proxy_dev(x) do {} while(0)
2015-07-28 16:46:16 +03:00
# endif
static void platform_msi_update_dom_ops ( struct msi_domain_info * info )
{
struct msi_domain_ops * ops = info - > ops ;
BUG_ON ( ! ops ) ;
if ( ops - > msi_init = = NULL )
ops - > msi_init = platform_msi_init ;
if ( ops - > set_desc = = NULL )
ops - > set_desc = platform_msi_set_desc ;
}
static void platform_msi_write_msg ( struct irq_data * data , struct msi_msg * msg )
{
2015-09-13 15:37:03 +03:00
struct msi_desc * desc = irq_data_get_msi_desc ( data ) ;
2015-07-28 16:46:16 +03:00
2021-12-11 01:19:11 +03:00
desc - > dev - > msi . data - > platform_data - > write_msg ( desc , msg ) ;
2015-07-28 16:46:16 +03:00
}
static void platform_msi_update_chip_ops ( struct msi_domain_info * info )
{
struct irq_chip * chip = info - > chip ;
BUG_ON ( ! chip ) ;
if ( ! chip - > irq_mask )
chip - > irq_mask = irq_chip_mask_parent ;
if ( ! chip - > irq_unmask )
chip - > irq_unmask = irq_chip_unmask_parent ;
if ( ! chip - > irq_eoi )
chip - > irq_eoi = irq_chip_eoi_parent ;
if ( ! chip - > irq_set_affinity )
chip - > irq_set_affinity = msi_domain_set_affinity ;
if ( ! chip - > irq_write_msi_msg )
chip - > irq_write_msi_msg = platform_msi_write_msg ;
2018-05-08 15:14:31 +03:00
if ( WARN_ON ( ( info - > flags & MSI_FLAG_LEVEL_CAPABLE ) & &
! ( chip - > flags & IRQCHIP_SUPPORTS_LEVEL_MSI ) ) )
info - > flags & = ~ MSI_FLAG_LEVEL_CAPABLE ;
2015-07-28 16:46:16 +03:00
}
/**
* platform_msi_create_irq_domain - Create a platform MSI interrupt domain
2015-10-13 14:51:44 +03:00
* @ fwnode : Optional fwnode of the interrupt controller
2015-07-28 16:46:16 +03:00
* @ info : MSI domain info
* @ parent : Parent irq domain
*
* Updates the domain and chip ops and creates a platform MSI
* interrupt domain .
*
* Returns :
* A domain pointer or NULL in case of failure .
*/
2015-10-13 14:51:44 +03:00
struct irq_domain * platform_msi_create_irq_domain ( struct fwnode_handle * fwnode ,
2015-07-28 16:46:16 +03:00
struct msi_domain_info * info ,
struct irq_domain * parent )
{
struct irq_domain * domain ;
if ( info - > flags & MSI_FLAG_USE_DEF_DOM_OPS )
platform_msi_update_dom_ops ( info ) ;
if ( info - > flags & MSI_FLAG_USE_DEF_CHIP_OPS )
platform_msi_update_chip_ops ( info ) ;
2021-12-07 01:51:41 +03:00
info - > flags | = MSI_FLAG_DEV_SYSFS | MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS |
MSI_FLAG_FREE_MSI_DESCS ;
2015-07-28 16:46:16 +03:00
2015-10-13 14:51:44 +03:00
domain = msi_create_irq_domain ( fwnode , info , parent ) ;
2015-07-28 16:46:16 +03:00
if ( domain )
2017-06-22 13:42:50 +03:00
irq_domain_update_bus_token ( domain , DOMAIN_BUS_PLATFORM_MSI ) ;
2015-07-28 16:46:16 +03:00
return domain ;
}
2021-12-11 01:19:11 +03:00
static int platform_msi_alloc_priv_data ( struct device * dev , unsigned int nvec ,
irq_write_msi_msg_t write_msi_msg )
2015-07-28 16:46:16 +03:00
{
2015-11-23 11:26:03 +03:00
struct platform_msi_priv_data * datap ;
2021-12-11 01:18:58 +03:00
int err ;
2015-07-28 16:46:16 +03:00
/*
2017-01-16 21:48:20 +03:00
* Limit the number of interrupts to 2048 per device . Should we
2015-07-28 16:46:16 +03:00
* need to bump this up , DEV_ID_SHIFT should be adjusted
* accordingly ( which would impact the max number of MSI
* capable devices ) .
*/
2021-12-11 01:18:54 +03:00
if ( ! dev - > msi . domain | | ! write_msi_msg | | ! nvec | | nvec > MAX_DEV_MSIS )
2021-12-11 01:19:11 +03:00
return - EINVAL ;
2015-07-28 16:46:16 +03:00
2021-12-11 01:18:54 +03:00
if ( dev - > msi . domain - > bus_token ! = DOMAIN_BUS_PLATFORM_MSI ) {
2015-07-28 16:46:16 +03:00
dev_err ( dev , " Incompatible msi_domain, giving up \n " ) ;
2021-12-11 01:19:11 +03:00
return - EINVAL ;
2015-07-28 16:46:16 +03:00
}
2021-12-11 01:18:58 +03:00
err = msi_setup_device_data ( dev ) ;
if ( err )
2021-12-11 01:19:11 +03:00
return err ;
2021-12-11 01:18:58 +03:00
2021-12-11 01:19:11 +03:00
/* Already initialized? */
if ( dev - > msi . data - > platform_data )
return - EBUSY ;
2015-11-23 11:26:03 +03:00
datap = kzalloc ( sizeof ( * datap ) , GFP_KERNEL ) ;
if ( ! datap )
2021-12-11 01:19:11 +03:00
return - ENOMEM ;
2015-11-23 11:26:03 +03:00
datap - > devid = ida_simple_get ( & platform_msi_devid_ida ,
0 , 1 < < DEV_ID_SHIFT , GFP_KERNEL ) ;
if ( datap - > devid < 0 ) {
2021-12-11 01:18:58 +03:00
err = datap - > devid ;
2015-11-23 11:26:03 +03:00
kfree ( datap ) ;
2021-12-11 01:19:11 +03:00
return err ;
2015-11-23 11:26:03 +03:00
}
2015-07-28 16:46:16 +03:00
2015-11-23 11:26:03 +03:00
datap - > write_msg = write_msi_msg ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
datap - > dev = dev ;
2021-12-11 01:19:11 +03:00
dev - > msi . data - > platform_data = datap ;
return 0 ;
2015-11-23 11:26:03 +03:00
}
2021-12-11 01:19:11 +03:00
static void platform_msi_free_priv_data ( struct device * dev )
2015-11-23 11:26:03 +03:00
{
2021-12-11 01:19:11 +03:00
struct platform_msi_priv_data * data = dev - > msi . data - > platform_data ;
dev - > msi . data - > platform_data = NULL ;
2015-11-23 11:26:03 +03:00
ida_simple_remove ( & platform_msi_devid_ida , data - > devid ) ;
kfree ( data ) ;
}
/**
* platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @ dev
* @ dev : The device for which to allocate interrupts
* @ nvec : The number of interrupts to allocate
* @ write_msi_msg : Callback to write an interrupt message for @ dev
*
* Returns :
* Zero for success , or an error code in case of failure
*/
int platform_msi_domain_alloc_irqs ( struct device * dev , unsigned int nvec ,
irq_write_msi_msg_t write_msi_msg )
{
int err ;
2015-07-28 16:46:16 +03:00
2021-12-11 01:19:11 +03:00
err = platform_msi_alloc_priv_data ( dev , nvec , write_msi_msg ) ;
if ( err )
return err ;
2015-07-28 16:46:16 +03:00
2021-12-11 01:18:54 +03:00
err = msi_domain_alloc_irqs ( dev - > msi . domain , dev , nvec ) ;
2015-07-28 16:46:16 +03:00
if ( err )
2021-12-07 01:51:41 +03:00
platform_msi_free_priv_data ( dev ) ;
2015-07-28 16:46:16 +03:00
return err ;
}
2016-01-26 16:52:27 +03:00
EXPORT_SYMBOL_GPL ( platform_msi_domain_alloc_irqs ) ;
2015-07-28 16:46:16 +03:00
/**
* platform_msi_domain_free_irqs - Free MSI interrupts for @ dev
* @ dev : The device for which to free interrupts
*/
void platform_msi_domain_free_irqs ( struct device * dev )
{
2021-12-11 01:18:54 +03:00
msi_domain_free_irqs ( dev - > msi . domain , dev ) ;
2021-12-11 01:19:11 +03:00
platform_msi_free_priv_data ( dev ) ;
2015-07-28 16:46:16 +03:00
}
2016-01-26 16:52:27 +03:00
EXPORT_SYMBOL_GPL ( platform_msi_domain_free_irqs ) ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
/**
* platform_msi_get_host_data - Query the private data associated with
* a platform - msi domain
* @ domain : The platform - msi domain
*
2021-12-11 01:19:09 +03:00
* Return : The private data provided when calling
* platform_msi_create_device_domain ( ) .
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*/
void * platform_msi_get_host_data ( struct irq_domain * domain )
{
struct platform_msi_priv_data * data = domain - > host_data ;
2021-12-11 01:19:09 +03:00
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
return data - > host_data ;
}
2021-12-07 01:51:42 +03:00
static struct lock_class_key platform_device_msi_lock_class ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
/**
2021-12-11 01:19:09 +03:00
* __platform_msi_create_device_domain - Create a platform - msi device domain
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*
* @ dev : The device generating the MSIs
* @ nvec : The number of MSIs that need to be allocated
2021-04-01 02:26:13 +03:00
* @ is_tree : flag to indicate tree hierarchy
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
* @ write_msi_msg : Callback to write an interrupt message for @ dev
* @ ops : The hierarchy domain operations to use
* @ host_data : Private data associated to this domain
*
2021-12-11 01:19:09 +03:00
* Return : An irqdomain for @ nvec interrupts on success , NULL in case of error .
*
* This is for interrupt domains which stack on a platform - msi domain
* created by platform_msi_create_irq_domain ( ) . @ dev - > msi . domain points to
* that platform - msi domain which is the parent for the new domain .
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*/
struct irq_domain *
2018-10-01 17:13:45 +03:00
__platform_msi_create_device_domain ( struct device * dev ,
unsigned int nvec ,
bool is_tree ,
irq_write_msi_msg_t write_msi_msg ,
const struct irq_domain_ops * ops ,
void * host_data )
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
{
struct platform_msi_priv_data * data ;
struct irq_domain * domain ;
int err ;
2021-12-11 01:19:11 +03:00
err = platform_msi_alloc_priv_data ( dev , nvec , write_msi_msg ) ;
if ( err )
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
return NULL ;
2021-12-07 01:51:42 +03:00
/*
* Use a separate lock class for the MSI descriptor mutex on
* platform MSI device domains because the descriptor mutex nests
* into the domain mutex . See alloc / free below .
*/
lockdep_set_class ( & dev - > msi . data - > mutex , & platform_device_msi_lock_class ) ;
2021-12-11 01:19:11 +03:00
data = dev - > msi . data - > platform_data ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
data - > host_data = host_data ;
2021-12-11 01:18:54 +03:00
domain = irq_domain_create_hierarchy ( dev - > msi . domain , 0 ,
2018-10-01 17:13:45 +03:00
is_tree ? 0 : nvec ,
2017-03-07 15:40:07 +03:00
dev - > fwnode , ops , data ) ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
if ( ! domain )
goto free_priv ;
2020-11-29 16:52:06 +03:00
platform_msi_set_proxy_dev ( & data - > arg ) ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
err = msi_domain_prepare_irqs ( domain - > parent , dev , nvec , & data - > arg ) ;
if ( err )
goto free_domain ;
return domain ;
free_domain :
irq_domain_remove ( domain ) ;
free_priv :
2021-12-11 01:19:11 +03:00
platform_msi_free_priv_data ( dev ) ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
return NULL ;
}
/**
2021-12-11 01:19:09 +03:00
* platform_msi_device_domain_free - Free interrupts associated with a platform - msi
* device domain
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*
2021-12-11 01:19:09 +03:00
* @ domain : The platform - msi device domain
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
* @ virq : The base irq from which to perform the free operation
2021-12-07 01:51:42 +03:00
* @ nr_irqs : How many interrupts to free from @ virq
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*/
2021-12-11 01:19:09 +03:00
void platform_msi_device_domain_free ( struct irq_domain * domain , unsigned int virq ,
2021-12-07 01:51:42 +03:00
unsigned int nr_irqs )
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
{
struct platform_msi_priv_data * data = domain - > host_data ;
2021-12-11 01:19:09 +03:00
2021-12-07 01:51:42 +03:00
msi_lock_descs ( data - > dev ) ;
irq_domain_free_irqs_common ( domain , virq , nr_irqs ) ;
msi_free_msi_descs_range ( data - > dev , MSI_DESC_ALL , virq , virq + nr_irqs - 1 ) ;
msi_unlock_descs ( data - > dev ) ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
}
/**
2021-12-11 01:19:09 +03:00
* platform_msi_device_domain_alloc - Allocate interrupts associated with
* a platform - msi device domain
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*
2021-12-11 01:19:09 +03:00
* @ domain : The platform - msi device domain
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
* @ virq : The base irq from which to perform the allocate operation
2021-12-07 01:51:42 +03:00
* @ nr_irqs : How many interrupts to allocate from @ virq
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
*
* Return 0 on success , or an error code on failure . Must be called
* with irq_domain_mutex held ( which can only be done as part of a
* top - level interrupt allocation ) .
*/
2021-12-11 01:19:09 +03:00
int platform_msi_device_domain_alloc ( struct irq_domain * domain , unsigned int virq ,
unsigned int nr_irqs )
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
{
struct platform_msi_priv_data * data = domain - > host_data ;
2021-12-07 01:51:42 +03:00
struct device * dev = data - > dev ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
2021-12-07 01:51:42 +03:00
return msi_domain_populate_irqs ( domain - > parent , dev , virq , nr_irqs , & data - > arg ) ;
platform-msi: Allow creation of a MSI-based stacked irq domain
We almost have all the needed bits requiredable to create a irq domain
on top of a MSI domain.
For this, we enable a few things:
- the virq is stored in the msi_desc
- device, msi_alloc_info and domain-specific data
are stored in the platform_priv_data structure
- we introduce a new API for platform-msi:
/* Create a MSI-based domain */
struct irq_domain *
platform_msi_create_device_domain(struct device *dev,
unsigned int nvec,
irq_write_msi_msg_t write_msi_msg,
const struct irq_domain_ops *ops,
void *host_data);
/* Allocate MSIs in an MSI domain */
int platform_msi_domain_alloc(struct irq_domain *domain,
unsigned int virq,
unsigned int nr_irqs);
/* Free MSIs from an MSI domain */
void platform_msi_domain_free(struct irq_domain *domain,
unsigned int virq,
unsigned int nvec);
/* Obtain the host data passed to platform_msi_create_device_domain */
void *platform_msi_get_host_data(struct irq_domain *domain);
platform_msi_create_device_domain() is a hybrid of irqdomain creation
and interrupt allocation, creating a domain backed by the MSIs associated
to a device. IRQs can then be allocated in that domain using
platform_msi_domain_alloc().
This now allows a wired irq to MSI bridge to be created.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
2015-11-23 11:26:07 +03:00
}