diff --git a/include/linux/msi.h b/include/linux/msi.h index 24a54248f1aeb..36ba6a0852ea4 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -552,6 +552,8 @@ enum { MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 5), /* Free MSI descriptors */ MSI_FLAG_FREE_MSI_DESCS = (1 << 6), + /* Use dev->fwnode for MSI device domain creation */ + MSI_FLAG_USE_DEV_FWNODE = (1 << 7), /* Mask for the generic functionality */ MSI_GENERIC_FLAGS_MASK = GENMASK(15, 0), diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 8d463901c8643..5289fc2c7630b 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -960,9 +960,9 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, void *chip_data) { struct irq_domain *domain, *parent = dev->msi.domain; - const struct msi_parent_ops *pops; + struct fwnode_handle *fwnode, *fwnalloced = NULL; struct msi_domain_template *bundle; - struct fwnode_handle *fwnode; + const struct msi_parent_ops *pops; if (!irq_domain_is_msi_parent(parent)) return false; @@ -985,7 +985,19 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, pops->prefix ? : "", bundle->chip.name, dev_name(dev)); bundle->chip.name = bundle->name; - fwnode = irq_domain_alloc_named_fwnode(bundle->name); + /* + * Using the device firmware node is required for wire to MSI + * device domains so that the existing firmware results in a domain + * match. + * All other device domains like PCI/MSI use the named firmware + * node as they are not guaranteed to have a fwnode. They are never + * looked up and always handled in the context of the device. + */ + if (bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE) + fwnode = dev->fwnode; + else + fwnode = fwnalloced = irq_domain_alloc_named_fwnode(bundle->name); + if (!fwnode) goto free_bundle; @@ -1012,7 +1024,7 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, fail: msi_unlock_descs(dev); free_fwnode: - irq_domain_free_fwnode(fwnode); + irq_domain_free_fwnode(fwnalloced); free_bundle: kfree(bundle); return false;