From 6f8f52fa2055c74b55e6ed4669e77f28a67b0d82 Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Sat, 7 Nov 2026 13:04:01 +0200 Subject: [PATCH 1/2] dt-bindings: interrupt-controller: apple,pcie-msi: Allow several ports The MSI map entries of all root ports of an Apple PCIe root complex name interrupts from one AIC range. Two controllers for two ports of one host would hand out the same interrupts, so one controller lists the MSI map registers of every port it serves. Assisted-by: LLM Signed-off-by: Dmitriy --- .../interrupt-controller/apple,pcie-msi.yaml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/apple,pcie-msi.yaml b/Documentation/devicetree/bindings/interrupt-controller/apple,pcie-msi.yaml index e08ca3bf7108a..4103dfef8633f 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/apple,pcie-msi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/apple,pcie-msi.yaml @@ -4,16 +4,17 @@ $id: http://devicetree.org/schemas/interrupt-controller/apple,pcie-msi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Apple PCIe port MSI controller +title: Apple PCIe root port MSI controller maintainers: - Thomas Glanzmann description: | - The MSI map of one Apple PCIe root port, for a port that the bootloader - trained and that Linux drives as a generic ECAM host. Endpoint MSI writes - to the doorbell are routed by this map to a contiguous range of AIC - interrupts. + The MSI maps of the Apple PCIe root ports that the bootloader trained + and that Linux drives as a generic ECAM host. Endpoint MSI writes to the + doorbell are routed by each port's map to a contiguous range of AIC + interrupts. The ports of a root complex share that range, so one + controller lists every port of the host. allOf: - $ref: /schemas/interrupt-controller/msi-controller.yaml# @@ -23,8 +24,9 @@ properties: const: apple,t8142-pcie-msi reg: - maxItems: 1 - description: The port's MSI map registers. + minItems: 1 + maxItems: 3 + description: The MSI map registers of each root port. msi-controller: true From deaac66d8270c63828623119b44b3afcd6f55add Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Sat, 7 Nov 2026 13:04:01 +0200 Subject: [PATCH 2/2] PCI: apple-msi: Program the MSI map of every listed port The MSI map entries of all root ports of an Apple PCIe root complex name interrupts from one AIC range, and endpoint MSI data selects the entry. Map and enable every port the controller lists, so the ports of one generic ECAM host share one allocator and never receive the same interrupt. A controller with one port behaves as before. Assisted-by: LLM Signed-off-by: Dmitriy --- drivers/pci/controller/pcie-apple-msi.c | 38 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/pci/controller/pcie-apple-msi.c b/drivers/pci/controller/pcie-apple-msi.c index 452e124c43b9b..d3757b6aa8704 100644 --- a/drivers/pci/controller/pcie-apple-msi.c +++ b/drivers/pci/controller/pcie-apple-msi.c @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 /* - * MSI controller for one Apple PCIe port whose link the bootloader trained. + * MSI controller for Apple PCIe ports whose links the bootloader trained. * * pcie-apple owns the port when Linux brings the link up itself. On T8142 * (J813) the bootloader trains apcie port 0 and Linux drives the root port as * a generic ECAM host, which has no MSI support. The port still turns writes * to the MSI doorbell into AIC interrupts through its MSI map; this driver * programs that map and provides the parent domain, as pcie-apple does. + * + * The map's entries name AIC interrupts from one range that all ports of the + * root complex share, so the ports of one host use a single controller that + * programs each port's map from one allocator. */ #include @@ -120,7 +124,8 @@ static int apple_msi_probe(struct platform_device *pdev) .ops = &apple_msi_domain_ops, }; struct apple_msi *msi; - void __iomem *port; + void __iomem **ports; + unsigned int nports; int ret; u32 i; @@ -129,9 +134,18 @@ static int apple_msi_probe(struct platform_device *pdev) return -ENOMEM; mutex_init(&msi->lock); - port = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(port)) - return PTR_ERR(port); + for (nports = 0; platform_get_resource(pdev, IORESOURCE_MEM, nports); nports++) + ; + if (!nports) + return -EINVAL; + ports = devm_kcalloc(dev, nports, sizeof(*ports), GFP_KERNEL); + if (!ports) + return -ENOMEM; + for (i = 0; i < nports; i++) { + ports[i] = devm_platform_ioremap_resource(pdev, i); + if (IS_ERR(ports[i])) + return PTR_ERR(ports[i]); + } ret = of_parse_phandle_with_args(dev->of_node, "msi-ranges", "#interrupt-cells", 0, &args); @@ -157,11 +171,15 @@ static int apple_msi_probe(struct platform_device *pdev) info.size = msi->nvecs; info.host_data = msi; - /* MSI data N goes to the Nth interrupt of msi-ranges. */ - writel(lower_32_bits(DOORBELL_ADDR), port + PORT_MSIADDR); - for (i = 0; i < msi->nvecs; i++) - writel(PORT_MSIMAP_ENABLE | i, port + PORT_MSIMAP + 4 * i); - writel(readl(port + PORT_MSICFG) | PORT_MSICFG_EN, port + PORT_MSICFG); + /* On every port, MSI data N goes to the Nth interrupt of msi-ranges. */ + while (nports--) { + void __iomem *port = ports[nports]; + + writel(lower_32_bits(DOORBELL_ADDR), port + PORT_MSIADDR); + for (i = 0; i < msi->nvecs; i++) + writel(PORT_MSIMAP_ENABLE | i, port + PORT_MSIMAP + 4 * i); + writel(readl(port + PORT_MSICFG) | PORT_MSICFG_EN, port + PORT_MSICFG); + } if (!msi_create_parent_irq_domain(&info, &apple_msi_parent_ops)) return -ENOMEM;