Creating an irq domain that serves as an MSI parent requires a substantial amount of esoteric boiler-plate code, some of which is often provided twice (such as the bus token). To make things a bit simpler for the unsuspecting MSI tinkerer, provide a helper that does it for them, and serves as documentation of what needs to be provided. Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx> --- include/linux/msi.h | 7 +++++++ kernel/irq/msi.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/linux/msi.h b/include/linux/msi.h index b10093c4d00ea..f08d14cf07103 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -594,6 +594,13 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode, struct msi_domain_info *info, struct irq_domain *parent); +struct irq_domain *msi_create_parent_irq_domain(struct fwnode_handle *fwnode, + const struct msi_parent_ops *msi_parent_ops, + const struct irq_domain_ops *ops, + unsigned long flags, unsigned long size, + void *host_data, + struct irq_domain *parent); + bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, const struct msi_domain_template *template, unsigned int hwsize, void *domain_data, diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 396a067a8a56b..037d85cf0b21c 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -885,6 +885,46 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode, return __msi_create_irq_domain(fwnode, info, 0, parent); } +/** + * msi_create_parent_irq_domain - Create an MSI-parent interrupt domain + * @fwnode: Optional fwnode of the interrupt controller + * @msi_parent_ops: MSI parent callbacks and configuration + * @ops: Interrupt domain ballbacks + * @flags: Interrupt domain flags + * @size: Interrupt domain size (0 if arbitrarily large) + * @host_data: Interrupt domain private data + * @parent: Parent irq domain + * + * Return: pointer to the created &struct irq_domain or %NULL on failure + */ +struct irq_domain *msi_create_parent_irq_domain(struct fwnode_handle *fwnode, + const struct msi_parent_ops *msi_parent_ops, + const struct irq_domain_ops *ops, + unsigned long flags, unsigned long size, + void *host_data, + struct irq_domain *parent) +{ + struct irq_domain_info info = { + .fwnode = fwnode, + .size = size, + .hwirq_max = size, + .ops = ops, + .host_data = host_data, + .domain_flags = flags | IRQ_DOMAIN_FLAG_MSI_PARENT, + .parent = parent, + .bus_token = msi_parent_ops->bus_select_token, + }; + struct irq_domain *d; + + d = irq_domain_instantiate(&info); + if (IS_ERR(d)) + return NULL; + + d->msi_parent_ops = msi_parent_ops; + return d; +} +EXPORT_SYMBOL_GPL(msi_create_parent_irq_domain); + /** * msi_parent_init_dev_msi_info - Delegate initialization of device MSI info down * in the domain hierarchy -- 2.39.2