diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-02 09:35:59 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-02 09:35:59 -0800 |
| commit | 9ce62ebbb7b24c28a1781f6b3bc6fdcd0b961392 (patch) | |
| tree | 371ad0a3ea2ecd465acaa191bcf835f20f3732d4 | |
| parent | 15b87bec89cb227b55b3689bf5de31b85cf88559 (diff) | |
| parent | 9c1fbc56ca0a98113e75dcc5030103a02eff8897 (diff) | |
Merge tag 'irq-msi-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull MSI updates from Thomas Gleixner:
"Updates for [PCI] MSI related code:
- Remove one variant of PCI/MSI management as all users have been
converted to use per device domains. That reduces the variants to
two:
The modern and the real archaic legacy variant, which keeps the
usual suspects in the museum category alive.
- Rework the platform MSI device ID detection mechanism in the ARM
GIC world to address resource leaks, duplicated code and other
details. This requires a corresponding preparatory step in the
PCI/iproc driver.
- Trivial core code cleanups"
* tag 'irq-msi-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
irqchip/gic-its: Rework platform MSI deviceID detection
PCI: iproc: Implement MSI controller node detection with of_msi_xlate()
genirq/msi: Slightly simplify msi_domain_alloc()
PCI/MSI: Delete pci_msi_create_irq_domain()
| -rw-r--r-- | drivers/irqchip/irq-gic-its-msi-parent.c | 91 | ||||
| -rw-r--r-- | drivers/pci/controller/pcie-iproc.c | 22 | ||||
| -rw-r--r-- | drivers/pci/msi/irqdomain.c | 90 | ||||
| -rw-r--r-- | include/linux/msi.h | 3 | ||||
| -rw-r--r-- | kernel/irq/msi.c | 2 |
5 files changed, 29 insertions, 179 deletions
diff --git a/drivers/irqchip/irq-gic-its-msi-parent.c b/drivers/irqchip/irq-gic-its-msi-parent.c index eb1473f1448a..12f45228c867 100644 --- a/drivers/irqchip/irq-gic-its-msi-parent.c +++ b/drivers/irqchip/irq-gic-its-msi-parent.c @@ -142,83 +142,38 @@ static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device *dev, #define its_v5_pci_msi_prepare NULL #endif /* !CONFIG_PCI_MSI */ -static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev, - u32 *dev_id) +static int of_pmsi_get_msi_info(struct irq_domain *domain, struct device *dev, u32 *dev_id, + phys_addr_t *pa) { - int ret, index = 0; + struct of_phandle_iterator it; + int ret; /* Suck the DeviceID out of the msi-parent property */ - do { - struct of_phandle_args args; - - ret = of_parse_phandle_with_args(dev->of_node, - "msi-parent", "#msi-cells", - index, &args); - if (args.np == irq_domain_get_of_node(domain)) { - if (WARN_ON(args.args_count != 1)) - return -EINVAL; - *dev_id = args.args[0]; - break; - } - index++; - } while (!ret); - - if (ret) { - struct device_node *np = NULL; + of_for_each_phandle(&it, ret, dev->of_node, "msi-parent", "#msi-cells", -1) { + /* GICv5 ITS domain matches the MSI controller node parent */ + struct device_node *np __free(device_node) = pa ? of_get_parent(it.node) + : of_node_get(it.node); - ret = of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np, dev_id); - if (np) - of_node_put(np); - } + if (np == irq_domain_get_of_node(domain)) { + u32 args; - return ret; -} + if (WARN_ON(of_phandle_iterator_args(&it, &args, 1) != 1)) + ret = -EINVAL; -static int of_v5_pmsi_get_msi_info(struct irq_domain *domain, struct device *dev, - u32 *dev_id, phys_addr_t *pa) -{ - int ret, index = 0; - /* - * Retrieve the DeviceID and the ITS translate frame node pointer - * out of the msi-parent property. - */ - do { - struct of_phandle_args args; - - ret = of_parse_phandle_with_args(dev->of_node, - "msi-parent", "#msi-cells", - index, &args); - if (ret) - break; - /* - * The IRQ domain fwnode is the msi controller parent - * in GICv5 (where the msi controller nodes are the - * ITS translate frames). - */ - if (args.np->parent == irq_domain_get_of_node(domain)) { - if (WARN_ON(args.args_count != 1)) - return -EINVAL; - *dev_id = args.args[0]; - - ret = its_translate_frame_address(args.np, pa); - if (ret) - return -ENODEV; - break; - } - index++; - } while (!ret); + if (!ret && pa) + ret = its_translate_frame_address(it.node, pa); - if (ret) { - struct device_node *np = NULL; + if (!ret) + *dev_id = args; - ret = of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np, dev_id); - if (np) { - ret = its_translate_frame_address(np, pa); - of_node_put(np); + of_node_put(it.node); + return ret; } } - return ret; + struct device_node *msi_ctrl __free(device_node) = NULL; + + return of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &msi_ctrl, dev_id); } int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) @@ -234,7 +189,7 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, int ret; if (dev->of_node) - ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id); + ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, NULL); else ret = iort_pmsi_get_dev_id(dev, &dev_id); if (ret) @@ -262,7 +217,7 @@ static int its_v5_pmsi_prepare(struct irq_domain *domain, struct device *dev, if (!dev->of_node) return -ENODEV; - ret = of_v5_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); + ret = of_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa); if (ret) return ret; diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index 22134e95574b..ccf71993ea35 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -17,6 +17,7 @@ #include <linux/irqchip/arm-gic-v3.h> #include <linux/platform_device.h> #include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_pci.h> #include <linux/of_platform.h> #include <linux/phy/phy.h> @@ -1337,29 +1338,16 @@ static int iproc_pcie_msi_steer(struct iproc_pcie *pcie, static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) { - struct device_node *msi_node; + struct device_node *msi_node = NULL; int ret; /* * Either the "msi-parent" or the "msi-map" phandle needs to exist * for us to obtain the MSI node. */ - - msi_node = of_parse_phandle(pcie->dev->of_node, "msi-parent", 0); - if (!msi_node) { - const __be32 *msi_map = NULL; - int len; - u32 phandle; - - msi_map = of_get_property(pcie->dev->of_node, "msi-map", &len); - if (!msi_map) - return -ENODEV; - - phandle = be32_to_cpup(msi_map + 1); - msi_node = of_find_node_by_phandle(phandle); - if (!msi_node) - return -ENODEV; - } + of_msi_xlate(pcie->dev, &msi_node, 0); + if (!msi_node) + return -ENODEV; /* * Certain revisions of the iProc PCIe controller require additional diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index ce741ed9dc3f..a329060287b5 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -49,96 +49,6 @@ static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg * __pci_write_msi_msg(desc, msg); } -/** - * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source - * @desc: Pointer to the MSI descriptor - * - * The ID number is only used within the irqdomain. - */ -static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc) -{ - struct pci_dev *dev = msi_desc_to_pci_dev(desc); - - return (irq_hw_number_t)desc->msi_index | - pci_dev_id(dev) << 11 | - ((irq_hw_number_t)(pci_domain_nr(dev->bus) & 0xFFFFFFFF)) << 27; -} - -static void pci_msi_domain_set_desc(msi_alloc_info_t *arg, - struct msi_desc *desc) -{ - arg->desc = desc; - arg->hwirq = pci_msi_domain_calc_hwirq(desc); -} - -static struct msi_domain_ops pci_msi_domain_ops_default = { - .set_desc = pci_msi_domain_set_desc, -}; - -static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) -{ - struct msi_domain_ops *ops = info->ops; - - if (ops == NULL) { - info->ops = &pci_msi_domain_ops_default; - } else { - if (ops->set_desc == NULL) - ops->set_desc = pci_msi_domain_set_desc; - } -} - -static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) -{ - struct irq_chip *chip = info->chip; - - BUG_ON(!chip); - if (!chip->irq_write_msi_msg) - chip->irq_write_msi_msg = pci_msi_domain_write_msg; - if (!chip->irq_mask) - chip->irq_mask = pci_msi_mask_irq; - if (!chip->irq_unmask) - chip->irq_unmask = pci_msi_unmask_irq; -} - -/** - * pci_msi_create_irq_domain - Create a MSI interrupt domain - * @fwnode: Optional fwnode of the interrupt controller - * @info: MSI domain info - * @parent: Parent irq domain - * - * Updates the domain and chip ops and creates a MSI interrupt domain. - * - * Returns: - * A domain pointer or NULL in case of failure. - */ -struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, - struct msi_domain_info *info, - struct irq_domain *parent) -{ - if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE)) - info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; - - if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) - pci_msi_domain_update_dom_ops(info); - if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) - pci_msi_domain_update_chip_ops(info); - - /* Let the core code free MSI descriptors when freeing interrupts */ - info->flags |= MSI_FLAG_FREE_MSI_DESCS; - - info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS; - if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE)) - info->flags |= MSI_FLAG_MUST_REACTIVATE; - - /* PCI-MSI is oneshot-safe */ - info->chip->flags |= IRQCHIP_ONESHOT_SAFE; - /* Let the core update the bus token */ - info->bus_token = DOMAIN_BUS_PCI_MSI; - - return msi_create_irq_domain(fwnode, info, parent); -} -EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain); - /* * Per device MSI[-X] domain functionality */ diff --git a/include/linux/msi.h b/include/linux/msi.h index d415dd15a0a9..8003e3218c46 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -701,9 +701,6 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void pci_msi_mask_irq(struct irq_data *data); void pci_msi_unmask_irq(struct irq_data *data); -struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, - struct msi_domain_info *info, - struct irq_domain *parent); u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev); u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **node); struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index e7ad99254841..68886881fe10 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -706,7 +706,7 @@ static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq = ops->get_hwirq(info, arg); int i, ret; - if (irq_find_mapping(domain, hwirq) > 0) + if (irq_resolve_mapping(domain, hwirq)) return -EEXIST; if (domain->parent) { |