From 643c0c9d0496c5727ca28cd841d069b5afee06cf Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 25 Jun 2025 12:18:05 +0100 Subject: [PATCH 1/3] PCI: apple: Add tracking of probed root ports The apple driver relies on being able to directly find the matching root port structure from the platform device that represents this port. A previous hack stashed a pointer to the root port structure in the config window private pointer, but that ended up relying on assumptions that break other drivers. Instead, bite the bullet and track the association as part of the driver itself as a list of probed root ports. Signed-off-by: Marc Zyngier Signed-off-by: Bjorn Helgaas Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250625111806.4153773-3-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 53 ++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 77fe73976654..0380d300adca 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -187,6 +187,7 @@ struct apple_pcie { const struct hw_info *hw; unsigned long *bitmap; struct list_head ports; + struct list_head entry; struct completion event; struct irq_fwspec fwspec; u32 nvecs; @@ -205,6 +206,9 @@ struct apple_pcie_port { int idx; }; +static LIST_HEAD(pcie_list); +static DEFINE_MUTEX(pcie_list_lock); + static void rmw_set(u32 set, void __iomem *addr) { writel_relaxed(readl_relaxed(addr) | set, addr); @@ -720,13 +724,45 @@ static int apple_msi_init(struct apple_pcie *pcie) return 0; } +static void apple_pcie_register(struct apple_pcie *pcie) +{ + guard(mutex)(&pcie_list_lock); + + list_add_tail(&pcie->entry, &pcie_list); +} + +static void apple_pcie_unregister(struct apple_pcie *pcie) +{ + guard(mutex)(&pcie_list_lock); + + list_del(&pcie->entry); +} + +static struct apple_pcie *apple_pcie_lookup(struct device *dev) +{ + struct apple_pcie *pcie; + + guard(mutex)(&pcie_list_lock); + + list_for_each_entry(pcie, &pcie_list, entry) { + if (pcie->dev == dev) + return pcie; + } + + return NULL; +} + static struct apple_pcie_port *apple_pcie_get_port(struct pci_dev *pdev) { struct pci_config_window *cfg = pdev->sysdata; - struct apple_pcie *pcie = cfg->priv; + struct apple_pcie *pcie; struct pci_dev *port_pdev; struct apple_pcie_port *port; + pcie = apple_pcie_lookup(cfg->parent); + if (WARN_ON(!pcie)) + return NULL; + /* Find the root port this device is on */ port_pdev = pcie_find_root_port(pdev); @@ -806,10 +842,14 @@ static void apple_pcie_disable_device(struct pci_host_bridge *bridge, struct pci static int apple_pcie_init(struct pci_config_window *cfg) { - struct apple_pcie *pcie = cfg->priv; struct device *dev = cfg->parent; + struct apple_pcie *pcie; int ret; + pcie = apple_pcie_lookup(dev); + if (WARN_ON(!pcie)) + return -ENOENT; + for_each_available_child_of_node_scoped(dev->of_node, of_port) { ret = apple_pcie_setup_port(pcie, of_port); if (ret) { @@ -852,13 +892,18 @@ static int apple_pcie_probe(struct platform_device *pdev) mutex_init(&pcie->lock); INIT_LIST_HEAD(&pcie->ports); - dev_set_drvdata(dev, pcie); ret = apple_msi_init(pcie); if (ret) return ret; - return pci_host_common_init(pdev, &apple_pcie_cfg_ecam_ops); + apple_pcie_register(pcie); + + ret = pci_host_common_init(pdev, &apple_pcie_cfg_ecam_ops); + if (ret) + apple_pcie_unregister(pcie); + + return ret; } static const struct of_device_id apple_pcie_of_match[] = { From bdb32a0f6780660512d2335db2ebe32e6582cdc8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 25 Jun 2025 12:18:04 +0100 Subject: [PATCH 2/3] PCI: host-generic: Set driver_data before calling gen_pci_init() On MicroChip MPFS Icicle: microchip-pcie 2000000000.pcie: host bridge /soc/pcie@2000000000 ranges: microchip-pcie 2000000000.pcie: Parsing ranges property... microchip-pcie 2000000000.pcie: MEM 0x2008000000..0x2087ffffff -> 0x0008000000 Unable to handle kernel NULL pointer dereference at virtual address 0000000000000368 Current swapper/0 pgtable: 4K pagesize, 39-bit VAs, pgdp=0x00000000814f1000 [0000000000000368] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 Oops [#1] Modules linked in: CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.15.0-rc1-icicle-00003-gafc0a570bb61 #232 NONE Hardware name: Microchip PolarFire-SoC Icicle Kit (DT) [...] [] plda_pcie_setup_iomems+0xe/0x78 [] mc_platform_init+0x80/0x1d2 [] pci_ecam_create+0x104/0x1e2 [] pci_host_common_init+0x120/0x228 [] pci_host_common_probe+0x7c/0x8a The initialization of driver_data was moved after the call to gen_pci_init(), while the pci_ecam_ops.init() callback mc_platform_init() expects it has already been initialized. Fix this by moving the initialization of driver_data up. Fixes: afc0a570bb613871 ("PCI: host-generic: Extract an ECAM bridge creation helper from pci_host_common_probe()") Signed-off-by: Geert Uytterhoeven Signed-off-by: Marc Zyngier Signed-off-by: Bjorn Helgaas Link: https://lore.kernel.org/r/774290708a6f0f683711914fda110742c18a7fb2.1750787223.git.geert+renesas@glider.be Link: https://patch.msgid.link/20250625111806.4153773-2-maz@kernel.org --- drivers/pci/controller/pci-host-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index b0992325dd65..b37052863847 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -64,13 +64,13 @@ int pci_host_common_init(struct platform_device *pdev, of_pci_check_probe_only(); + platform_set_drvdata(pdev, bridge); + /* Parse and map our Configuration Space windows */ cfg = gen_pci_init(dev, bridge, ops); if (IS_ERR(cfg)) return PTR_ERR(cfg); - platform_set_drvdata(pdev, bridge); - bridge->sysdata = cfg; bridge->ops = (struct pci_ops *)&ops->pci_ops; bridge->enable_device = ops->enable_device; From ba74278c638df7c333a970a265dfcc258e70807b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 25 Jun 2025 12:18:06 +0100 Subject: [PATCH 3/3] Revert "PCI: ecam: Allow cfg->priv to be pre-populated from the root port device" This reverts commit 4900454b4f819e88e9c57ed93542bf9325d7e161. Now that nobody relies of cfg->priv containing anything useful before the .init() callback is used, restore the previous behaviour. Signed-off-by: Marc Zyngier Signed-off-by: Bjorn Helgaas Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250625111806.4153773-4-maz@kernel.org --- drivers/pci/ecam.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index 2c5e6446e00e..260b7de2dbd5 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -84,8 +84,6 @@ struct pci_config_window *pci_ecam_create(struct device *dev, goto err_exit_iomap; } - cfg->priv = dev_get_drvdata(dev); - if (ops->init) { err = ops->init(cfg); if (err)