From ebf7547fd1df2db32b83de6f341c7bd9f0e98200 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 27 Mar 2025 12:07:07 +0100 Subject: [PATCH 001/147] mtip32xx: Remove unnecessary pcim_iounmap_regions() calls pcim_iounmap_regions() is deprecated. Moreover, it is not necessary to call it in the driver's remove() function or if probe() fails, since it does cleanup automatically on driver detach. Remove all calls to pcim_iounmap_regions(). Signed-off-by: Philipp Stanner Signed-off-by: Bjorn Helgaas Reviewed-by: Andy Shevchenko Acked-by: Jens Axboe Acked-by: Mark Brown Link: https://patch.msgid.link/20250327110707.20025-3-phasta@kernel.org --- drivers/block/mtip32xx/mtip32xx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 0d619df03fa9..66ce6b81c7d9 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3717,7 +3717,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rv) { dev_warn(&pdev->dev, "64-bit DMA enable failed\n"); - goto setmask_err; + goto iomap_err; } /* Copy the info we may need later into the private data structure. */ @@ -3733,7 +3733,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, if (!dd->isr_workq) { dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance); rv = -ENOMEM; - goto setmask_err; + goto iomap_err; } memset(cpu_list, 0, sizeof(cpu_list)); @@ -3830,8 +3830,6 @@ msi_initialize_err: drop_cpu(dd->work[1].cpu_binding); drop_cpu(dd->work[2].cpu_binding); } -setmask_err: - pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); iomap_err: kfree(dd); @@ -3907,7 +3905,6 @@ static void mtip_pci_remove(struct pci_dev *pdev) pci_disable_msi(pdev); - pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); pci_set_drvdata(pdev, NULL); put_disk(dd->disk); From 855c634930f04c21434fae9c41a7a7372b6ac879 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 27 Mar 2025 12:07:08 +0100 Subject: [PATCH 002/147] PCI: Remove pcim_iounmap_regions() All users of the deprecated function pcim_iounmap_regions() have been ported by now. Remove it. Signed-off-by: Philipp Stanner Signed-off-by: Bjorn Helgaas Reviewed-by: Zijun Hu Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20250327110707.20025-4-phasta@kernel.org --- .../driver-api/driver-model/devres.rst | 1 - drivers/pci/devres.c | 24 ------------------- include/linux/pci.h | 1 - 3 files changed, 26 deletions(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index d75728eb05f8..601f1a74d34d 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -396,7 +396,6 @@ PCI pcim_iomap_regions() : do request_region() and iomap() on multiple BARs pcim_iomap_table() : array of mapped addresses indexed by BAR pcim_iounmap() : do iounmap() on a single BAR - pcim_iounmap_regions() : do iounmap() and release_region() on multiple BARs pcim_pin_device() : keep PCI device enabled after release pcim_set_mwi() : enable Memory-Write-Invalidate PCI transaction diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index 73047316889e..0317c56ac27d 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -955,30 +955,6 @@ err: } EXPORT_SYMBOL(pcim_request_all_regions); -/** - * pcim_iounmap_regions - Unmap and release PCI BARs (DEPRECATED) - * @pdev: PCI device to map IO resources for - * @mask: Mask of BARs to unmap and release - * - * Unmap and release regions specified by @mask. - * - * This function is DEPRECATED. Do not use it in new code. - * Use pcim_iounmap_region() instead. - */ -void pcim_iounmap_regions(struct pci_dev *pdev, int mask) -{ - int i; - - for (i = 0; i < PCI_STD_NUM_BARS; i++) { - if (!mask_contains_bar(mask, i)) - continue; - - pcim_iounmap_region(pdev, i); - pcim_remove_bar_from_legacy_table(pdev, i); - } -} -EXPORT_SYMBOL(pcim_iounmap_regions); - /** * pcim_iomap_range - Create a ranged __iomap mapping within a PCI BAR * @pdev: PCI device to map IO resources for diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..a60fdb344d9e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2322,7 +2322,6 @@ void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); void __iomem * const *pcim_iomap_table(struct pci_dev *pdev); int pcim_request_region(struct pci_dev *pdev, int bar, const char *name); int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name); -void pcim_iounmap_regions(struct pci_dev *pdev, int mask); void __iomem *pcim_iomap_range(struct pci_dev *pdev, int bar, unsigned long offset, unsigned long len); From 74a70e80daa993445a8f0be817f8152a3b9d3b41 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 9 Apr 2025 22:43:10 +0200 Subject: [PATCH 003/147] PCI: Remove pci_fixup_cardbus() Since 1c7f4fe86f17 ("powerpc/pci: Remove pcibios_setup_bus_devices()") there's no architecture left setting pci_fixup_cardbus. Therefore remove support from PCI core. Signed-off-by: Heiner Kallweit Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/8de7da4c-2b16-4ee1-8c42-0d04f3c821c6@gmail.com --- drivers/pci/pci.c | 5 ----- drivers/pcmcia/cardbus.c | 1 - include/linux/pci.h | 3 --- 3 files changed, 9 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d7c9f64ea24..c24d6f5a1012 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6806,11 +6806,6 @@ int __weak pci_ext_cfg_avail(void) return 1; } -void __weak pci_fixup_cardbus(struct pci_bus *bus) -{ -} -EXPORT_SYMBOL(pci_fixup_cardbus); - static int __init pci_setup(char *str) { while (str) { diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index 45c8252c8edc..5e5cf2c3e2c8 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -72,7 +72,6 @@ int __ref cb_alloc(struct pcmcia_socket *s) pci_lock_rescan_remove(); s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); - pci_fixup_cardbus(bus); max = bus->busn_res.start; for (pass = 0; pass < 2; pass++) diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..d26e6611bd00 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1139,9 +1139,6 @@ resource_size_t pcibios_align_resource(void *, const struct resource *, resource_size_t, resource_size_t); -/* Weak but can be overridden by arch */ -void pci_fixup_cardbus(struct pci_bus *); - /* Generic PCI functions used internally */ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, From c3be50f7547ccb533284b22f74baf37d3379843e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 10 Apr 2025 17:27:11 +0200 Subject: [PATCH 004/147] PCI: pciehp: Ignore Presence Detect Changed caused by DPC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit a97396c6eb13 ("PCI: pciehp: Ignore Link Down/Up caused by DPC") amended PCIe hotplug to not bring down the slot upon Data Link Layer State Changed events caused by Downstream Port Containment. However Keith reports off-list that if the slot uses in-band presence detect (i.e. Presence Detect State is derived from Data Link Layer Link Active), DPC also causes a spurious Presence Detect Changed event. This needs to be ignored as well. Unfortunately there's no register indicating that in-band presence detect is used. PCIe r5.0 sec 7.5.3.10 introduced the In-Band PD Disable bit in the Slot Control Register. The PCIe hotplug driver sets this bit on ports supporting it. But older ports may still use in-band presence detect. If in-band presence detect can be disabled, Presence Detect Changed events occurring during DPC must not be ignored because they signal device replacement. On all other ports, device replacement cannot be detected reliably because the Presence Detect Changed event could be a side effect of DPC. On those (older) ports, perform a best-effort device replacement check by comparing the Vendor ID, Device ID and other data in Config Space with the values cached in struct pci_dev. Use the existing helper pciehp_device_replaced() to accomplish this. It is currently #ifdef'ed to CONFIG_PM_SLEEP in pciehp_core.c, so move it to pciehp_hpc.c where most other functions accessing config space reside. Reported-by: Keith Busch Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/fa264ff71952915c4e35a53c89eb0cde8455a5c5.1744298239.git.lukas@wunner.de --- drivers/pci/hotplug/pciehp.h | 1 + drivers/pci/hotplug/pciehp_core.c | 29 ------------------ drivers/pci/hotplug/pciehp_hpc.c | 49 ++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 273dd8c66f4e..debc79b0adfb 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -187,6 +187,7 @@ int pciehp_card_present(struct controller *ctrl); int pciehp_card_present_or_link_active(struct controller *ctrl); int pciehp_check_link_status(struct controller *ctrl); int pciehp_check_link_active(struct controller *ctrl); +bool pciehp_device_replaced(struct controller *ctrl); void pciehp_release_ctrl(struct controller *ctrl); int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 997841c69893..f59baa912970 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -284,35 +284,6 @@ static int pciehp_suspend(struct pcie_device *dev) return 0; } -static bool pciehp_device_replaced(struct controller *ctrl) -{ - struct pci_dev *pdev __free(pci_dev_put) = NULL; - u32 reg; - - if (pci_dev_is_disconnected(ctrl->pcie->port)) - return false; - - pdev = pci_get_slot(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0)); - if (!pdev) - return true; - - if (pci_read_config_dword(pdev, PCI_VENDOR_ID, ®) || - reg != (pdev->vendor | (pdev->device << 16)) || - pci_read_config_dword(pdev, PCI_CLASS_REVISION, ®) || - reg != (pdev->revision | (pdev->class << 8))) - return true; - - if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL && - (pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, ®) || - reg != (pdev->subsystem_vendor | (pdev->subsystem_device << 16)))) - return true; - - if (pci_get_dsn(pdev) != ctrl->dsn) - return true; - - return false; -} - static int pciehp_resume_noirq(struct pcie_device *dev) { struct controller *ctrl = get_service_data(dev); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 8a09fb6083e2..388fbed25402 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -563,18 +563,48 @@ void pciehp_power_off_slot(struct controller *ctrl) PCI_EXP_SLTCTL_PWR_OFF); } +bool pciehp_device_replaced(struct controller *ctrl) +{ + struct pci_dev *pdev __free(pci_dev_put) = NULL; + u32 reg; + + if (pci_dev_is_disconnected(ctrl->pcie->port)) + return false; + + pdev = pci_get_slot(ctrl->pcie->port->subordinate, PCI_DEVFN(0, 0)); + if (!pdev) + return true; + + if (pci_read_config_dword(pdev, PCI_VENDOR_ID, ®) || + reg != (pdev->vendor | (pdev->device << 16)) || + pci_read_config_dword(pdev, PCI_CLASS_REVISION, ®) || + reg != (pdev->revision | (pdev->class << 8))) + return true; + + if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL && + (pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, ®) || + reg != (pdev->subsystem_vendor | (pdev->subsystem_device << 16)))) + return true; + + if (pci_get_dsn(pdev) != ctrl->dsn) + return true; + + return false; +} + static void pciehp_ignore_dpc_link_change(struct controller *ctrl, - struct pci_dev *pdev, int irq) + struct pci_dev *pdev, int irq, + u16 ignored_events) { /* * Ignore link changes which occurred while waiting for DPC recovery. * Could be several if DPC triggered multiple times consecutively. */ synchronize_hardirq(irq); - atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events); + atomic_and(~ignored_events, &ctrl->pending_events); if (pciehp_poll_mode) pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_DLLSC); + ignored_events); ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n", slot_name(ctrl)); @@ -584,8 +614,8 @@ static void pciehp_ignore_dpc_link_change(struct controller *ctrl, * Synthesize it to ensure that it is acted on. */ down_read_nested(&ctrl->reset_lock, ctrl->depth); - if (!pciehp_check_link_active(ctrl)) - pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); + if (!pciehp_check_link_active(ctrl) || pciehp_device_replaced(ctrl)) + pciehp_request(ctrl, ignored_events); up_read(&ctrl->reset_lock); } @@ -736,8 +766,13 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) */ if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) && ctrl->state == ON_STATE) { - events &= ~PCI_EXP_SLTSTA_DLLSC; - pciehp_ignore_dpc_link_change(ctrl, pdev, irq); + u16 ignored_events = PCI_EXP_SLTSTA_DLLSC; + + if (!ctrl->inband_presence_disabled) + ignored_events |= events & PCI_EXP_SLTSTA_PDC; + + events &= ~ignored_events; + pciehp_ignore_dpc_link_change(ctrl, pdev, irq, ignored_events); } /* From 2af781a9edc4ef5f6684c0710cc3542d9be48b31 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 10 Apr 2025 17:27:12 +0200 Subject: [PATCH 005/147] PCI: pciehp: Ignore Link Down/Up caused by Secondary Bus Reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a Secondary Bus Reset is issued at a hotplug port, it causes a Data Link Layer State Changed event as a side effect. On hotplug ports using in-band presence detect, it additionally causes a Presence Detect Changed event. These spurious events should not result in teardown and re-enumeration of the device in the slot. Hence commit 2e35afaefe64 ("PCI: pciehp: Add reset_slot() method") masked the Presence Detect Changed Enable bit in the Slot Control register during a Secondary Bus Reset. Commit 06a8d89af551 ("PCI: pciehp: Disable link notification across slot reset") additionally masked the Data Link Layer State Changed Enable bit. However masking those bits only disables interrupt generation (PCIe r6.2 sec 6.7.3.1). The events are still visible in the Slot Status register and picked up by the IRQ handler if it runs during a Secondary Bus Reset. This can happen if the interrupt is shared or if an unmasked hotplug event occurs, e.g. Attention Button Pressed or Power Fault Detected. The likelihood of this happening used to be small, so it wasn't much of a problem in practice. That has changed with the recent introduction of bandwidth control in v6.13-rc1 with commit 665745f27487 ("PCI/bwctrl: Re-add BW notification portdrv as PCIe BW controller"): Bandwidth control shares the interrupt with PCIe hotplug. A Secondary Bus Reset causes a Link Bandwidth Notification, so the hotplug IRQ handler runs, picks up the masked events and tears down the device in the slot. As a result, Joel reports VFIO passthrough failure of a GPU, which Ilpo root-caused to the incorrect handling of masked hotplug events. Clearly, a more reliable way is needed to ignore spurious hotplug events. For Downstream Port Containment, a new ignore mechanism was introduced by commit a97396c6eb13 ("PCI: pciehp: Ignore Link Down/Up caused by DPC"). It has been working reliably for the past four years. Adapt it for Secondary Bus Resets. Introduce two helpers to annotate code sections which cause spurious link changes: pci_hp_ignore_link_change() and pci_hp_unignore_link_change() Use those helpers in lieu of masking interrupts in the Slot Control register. Introduce a helper to check whether such a code section is executing concurrently and if so, await it: pci_hp_spurious_link_change() Invoke the helper in the hotplug IRQ thread pciehp_ist(). Re-use the IRQ thread's existing code which ignores DPC-induced link changes unless the link is unexpectedly down after reset recovery or the device was replaced during the bus reset. That code block in pciehp_ist() was previously only executed if a Data Link Layer State Changed event has occurred. Additionally execute it for Presence Detect Changed events. That's necessary for compatibility with PCIe r1.0 hotplug ports because Data Link Layer State Changed didn't exist before PCIe r1.1. DPC was added with PCIe r3.1 and thus DPC-capable hotplug ports always support Data Link Layer State Changed events. But the same cannot be assumed for Secondary Bus Reset, which already existed in PCIe r1.0. Secondary Bus Reset is only one of many causes of spurious link changes. Others include runtime suspend to D3cold, firmware updates or FPGA reconfiguration. The new pci_hp_{,un}ignore_link_change() helpers may be used by all kinds of drivers to annotate such code sections, hence their declarations are publicly visible in . A case in point is the Mellanox Ethernet driver which disables a firmware reset feature if the Ethernet card is attached to a hotplug port, see commit 3d7a3f2612d7 ("net/mlx5: Nack sync reset request when HotPlug is enabled"). Going forward, PCIe hotplug will be able to cope gracefully with all such use cases once the code sections are properly annotated. The new helpers internally use two bits in struct pci_dev's priv_flags as well as a wait_queue. This mirrors what was done for DPC by commit a97396c6eb13 ("PCI: pciehp: Ignore Link Down/Up caused by DPC"). That may be insufficient if spurious link changes are caused by multiple sources simultaneously. An example might be a Secondary Bus Reset issued by AER during FPGA reconfiguration. If this turns out to happen in real life, support for it can easily be added by replacing the PCI_LINK_CHANGING flag with an atomic_t counter incremented by pci_hp_ignore_link_change() and decremented by pci_hp_unignore_link_change(). Instead of awaiting a zero PCI_LINK_CHANGING flag, the pci_hp_spurious_link_change() helper would then simply await a zero counter. Fixes: 665745f27487 ("PCI/bwctrl: Re-add BW notification portdrv as PCIe BW controller") Reported-by: Joel Mathew Thomas Closes: https://bugzilla.kernel.org/show_bug.cgi?id=219765 Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Tested-by: Joel Mathew Thomas Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/d04deaf49d634a2edf42bf3c06ed81b4ca54d17b.1744298239.git.lukas@wunner.de --- drivers/pci/hotplug/pci_hotplug_core.c | 69 ++++++++++++++++++++++++++ drivers/pci/hotplug/pciehp_hpc.c | 35 +++++-------- drivers/pci/pci.h | 3 ++ include/linux/pci.h | 8 +++ 4 files changed, 92 insertions(+), 23 deletions(-) diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index d30f1316c98e..d7fc3bc03964 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -492,6 +492,75 @@ void pci_hp_destroy(struct hotplug_slot *slot) } EXPORT_SYMBOL_GPL(pci_hp_destroy); +static DECLARE_WAIT_QUEUE_HEAD(pci_hp_link_change_wq); + +/** + * pci_hp_ignore_link_change - begin code section causing spurious link changes + * @pdev: PCI hotplug bridge + * + * Mark the beginning of a code section causing spurious link changes on the + * Secondary Bus of @pdev, e.g. as a side effect of a Secondary Bus Reset, + * D3cold transition, firmware update or FPGA reconfiguration. + * + * Hotplug drivers can thus check whether such a code section is executing + * concurrently, await it with pci_hp_spurious_link_change() and ignore the + * resulting link change events. + * + * Must be paired with pci_hp_unignore_link_change(). May be called both + * from the PCI core and from Endpoint drivers. May be called for bridges + * which are not hotplug-capable, in which case it has no effect because + * no hotplug driver is bound to the bridge. + */ +void pci_hp_ignore_link_change(struct pci_dev *pdev) +{ + set_bit(PCI_LINK_CHANGING, &pdev->priv_flags); + smp_mb__after_atomic(); /* pairs with implied barrier of wait_event() */ +} + +/** + * pci_hp_unignore_link_change - end code section causing spurious link changes + * @pdev: PCI hotplug bridge + * + * Mark the end of a code section causing spurious link changes on the + * Secondary Bus of @pdev. Must be paired with pci_hp_ignore_link_change(). + */ +void pci_hp_unignore_link_change(struct pci_dev *pdev) +{ + set_bit(PCI_LINK_CHANGED, &pdev->priv_flags); + mb(); /* ensure pci_hp_spurious_link_change() sees either bit set */ + clear_bit(PCI_LINK_CHANGING, &pdev->priv_flags); + wake_up_all(&pci_hp_link_change_wq); +} + +/** + * pci_hp_spurious_link_change - check for spurious link changes + * @pdev: PCI hotplug bridge + * + * Check whether a code section is executing concurrently which is causing + * spurious link changes on the Secondary Bus of @pdev. Await the end of the + * code section if so. + * + * May be called by hotplug drivers to check whether a link change is spurious + * and can be ignored. + * + * Because a genuine link change may have occurred in-between a spurious link + * change and the invocation of this function, hotplug drivers should perform + * sanity checks such as retrieving the current link state and bringing down + * the slot if the link is down. + * + * Return: %true if such a code section has been executing concurrently, + * otherwise %false. Also return %true if such a code section has not been + * executing concurrently, but at least once since the last invocation of this + * function. + */ +bool pci_hp_spurious_link_change(struct pci_dev *pdev) +{ + wait_event(pci_hp_link_change_wq, + !test_bit(PCI_LINK_CHANGING, &pdev->priv_flags)); + + return test_and_clear_bit(PCI_LINK_CHANGED, &pdev->priv_flags); +} + static int __init pci_hotplug_init(void) { int result; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 388fbed25402..ebd342bda235 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -592,21 +592,21 @@ bool pciehp_device_replaced(struct controller *ctrl) return false; } -static void pciehp_ignore_dpc_link_change(struct controller *ctrl, - struct pci_dev *pdev, int irq, - u16 ignored_events) +static void pciehp_ignore_link_change(struct controller *ctrl, + struct pci_dev *pdev, int irq, + u16 ignored_events) { /* * Ignore link changes which occurred while waiting for DPC recovery. * Could be several if DPC triggered multiple times consecutively. + * Also ignore link changes caused by Secondary Bus Reset, etc. */ synchronize_hardirq(irq); atomic_and(~ignored_events, &ctrl->pending_events); if (pciehp_poll_mode) pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, ignored_events); - ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n", - slot_name(ctrl)); + ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored\n", slot_name(ctrl)); /* * If the link is unexpectedly down after successful recovery, @@ -762,9 +762,11 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) /* * Ignore Link Down/Up events caused by Downstream Port Containment - * if recovery from the error succeeded. + * if recovery succeeded, or caused by Secondary Bus Reset, + * suspend to D3cold, firmware update, FPGA reconfiguration, etc. */ - if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) && + if ((events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) && + (pci_dpc_recovered(pdev) || pci_hp_spurious_link_change(pdev)) && ctrl->state == ON_STATE) { u16 ignored_events = PCI_EXP_SLTSTA_DLLSC; @@ -772,7 +774,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) ignored_events |= events & PCI_EXP_SLTSTA_PDC; events &= ~ignored_events; - pciehp_ignore_dpc_link_change(ctrl, pdev, irq, ignored_events); + pciehp_ignore_link_change(ctrl, pdev, irq, ignored_events); } /* @@ -937,7 +939,6 @@ int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, bool probe) { struct controller *ctrl = to_ctrl(hotplug_slot); struct pci_dev *pdev = ctrl_dev(ctrl); - u16 stat_mask = 0, ctrl_mask = 0; int rc; if (probe) @@ -945,23 +946,11 @@ int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, bool probe) down_write_nested(&ctrl->reset_lock, ctrl->depth); - if (!ATTN_BUTTN(ctrl)) { - ctrl_mask |= PCI_EXP_SLTCTL_PDCE; - stat_mask |= PCI_EXP_SLTSTA_PDC; - } - ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE; - stat_mask |= PCI_EXP_SLTSTA_DLLSC; - - pcie_write_cmd(ctrl, 0, ctrl_mask); - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, - pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0); + pci_hp_ignore_link_change(pdev); rc = pci_bridge_secondary_bus_reset(ctrl->pcie->port); - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask); - pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask); - ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, - pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask); + pci_hp_unignore_link_change(pdev); up_write(&ctrl->reset_lock); return rc; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..7db798bdcaaa 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -227,6 +227,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } /* Functions for PCI Hotplug drivers to use */ int pci_hp_add_bridge(struct pci_dev *dev); +bool pci_hp_spurious_link_change(struct pci_dev *pdev); #if defined(CONFIG_SYSFS) && defined(HAVE_PCI_LEGACY) void pci_create_legacy_files(struct pci_bus *bus); @@ -557,6 +558,8 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) #define PCI_DPC_RECOVERED 1 #define PCI_DPC_RECOVERING 2 #define PCI_DEV_REMOVED 3 +#define PCI_LINK_CHANGED 4 +#define PCI_LINK_CHANGING 5 static inline void pci_dev_assign_added(struct pci_dev *dev) { diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..833b54f3ce6d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1848,6 +1848,14 @@ static inline bool pcie_aspm_support_enabled(void) { return false; } static inline bool pcie_aspm_enabled(struct pci_dev *pdev) { return false; } #endif +#ifdef CONFIG_HOTPLUG_PCI +void pci_hp_ignore_link_change(struct pci_dev *pdev); +void pci_hp_unignore_link_change(struct pci_dev *pdev); +#else +static inline void pci_hp_ignore_link_change(struct pci_dev *pdev) { } +static inline void pci_hp_unignore_link_change(struct pci_dev *pdev) { } +#endif + #ifdef CONFIG_PCIEAER bool pci_aer_available(void); #else From 5fe8d08139280a552bb3e8471284362c65c5b032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 16 Apr 2025 13:02:39 +0300 Subject: [PATCH 006/147] PCI: Use PCI_STD_NUM_BARS instead of 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_read_bases() is given literal 6 that means PCI_STD_NUM_BARS. Replace the literal with the define to annotate the code better. Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250416100239.6958-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 364fa2a514f8..08971fca0819 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2058,7 +2058,7 @@ int pci_setup_device(struct pci_dev *dev) if (class == PCI_CLASS_BRIDGE_PCI) goto bad; pci_read_irq(dev); - pci_read_bases(dev, 6, PCI_ROM_ADDRESS); + pci_read_bases(dev, PCI_STD_NUM_BARS, PCI_ROM_ADDRESS); pci_subsystem_ids(dev, &dev->subsystem_vendor, &dev->subsystem_device); From d46b3918fac499f60b7df1cb1437af7344480576 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 14 Apr 2025 16:25:21 +0200 Subject: [PATCH 007/147] PCI: hotplug: Drop superfluous #include directives In February 2003, historic commit https://git.kernel.org/tglx/history/c/280c1c9a0ea4 ("[PATCH] PCI Hotplug: Replace pcihpfs with sysfs.") removed all invocations of __get_free_page() and free_page() from the PCI hotplug core without also removing the #include directive. It removed all invocations of kern_mount(), mntget() and mntput() without also removing the #include directive. It removed all invocations of lookup_hash() without also removing the #include directive. It removed all invocations of copy_to_user() and copy_from_user() without also removing the #include directive. These #include directives are still unnecessary today, so drop them. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/c19e25bf2cefecc14e0822c6a9bb3a7f546258bc.1744640331.git.lukas@wunner.de --- drivers/pci/hotplug/pci_hotplug_core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index d7fc3bc03964..fadcf98a8a66 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -20,13 +20,9 @@ #include #include #include -#include #include -#include -#include #include #include -#include #include "../pci.h" #include "cpci_hotplug.h" From a2c6c1c23bed3506fd87e00c88540ac47832c867 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Apr 2025 10:03:21 +0300 Subject: [PATCH 008/147] x86/PCI: Drop 'pci' suffix from intel_mid_pci.c CE4100 PCI specific code has no 'pci' suffix in the filename, intel_mid_pci.c is the only one that duplicates the folder name in its filename, drop that redundancy. While at it, group the respective modules in the Makefile. Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas Acked-by: Ingo Molnar Link: https://patch.msgid.link/20250407070321.3761063-1-andriy.shevchenko@linux.intel.com --- MAINTAINERS | 2 +- arch/x86/pci/Makefile | 6 +++--- arch/x86/pci/{intel_mid_pci.c => intel_mid.c} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename arch/x86/pci/{intel_mid_pci.c => intel_mid.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..1f6514d55b17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12120,7 +12120,7 @@ M: Andy Shevchenko L: linux-kernel@vger.kernel.org S: Supported F: arch/x86/include/asm/intel-mid.h -F: arch/x86/pci/intel_mid_pci.c +F: arch/x86/pci/intel_mid.c F: arch/x86/platform/intel-mid/ F: drivers/dma/hsu/ F: drivers/extcon/extcon-intel-mrfld.c diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index 4933fb337983..c1efd5b0d198 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile @@ -8,13 +8,13 @@ obj-$(CONFIG_PCI_OLPC) += olpc.o obj-$(CONFIG_PCI_XEN) += xen.o obj-y += fixup.o -obj-$(CONFIG_X86_INTEL_CE) += ce4100.o obj-$(CONFIG_ACPI) += acpi.o obj-y += legacy.o irq.o -obj-$(CONFIG_X86_NUMACHIP) += numachip.o +obj-$(CONFIG_X86_INTEL_CE) += ce4100.o +obj-$(CONFIG_X86_INTEL_MID) += intel_mid.o -obj-$(CONFIG_X86_INTEL_MID) += intel_mid_pci.o +obj-$(CONFIG_X86_NUMACHIP) += numachip.o obj-y += common.o early.o obj-y += bus_numa.o diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid.c similarity index 100% rename from arch/x86/pci/intel_mid_pci.c rename to arch/x86/pci/intel_mid.c From d24eba726aadf8778f2907dd42281c6380b0ccaa Mon Sep 17 00:00:00 2001 From: Wilfred Mallawa Date: Mon, 14 Apr 2025 10:15:06 +1000 Subject: [PATCH 009/147] PCI: Print the actual delay time in pci_bridge_wait_for_secondary_bus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print the delay amount that pcie_wait_for_link_delay() is invoked with instead of the hardcoded 1000ms value in the debug info print. Fixes: 7b3ba09febf4 ("PCI/PM: Shorten pci_bridge_wait_for_secondary_bus() wait time for slow links") Signed-off-by: Wilfred Mallawa Signed-off-by: Bjorn Helgaas Reviewed-by: Damien Le Moal Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Mika Westerberg Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20250414001505.21243-2-wilfred.opensource@gmail.com --- drivers/pci/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c24d6f5a1012..53a070394739 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4954,7 +4954,7 @@ int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type) delay); if (!pcie_wait_for_link_delay(dev, true, delay)) { /* Did not train, no need to wait any further */ - pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n"); + pci_info(dev, "Data Link Layer Link Active not set in %d msec\n", delay); return -ENOTTY; } From 1f3303aa92e15fa273779acac2d0023609de30f1 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 3 Apr 2025 12:07:56 +0800 Subject: [PATCH 010/147] PCI: Add ACS quirk for Loongson PCIe Loongson PCIe Root Ports don't advertise an ACS capability, but they do not allow peer-to-peer transactions between Root Ports. Add an ACS quirk so each Root Port can be in a separate IOMMU group. Signed-off-by: Xianglai Li Signed-off-by: Huacai Chen Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250403040756.720409-1-chenhuacai@loongson.cn --- drivers/pci/quirks.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8d610c17e0f2..eee96ad03614 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4995,6 +4995,18 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } +static int pci_quirk_loongson_acs(struct pci_dev *dev, u16 acs_flags) +{ + /* + * Loongson PCIe Root Ports don't advertise an ACS capability, but + * they do not allow peer-to-peer transactions between Root Ports. + * Allow each Root Port to be in a separate IOMMU group by masking + * SV/RR/CR/UF bits. + */ + return pci_acs_ctrl_enabled(acs_flags, + PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); +} + /* * Wangxun 40G/25G/10G/1G NICs have no ACS capability, but on * multi-function devices, the hardware isolates the functions by @@ -5128,6 +5140,17 @@ static const struct pci_dev_acs_enabled { { PCI_VENDOR_ID_BROADCOM, 0x1762, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_BROADCOM, 0x1763, pci_quirk_mf_endpoint_acs }, { PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs }, + /* Loongson PCIe Root Ports */ + { PCI_VENDOR_ID_LOONGSON, 0x3C09, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x3C19, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x3C29, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A09, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A19, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A29, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A39, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A49, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A59, pci_quirk_loongson_acs }, + { PCI_VENDOR_ID_LOONGSON, 0x7A69, pci_quirk_loongson_acs }, /* Amazon Annapurna Labs */ { PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031, pci_quirk_al_acs }, /* Zhaoxin multi-function devices */ From c7540e5423d7f588c7210a9941ceb6a836963ccc Mon Sep 17 00:00:00 2001 From: Jensen Huang Date: Fri, 28 Mar 2025 18:58:22 +0800 Subject: [PATCH 011/147] PCI: rockchip: Fix order of rockchip_pci_core_rsts The order of rockchip_pci_core_rsts introduced in the offending commit followed the previous comment that warned not to reorder them. But the commit failed to take into account that reset_control_bulk_deassert() deasserts the resets in reverse order. So this leads to the link getting downgraded to 2.5 GT/s. Hence, restore the deassert order and also add back the comments for rockchip_pci_core_rsts. Tested on NanoPC-T4 with Samsung 970 Pro. Fixes: 18715931a5c0 ("PCI: rockchip: Simplify reset control handling by using reset_control_bulk*() function") Signed-off-by: Jensen Huang [mani: reworded the commit message and the comment above rockchip_pci_core_rsts] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Acked-by: Shawn Lin Link: https://patch.msgid.link/20250328105822.3946767-1-jensenhuang@friendlyarm.com --- drivers/pci/controller/pcie-rockchip.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index 14954f43e5e9..5864a20323f2 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h @@ -319,11 +319,12 @@ static const char * const rockchip_pci_pm_rsts[] = { "aclk", }; +/* NOTE: Do not reorder the deassert sequence of the following reset pins */ static const char * const rockchip_pci_core_rsts[] = { - "mgmt-sticky", - "core", - "mgmt", "pipe", + "mgmt", + "core", + "mgmt-sticky", }; struct rockchip_pcie { From 494b26086f75835722bf8ccb9312bda814a9cb4d Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:43 +0530 Subject: [PATCH 012/147] dt-bindings: PCI: qcom,pcie-sm8150: Add 'global' interrupt 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-1-2b70a7819d1e@linaro.org --- .../devicetree/bindings/pci/qcom,pcie-sm8150.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml index 9d569644fda9..a604f2a79de3 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8150.yaml @@ -49,9 +49,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -61,6 +62,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: maxItems: 1 @@ -128,9 +130,10 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7"; + "msi4", "msi5", "msi6", "msi7", "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ From bfc1752fbbe78cbe10976e5beb52311043a38173 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:45 +0530 Subject: [PATCH 013/147] dt-bindings: PCI: qcom,pcie-sm8250: Add 'global' interrupt 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-3-2b70a7819d1e@linaro.org --- .../devicetree/bindings/pci/qcom,pcie-sm8250.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml index 4d060bce6f9d..af4dae68d508 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8250.yaml @@ -61,9 +61,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -73,6 +74,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: maxItems: 1 @@ -143,9 +145,10 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7"; + "msi4", "msi5", "msi6", "msi7", "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ From 985b22d2f88cba382345b373322b669d75ec50fc Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:47 +0530 Subject: [PATCH 014/147] dt-bindings: PCI: qcom,pcie-sm8350: Add 'global' interrupt 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-5-2b70a7819d1e@linaro.org --- .../devicetree/bindings/pci/qcom,pcie-sm8350.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml index 2a4cc41fc710..dde3079adbb3 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8350.yaml @@ -51,9 +51,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -63,6 +64,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: maxItems: 1 @@ -132,9 +134,10 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7"; + "msi4", "msi5", "msi6", "msi7", "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ From 236d500c67e26ab3a7b58d4a90fde182f7c57279 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:49 +0530 Subject: [PATCH 015/147] dt-bindings: PCI: qcom,pcie-sa8775p: Add 'global' interrupt 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-7-2b70a7819d1e@linaro.org --- .../devicetree/bindings/pci/qcom,pcie-sa8775p.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sa8775p.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sa8775p.yaml index efde49d1bef8..e3fa232da2ca 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sa8775p.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sa8775p.yaml @@ -45,9 +45,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -57,6 +58,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: maxItems: 1 @@ -129,7 +131,8 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", @@ -137,7 +140,8 @@ examples: "msi4", "msi5", "msi6", - "msi7"; + "msi7", + "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>, From 54340357c0096aa2e10036c88c9a4cd9048306f9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:51 +0530 Subject: [PATCH 016/147] dt-bindings: PCI: qcom,pcie-sc7280: Add 'global' interrupt 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-9-2b70a7819d1e@linaro.org --- .../devicetree/bindings/pci/qcom,pcie-sc7280.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml index 76cb9fbfd476..ff508f592a1a 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sc7280.yaml @@ -54,9 +54,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -66,6 +67,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: maxItems: 1 @@ -149,9 +151,10 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7"; + "msi4", "msi5", "msi6", "msi7", "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, From ff9be267fee89de9d9972677739396445d2d2499 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:53 +0530 Subject: [PATCH 017/147] dt-bindings: PCI: qcom: Add 'global' interrupt for SDM845 SoC 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-11-2b70a7819d1e@linaro.org --- Documentation/devicetree/bindings/pci/qcom,pcie.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index 8f628939209e..a34e141a7292 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -602,8 +602,9 @@ allOf: - properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -613,6 +614,7 @@ allOf: - const: msi5 - const: msi6 - const: msi7 + - const: global - if: properties: From c9dc3a0996608969fe00eeb78bf98e2bed5fca41 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:56 +0530 Subject: [PATCH 018/147] dt-bindings: PCI: qcom: Allow MSM8998 to use 8 MSI and one 'global' interrupt MSM8998 has 8 MSI SPI and one 'global' interrupt. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-14-2b70a7819d1e@linaro.org --- Documentation/devicetree/bindings/pci/qcom,pcie.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index a34e141a7292..1b875d7441dd 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -590,6 +590,7 @@ allOf: contains: enum: - qcom,pcie-msm8996 + - qcom,pcie-msm8998 - qcom,pcie-sdm845 then: oneOf: From 90fe2c27577d0914a00787e99d9163d87a8011f6 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:10:58 +0530 Subject: [PATCH 019/147] dt-bindings: PCI: qcom: Allow IPQ8074 to use 8 MSI and one 'global' interrupt IPA8074 has 8 MSI SPI and one 'global' interrupt. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-16-2b70a7819d1e@linaro.org --- Documentation/devicetree/bindings/pci/qcom,pcie.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index 1b875d7441dd..804124aad03c 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -589,6 +589,8 @@ allOf: compatible: contains: enum: + - qcom,pcie-ipq8074 + - qcom,pcie-ipq8074-gen3 - qcom,pcie-msm8996 - qcom,pcie-msm8998 - qcom,pcie-sdm845 @@ -628,8 +630,6 @@ allOf: - qcom,pcie-ipq6018 - qcom,pcie-ipq8064 - qcom,pcie-ipq8064-v2 - - qcom,pcie-ipq8074 - - qcom,pcie-ipq8074-gen3 - qcom,pcie-qcs404 then: properties: From 37974556170cb0027d6c21b4080fc713e1ba1e9b Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:11:00 +0530 Subject: [PATCH 020/147] dt-bindings: PCI: qcom: Allow IPQ6018 to use 8 MSI and one 'global' interrupt IPQ6018 has 8 MSI SPI and one 'global' interrupt. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-18-2b70a7819d1e@linaro.org --- Documentation/devicetree/bindings/pci/qcom,pcie.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index 804124aad03c..e20f142316cc 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -589,6 +589,7 @@ allOf: compatible: contains: enum: + - qcom,pcie-ipq6018 - qcom,pcie-ipq8074 - qcom,pcie-ipq8074-gen3 - qcom,pcie-msm8996 @@ -627,7 +628,6 @@ allOf: - qcom,pcie-apq8064 - qcom,pcie-apq8084 - qcom,pcie-ipq4019 - - qcom,pcie-ipq6018 - qcom,pcie-ipq8064 - qcom,pcie-ipq8064-v2 - qcom,pcie-qcs404 From cc9f71da538dce00dfdef08166f92ee315003356 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 27 Feb 2025 19:11:02 +0530 Subject: [PATCH 021/147] dt-bindings: PCI: qcom,pcie-sc8180x: Add 'global' interrupt 'global' interrupt is used to receive PCIe controller and link specific events. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Dmitry Baryshkov Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250227-pcie-global-irq-v1-20-2b70a7819d1e@linaro.org --- .../devicetree/bindings/pci/qcom,pcie-sc8180x.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sc8180x.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sc8180x.yaml index baf1813ec0ac..331fc25d7a17 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sc8180x.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sc8180x.yaml @@ -49,9 +49,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -61,6 +62,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: maxItems: 1 @@ -136,7 +138,8 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", @@ -144,7 +147,8 @@ examples: "msi4", "msi5", "msi6", - "msi7"; + "msi7", + "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ From b584ab12d59f646b9254b2b16ff197d612fd4935 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 28 Mar 2025 15:30:44 +0100 Subject: [PATCH 022/147] PCI: rcar-gen4: set ep BAR4 fixed size On rcar-gen4, the ep BAR4 has a fixed size of 256B. Document this constraint in the epc features of the platform. Fixes: e311b3834dfa ("PCI: rcar-gen4: Add endpoint mode support") Signed-off-by: Jerome Brunet Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-rcar-gen4-bar4-v1-1-10bb6ce9ee7f@baylibre.com --- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index fc872dd35029..02638ec442e7 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -403,6 +403,7 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = { .msix_capable = false, .bar[BAR_1] = { .type = BAR_RESERVED, }, .bar[BAR_3] = { .type = BAR_RESERVED, }, + .bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256 }, .bar[BAR_5] = { .type = BAR_RESERVED, }, .align = SZ_1M, }; From 57a4591df70900252265ecfd6eeba95ce2021504 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 28 Mar 2025 15:58:30 +0530 Subject: [PATCH 023/147] PCI: of: Add of_pci_get_equalization_presets() API PCIe equalization presets are predefined settings used to optimize signal integrity by compensating for signal loss and distortion in high-speed data transmission. As per PCIe spec 6.0.1 revision section 8.3.3.3 & 4.2.4 for data rates of 8.0 GT/s, 16.0 GT/s, 32.0 GT/s, and 64.0 GT/s, there is a way to configure lane equalization presets for each lane to enhance the PCIe link reliability. Each preset value represents a different combination of pre-shoot and de-emphasis values. For each data rate, different registers are defined: for 8.0 GT/s, registers are defined in section 7.7.3.4; for 16.0 GT/s, in section 7.7.5.9, etc. The 8.0 GT/s rate has an extra receiver preset hint, requiring 16 bits per lane, while the remaining data rates use 8 bits per lane. Based on the number of lanes and the supported data rate, of_pci_get_equalization_presets() reads the device tree property and stores in the presets structure. Signed-off-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-preset_v6-v9-2-22cfa0490518@oss.qualcomm.com --- drivers/pci/of.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 32 +++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/pci/of.c b/drivers/pci/of.c index ab7a8252bf41..3579265f1198 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -966,3 +966,47 @@ u32 of_pci_get_slot_power_limit(struct device_node *node, return slot_power_limit_mw; } EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit); + +/** + * of_pci_get_equalization_presets - Parses the "eq-presets-Ngts" property. + * + * @dev: Device containing the properties. + * @presets: Pointer to store the parsed data. + * @num_lanes: Maximum number of lanes supported. + * + * If the property is present, read and store the data in the @presets structure. + * Else, assign a default value of PCI_EQ_RESV. + * + * Return: 0 if the property is not available or successfully parsed else + * errno otherwise. + */ +int of_pci_get_equalization_presets(struct device *dev, + struct pci_eq_presets *presets, + int num_lanes) +{ + char name[20]; + int ret; + + presets->eq_presets_8gts[0] = PCI_EQ_RESV; + ret = of_property_read_u16_array(dev->of_node, "eq-presets-8gts", + presets->eq_presets_8gts, num_lanes); + if (ret && ret != -EINVAL) { + dev_err(dev, "Error reading eq-presets-8gts: %d\n", ret); + return ret; + } + + for (int i = 0; i < EQ_PRESET_TYPE_MAX - 1; i++) { + presets->eq_presets_Ngts[i][0] = PCI_EQ_RESV; + snprintf(name, sizeof(name), "eq-presets-%dgts", 8 << (i + 1)); + ret = of_property_read_u8_array(dev->of_node, name, + presets->eq_presets_Ngts[i], + num_lanes); + if (ret && ret != -EINVAL) { + dev_err(dev, "Error reading %s: %d\n", name, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_pci_get_equalization_presets); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..f9e345ee634c 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -9,6 +9,8 @@ struct pcie_tlp_log; /* Number of possible devfns: 0.0 to 1f.7 inclusive */ #define MAX_NR_DEVFNS 256 +#define MAX_NR_LANES 16 + #define PCI_FIND_CAP_TTL 48 #define PCI_VSEC_ID_INTEL_TBT 0x1234 /* Thunderbolt */ @@ -876,6 +878,21 @@ static inline u64 pci_rebar_size_to_bytes(int size) struct device_node; +#define PCI_EQ_RESV 0xff + +enum equalization_preset_type { + EQ_PRESET_TYPE_8GTS, + EQ_PRESET_TYPE_16GTS, + EQ_PRESET_TYPE_32GTS, + EQ_PRESET_TYPE_64GTS, + EQ_PRESET_TYPE_MAX +}; + +struct pci_eq_presets { + u16 eq_presets_8gts[MAX_NR_LANES]; + u8 eq_presets_Ngts[EQ_PRESET_TYPE_MAX - 1][MAX_NR_LANES]; +}; + #ifdef CONFIG_OF int of_get_pci_domain_nr(struct device_node *node); int of_pci_get_max_link_speed(struct device_node *node); @@ -890,7 +907,9 @@ void pci_release_bus_of_node(struct pci_bus *bus); int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge); bool of_pci_supply_present(struct device_node *np); - +int of_pci_get_equalization_presets(struct device *dev, + struct pci_eq_presets *presets, + int num_lanes); #else static inline int of_get_pci_domain_nr(struct device_node *node) @@ -935,6 +954,17 @@ static inline bool of_pci_supply_present(struct device_node *np) { return false; } + +static inline int of_pci_get_equalization_presets(struct device *dev, + struct pci_eq_presets *presets, + int num_lanes) +{ + presets->eq_presets_8gts[0] = PCI_EQ_RESV; + for (int i = 0; i < EQ_PRESET_TYPE_MAX - 1; i++) + presets->eq_presets_Ngts[i][0] = PCI_EQ_RESV; + + return 0; +} #endif /* CONFIG_OF */ struct of_changeset; From f9eb654fb194e7c404d4984481a18edb9b1c1d7c Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 28 Mar 2025 15:58:31 +0530 Subject: [PATCH 024/147] PCI: dwc: Update pci->num_lanes to maximum supported link width If the num-lanes property is not present in the devicetree, update pci->num_lanes with the hardware supported maximum link width using the newly introduced dw_pcie_link_get_max_link_width() API. The API is used to get the Maximum Link Width (MLW) of the controller. Signed-off-by: Krishna Chaitanya Chundru [mani: reworded commit message a bit] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-preset_v6-v9-3-22cfa0490518@oss.qualcomm.com --- drivers/pci/controller/dwc/pcie-designware-host.c | 3 +++ drivers/pci/controller/dwc/pcie-designware.c | 8 ++++++++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 3 files changed, 12 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ecc33f6789e3..e8eccf6a1b2f 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -523,6 +523,9 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) dw_pcie_iatu_detect(pci); + if (pci->num_lanes < 1) + pci->num_lanes = dw_pcie_link_get_max_link_width(pci); + /* * Allocate the resource for MSG TLP before programming the iATU * outbound window in dw_pcie_setup_rc(). Since the allocation depends diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..cafe91bd9c34 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -781,6 +781,14 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci) } +int dw_pcie_link_get_max_link_width(struct dw_pcie *pci) +{ + u8 cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + u32 lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP); + + return FIELD_GET(PCI_EXP_LNKCAP_MLW, lnkcap); +} + static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes) { u32 lnkcap, lwsc, plc; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 56aafdbcdaca..dda788e3bd24 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -540,6 +540,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); +int dw_pcie_link_get_max_link_width(struct dw_pcie *pci); int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, const struct dw_pcie_ob_atu_cfg *atu); int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type, From 178af54a678d08735233e070a9329651e1589587 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 28 Mar 2025 15:58:32 +0530 Subject: [PATCH 025/147] PCI: Add lane equalization register offsets As per PCIe spec 6.0.1, add PCIe lane equalization register offset for data rates 8.0 GT/s, 32.0 GT/s and 64.0 GT/s. Also add a macro for defining data rate 64.0 GT/s physical layer capability ID. Signed-off-by: Krishna Chaitanya Chundru Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-preset_v6-v9-4-22cfa0490518@oss.qualcomm.com --- include/uapi/linux/pci_regs.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index ba326710f9c8..a3a3e942dedf 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -750,7 +750,8 @@ #define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */ #define PCI_EXT_CAP_ID_PL_32GT 0x2A /* Physical Layer 32.0 GT/s */ #define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE +#define PCI_EXT_CAP_ID_PL_64GT 0x31 /* Physical Layer 64.0 GT/s */ +#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_64GT #define PCI_EXT_CAP_DSN_SIZEOF 12 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 @@ -1144,12 +1145,21 @@ #define PCI_DLF_CAP 0x04 /* Capabilities Register */ #define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */ +/* Secondary PCIe Capability 8.0 GT/s */ +#define PCI_SECPCI_LE_CTRL 0x0c /* Lane Equalization Control Register */ + /* Physical Layer 16.0 GT/s */ #define PCI_PL_16GT_LE_CTRL 0x20 /* Lane Equalization Control Register */ #define PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK 0x0000000F #define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0 #define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4 +/* Physical Layer 32.0 GT/s */ +#define PCI_PL_32GT_LE_CTRL 0x20 /* Lane Equalization Control Register */ + +/* Physical Layer 64.0 GT/s */ +#define PCI_PL_64GT_LE_CTRL 0x20 /* Lane Equalization Control Register */ + /* Native PCIe Enclosure Management */ #define PCI_NPEM_CAP 0x04 /* NPEM capability register */ #define PCI_NPEM_CAP_CAPABLE 0x00000001 /* NPEM Capable */ From 5da3d94a23c6c1ee1f896aeeb00965eacf1d0bb3 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 7 Nov 2024 09:32:55 -0600 Subject: [PATCH 026/147] PCI: mvebu: Use for_each_of_range() iterator for parsing "ranges" The mvebu "ranges" is a bit unusual with its own encoding of addresses, but it's still just normal "ranges" as far as parsing is concerned. Convert mvebu_get_tgt_attr() to use the for_each_of_range() iterator instead of open coding the parsing. Signed-off-by: Rob Herring (Arm) Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20241107153255.2740610-1-robh@kernel.org --- drivers/pci/controller/pci-mvebu.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index b0e3bce10aa4..c635b27ccbc2 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1179,37 +1179,29 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn, unsigned int *tgt, unsigned int *attr) { - const int na = 3, ns = 2; - const __be32 *range; - int rlen, nranges, rangesz, pna, i; + struct of_range range; + struct of_range_parser parser; *tgt = -1; *attr = -1; - range = of_get_property(np, "ranges", &rlen); - if (!range) + if (of_pci_range_parser_init(&parser, np)) return -EINVAL; - pna = of_n_addr_cells(np); - rangesz = pna + na + ns; - nranges = rlen / sizeof(__be32) / rangesz; - - for (i = 0; i < nranges; i++, range += rangesz) { - u32 flags = of_read_number(range, 1); - u32 slot = of_read_number(range + 1, 1); - u64 cpuaddr = of_read_number(range + na, pna); + for_each_of_range(&parser, &range) { unsigned long rtype; + u32 slot = upper_32_bits(range.bus_addr); - if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_IO) + if (DT_FLAGS_TO_TYPE(range.flags) == DT_TYPE_IO) rtype = IORESOURCE_IO; - else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32) + else if (DT_FLAGS_TO_TYPE(range.flags) == DT_TYPE_MEM32) rtype = IORESOURCE_MEM; else continue; if (slot == PCI_SLOT(devfn) && type == rtype) { - *tgt = DT_CPUADDR_TO_TARGET(cpuaddr); - *attr = DT_CPUADDR_TO_ATTR(cpuaddr); + *tgt = DT_CPUADDR_TO_TARGET(range.cpu_addr); + *attr = DT_CPUADDR_TO_ATTR(range.cpu_addr); return 0; } } From 751bec089c4eed486578994abd2c5395f08d0302 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 1 Apr 2025 10:17:01 +0100 Subject: [PATCH 027/147] PCI: apple: Set only available ports up Iterating over disabled ports results in of_irq_parse_raw() parsing the wrong "interrupt-map" entries, as it takes the status of the node into account. This became apparent after disabling unused PCIe ports in the Apple Silicon device trees instead of deleting them. Switching from for_each_child_of_node_scoped() to for_each_available_child_of_node_scoped() solves this issue. Fixes: 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up") Fixes: a0189fdfb73d ("arm64: dts: apple: t8103: Disable unused PCIe ports") Signed-off-by: Janne Grunau Signed-off-by: Alyssa Rosenzweig Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Cc: stable@vger.kernel.org Link: https://lore.kernel.org/asahi/20230214-apple_dts_pcie_disable_unused-v1-0-5ea0d3ddcde3@jannau.net/ Link: https://lore.kernel.org/asahi/1ea2107a-bb86-8c22-0bbc-82c453ab08ce@linaro.org/ Link: https://patch.msgid.link/20250401091713.2765724-2-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 18e11b9a7f46..996cef8a2e17 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -754,7 +754,7 @@ static int apple_pcie_init(struct pci_config_window *cfg) if (ret) return ret; - for_each_child_of_node_scoped(dev->of_node, of_port) { + for_each_available_child_of_node_scoped(dev->of_node, of_port) { ret = apple_pcie_setup_port(pcie, of_port); if (ret) { dev_err(pcie->dev, "Port %pOF setup fail: %d\n", of_port, ret); From 6b7f49be74758a60b760d6c19a48f65a23511dbe Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Tue, 1 Apr 2025 10:17:02 +0100 Subject: [PATCH 028/147] dt-bindings: pci: apple,pcie: Add t6020 compatible string t6020 adds some register ranges compared to t8103, so requires a new compatible as well as the new PHY registers. Thanks to Mark and Rob for their helpful suggestions in updating the binding. Suggested-by: Mark Kettenis Suggested-by: Rob Herring Signed-off-by: Alyssa Rosenzweig [maz: added PHY registers, constraints] Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Acked-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-3-maz@kernel.org --- .../devicetree/bindings/pci/apple,pcie.yaml | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/apple,pcie.yaml b/Documentation/devicetree/bindings/pci/apple,pcie.yaml index c8775f9cb071..c0852be04f6d 100644 --- a/Documentation/devicetree/bindings/pci/apple,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/apple,pcie.yaml @@ -17,6 +17,10 @@ description: | implements its root ports. But the ATU found on most DesignWare PCIe host bridges is absent. + On systems derived from T602x, the PHY registers are in a region + separate from the port registers. In that case, there is one PHY + register range per port register range. + All root ports share a single ECAM space, but separate GPIOs are used to take the PCI devices on those ports out of reset. Therefore the standard "reset-gpios" and "max-link-speed" properties appear on @@ -30,16 +34,18 @@ description: | properties: compatible: - items: - - enum: - - apple,t8103-pcie - - apple,t8112-pcie - - apple,t6000-pcie - - const: apple,pcie + oneOf: + - items: + - enum: + - apple,t8103-pcie + - apple,t8112-pcie + - apple,t6000-pcie + - const: apple,pcie + - const: apple,t6020-pcie reg: minItems: 3 - maxItems: 6 + maxItems: 10 reg-names: minItems: 3 @@ -50,6 +56,10 @@ properties: - const: port1 - const: port2 - const: port3 + - const: phy0 + - const: phy1 + - const: phy2 + - const: phy3 ranges: minItems: 2 @@ -98,6 +108,15 @@ allOf: maxItems: 5 interrupts: maxItems: 3 + - if: + properties: + compatible: + contains: + const: apple,t6020-pcie + then: + properties: + reg-names: + minItems: 10 examples: - | From a7d824b2df0d8b9e19c334594cdbffab97ff8d66 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 16 Apr 2025 16:27:49 +0200 Subject: [PATCH 029/147] PCI: rockchip-ep: Mark RK3399 as intx_capable RK3399 can raise INTx interrupts, as can be seen by rockchip_pcie_ep_send_intx_irq(). This is also in line with the register description of PCIE_CLIENT_LEGACY_INT_CTRL, section "17.6.3 PCIe Client Detail Register Description" of the RK3399 TRM. Thus, mark RK3399 as intx_capable. Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416142749.336298-2-cassel@kernel.org --- drivers/pci/controller/pcie-rockchip-ep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 85ea36df2f59..626f6b31b0f6 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -694,6 +694,7 @@ static const struct pci_epc_features rockchip_pcie_epc_features = { .linkup_notifier = true, .msi_capable = true, .msix_capable = false, + .intx_capable = true, .align = ROCKCHIP_PCIE_AT_SIZE_ALIGN, }; From 8805f32a96d3b97cef07999fa6f52112678f7e65 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sat, 19 Apr 2025 21:30:58 +0800 Subject: [PATCH 030/147] PCI: cadence: Fix runtime atomic count underflow If the call to pci_host_probe() in cdns_pcie_host_setup() fails, PM runtime count is decremented in the error path using pm_runtime_put_sync(). But the runtime count is not incremented by this driver, but only by the callers (cdns_plat_pcie_probe/j721e_pcie_probe). And the callers also decrement the runtime PM count in their error path. So this leads to the below warning from the PM core: "runtime PM usage count underflow!" So fix it by getting rid of pm_runtime_put_sync() in the error path and directly return the errno. Fixes: 49e427e6bdd1 ("Merge branch 'pci/host-probe-refactor'") Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250419133058.162048-1-18255117159@163.com --- drivers/pci/controller/cadence/pcie-cadence-host.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c index 8af95e9da7ce..741e10a575ec 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c @@ -570,14 +570,5 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) if (!bridge->ops) bridge->ops = &cdns_pcie_host_ops; - ret = pci_host_probe(bridge); - if (ret < 0) - goto err_init; - - return 0; - - err_init: - pm_runtime_put_sync(dev); - - return ret; + return pci_host_probe(bridge); } From 215113ab9cc899914254746160d86eeb35faaee5 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Mon, 14 Apr 2025 22:51:09 +0800 Subject: [PATCH 031/147] dt-bindings: PCI: dw: rockchip: Add rk3576 support rk3576 is using DWC PCIe controller, with msi interrupt directly to GIC instead of using GIC ITS, so - no ITS support is required and the 'msi-map' is not required, - a new 'msi' interrupt is needed. Co-developed-by: Sebastian Reichel Signed-off-by: Sebastian Reichel Signed-off-by: Kever Yang [mani: changed 'its' to 'ITS' in the binding, spelling mistake fix] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Reviewed-by: Heiko Stuebner Link: https://patch.msgid.link/20250414145110.11275-2-kever.yang@rock-chips.com --- .../bindings/pci/rockchip-dw-pcie-common.yaml | 10 +++- .../bindings/pci/rockchip-dw-pcie.yaml | 55 +++++++++++++++++-- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie-common.yaml index cc9adfc7611c..fde9b87508b3 100644 --- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie-common.yaml +++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie-common.yaml @@ -65,7 +65,11 @@ properties: tx_cpl_timeout, cor_err_sent, nf_err_sent, f_err_sent, cor_err_rx, nf_err_rx, f_err_rx, radm_qoverflow - description: - eDMA write channel 0 interrupt + If the matching interrupt name is "msi", then this is the combined + MSI line interrupt, which is to support MSI interrupts output to GIC + controller via GIC SPI interrupt instead of GIC ITS interrupt. + If the matching interrupt name is "dma0", then this is the eDMA write + channel 0 interrupt. - description: eDMA write channel 1 interrupt - description: @@ -81,7 +85,9 @@ properties: - const: msg - const: legacy - const: err - - const: dma0 + - enum: + - msi + - dma0 - const: dma1 - const: dma2 - const: dma3 diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml index 550d8a684af3..4764a0173ae4 100644 --- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml @@ -16,16 +16,13 @@ description: |+ PCIe IP and thus inherits all the common properties defined in snps,dw-pcie.yaml. -allOf: - - $ref: /schemas/pci/snps,dw-pcie.yaml# - - $ref: /schemas/pci/rockchip-dw-pcie-common.yaml# - properties: compatible: oneOf: - const: rockchip,rk3568-pcie - items: - enum: + - rockchip,rk3576-pcie - rockchip,rk3588-pcie - const: rockchip,rk3568-pcie @@ -71,8 +68,54 @@ properties: vpcie3v3-supply: true -required: - - msi-map +allOf: + - $ref: /schemas/pci/snps,dw-pcie.yaml# + - $ref: /schemas/pci/rockchip-dw-pcie-common.yaml# + - if: + not: + properties: + compatible: + contains: + const: rockchip,rk3576-pcie + then: + required: + - msi-map + + - if: + properties: + compatible: + contains: + const: rockchip,rk3576-pcie + then: + properties: + interrupts: + minItems: 6 + maxItems: 6 + interrupt-names: + items: + - const: sys + - const: pmc + - const: msg + - const: legacy + - const: err + - const: msi + else: + properties: + interrupts: + minItems: 5 + interrupt-names: + minItems: 5 + items: + - const: sys + - const: pmc + - const: msg + - const: legacy + - const: err + - const: dma0 + - const: dma1 + - const: dma2 + - const: dma3 + unevaluatedProperties: false From c928080166a1fe4f45e396305c06fc22b7018ac6 Mon Sep 17 00:00:00 2001 From: Kever Yang Date: Tue, 15 Apr 2025 13:18:49 +0800 Subject: [PATCH 032/147] dt-bindings: PCI: dwc: rockchip: Add rk3562 support rk3562 is using the same dwc controller as rk3576. Signed-off-by: Kever Yang Signed-off-by: Manivannan Sadhasivam Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250415051855.59740-2-kever.yang@rock-chips.com --- .../devicetree/bindings/pci/rockchip-dw-pcie.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml index 4764a0173ae4..6c6d828ce964 100644 --- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml @@ -22,6 +22,7 @@ properties: - const: rockchip,rk3568-pcie - items: - enum: + - rockchip,rk3562-pcie - rockchip,rk3576-pcie - rockchip,rk3588-pcie - const: rockchip,rk3568-pcie @@ -76,7 +77,9 @@ allOf: properties: compatible: contains: - const: rockchip,rk3576-pcie + enum: + - rockchip,rk3562-pcie + - rockchip,rk3576-pcie then: required: - msi-map @@ -85,7 +88,9 @@ allOf: properties: compatible: contains: - const: rockchip,rk3576-pcie + enum: + - rockchip,rk3562-pcie + - rockchip,rk3576-pcie then: properties: interrupts: From 2a24e06885d728675f4723b7ee3692160a23b924 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 24 Mar 2025 13:52:01 +0100 Subject: [PATCH 033/147] dt-bindings: PCI: Correct indentation and style in DTS example DTS example in the bindings should be indented with 2- or 4-spaces and aligned with opening '- |', so correct any differences like 3-spaces or mixtures 2- and 4-spaces in one binding. No functional changes here, but saves some comments during reviews of new patches built on existing code. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Reviewed-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20250324125202.81986-1-krzysztof.kozlowski@linaro.org --- .../bindings/pci/brcm,stb-pcie.yaml | 81 +++++++------ .../bindings/pci/cdns,cdns-pcie-ep.yaml | 16 +-- .../bindings/pci/intel,keembay-pcie-ep.yaml | 26 ++-- .../bindings/pci/intel,keembay-pcie.yaml | 38 +++--- .../bindings/pci/microchip,pcie-host.yaml | 54 ++++----- .../devicetree/bindings/pci/rcar-pci-ep.yaml | 34 +++--- .../bindings/pci/rcar-pci-host.yaml | 46 +++---- .../bindings/pci/xilinx-versal-cpm.yaml | 112 +++++++++--------- 8 files changed, 202 insertions(+), 205 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml index 29f0e1eb5096..c4f9674e8695 100644 --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml @@ -186,49 +186,48 @@ examples: #include scb { - #address-cells = <2>; - #size-cells = <1>; - pcie0: pcie@7d500000 { - compatible = "brcm,bcm2711-pcie"; - reg = <0x0 0x7d500000 0x9310>; - device_type = "pci"; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - interrupts = , - ; - interrupt-names = "pcie", "msi"; - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH - 0 0 0 2 &gicv2 GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH - 0 0 0 3 &gicv2 GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH - 0 0 0 4 &gicv2 GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <2>; + #size-cells = <1>; + pcie0: pcie@7d500000 { + compatible = "brcm,bcm2711-pcie"; + reg = <0x0 0x7d500000 0x9310>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupts = , + ; + interrupt-names = "pcie", "msi"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH + 0 0 0 2 &gicv2 GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH + 0 0 0 3 &gicv2 GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH + 0 0 0 4 &gicv2 GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>; - msi-parent = <&pcie0>; - msi-controller; - ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 0x0 0x04000000>; - dma-ranges = <0x42000000 0x1 0x00000000 0x0 0x40000000 0x0 0x80000000>, - <0x42000000 0x1 0x80000000 0x3 0x00000000 0x0 0x80000000>; - brcm,enable-ssc; - brcm,scb-sizes = <0x0000000080000000 0x0000000080000000>; + msi-parent = <&pcie0>; + msi-controller; + ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 0x0 0x04000000>; + dma-ranges = <0x42000000 0x1 0x00000000 0x0 0x40000000 0x0 0x80000000>, + <0x42000000 0x1 0x80000000 0x3 0x00000000 0x0 0x80000000>; + brcm,enable-ssc; + brcm,scb-sizes = <0x0000000080000000 0x0000000080000000>; - /* PCIe bridge, Root Port */ - pci@0,0 { - #address-cells = <3>; - #size-cells = <2>; - reg = <0x0 0x0 0x0 0x0 0x0>; - compatible = "pciclass,0604"; - device_type = "pci"; - vpcie3v3-supply = <&vreg7>; - ranges; + /* PCIe bridge, Root Port */ + pci@0,0 { + #address-cells = <3>; + #size-cells = <2>; + reg = <0x0 0x0 0x0 0x0 0x0>; + compatible = "pciclass,0604"; + device_type = "pci"; + vpcie3v3-supply = <&vreg7>; + ranges; - /* PCIe endpoint */ - pci-ep@0,0 { - assigned-addresses = - <0x82010000 0x0 0xf8000000 0x6 0x00000000 0x0 0x2000>; - reg = <0x0 0x0 0x0 0x0 0x0>; - compatible = "pci14e4,1688"; - }; - }; + /* PCIe endpoint */ + pci-ep@0,0 { + assigned-addresses = <0x82010000 0x0 0xf8000000 0x6 0x00000000 0x0 0x2000>; + reg = <0x0 0x0 0x0 0x0 0x0>; + compatible = "pci14e4,1688"; + }; }; + }; }; diff --git a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.yaml index 98651ab22103..8735293962ee 100644 --- a/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.yaml +++ b/Documentation/devicetree/bindings/pci/cdns,cdns-pcie-ep.yaml @@ -37,14 +37,14 @@ examples: #size-cells = <2>; pcie-ep@fc000000 { - compatible = "cdns,cdns-pcie-ep"; - reg = <0x0 0xfc000000 0x0 0x01000000>, - <0x0 0x80000000 0x0 0x40000000>; - reg-names = "reg", "mem"; - cdns,max-outbound-regions = <16>; - max-functions = /bits/ 8 <8>; - phys = <&pcie_phy0>; - phy-names = "pcie-phy"; + compatible = "cdns,cdns-pcie-ep"; + reg = <0x0 0xfc000000 0x0 0x01000000>, + <0x0 0x80000000 0x0 0x40000000>; + reg-names = "reg", "mem"; + cdns,max-outbound-regions = <16>; + max-functions = /bits/ 8 <8>; + phys = <&pcie_phy0>; + phy-names = "pcie-phy"; }; }; ... diff --git a/Documentation/devicetree/bindings/pci/intel,keembay-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/intel,keembay-pcie-ep.yaml index 730e63fd7669..b19f61ae72fb 100644 --- a/Documentation/devicetree/bindings/pci/intel,keembay-pcie-ep.yaml +++ b/Documentation/devicetree/bindings/pci/intel,keembay-pcie-ep.yaml @@ -53,17 +53,17 @@ examples: #include #include pcie-ep@37000000 { - compatible = "intel,keembay-pcie-ep"; - reg = <0x37000000 0x00001000>, - <0x37100000 0x00001000>, - <0x37300000 0x00001000>, - <0x36000000 0x01000000>, - <0x37800000 0x00000200>; - reg-names = "dbi", "dbi2", "atu", "addr_space", "apb"; - interrupts = , - , - , - ; - interrupt-names = "pcie", "pcie_ev", "pcie_err", "pcie_mem_access"; - num-lanes = <2>; + compatible = "intel,keembay-pcie-ep"; + reg = <0x37000000 0x00001000>, + <0x37100000 0x00001000>, + <0x37300000 0x00001000>, + <0x36000000 0x01000000>, + <0x37800000 0x00000200>; + reg-names = "dbi", "dbi2", "atu", "addr_space", "apb"; + interrupts = , + , + , + ; + interrupt-names = "pcie", "pcie_ev", "pcie_err", "pcie_mem_access"; + num-lanes = <2>; }; diff --git a/Documentation/devicetree/bindings/pci/intel,keembay-pcie.yaml b/Documentation/devicetree/bindings/pci/intel,keembay-pcie.yaml index 1fd557504b10..dd71e3d6bf94 100644 --- a/Documentation/devicetree/bindings/pci/intel,keembay-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/intel,keembay-pcie.yaml @@ -75,23 +75,23 @@ examples: #define KEEM_BAY_A53_PCIE #define KEEM_BAY_A53_AUX_PCIE pcie@37000000 { - compatible = "intel,keembay-pcie"; - reg = <0x37000000 0x00001000>, - <0x37300000 0x00001000>, - <0x36e00000 0x00200000>, - <0x37800000 0x00000200>; - reg-names = "dbi", "atu", "config", "apb"; - #address-cells = <3>; - #size-cells = <2>; - device_type = "pci"; - ranges = <0x02000000 0 0x36000000 0x36000000 0 0x00e00000>; - interrupts = , - , - ; - interrupt-names = "pcie", "pcie_ev", "pcie_err"; - clocks = <&scmi_clk KEEM_BAY_A53_PCIE>, - <&scmi_clk KEEM_BAY_A53_AUX_PCIE>; - clock-names = "master", "aux"; - reset-gpios = <&pca2 9 GPIO_ACTIVE_LOW>; - num-lanes = <2>; + compatible = "intel,keembay-pcie"; + reg = <0x37000000 0x00001000>, + <0x37300000 0x00001000>, + <0x36e00000 0x00200000>, + <0x37800000 0x00000200>; + reg-names = "dbi", "atu", "config", "apb"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x02000000 0 0x36000000 0x36000000 0 0x00e00000>; + interrupts = , + , + ; + interrupt-names = "pcie", "pcie_ev", "pcie_err"; + clocks = <&scmi_clk KEEM_BAY_A53_PCIE>, + <&scmi_clk KEEM_BAY_A53_AUX_PCIE>; + clock-names = "master", "aux"; + reset-gpios = <&pca2 9 GPIO_ACTIVE_LOW>; + num-lanes = <2>; }; diff --git a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml index 103574d18dbc..1aadfdee868f 100644 --- a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml +++ b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml @@ -65,33 +65,33 @@ unevaluatedProperties: false examples: - | soc { - #address-cells = <2>; + #address-cells = <2>; + #size-cells = <2>; + pcie0: pcie@2030000000 { + compatible = "microchip,pcie-host-1.0"; + reg = <0x0 0x70000000 0x0 0x08000000>, + <0x0 0x43008000 0x0 0x00002000>, + <0x0 0x4300a000 0x0 0x00002000>; + reg-names = "cfg", "bridge", "ctrl"; + device_type = "pci"; + #address-cells = <3>; #size-cells = <2>; - pcie0: pcie@2030000000 { - compatible = "microchip,pcie-host-1.0"; - reg = <0x0 0x70000000 0x0 0x08000000>, - <0x0 0x43008000 0x0 0x00002000>, - <0x0 0x4300a000 0x0 0x00002000>; - reg-names = "cfg", "bridge", "ctrl"; - device_type = "pci"; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - interrupts = <119>; - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = <0 0 0 1 &pcie_intc0 0>, - <0 0 0 2 &pcie_intc0 1>, - <0 0 0 3 &pcie_intc0 2>, - <0 0 0 4 &pcie_intc0 3>; - interrupt-parent = <&plic0>; - msi-parent = <&pcie0>; - msi-controller; - bus-range = <0x00 0x7f>; - ranges = <0x03000000 0x0 0x78000000 0x0 0x78000000 0x0 0x04000000>; - pcie_intc0: interrupt-controller { - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; + #interrupt-cells = <1>; + interrupts = <119>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, + <0 0 0 3 &pcie_intc0 2>, + <0 0 0 4 &pcie_intc0 3>; + interrupt-parent = <&plic0>; + msi-parent = <&pcie0>; + msi-controller; + bus-range = <0x00 0x7f>; + ranges = <0x03000000 0x0 0x78000000 0x0 0x78000000 0x0 0x04000000>; + pcie_intc0: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; }; + }; }; diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml index 32a3b7665ff5..6b91581c30ae 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml +++ b/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml @@ -73,21 +73,21 @@ examples: #include #include - pcie0_ep: pcie-ep@fe000000 { - compatible = "renesas,r8a774c0-pcie-ep", - "renesas,rcar-gen3-pcie-ep"; - reg = <0xfe000000 0x80000>, - <0xfe100000 0x100000>, - <0xfe200000 0x200000>, - <0x30000000 0x8000000>, - <0x38000000 0x8000000>; - reg-names = "apb-base", "memory0", "memory1", "memory2", "memory3"; - interrupts = , - , - ; - resets = <&cpg 319>; - power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; - clocks = <&cpg CPG_MOD 319>; - clock-names = "pcie"; - max-functions = /bits/ 8 <1>; + pcie0_ep: pcie-ep@fe000000 { + compatible = "renesas,r8a774c0-pcie-ep", + "renesas,rcar-gen3-pcie-ep"; + reg = <0xfe000000 0x80000>, + <0xfe100000 0x100000>, + <0xfe200000 0x200000>, + <0x30000000 0x8000000>, + <0x38000000 0x8000000>; + reg-names = "apb-base", "memory0", "memory1", "memory2", "memory3"; + interrupts = , + , + ; + resets = <&cpg 319>; + power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>; + clocks = <&cpg CPG_MOD 319>; + clock-names = "pcie"; + max-functions = /bits/ 8 <1>; }; diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml index 666f013e3af8..7896576920aa 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml @@ -113,27 +113,27 @@ examples: pcie: pcie@fe000000 { compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2"; reg = <0 0xfe000000 0 0x80000>; - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x00 0xff>; - device_type = "pci"; - ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000>, - <0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000>, - <0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>, - <0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; - dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>, - <0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>; - interrupts = , - , - ; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>; - clock-names = "pcie", "pcie_bus"; - power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; - resets = <&cpg 319>; - vpcie3v3-supply = <&pcie_3v3>; - vpcie12v-supply = <&pcie_12v>; - }; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000>, + <0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000>, + <0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>, + <0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>, + <0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>; + interrupts = , + , + ; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; + resets = <&cpg 319>; + vpcie3v3-supply = <&pcie_3v3>; + vpcie12v-supply = <&pcie_12v>; + }; }; diff --git a/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml b/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml index d674a24c8ccc..9823456addea 100644 --- a/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml +++ b/Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml @@ -76,64 +76,62 @@ unevaluatedProperties: false examples: - | - versal { - #address-cells = <2>; - #size-cells = <2>; - cpm_pcie: pcie@fca10000 { - compatible = "xlnx,versal-cpm-host-1.00"; - device_type = "pci"; - #address-cells = <3>; - #interrupt-cells = <1>; - #size-cells = <2>; - interrupts = <0 72 4>; - interrupt-parent = <&gic>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0 0 0 1 &pcie_intc_0 0>, - <0 0 0 2 &pcie_intc_0 1>, - <0 0 0 3 &pcie_intc_0 2>, - <0 0 0 4 &pcie_intc_0 3>; - bus-range = <0x00 0xff>; - ranges = <0x02000000 0x0 0xe0010000 0x0 0xe0010000 0x0 0x10000000>, - <0x43000000 0x80 0x00000000 0x80 0x00000000 0x0 0x80000000>; - msi-map = <0x0 &its_gic 0x0 0x10000>; - reg = <0x0 0xfca10000 0x0 0x1000>, - <0x6 0x00000000 0x0 0x10000000>; - reg-names = "cpm_slcr", "cfg"; - pcie_intc_0: interrupt-controller { - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; + #address-cells = <2>; + #size-cells = <2>; + pcie@fca10000 { + compatible = "xlnx,versal-cpm-host-1.00"; + device_type = "pci"; + #address-cells = <3>; + #interrupt-cells = <1>; + #size-cells = <2>; + interrupts = <0 72 4>; + interrupt-parent = <&gic>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc_0 0>, + <0 0 0 2 &pcie_intc_0 1>, + <0 0 0 3 &pcie_intc_0 2>, + <0 0 0 4 &pcie_intc_0 3>; + bus-range = <0x00 0xff>; + ranges = <0x02000000 0x0 0xe0010000 0x0 0xe0010000 0x0 0x10000000>, + <0x43000000 0x80 0x00000000 0x80 0x00000000 0x0 0x80000000>; + msi-map = <0x0 &its_gic 0x0 0x10000>; + reg = <0x0 0xfca10000 0x0 0x1000>, + <0x6 0x00000000 0x0 0x10000000>; + reg-names = "cpm_slcr", "cfg"; + pcie_intc_0: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; - cpm5_pcie: pcie@fcdd0000 { - compatible = "xlnx,versal-cpm5-host"; - device_type = "pci"; - #address-cells = <3>; - #interrupt-cells = <1>; - #size-cells = <2>; - interrupts = <0 72 4>; - interrupt-parent = <&gic>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0 0 0 1 &pcie_intc_1 0>, - <0 0 0 2 &pcie_intc_1 1>, - <0 0 0 3 &pcie_intc_1 2>, - <0 0 0 4 &pcie_intc_1 3>; - bus-range = <0x00 0xff>; - ranges = <0x02000000 0x0 0xe0000000 0x0 0xe0000000 0x0 0x10000000>, - <0x43000000 0x80 0x00000000 0x80 0x00000000 0x0 0x80000000>; - msi-map = <0x0 &its_gic 0x0 0x10000>; - reg = <0x00 0xfcdd0000 0x00 0x1000>, - <0x06 0x00000000 0x00 0x1000000>, - <0x00 0xfce20000 0x00 0x1000000>; - reg-names = "cpm_slcr", "cfg", "cpm_csr"; - - pcie_intc_1: interrupt-controller { - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - }; - }; + pcie@fcdd0000 { + compatible = "xlnx,versal-cpm5-host"; + device_type = "pci"; + #address-cells = <3>; + #interrupt-cells = <1>; + #size-cells = <2>; + interrupts = <0 72 4>; + interrupt-parent = <&gic>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc_1 0>, + <0 0 0 2 &pcie_intc_1 1>, + <0 0 0 3 &pcie_intc_1 2>, + <0 0 0 4 &pcie_intc_1 3>; + bus-range = <0x00 0xff>; + ranges = <0x02000000 0x0 0xe0000000 0x0 0xe0000000 0x0 0x10000000>, + <0x43000000 0x80 0x00000000 0x80 0x00000000 0x0 0x80000000>; + msi-map = <0x0 &its_gic 0x0 0x10000>; + reg = <0x00 0xfcdd0000 0x00 0x1000>, + <0x06 0x00000000 0x00 0x1000000>, + <0x00 0xfce20000 0x00 0x1000000>; + reg-names = "cpm_slcr", "cfg", "cpm_csr"; + pcie_intc_1: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; }; From 39813e1865c24db95527c39c0d664d4ef2e111c0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 24 Mar 2025 13:52:02 +0100 Subject: [PATCH 034/147] dt-bindings: PCI: sifive,fu740-pcie: Fix include placement in DTS example Coding style and common logic dictates that headers should not be included in device nodes. No functional impact. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Link: https://patch.msgid.link/20250324125202.81986-2-krzysztof.kozlowski@linaro.org --- Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml index 844fc7142302..d35ff807936b 100644 --- a/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml @@ -81,10 +81,10 @@ unevaluatedProperties: false examples: - | + #include bus { #address-cells = <2>; #size-cells = <2>; - #include pcie@e00000000 { compatible = "sifive,fu740-pcie"; From 0c983d3544a5fb6b8b5770d958050280e3b85cc4 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 14 Apr 2025 16:41:48 -0500 Subject: [PATCH 035/147] dt-bindings: PCI: Convert Marvell EBU to schema Convert the Marvell EBU (Kirkwood, Dove, Armada XP/370) to DT schema format. Add "error" to interrupt-names which is in use, but missing. Shorten the example from 10 child nodes to 6 as the additional ones don't add much value to the example. Signed-off-by: Rob Herring (Arm) Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250414214157.1680484-1-robh@kernel.org --- .../bindings/pci/marvell,kirkwood-pcie.yaml | 277 ++++++++++++++++ .../devicetree/bindings/pci/mvebu-pci.txt | 310 ------------------ 2 files changed, 277 insertions(+), 310 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml delete mode 100644 Documentation/devicetree/bindings/pci/mvebu-pci.txt diff --git a/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml b/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml new file mode 100644 index 000000000000..7be695320ddf --- /dev/null +++ b/Documentation/devicetree/bindings/pci/marvell,kirkwood-pcie.yaml @@ -0,0 +1,277 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/marvell,kirkwood-pcie.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell EBU PCIe interfaces + +maintainers: + - Thomas Petazzoni + - Pali Rohár + +allOf: + - $ref: /schemas/pci/pci-host-bridge.yaml# + +properties: + compatible: + enum: + - marvell,armada-370-pcie + - marvell,armada-xp-pcie + - marvell,dove-pcie + - marvell,kirkwood-pcie + + ranges: + description: > + The ranges describing the MMIO registers have the following layout: + + 0x82000000 0 r MBUS_ID(0xf0, 0x01) r 0 s + + where: + + * r is a 32-bits value that gives the offset of the MMIO registers of + this PCIe interface, from the base of the internal registers. + + * s is a 32-bits value that give the size of this MMIO registers area. + This range entry translates the '0x82000000 0 r' PCI address into the + 'MBUS_ID(0xf0, 0x01) r' CPU address, which is part of the internal + register window (as identified by MBUS_ID(0xf0, 0x01)). + + The ranges describing the MBus windows have the following layout: + + 0x8t000000 s 0 MBUS_ID(w, a) 0 1 0 + + where: + + * t is the type of the MBus window (as defined by the standard PCI DT + bindings), 1 for I/O and 2 for memory. + + * s is the PCI slot that corresponds to this PCIe interface + + * w is the 'target ID' value for the MBus window + + * a the 'attribute' value for the MBus window. + + Since the location and size of the different MBus windows is not fixed in + hardware, and only determined in runtime, those ranges cover the full first + 4 GB of the physical address space, and do not translate into a valid CPU + address. + + msi-parent: + maxItems: 1 + +patternProperties: + '^pcie@': + type: object + allOf: + - $ref: /schemas/pci/pci-bus-common.yaml# + - $ref: /schemas/pci/pci-device.yaml# + unevaluatedProperties: false + + properties: + clocks: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + items: + - const: intx + - const: error + + reset-delay-us: + default: 100000 + description: todo + + marvell,pcie-port: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 3 + description: todo + + marvell,pcie-lane: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 3 + description: todo + + interrupt-controller: + type: object + additionalProperties: false + + properties: + interrupt-controller: true + + '#interrupt-cells': + const: 1 + + required: + - assigned-addresses + - clocks + - interrupt-map + - marvell,pcie-port + +unevaluatedProperties: false + +examples: + - | + #define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16)) + + soc { + #address-cells = <2>; + #size-cells = <2>; + + pcie@f001000000000000 { + compatible = "marvell,armada-xp-pcie"; + device_type = "pci"; + + #address-cells = <3>; + #size-cells = <2>; + + bus-range = <0x00 0xff>; + msi-parent = <&mpic>; + + ranges = + <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */ + 0x82000000 0 0x42000 MBUS_ID(0xf0, 0x01) 0x42000 0 0x00002000 /* Port 2.0 registers */ + 0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 /* Port 0.1 registers */ + 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */ + 0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */ + 0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */ + 0x82000000 0 0x82000 MBUS_ID(0xf0, 0x01) 0x82000 0 0x00002000 /* Port 3.0 registers */ + 0x82000000 0 0x84000 MBUS_ID(0xf0, 0x01) 0x84000 0 0x00002000 /* Port 1.1 registers */ + 0x82000000 0 0x88000 MBUS_ID(0xf0, 0x01) 0x88000 0 0x00002000 /* Port 1.2 registers */ + 0x82000000 0 0x8c000 MBUS_ID(0xf0, 0x01) 0x8c000 0 0x00002000 /* Port 1.3 registers */ + 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ + 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */ + 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */ + 0x81000000 0x2 0 MBUS_ID(0x04, 0xd0) 0 1 0 /* Port 0.1 IO */ + 0x82000000 0x3 0 MBUS_ID(0x04, 0xb8) 0 1 0 /* Port 0.2 MEM */ + 0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */ + 0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */ + 0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */ + + 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */ + 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */ + 0x82000000 0x6 0 MBUS_ID(0x08, 0xd8) 0 1 0 /* Port 1.1 MEM */ + 0x81000000 0x6 0 MBUS_ID(0x08, 0xd0) 0 1 0 /* Port 1.1 IO */ + 0x82000000 0x7 0 MBUS_ID(0x08, 0xb8) 0 1 0 /* Port 1.2 MEM */ + 0x81000000 0x7 0 MBUS_ID(0x08, 0xb0) 0 1 0 /* Port 1.2 IO */ + 0x82000000 0x8 0 MBUS_ID(0x08, 0x78) 0 1 0 /* Port 1.3 MEM */ + 0x81000000 0x8 0 MBUS_ID(0x08, 0x70) 0 1 0 /* Port 1.3 IO */ + + 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */ + 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */ + + 0x82000000 0xa 0 MBUS_ID(0x08, 0xf8) 0 1 0 /* Port 3.0 MEM */ + 0x81000000 0xa 0 MBUS_ID(0x08, 0xf0) 0 1 0 /* Port 3.0 IO */>; + + pcie@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x40000 0 0x2000>; + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0 + 0x81000000 0 0 0x81000000 0x1 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 58>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <0>; + num-lanes = <1>; + /* low-active PERST# reset on GPIO 25 */ + reset-gpios = <&gpio0 25 1>; + /* wait 20ms for device settle after reset deassertion */ + reset-delay-us = <20000>; + clocks = <&gateclk 5>; + }; + + pcie@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x44000 0 0x2000>; + reg = <0x1000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0 + 0x81000000 0 0 0x81000000 0x2 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 59>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <1>; + num-lanes = <1>; + clocks = <&gateclk 6>; + }; + + pcie@3,0 { + device_type = "pci"; + assigned-addresses = <0x82001800 0 0x48000 0 0x2000>; + reg = <0x1800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x3 0 1 0 + 0x81000000 0 0 0x81000000 0x3 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 60>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <2>; + num-lanes = <1>; + clocks = <&gateclk 7>; + }; + + pcie@4,0 { + device_type = "pci"; + assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>; + reg = <0x2000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x4 0 1 0 + 0x81000000 0 0 0x81000000 0x4 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 61>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <3>; + num-lanes = <1>; + clocks = <&gateclk 8>; + }; + + pcie@5,0 { + device_type = "pci"; + assigned-addresses = <0x82002800 0 0x80000 0 0x2000>; + reg = <0x2800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0 + 0x81000000 0 0 0x81000000 0x5 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 62>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <0>; + num-lanes = <1>; + clocks = <&gateclk 9>; + }; + + pcie@6,0 { + device_type = "pci"; + assigned-addresses = <0x82003000 0 0x84000 0 0x2000>; + reg = <0x3000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x6 0 1 0 + 0x81000000 0 0 0x81000000 0x6 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 63>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <1>; + num-lanes = <1>; + clocks = <&gateclk 10>; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pci/mvebu-pci.txt b/Documentation/devicetree/bindings/pci/mvebu-pci.txt deleted file mode 100644 index 6d022a9d36ee..000000000000 --- a/Documentation/devicetree/bindings/pci/mvebu-pci.txt +++ /dev/null @@ -1,310 +0,0 @@ -* Marvell EBU PCIe interfaces - -Mandatory properties: - -- compatible: one of the following values: - marvell,armada-370-pcie - marvell,armada-xp-pcie - marvell,dove-pcie - marvell,kirkwood-pcie -- #address-cells, set to <3> -- #size-cells, set to <2> -- #interrupt-cells, set to <1> -- bus-range: PCI bus numbers covered -- device_type, set to "pci" -- ranges: ranges describing the MMIO registers to control the PCIe - interfaces, and ranges describing the MBus windows needed to access - the memory and I/O regions of each PCIe interface. -- msi-parent: Link to the hardware entity that serves as the Message - Signaled Interrupt controller for this PCI controller. - -The ranges describing the MMIO registers have the following layout: - - 0x82000000 0 r MBUS_ID(0xf0, 0x01) r 0 s - -where: - - * r is a 32-bits value that gives the offset of the MMIO - registers of this PCIe interface, from the base of the internal - registers. - - * s is a 32-bits value that give the size of this MMIO - registers area. This range entry translates the '0x82000000 0 r' PCI - address into the 'MBUS_ID(0xf0, 0x01) r' CPU address, which is part - of the internal register window (as identified by MBUS_ID(0xf0, - 0x01)). - -The ranges describing the MBus windows have the following layout: - - 0x8t000000 s 0 MBUS_ID(w, a) 0 1 0 - -where: - - * t is the type of the MBus window (as defined by the standard PCI DT - bindings), 1 for I/O and 2 for memory. - - * s is the PCI slot that corresponds to this PCIe interface - - * w is the 'target ID' value for the MBus window - - * a the 'attribute' value for the MBus window. - -Since the location and size of the different MBus windows is not fixed in -hardware, and only determined in runtime, those ranges cover the full first -4 GB of the physical address space, and do not translate into a valid CPU -address. - -In addition, the device tree node must have sub-nodes describing each -PCIe interface, having the following mandatory properties: - -- reg: used only for interrupt mapping, so only the first four bytes - are used to refer to the correct bus number and device number. -- assigned-addresses: reference to the MMIO registers used to control - this PCIe interface. -- clocks: the clock associated to this PCIe interface -- marvell,pcie-port: the physical PCIe port number -- status: either "disabled" or "okay" -- device_type, set to "pci" -- #address-cells, set to <3> -- #size-cells, set to <2> -- #interrupt-cells, set to <1> -- ranges, translating the MBus windows ranges of the parent node into - standard PCI addresses. -- interrupt-map-mask and interrupt-map, standard PCI properties to - define the mapping of the PCIe interface to interrupt numbers. - -and the following optional properties: -- marvell,pcie-lane: the physical PCIe lane number, for ports having - multiple lanes. If this property is not found, we assume that the - value is 0. -- num-lanes: number of SerDes PCIe lanes for this link (1 or 4) -- reset-gpios: optional GPIO to PERST# -- reset-delay-us: delay in us to wait after reset de-assertion, if not - specified will default to 100ms, as required by the PCIe specification. -- interrupt-names: list of interrupt names, supported are: - - "intx" - interrupt line triggered by one of the legacy interrupt -- interrupts or interrupts-extended: List of the interrupt sources which - corresponding to the "interrupt-names". If non-empty then also additional - 'interrupt-controller' subnode must be defined. - -Example: - -pcie-controller { - compatible = "marvell,armada-xp-pcie"; - device_type = "pci"; - - #address-cells = <3>; - #size-cells = <2>; - - bus-range = <0x00 0xff>; - msi-parent = <&mpic>; - - ranges = - <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */ - 0x82000000 0 0x42000 MBUS_ID(0xf0, 0x01) 0x42000 0 0x00002000 /* Port 2.0 registers */ - 0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 /* Port 0.1 registers */ - 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */ - 0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */ - 0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */ - 0x82000000 0 0x82000 MBUS_ID(0xf0, 0x01) 0x82000 0 0x00002000 /* Port 3.0 registers */ - 0x82000000 0 0x84000 MBUS_ID(0xf0, 0x01) 0x84000 0 0x00002000 /* Port 1.1 registers */ - 0x82000000 0 0x88000 MBUS_ID(0xf0, 0x01) 0x88000 0 0x00002000 /* Port 1.2 registers */ - 0x82000000 0 0x8c000 MBUS_ID(0xf0, 0x01) 0x8c000 0 0x00002000 /* Port 1.3 registers */ - 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ - 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */ - 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */ - 0x81000000 0x2 0 MBUS_ID(0x04, 0xd0) 0 1 0 /* Port 0.1 IO */ - 0x82000000 0x3 0 MBUS_ID(0x04, 0xb8) 0 1 0 /* Port 0.2 MEM */ - 0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */ - 0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */ - 0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */ - - 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */ - 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */ - 0x82000000 0x6 0 MBUS_ID(0x08, 0xd8) 0 1 0 /* Port 1.1 MEM */ - 0x81000000 0x6 0 MBUS_ID(0x08, 0xd0) 0 1 0 /* Port 1.1 IO */ - 0x82000000 0x7 0 MBUS_ID(0x08, 0xb8) 0 1 0 /* Port 1.2 MEM */ - 0x81000000 0x7 0 MBUS_ID(0x08, 0xb0) 0 1 0 /* Port 1.2 IO */ - 0x82000000 0x8 0 MBUS_ID(0x08, 0x78) 0 1 0 /* Port 1.3 MEM */ - 0x81000000 0x8 0 MBUS_ID(0x08, 0x70) 0 1 0 /* Port 1.3 IO */ - - 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */ - 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */ - - 0x82000000 0xa 0 MBUS_ID(0x08, 0xf8) 0 1 0 /* Port 3.0 MEM */ - 0x81000000 0xa 0 MBUS_ID(0x08, 0xf0) 0 1 0 /* Port 3.0 IO */>; - - pcie@1,0 { - device_type = "pci"; - assigned-addresses = <0x82000800 0 0x40000 0 0x2000>; - reg = <0x0800 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0 - 0x81000000 0 0 0x81000000 0x1 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 58>; - marvell,pcie-port = <0>; - marvell,pcie-lane = <0>; - num-lanes = <1>; - /* low-active PERST# reset on GPIO 25 */ - reset-gpios = <&gpio0 25 1>; - /* wait 20ms for device settle after reset deassertion */ - reset-delay-us = <20000>; - clocks = <&gateclk 5>; - }; - - pcie@2,0 { - device_type = "pci"; - assigned-addresses = <0x82001000 0 0x44000 0 0x2000>; - reg = <0x1000 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0 - 0x81000000 0 0 0x81000000 0x2 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 59>; - marvell,pcie-port = <0>; - marvell,pcie-lane = <1>; - num-lanes = <1>; - clocks = <&gateclk 6>; - }; - - pcie@3,0 { - device_type = "pci"; - assigned-addresses = <0x82001800 0 0x48000 0 0x2000>; - reg = <0x1800 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x3 0 1 0 - 0x81000000 0 0 0x81000000 0x3 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 60>; - marvell,pcie-port = <0>; - marvell,pcie-lane = <2>; - num-lanes = <1>; - clocks = <&gateclk 7>; - }; - - pcie@4,0 { - device_type = "pci"; - assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>; - reg = <0x2000 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x4 0 1 0 - 0x81000000 0 0 0x81000000 0x4 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 61>; - marvell,pcie-port = <0>; - marvell,pcie-lane = <3>; - num-lanes = <1>; - clocks = <&gateclk 8>; - }; - - pcie@5,0 { - device_type = "pci"; - assigned-addresses = <0x82002800 0 0x80000 0 0x2000>; - reg = <0x2800 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0 - 0x81000000 0 0 0x81000000 0x5 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 62>; - marvell,pcie-port = <1>; - marvell,pcie-lane = <0>; - num-lanes = <1>; - clocks = <&gateclk 9>; - }; - - pcie@6,0 { - device_type = "pci"; - assigned-addresses = <0x82003000 0 0x84000 0 0x2000>; - reg = <0x3000 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x6 0 1 0 - 0x81000000 0 0 0x81000000 0x6 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 63>; - marvell,pcie-port = <1>; - marvell,pcie-lane = <1>; - num-lanes = <1>; - clocks = <&gateclk 10>; - }; - - pcie@7,0 { - device_type = "pci"; - assigned-addresses = <0x82003800 0 0x88000 0 0x2000>; - reg = <0x3800 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x7 0 1 0 - 0x81000000 0 0 0x81000000 0x7 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 64>; - marvell,pcie-port = <1>; - marvell,pcie-lane = <2>; - num-lanes = <1>; - clocks = <&gateclk 11>; - }; - - pcie@8,0 { - device_type = "pci"; - assigned-addresses = <0x82004000 0 0x8c000 0 0x2000>; - reg = <0x4000 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x8 0 1 0 - 0x81000000 0 0 0x81000000 0x8 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 65>; - marvell,pcie-port = <1>; - marvell,pcie-lane = <3>; - num-lanes = <1>; - clocks = <&gateclk 12>; - }; - - pcie@9,0 { - device_type = "pci"; - assigned-addresses = <0x82004800 0 0x42000 0 0x2000>; - reg = <0x4800 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0 - 0x81000000 0 0 0x81000000 0x9 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 99>; - marvell,pcie-port = <2>; - marvell,pcie-lane = <0>; - num-lanes = <1>; - clocks = <&gateclk 26>; - }; - - pcie@a,0 { - device_type = "pci"; - assigned-addresses = <0x82005000 0 0x82000 0 0x2000>; - reg = <0x5000 0 0 0 0>; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - ranges = <0x82000000 0 0 0x82000000 0xa 0 1 0 - 0x81000000 0 0 0x81000000 0xa 0 1 0>; - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &mpic 103>; - marvell,pcie-port = <3>; - marvell,pcie-lane = <0>; - num-lanes = <1>; - clocks = <&gateclk 27>; - }; -}; From 096d05bf3e3aa0273bd9eef248ce43dce0cb4c96 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 14 Apr 2025 16:41:33 -0500 Subject: [PATCH 036/147] dt-bindings: PCI: Convert marvell,armada8k-pcie to schema Convert the marvell,armada8k-pcie binding to DT schema. The binding uses different names for reg, clocks, and phys which have to be added to the common Synopsys DWC binding. The "marvell,reset-gpio" property was not documented. Mark it deprecated as the "reset-gpios" property can be used instead. The "msi-parent" property was also not documented. Signed-off-by: Rob Herring (Arm) Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250414214135.1680076-1-robh@kernel.org --- .../bindings/pci/marvell,armada8k-pcie.yaml | 100 ++++++++++++++++++ .../devicetree/bindings/pci/pci-armada8k.txt | 48 --------- .../bindings/pci/snps,dw-pcie-common.yaml | 3 +- .../devicetree/bindings/pci/snps,dw-pcie.yaml | 4 +- MAINTAINERS | 2 +- 5 files changed, 106 insertions(+), 51 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/marvell,armada8k-pcie.yaml delete mode 100644 Documentation/devicetree/bindings/pci/pci-armada8k.txt diff --git a/Documentation/devicetree/bindings/pci/marvell,armada8k-pcie.yaml b/Documentation/devicetree/bindings/pci/marvell,armada8k-pcie.yaml new file mode 100644 index 000000000000..f3ba9230ce2a --- /dev/null +++ b/Documentation/devicetree/bindings/pci/marvell,armada8k-pcie.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/marvell,armada8k-pcie.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Armada 7K/8K PCIe interface + +maintainers: + - Thomas Petazzoni + +description: + This PCIe host controller is based on the Synopsys DesignWare PCIe IP. + +select: + properties: + compatible: + contains: + enum: + - marvell,armada8k-pcie + required: + - compatible + +allOf: + - $ref: snps,dw-pcie.yaml# + +properties: + compatible: + items: + - enum: + - marvell,armada8k-pcie + - const: snps,dw-pcie + + reg: + maxItems: 2 + + reg-names: + items: + - const: ctrl + - const: config + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: core + - const: reg + + interrupts: + maxItems: 1 + + msi-parent: + maxItems: 1 + + phys: + minItems: 1 + maxItems: 4 + + phy-names: + minItems: 1 + maxItems: 4 + + marvell,reset-gpio: + maxItems: 1 + deprecated: true + +required: + - interrupt-map + - clocks + - msi-parent + +unevaluatedProperties: false + +examples: + - | + #include + #include + + pcie@f2600000 { + compatible = "marvell,armada8k-pcie", "snps,dw-pcie"; + reg = <0xf2600000 0x10000>, <0xf6f00000 0x80000>; + reg-names = "ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + dma-coherent; + msi-parent = <&gic_v2m0>; + + ranges = <0x81000000 0 0xf9000000 0xf9000000 0 0x10000>, /* downstream I/O */ + <0x82000000 0 0xf6000000 0xf6000000 0 0xf00000>; /* non-prefetchable memory */ + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + interrupts = ; + num-lanes = <1>; + clocks = <&cpm_syscon0 1 13>; + }; +... diff --git a/Documentation/devicetree/bindings/pci/pci-armada8k.txt b/Documentation/devicetree/bindings/pci/pci-armada8k.txt deleted file mode 100644 index ff25a134befa..000000000000 --- a/Documentation/devicetree/bindings/pci/pci-armada8k.txt +++ /dev/null @@ -1,48 +0,0 @@ -* Marvell Armada 7K/8K PCIe interface - -This PCIe host controller is based on the Synopsys DesignWare PCIe IP -and thus inherits all the common properties defined in snps,dw-pcie.yaml. - -Required properties: -- compatible: "marvell,armada8k-pcie" -- reg: must contain two register regions - - the control register region - - the config space region -- reg-names: - - "ctrl" for the control register region - - "config" for the config space region -- interrupts: Interrupt specifier for the PCIe controller -- clocks: reference to the PCIe controller clocks -- clock-names: mandatory if there is a second clock, in this case the - name must be "core" for the first clock and "reg" for the second - one - -Optional properties: -- phys: phandle(s) to PHY node(s) following the generic PHY bindings. - Either 1, 2 or 4 PHYs might be needed depending on the number of - PCIe lanes. -- phy-names: names of the PHYs corresponding to the number of lanes. - Must be "cp0-pcie0-x4-lane0-phy", "cp0-pcie0-x4-lane1-phy" for - 2 PHYs. - -Example: - - pcie@f2600000 { - compatible = "marvell,armada8k-pcie", "snps,dw-pcie"; - reg = <0 0xf2600000 0 0x10000>, <0 0xf6f00000 0 0x80000>; - reg-names = "ctrl", "config"; - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - device_type = "pci"; - dma-coherent; - - bus-range = <0 0xff>; - ranges = <0x81000000 0 0xf9000000 0 0xf9000000 0 0x10000 /* downstream I/O */ - 0x82000000 0 0xf6000000 0 0xf6000000 0 0xf00000>; /* non-prefetchable memory */ - interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; - interrupts = ; - num-lanes = <1>; - clocks = <&cpm_syscon0 1 13>; - }; diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml index dc05761c5cf9..34594972d8db 100644 --- a/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie-common.yaml @@ -115,7 +115,7 @@ properties: above for new bindings. oneOf: - description: See native 'dbi' clock for details - enum: [ pcie, pcie_apb_sys, aclk_dbi ] + enum: [ pcie, pcie_apb_sys, aclk_dbi, reg ] - description: See native 'mstr/slv' clock for details enum: [ pcie_bus, pcie_inbound_axi, pcie_aclk, aclk_mst, aclk_slv ] - description: See native 'pipe' clock for details @@ -201,6 +201,7 @@ properties: oneOf: - pattern: '^pcie(-?phy[0-9]*)?$' - pattern: '^p2u-[0-7]$' + - pattern: '^cp[01]-pcie[0-2]-x[124](-lane[0-3])?-phy$' # marvell,armada8k-pcie reset-gpio: deprecated: true diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml index 1117a86fb6f7..69e82f438f58 100644 --- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml @@ -105,6 +105,8 @@ properties: Vendor-specific CSR names. Consider using the generic names above for new bindings. oneOf: + - description: See native 'dbi' CSR region for details. + enum: [ ctrl ] - description: See native 'elbi/app' CSR region for details. enum: [ apb, mgmt, link, ulreg, appl ] - description: See native 'atu' CSR region for details. @@ -117,7 +119,7 @@ properties: const: slcr allOf: - contains: - const: dbi + enum: [ dbi, ctrl ] - contains: const: config diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..9764b87ea304 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18411,7 +18411,7 @@ M: Thomas Petazzoni L: linux-pci@vger.kernel.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: Documentation/devicetree/bindings/pci/pci-armada8k.txt +F: Documentation/devicetree/bindings/pci/marvell,armada8k-pcie.yaml F: drivers/pci/controller/dwc/pcie-armada8k.c PCI DRIVER FOR CADENCE PCIE IP From d63dbfc6f27de1dd5741107db07b585d344676ee Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 4 Apr 2025 17:15:57 -0500 Subject: [PATCH 037/147] dt-bindings: PCI: Remove obsolete .txt docs The content in these files has been moved to the schemas in dtschema. pci.txt is covered by pci-bus-common.yaml and pci-host-bridge.yaml. pci-iommu.txt is covered by pci-iommu.yaml. pci-msi.txt is covered in msi-map property in pci-host-bridge.yaml. Signed-off-by: Rob Herring (Arm) Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Cc: Frank Li Link: https://patch.msgid.link/20250404221559.552201-1-robh@kernel.org --- .../bindings/pci/nvidia,tegra194-pcie-ep.yaml | 2 +- .../devicetree/bindings/pci/pci-iommu.txt | 171 -------------- .../devicetree/bindings/pci/pci-msi.txt | 220 ------------------ Documentation/devicetree/bindings/pci/pci.txt | 84 ------- 4 files changed, 1 insertion(+), 476 deletions(-) delete mode 100644 Documentation/devicetree/bindings/pci/pci-iommu.txt delete mode 100644 Documentation/devicetree/bindings/pci/pci-msi.txt delete mode 100644 Documentation/devicetree/bindings/pci/pci.txt diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie-ep.yaml index a24fb8307d29..6d6052a2748f 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie-ep.yaml +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra194-pcie-ep.yaml @@ -74,7 +74,7 @@ properties: reset-gpios: description: Must contain a phandle to a GPIO controller followed by GPIO - that is being used as PERST input signal. Please refer to pci.txt. + that is being used as PERST input signal. phys: minItems: 1 diff --git a/Documentation/devicetree/bindings/pci/pci-iommu.txt b/Documentation/devicetree/bindings/pci/pci-iommu.txt deleted file mode 100644 index 0def586fdcdf..000000000000 --- a/Documentation/devicetree/bindings/pci/pci-iommu.txt +++ /dev/null @@ -1,171 +0,0 @@ -This document describes the generic device tree binding for describing the -relationship between PCI(e) devices and IOMMU(s). - -Each PCI(e) device under a root complex is uniquely identified by its Requester -ID (AKA RID). A Requester ID is a triplet of a Bus number, Device number, and -Function number. - -For the purpose of this document, when treated as a numeric value, a RID is -formatted such that: - -* Bits [15:8] are the Bus number. -* Bits [7:3] are the Device number. -* Bits [2:0] are the Function number. -* Any other bits required for padding must be zero. - -IOMMUs may distinguish PCI devices through sideband data derived from the -Requester ID. While a given PCI device can only master through one IOMMU, a -root complex may split masters across a set of IOMMUs (e.g. with one IOMMU per -bus). - -The generic 'iommus' property is insufficient to describe this relationship, -and a mechanism is required to map from a PCI device to its IOMMU and sideband -data. - -For generic IOMMU bindings, see -Documentation/devicetree/bindings/iommu/iommu.txt. - - -PCI root complex -================ - -Optional properties -------------------- - -- iommu-map: Maps a Requester ID to an IOMMU and associated IOMMU specifier - data. - - The property is an arbitrary number of tuples of - (rid-base,iommu,iommu-base,length). - - Any RID r in the interval [rid-base, rid-base + length) is associated with - the listed IOMMU, with the IOMMU specifier (r - rid-base + iommu-base). - -- iommu-map-mask: A mask to be applied to each Requester ID prior to being - mapped to an IOMMU specifier per the iommu-map property. - - -Example (1) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - iommu: iommu@a { - reg = <0xa 0x1>; - compatible = "vendor,some-iommu"; - #iommu-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the IOMMU is the RID, - * identity-mapped. - */ - iommu-map = <0x0 &iommu 0x0 0x10000>; - }; -}; - - -Example (2) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - iommu: iommu@a { - reg = <0xa 0x1>; - compatible = "vendor,some-iommu"; - #iommu-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the IOMMU is the RID with the - * function bits masked out. - */ - iommu-map = <0x0 &iommu 0x0 0x10000>; - iommu-map-mask = <0xfff8>; - }; -}; - - -Example (3) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - iommu: iommu@a { - reg = <0xa 0x1>; - compatible = "vendor,some-iommu"; - #iommu-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the IOMMU is the RID, - * but the high bits of the bus number are flipped. - */ - iommu-map = <0x0000 &iommu 0x8000 0x8000>, - <0x8000 &iommu 0x0000 0x8000>; - }; -}; - - -Example (4) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - iommu_a: iommu@a { - reg = <0xa 0x1>; - compatible = "vendor,some-iommu"; - #iommu-cells = <1>; - }; - - iommu_b: iommu@b { - reg = <0xb 0x1>; - compatible = "vendor,some-iommu"; - #iommu-cells = <1>; - }; - - iommu_c: iommu@c { - reg = <0xc 0x1>; - compatible = "vendor,some-iommu"; - #iommu-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * Devices with bus number 0-127 are mastered via IOMMU - * a, with sideband data being RID[14:0]. - * Devices with bus number 128-255 are mastered via - * IOMMU b, with sideband data being RID[14:0]. - * No devices master via IOMMU c. - */ - iommu-map = <0x0000 &iommu_a 0x0000 0x8000>, - <0x8000 &iommu_b 0x0000 0x8000>; - }; -}; diff --git a/Documentation/devicetree/bindings/pci/pci-msi.txt b/Documentation/devicetree/bindings/pci/pci-msi.txt deleted file mode 100644 index b73d839657b6..000000000000 --- a/Documentation/devicetree/bindings/pci/pci-msi.txt +++ /dev/null @@ -1,220 +0,0 @@ -This document describes the generic device tree binding for describing the -relationship between PCI devices and MSI controllers. - -Each PCI device under a root complex is uniquely identified by its Requester ID -(AKA RID). A Requester ID is a triplet of a Bus number, Device number, and -Function number. - -For the purpose of this document, when treated as a numeric value, a RID is -formatted such that: - -* Bits [15:8] are the Bus number. -* Bits [7:3] are the Device number. -* Bits [2:0] are the Function number. -* Any other bits required for padding must be zero. - -MSIs may be distinguished in part through the use of sideband data accompanying -writes. In the case of PCI devices, this sideband data may be derived from the -Requester ID. A mechanism is required to associate a device with both the MSI -controllers it can address, and the sideband data that will be associated with -its writes to those controllers. - -For generic MSI bindings, see -Documentation/devicetree/bindings/interrupt-controller/msi.txt. - - -PCI root complex -================ - -Optional properties -------------------- - -- msi-map: Maps a Requester ID to an MSI controller and associated - msi-specifier data. The property is an arbitrary number of tuples of - (rid-base,msi-controller,msi-base,length), where: - - * rid-base is a single cell describing the first RID matched by the entry. - - * msi-controller is a single phandle to an MSI controller - - * msi-base is an msi-specifier describing the msi-specifier produced for the - first RID matched by the entry. - - * length is a single cell describing how many consecutive RIDs are matched - following the rid-base. - - Any RID r in the interval [rid-base, rid-base + length) is associated with - the listed msi-controller, with the msi-specifier (r - rid-base + msi-base). - -- msi-map-mask: A mask to be applied to each Requester ID prior to being mapped - to an msi-specifier per the msi-map property. - -- msi-parent: Describes the MSI parent of the root complex itself. Where - the root complex and MSI controller do not pass sideband data with MSI - writes, this property may be used to describe the MSI controller(s) - used by PCI devices under the root complex, if defined as such in the - binding for the root complex. - - -Example (1) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - msi: msi-controller@a { - reg = <0xa 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the MSI controller is - * the RID, identity-mapped. - */ - msi-map = <0x0 &msi_a 0x0 0x10000>, - }; -}; - - -Example (2) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - msi: msi-controller@a { - reg = <0xa 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the MSI controller is - * the RID, masked to only the device and function bits. - */ - msi-map = <0x0 &msi_a 0x0 0x100>, - msi-map-mask = <0xff> - }; -}; - - -Example (3) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - msi: msi-controller@a { - reg = <0xa 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the MSI controller is - * the RID, but the high bit of the bus number is - * ignored. - */ - msi-map = <0x0000 &msi 0x0000 0x8000>, - <0x8000 &msi 0x0000 0x8000>; - }; -}; - - -Example (4) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - msi: msi-controller@a { - reg = <0xa 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to the MSI controller is - * the RID, but the high bit of the bus number is - * negated. - */ - msi-map = <0x0000 &msi 0x8000 0x8000>, - <0x8000 &msi 0x0000 0x8000>; - }; -}; - - -Example (5) -=========== - -/ { - #address-cells = <1>; - #size-cells = <1>; - - msi_a: msi-controller@a { - reg = <0xa 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - msi_b: msi-controller@b { - reg = <0xb 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - msi_c: msi-controller@c { - reg = <0xc 0x1>; - compatible = "vendor,some-controller"; - msi-controller; - #msi-cells = <1>; - }; - - pci: pci@f { - reg = <0xf 0x1>; - compatible = "vendor,pcie-root-complex"; - device_type = "pci"; - - /* - * The sideband data provided to MSI controller a is the - * RID, but the high bit of the bus number is negated. - * The sideband data provided to MSI controller b is the - * RID, identity-mapped. - * MSI controller c is not addressable. - */ - msi-map = <0x0000 &msi_a 0x8000 0x08000>, - <0x8000 &msi_a 0x0000 0x08000>, - <0x0000 &msi_b 0x0000 0x10000>; - }; -}; diff --git a/Documentation/devicetree/bindings/pci/pci.txt b/Documentation/devicetree/bindings/pci/pci.txt deleted file mode 100644 index 6a8f2874a24d..000000000000 --- a/Documentation/devicetree/bindings/pci/pci.txt +++ /dev/null @@ -1,84 +0,0 @@ -PCI bus bridges have standardized Device Tree bindings: - -PCI Bus Binding to: IEEE Std 1275-1994 -https://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf - -And for the interrupt mapping part: - -Open Firmware Recommended Practice: Interrupt Mapping -https://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf - -Additionally to the properties specified in the above standards a host bridge -driver implementation may support the following properties: - -- linux,pci-domain: - If present this property assigns a fixed PCI domain number to a host bridge, - otherwise an unstable (across boots) unique number will be assigned. - It is required to either not set this property at all or set it for all - host bridges in the system, otherwise potentially conflicting domain numbers - may be assigned to root buses behind different host bridges. The domain - number for each host bridge in the system must be unique. -- max-link-speed: - If present this property specifies PCI gen for link capability. Host - drivers could add this as a strategy to avoid unnecessary operation for - unsupported link speed, for instance, trying to do training for - unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2' - for gen2, and '1' for gen1. Any other values are invalid. -- reset-gpios: - If present this property specifies PERST# GPIO. Host drivers can parse the - GPIO and apply fundamental reset to endpoints. -- supports-clkreq: - If present this property specifies that CLKREQ signal routing exists from - root port to downstream device and host bridge drivers can do programming - which depends on CLKREQ signal existence. For example, programming root port - not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal. - -PCI-PCI Bridge properties -------------------------- - -PCIe root ports and switch ports may be described explicitly in the device -tree, as children of the host bridge node. Even though those devices are -discoverable by probing, it might be necessary to describe properties that -aren't provided by standard PCIe capabilities. - -Required properties: - -- reg: - Identifies the PCI-PCI bridge. As defined in the IEEE Std 1275-1994 - document, it is a five-cell address encoded as (phys.hi phys.mid - phys.lo size.hi size.lo). phys.hi should contain the device's BDF as - 0b00000000 bbbbbbbb dddddfff 00000000. The other cells should be zero. - - The bus number is defined by firmware, through the standard bridge - configuration mechanism. If this port is a switch port, then firmware - allocates the bus number and writes it into the Secondary Bus Number - register of the bridge directly above this port. Otherwise, the bus - number of a root port is the first number in the bus-range property, - defaulting to zero. - - If firmware leaves the ARI Forwarding Enable bit set in the bridge - above this port, then phys.hi contains the 8-bit function number as - 0b00000000 bbbbbbbb ffffffff 00000000. Note that the PCIe specification - recommends that firmware only leaves ARI enabled when it knows that the - OS is ARI-aware. - -Optional properties: - -- external-facing: - When present, the port is external-facing. All bridges and endpoints - downstream of this port are external to the machine. The OS can, for - example, use this information to identify devices that cannot be - trusted with relaxed DMA protection, as users could easily attach - malicious devices to this port. - -Example: - -pcie@10000000 { - compatible = "pci-host-ecam-generic"; - ... - pcie@0008 { - /* Root port 00:01.0 is external-facing */ - reg = <0x00000800 0 0 0 0>; - external-facing; - }; -}; From 09483959e34d2577142ad7c56491c82f50da540d Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru Date: Fri, 28 Mar 2025 15:58:33 +0530 Subject: [PATCH 038/147] PCI: dwc: Add support for configuring lane equalization presets PCIe equalization presets are predefined settings used to optimize signal integrity by compensating for signal loss and distortion in high-speed data transmission. Based upon the number of lanes and the data rate supported, write the preset data read from the device tree in to the lane equalization control registers. These preset values will be used by the controller during the LTSSM lane equalization procedure. Signed-off-by: Krishna Chaitanya Chundru [mani: reworded the commit message and comments in the driver] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250328-preset_v6-v9-5-22cfa0490518@oss.qualcomm.com --- .../pci/controller/dwc/pcie-designware-host.c | 76 +++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 3 + 2 files changed, 79 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index e8eccf6a1b2f..b7faef26ed44 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -526,6 +526,10 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (pci->num_lanes < 1) pci->num_lanes = dw_pcie_link_get_max_link_width(pci); + ret = of_pci_get_equalization_presets(dev, &pp->presets, pci->num_lanes); + if (ret) + goto err_free_msi; + /* * Allocate the resource for MSG TLP before programming the iATU * outbound window in dw_pcie_setup_rc(). Since the allocation depends @@ -831,6 +835,77 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) return 0; } +static void dw_pcie_program_presets(struct dw_pcie_rp *pp, enum pci_bus_speed speed) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + u8 lane_eq_offset, lane_reg_size, cap_id; + u8 *presets; + u32 cap; + int i; + + if (speed == PCIE_SPEED_8_0GT) { + presets = (u8 *)pp->presets.eq_presets_8gts; + lane_eq_offset = PCI_SECPCI_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_SECPCI; + /* For data rate of 8 GT/S each lane equalization control is 16bits wide*/ + lane_reg_size = 0x2; + } else if (speed == PCIE_SPEED_16_0GT) { + presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_16GTS - 1]; + lane_eq_offset = PCI_PL_16GT_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_PL_16GT; + lane_reg_size = 0x1; + } else if (speed == PCIE_SPEED_32_0GT) { + presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_32GTS - 1]; + lane_eq_offset = PCI_PL_32GT_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_PL_32GT; + lane_reg_size = 0x1; + } else if (speed == PCIE_SPEED_64_0GT) { + presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_64GTS - 1]; + lane_eq_offset = PCI_PL_64GT_LE_CTRL; + cap_id = PCI_EXT_CAP_ID_PL_64GT; + lane_reg_size = 0x1; + } else { + return; + } + + if (presets[0] == PCI_EQ_RESV) + return; + + cap = dw_pcie_find_ext_capability(pci, cap_id); + if (!cap) + return; + + /* + * Write preset values to the registers byte-by-byte for the given + * number of lanes and register size. + */ + for (i = 0; i < pci->num_lanes * lane_reg_size; i++) + dw_pcie_writeb_dbi(pci, cap + lane_eq_offset + i, presets[i]); +} + +static void dw_pcie_config_presets(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + enum pci_bus_speed speed = pcie_link_speed[pci->max_link_speed]; + + /* + * Lane equalization settings need to be applied for all data rates the + * controller supports and for all supported lanes. + */ + + if (speed >= PCIE_SPEED_8_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_8_0GT); + + if (speed >= PCIE_SPEED_16_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_16_0GT); + + if (speed >= PCIE_SPEED_32_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_32_0GT); + + if (speed >= PCIE_SPEED_64_0GT) + dw_pcie_program_presets(pp, PCIE_SPEED_64_0GT); +} + int dw_pcie_setup_rc(struct dw_pcie_rp *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); @@ -884,6 +959,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp) PCI_COMMAND_MASTER | PCI_COMMAND_SERR; dw_pcie_writel_dbi(pci, PCI_COMMAND, val); + dw_pcie_config_presets(pp); /* * If the platform provides its own child bus config accesses, it means * the platform uses its own address translation component rather than diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index dda788e3bd24..7add69f13759 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -25,6 +25,8 @@ #include #include +#include "../../pci.h" + /* DWC PCIe IP-core versions (native support since v4.70a) */ #define DW_PCIE_VER_365A 0x3336352a #define DW_PCIE_VER_460A 0x3436302a @@ -412,6 +414,7 @@ struct dw_pcie_rp { int msg_atu_index; struct resource *msg_res; bool use_linkup_irq; + struct pci_eq_presets presets; }; struct dw_pcie_ep_ops { From b649d91322e65f9ea455da58c54b353826dc2dd5 Mon Sep 17 00:00:00 2001 From: Nitheesh Sekar Date: Wed, 26 Mar 2025 12:10:57 +0400 Subject: [PATCH 039/147] dt-bindings: PCI: qcom: Add IPQ5018 SoC Add support for the PCIe controller on the Qualcomm IPQ5108 SoC to the bindings. Signed-off-by: Nitheesh Sekar Signed-off-by: Sricharan Ramabadhran Signed-off-by: George Moussalem Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krzysztof Kozlowski Acked-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250326-ipq5018-pcie-v7-3-e1828fef06c9@outlook.com --- .../devicetree/bindings/pci/qcom,pcie.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index 8f628939209e..b1643c079429 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -21,6 +21,7 @@ properties: - qcom,pcie-apq8064 - qcom,pcie-apq8084 - qcom,pcie-ipq4019 + - qcom,pcie-ipq5018 - qcom,pcie-ipq6018 - qcom,pcie-ipq8064 - qcom,pcie-ipq8064-v2 @@ -168,6 +169,7 @@ allOf: compatible: contains: enum: + - qcom,pcie-ipq5018 - qcom,pcie-ipq6018 - qcom,pcie-ipq8074-gen3 - qcom,pcie-ipq9574 @@ -322,6 +324,53 @@ allOf: - const: ahb # AHB reset - const: phy_ahb # PHY AHB reset + - if: + properties: + compatible: + contains: + enum: + - qcom,pcie-ipq5018 + then: + properties: + clocks: + minItems: 6 + maxItems: 6 + clock-names: + items: + - const: iface # PCIe to SysNOC BIU clock + - const: axi_m # AXI Master clock + - const: axi_s # AXI Slave clock + - const: ahb # AHB clock + - const: aux # Auxiliary clock + - const: axi_bridge # AXI bridge clock + resets: + minItems: 8 + maxItems: 8 + reset-names: + items: + - const: pipe # PIPE reset + - const: sleep # Sleep reset + - const: sticky # Core sticky reset + - const: axi_m # AXI master reset + - const: axi_s # AXI slave reset + - const: ahb # AHB reset + - const: axi_m_sticky # AXI master sticky reset + - const: axi_s_sticky # AXI slave sticky reset + interrupts: + minItems: 9 + maxItems: 9 + interrupt-names: + items: + - const: msi0 + - const: msi1 + - const: msi2 + - const: msi3 + - const: msi4 + - const: msi5 + - const: msi6 + - const: msi7 + - const: global + - if: properties: compatible: @@ -562,6 +611,7 @@ allOf: enum: - qcom,pcie-apq8064 - qcom,pcie-ipq4019 + - qcom,pcie-ipq5018 - qcom,pcie-ipq8064 - qcom,pcie-ipq8064v2 - qcom,pcie-ipq8074 From 3e5127469a8d41153fb30031a271788f52dd17ec Mon Sep 17 00:00:00 2001 From: Nitheesh Sekar Date: Wed, 26 Mar 2025 12:10:58 +0400 Subject: [PATCH 040/147] PCI: qcom: Add support for IPQ5018 Add IPQ5018 platform with is based on Qcom IP rev. 2.9.0 and Synopsys IP rev. 5.00a. The platform itself has two PCIe Gen2 controllers: one single-lane and one dual-lane. So add the IPQ5018 compatible and re-use 2_9_0 ops. Signed-off-by: Nitheesh Sekar Signed-off-by: Sricharan R Signed-off-by: George Moussalem Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250326-ipq5018-pcie-v7-4-e1828fef06c9@outlook.com --- drivers/pci/controller/dwc/pcie-qcom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index dc98ae63362d..e91bbe218569 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1840,6 +1840,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 }, { .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 }, + { .compatible = "qcom,pcie-ipq5018", .data = &cfg_2_9_0 }, { .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 }, { .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 }, From afc0a570bb6138713d74784a032e4eb5b7f919ca Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 1 Apr 2025 10:17:03 +0100 Subject: [PATCH 041/147] PCI: host-generic: Extract an ECAM bridge creation helper from pci_host_common_probe() pci_host_common_probe() is an extremely useful helper, as it abstracts away most of the gunk that a "mostly-ECAM-compliant" device driver needs. However, it is structured as a probe function, meaning that a lot of the driver-specific setup has to happen in a .init() callback, after the bridge and config space have been instantiated. This is a bit awkward, and results in a number of convolutions that could be avoided if the host-common code was more like a library. Introduce a pci_host_common_init() helper that does exactly that, taking the platform device and a struct pci_ecam_op as parameters. This can then be called from the probe routine, and a lot of the code that isn't relevant to PCI setup moved away from the .init() callback. This also removes the dependency on the device match data, which is an oddity. Signed-off-by: Marc Zyngier [mani: fixed spelling mistakes] Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-4-maz@kernel.org --- drivers/pci/controller/pci-host-common.c | 24 ++++++++++++++++-------- include/linux/pci-ecam.h | 2 ++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index f441bfd6f96a..466a1e6a7ffc 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -49,23 +49,17 @@ static struct pci_config_window *gen_pci_init(struct device *dev, return cfg; } -int pci_host_common_probe(struct platform_device *pdev) +int pci_host_common_init(struct platform_device *pdev, + const struct pci_ecam_ops *ops) { struct device *dev = &pdev->dev; struct pci_host_bridge *bridge; struct pci_config_window *cfg; - const struct pci_ecam_ops *ops; - - ops = of_device_get_match_data(&pdev->dev); - if (!ops) - return -ENODEV; bridge = devm_pci_alloc_host_bridge(dev, 0); if (!bridge) return -ENOMEM; - platform_set_drvdata(pdev, bridge); - of_pci_check_probe_only(); /* Parse and map our Configuration Space windows */ @@ -73,6 +67,8 @@ int pci_host_common_probe(struct platform_device *pdev) 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; @@ -81,6 +77,18 @@ int pci_host_common_probe(struct platform_device *pdev) return pci_host_probe(bridge); } +EXPORT_SYMBOL_GPL(pci_host_common_init); + +int pci_host_common_probe(struct platform_device *pdev) +{ + const struct pci_ecam_ops *ops; + + ops = of_device_get_match_data(&pdev->dev); + if (!ops) + return -ENODEV; + + return pci_host_common_init(pdev, ops); +} EXPORT_SYMBOL_GPL(pci_host_common_probe); void pci_host_common_remove(struct platform_device *pdev) diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 3a10f8cfc3ad..bc2ca2c72ee2 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -97,6 +97,8 @@ extern const struct pci_ecam_ops loongson_pci_ecam_ops; /* Loongson PCIe */ #if IS_ENABLED(CONFIG_PCI_HOST_COMMON) /* for DT-based PCI controllers that support ECAM */ int pci_host_common_probe(struct platform_device *pdev); +int pci_host_common_init(struct platform_device *pdev, + const struct pci_ecam_ops *ops); void pci_host_common_remove(struct platform_device *pdev); #endif #endif From 4900454b4f819e88e9c57ed93542bf9325d7e161 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 1 Apr 2025 10:17:04 +0100 Subject: [PATCH 042/147] PCI: ecam: Allow cfg->priv to be pre-populated from the root port device In order to decouple ecam config space creation from probing via pci_host_common_probe(), allow the private pointer to be populated via the device drvdata pointer. Crucially, this is set before calling ops->init(), allowing that particular callback to have access to probe data. This should have no impact on existing code which ignores the current value of cfg->priv. Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-5-maz@kernel.org --- drivers/pci/ecam.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index 260b7de2dbd5..2c5e6446e00e 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -84,6 +84,8 @@ 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) From 4785591f96c76534d9ccb7ec515ab4bc407f3191 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 1 Apr 2025 10:17:05 +0100 Subject: [PATCH 043/147] PCI: apple: Move over to standalone probing Now that we have the required infrastructure, split the Apple PCIe setup into two categories: - stuff that has to do with PCI setup stays in the .init() callback - stuff that is just driver gunk (such as MSI setup) goes into a probe routine, which will eventually call into the host-common code The result is a far more logical setup process. Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-6-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 54 ++++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 996cef8a2e17..6d7a95ab8b14 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -730,34 +730,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 platform_device *platform = to_platform_device(dev); - struct apple_pcie *pcie; int ret; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) - return -ENOMEM; - - pcie->dev = dev; - - mutex_init(&pcie->lock); - - pcie->base = devm_platform_ioremap_resource(platform, 1); - if (IS_ERR(pcie->base)) - return PTR_ERR(pcie->base); - - cfg->priv = pcie; - INIT_LIST_HEAD(&pcie->ports); - - ret = apple_msi_init(pcie); - if (ret) - return ret; - for_each_available_child_of_node_scoped(dev->of_node, of_port) { ret = apple_pcie_setup_port(pcie, of_port); if (ret) { - dev_err(pcie->dev, "Port %pOF setup fail: %d\n", of_port, ret); + dev_err(dev, "Port %pOF setup fail: %d\n", of_port, ret); return ret; } } @@ -776,14 +756,40 @@ static const struct pci_ecam_ops apple_pcie_cfg_ecam_ops = { } }; +static int apple_pcie_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apple_pcie *pcie; + int ret; + + pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie->dev = dev; + pcie->base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(pcie->base)) + return PTR_ERR(pcie->base); + + 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); +} + static const struct of_device_id apple_pcie_of_match[] = { - { .compatible = "apple,pcie", .data = &apple_pcie_cfg_ecam_ops }, + { .compatible = "apple,pcie" }, { } }; MODULE_DEVICE_TABLE(of, apple_pcie_of_match); static struct platform_driver apple_pcie_driver = { - .probe = pci_host_common_probe, + .probe = apple_pcie_probe, .driver = { .name = "pcie-apple", .of_match_table = apple_pcie_of_match, From ed982862ce980c578c8c80917a69c8fa1c504b85 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 1 Apr 2025 10:17:06 +0100 Subject: [PATCH 044/147] PCI: apple: Dynamically allocate RID-to_SID bitmap As we move towards supporting SoCs with varying RID-to-SID mapping capabilities, turn the static SID tracking bitmap into a dynamically allocated one. The current allocation size is still the same, but that's about to change. Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Tested-by: Janne Grunau Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-7-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 6d7a95ab8b14..8ac21d46c031 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -147,7 +147,7 @@ struct apple_pcie_port { void __iomem *base; struct irq_domain *domain; struct list_head entry; - DECLARE_BITMAP(sid_map, MAX_RID2SID); + unsigned long *sid_map; int sid_map_sz; int idx; }; @@ -524,6 +524,10 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, if (!port) return -ENOMEM; + port->sid_map = devm_bitmap_zalloc(pcie->dev, MAX_RID2SID, GFP_KERNEL); + if (!port->sid_map) + return -ENOMEM; + ret = of_property_read_u32_index(np, "reg", 0, &idx); if (ret) return ret; From 0411c90eee6fc97b30d3f5767e9cb82d4594faa1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 1 Apr 2025 10:17:07 +0100 Subject: [PATCH 045/147] PCI: apple: Move away from INTMSK{SET,CLR} for INTx and private interrupts T602x seems to have dropped the rather useful SET/CLR accessors to the masking register. Instead, let's use the mask register directly, and wrap it with a brand new spinlock. No, this isn't moving in the right direction. Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-8-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 8ac21d46c031..152a65db3ff0 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -142,6 +142,7 @@ struct apple_pcie { }; struct apple_pcie_port { + raw_spinlock_t lock; struct apple_pcie *pcie; struct device_node *np; void __iomem *base; @@ -261,14 +262,16 @@ static void apple_port_irq_mask(struct irq_data *data) { struct apple_pcie_port *port = irq_data_get_irq_chip_data(data); - writel_relaxed(BIT(data->hwirq), port->base + PORT_INTMSKSET); + guard(raw_spinlock_irqsave)(&port->lock); + rmw_set(BIT(data->hwirq), port->base + PORT_INTMSK); } static void apple_port_irq_unmask(struct irq_data *data) { struct apple_pcie_port *port = irq_data_get_irq_chip_data(data); - writel_relaxed(BIT(data->hwirq), port->base + PORT_INTMSKCLR); + guard(raw_spinlock_irqsave)(&port->lock); + rmw_clear(BIT(data->hwirq), port->base + PORT_INTMSK); } static bool hwirq_is_intx(unsigned int hwirq) @@ -387,7 +390,7 @@ static int apple_pcie_port_setup_irq(struct apple_pcie_port *port) return -ENOMEM; /* Disable all interrupts */ - writel_relaxed(~0, port->base + PORT_INTMSKSET); + writel_relaxed(~0, port->base + PORT_INTMSK); writel_relaxed(~0, port->base + PORT_INTSTAT); irq_set_chained_handler_and_data(irq, apple_port_irq_handler, port); @@ -537,6 +540,8 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, port->pcie = pcie; port->np = np; + raw_spin_lock_init(&port->lock); + port->base = devm_platform_ioremap_resource(platform, port->idx + 2); if (IS_ERR(port->base)) return PTR_ERR(port->base); From 7fa9fbf39116b061f8a41cd84f1884c545f322c4 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 1 Apr 2025 10:17:08 +0100 Subject: [PATCH 046/147] PCI: apple: Fix missing OF node reference in apple_pcie_setup_port In the success path, we hang onto a reference to the node, so make sure to grab one. The caller iterator puts our borrowed reference when we return. Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-9-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 152a65db3ff0..cd02aa93a5c4 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -593,6 +593,9 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, list_add_tail(&port->entry, &pcie->ports); init_completion(&pcie->event); + /* In the success path, we keep a reference to np around */ + of_node_get(np); + ret = apple_pcie_port_register_irqs(port); WARN_ON(ret); From 80b31fbbcac4e4799fde34992b07d4f0692cfbb8 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 1 Apr 2025 10:17:09 +0100 Subject: [PATCH 047/147] PCI: apple: Move port PHY registers to their own reg items T602x PCIe cores move these registers around. Instead of hardcoding in another offset, let's move them into their own reg entries. This matches what Apple does on macOS device trees too. Maintains backwards compatibility with old DTs by using the old offsets. Note that we open code devm_platform_ioremap_resource_byname() to avoid error messages on older platforms with missing resources in the pcie node. ("pcie-apple 590000000.pcie: invalid resource (null)" on probe) Co-developed-by: Janne Grunau Signed-off-by: Janne Grunau Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-10-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 55 +++++++++++++++++++---------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index cd02aa93a5c4..b8d9b07f35b5 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -39,14 +39,18 @@ #define CORE_RC_STAT_READY BIT(0) #define CORE_FABRIC_STAT 0x04000 #define CORE_FABRIC_STAT_MASK 0x001F001F -#define CORE_LANE_CFG(port) (0x84000 + 0x4000 * (port)) -#define CORE_LANE_CFG_REFCLK0REQ BIT(0) -#define CORE_LANE_CFG_REFCLK1REQ BIT(1) -#define CORE_LANE_CFG_REFCLK0ACK BIT(2) -#define CORE_LANE_CFG_REFCLK1ACK BIT(3) -#define CORE_LANE_CFG_REFCLKEN (BIT(9) | BIT(10)) -#define CORE_LANE_CTL(port) (0x84004 + 0x4000 * (port)) -#define CORE_LANE_CTL_CFGACC BIT(15) + +#define CORE_PHY_DEFAULT_BASE(port) (0x84000 + 0x4000 * (port)) + +#define PHY_LANE_CFG 0x00000 +#define PHY_LANE_CFG_REFCLK0REQ BIT(0) +#define PHY_LANE_CFG_REFCLK1REQ BIT(1) +#define PHY_LANE_CFG_REFCLK0ACK BIT(2) +#define PHY_LANE_CFG_REFCLK1ACK BIT(3) +#define PHY_LANE_CFG_REFCLKEN (BIT(9) | BIT(10)) +#define PHY_LANE_CFG_REFCLKCGEN (BIT(30) | BIT(31)) +#define PHY_LANE_CTL 0x00004 +#define PHY_LANE_CTL_CFGACC BIT(15) #define PORT_LTSSMCTL 0x00080 #define PORT_LTSSMCTL_START BIT(0) @@ -146,6 +150,7 @@ struct apple_pcie_port { struct apple_pcie *pcie; struct device_node *np; void __iomem *base; + void __iomem *phy; struct irq_domain *domain; struct list_head entry; unsigned long *sid_map; @@ -476,26 +481,26 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie, if (res < 0) return res; - rmw_set(CORE_LANE_CTL_CFGACC, pcie->base + CORE_LANE_CTL(port->idx)); - rmw_set(CORE_LANE_CFG_REFCLK0REQ, pcie->base + CORE_LANE_CFG(port->idx)); + rmw_set(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL); + rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG); - res = readl_relaxed_poll_timeout(pcie->base + CORE_LANE_CFG(port->idx), - stat, stat & CORE_LANE_CFG_REFCLK0ACK, + res = readl_relaxed_poll_timeout(port->phy + PHY_LANE_CFG, + stat, stat & PHY_LANE_CFG_REFCLK0ACK, 100, 50000); if (res < 0) return res; - rmw_set(CORE_LANE_CFG_REFCLK1REQ, pcie->base + CORE_LANE_CFG(port->idx)); - res = readl_relaxed_poll_timeout(pcie->base + CORE_LANE_CFG(port->idx), - stat, stat & CORE_LANE_CFG_REFCLK1ACK, + rmw_set(PHY_LANE_CFG_REFCLK1REQ, port->phy + PHY_LANE_CFG); + res = readl_relaxed_poll_timeout(port->phy + PHY_LANE_CFG, + stat, stat & PHY_LANE_CFG_REFCLK1ACK, 100, 50000); if (res < 0) return res; - rmw_clear(CORE_LANE_CTL_CFGACC, pcie->base + CORE_LANE_CTL(port->idx)); + rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL); - rmw_set(CORE_LANE_CFG_REFCLKEN, pcie->base + CORE_LANE_CFG(port->idx)); + rmw_set(PHY_LANE_CFG_REFCLKEN, port->phy + PHY_LANE_CFG); rmw_set(PORT_REFCLK_EN, port->base + PORT_REFCLK); return 0; @@ -515,6 +520,8 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, struct platform_device *platform = to_platform_device(pcie->dev); struct apple_pcie_port *port; struct gpio_desc *reset; + struct resource *res; + char name[16]; u32 stat, idx; int ret, i; @@ -542,10 +549,22 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, raw_spin_lock_init(&port->lock); - port->base = devm_platform_ioremap_resource(platform, port->idx + 2); + snprintf(name, sizeof(name), "port%d", port->idx); + res = platform_get_resource_byname(platform, IORESOURCE_MEM, name); + if (!res) + res = platform_get_resource(platform, IORESOURCE_MEM, port->idx + 2); + + port->base = devm_ioremap_resource(&platform->dev, res); if (IS_ERR(port->base)) return PTR_ERR(port->base); + snprintf(name, sizeof(name), "phy%d", port->idx); + res = platform_get_resource_byname(platform, IORESOURCE_MEM, name); + if (res) + port->phy = devm_ioremap_resource(&platform->dev, res); + else + port->phy = pcie->base + CORE_PHY_DEFAULT_BASE(port->idx); + rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); /* Assert PERST# before setting up the clock */ From de9637c9f7827e0a2420bf1578758614530ac964 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 1 Apr 2025 10:17:10 +0100 Subject: [PATCH 048/147] PCI: apple: Drop poll for CORE_RC_PHYIF_STAT_REFCLK This is checking a core refclk in per-port setup which doesn't make a lot of sense, and the bootloader needs to have gone through this anyway. It doesn't work on T602x, so just drop it across the board. Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-11-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index b8d9b07f35b5..a3ff225d54ce 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -475,12 +475,6 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie, u32 stat; int res; - res = readl_relaxed_poll_timeout(pcie->base + CORE_RC_PHYIF_STAT, stat, - stat & CORE_RC_PHYIF_STAT_REFCLK, - 100, 50000); - if (res < 0) - return res; - rmw_set(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL); rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG); From 7334364f9de79a9a236dd0243ba574b8d2876e89 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 1 Apr 2025 10:17:11 +0100 Subject: [PATCH 049/147] PCI: apple: Use gpiod_set_value_cansleep in probe flow We're allowed to sleep here, so tell the GPIO core by using gpiod_set_value_cansleep instead of gpiod_set_value. Fixes: 1e33888fbe44 ("PCI: apple: Add initial hardware bring-up") Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-12-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index a3ff225d54ce..eadce67e30c0 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -562,7 +562,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, rmw_set(PORT_APPCLK_EN, port->base + PORT_APPCLK); /* Assert PERST# before setting up the clock */ - gpiod_set_value(reset, 1); + gpiod_set_value_cansleep(reset, 1); ret = apple_pcie_setup_refclk(pcie, port); if (ret < 0) @@ -573,7 +573,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, /* Deassert PERST# */ rmw_set(PORT_PERST_OFF, port->base + PORT_PERST); - gpiod_set_value(reset, 0); + gpiod_set_value_cansleep(reset, 0); /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ msleep(100); From 3f1ccd6e85d7b57460efb71e73da91fbea48d98a Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 1 Apr 2025 10:17:12 +0100 Subject: [PATCH 050/147] PCI: apple: Abstract register offsets via a SoC-specific structure Newer versions of the Apple PCIe block have a bunch of small, but annoying differences. In order to embrace this diversity of implementations, move the currently hardcoded offsets into a hw_info structure. Future SoCs will provide their own structure describing the applicable offsets. Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig [maz: split from original patch to only address T8103] Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-13-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 89 +++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index eadce67e30c0..1ffab0c068e3 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -18,6 +18,7 @@ * Author: Marc Zyngier */ +#include #include #include #include @@ -29,6 +30,7 @@ #include #include +/* T8103 (original M1) and related SoCs */ #define CORE_RC_PHYIF_CTL 0x00024 #define CORE_RC_PHYIF_CTL_RUN BIT(0) #define CORE_RC_PHYIF_STAT 0x00028 @@ -104,7 +106,7 @@ #define PORT_REFCLK_CGDIS BIT(8) #define PORT_PERST 0x00814 #define PORT_PERST_OFF BIT(0) -#define PORT_RID2SID(i16) (0x00828 + 4 * (i16)) +#define PORT_RID2SID 0x00828 #define PORT_RID2SID_VALID BIT(31) #define PORT_RID2SID_SID_SHIFT 16 #define PORT_RID2SID_BUS_SHIFT 8 @@ -122,7 +124,8 @@ #define PORT_TUNSTAT_PERST_ACK_PEND BIT(1) #define PORT_PREFMEM_ENABLE 0x00994 -#define MAX_RID2SID 64 +#define PORT_MSIMAP_ENABLE BIT(31) +#define PORT_MSIMAP_TARGET GENMASK(7, 0) /* * The doorbell address is set to 0xfffff000, which by convention @@ -133,10 +136,33 @@ */ #define DOORBELL_ADDR CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR +struct hw_info { + u32 phy_lane_ctl; + u32 port_msiaddr; + u32 port_msiaddr_hi; + u32 port_refclk; + u32 port_perst; + u32 port_rid2sid; + u32 port_msimap; + u32 max_rid2sid; +}; + +static const struct hw_info t8103_hw = { + .phy_lane_ctl = PHY_LANE_CTL, + .port_msiaddr = PORT_MSIADDR, + .port_msiaddr_hi = 0, + .port_refclk = PORT_REFCLK, + .port_perst = PORT_PERST, + .port_rid2sid = PORT_RID2SID, + .port_msimap = 0, + .max_rid2sid = 64, +}; + struct apple_pcie { struct mutex lock; struct device *dev; void __iomem *base; + const struct hw_info *hw; struct irq_domain *domain; unsigned long *bitmap; struct list_head ports; @@ -380,7 +406,9 @@ static void apple_port_irq_handler(struct irq_desc *desc) static int apple_pcie_port_setup_irq(struct apple_pcie_port *port) { struct fwnode_handle *fwnode = &port->np->fwnode; + struct apple_pcie *pcie = port->pcie; unsigned int irq; + u32 val = 0; /* FIXME: consider moving each interrupt under each port */ irq = irq_of_parse_and_map(to_of_node(dev_fwnode(port->pcie->dev)), @@ -402,13 +430,23 @@ static int apple_pcie_port_setup_irq(struct apple_pcie_port *port) /* Configure MSI base address */ BUILD_BUG_ON(upper_32_bits(DOORBELL_ADDR)); - writel_relaxed(lower_32_bits(DOORBELL_ADDR), port->base + PORT_MSIADDR); + writel_relaxed(lower_32_bits(DOORBELL_ADDR), + port->base + pcie->hw->port_msiaddr); + if (pcie->hw->port_msiaddr_hi) + writel_relaxed(0, port->base + pcie->hw->port_msiaddr_hi); /* Enable MSIs, shared between all ports */ - writel_relaxed(0, port->base + PORT_MSIBASE); - writel_relaxed((ilog2(port->pcie->nvecs) << PORT_MSICFG_L2MSINUM_SHIFT) | - PORT_MSICFG_EN, port->base + PORT_MSICFG); + if (pcie->hw->port_msimap) { + for (int i = 0; i < pcie->nvecs; i++) + writel_relaxed(FIELD_PREP(PORT_MSIMAP_TARGET, i) | + PORT_MSIMAP_ENABLE, + port->base + pcie->hw->port_msimap + 4 * i); + } else { + writel_relaxed(0, port->base + PORT_MSIBASE); + val = ilog2(pcie->nvecs) << PORT_MSICFG_L2MSINUM_SHIFT; + } + writel_relaxed(val | PORT_MSICFG_EN, port->base + PORT_MSICFG); return 0; } @@ -475,7 +513,9 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie, u32 stat; int res; - rmw_set(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL); + if (pcie->hw->phy_lane_ctl) + rmw_set(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl); + rmw_set(PHY_LANE_CFG_REFCLK0REQ, port->phy + PHY_LANE_CFG); res = readl_relaxed_poll_timeout(port->phy + PHY_LANE_CFG, @@ -492,20 +532,28 @@ static int apple_pcie_setup_refclk(struct apple_pcie *pcie, if (res < 0) return res; - rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + PHY_LANE_CTL); + if (pcie->hw->phy_lane_ctl) + rmw_clear(PHY_LANE_CTL_CFGACC, port->phy + pcie->hw->phy_lane_ctl); rmw_set(PHY_LANE_CFG_REFCLKEN, port->phy + PHY_LANE_CFG); - rmw_set(PORT_REFCLK_EN, port->base + PORT_REFCLK); + + if (pcie->hw->port_refclk) + rmw_set(PORT_REFCLK_EN, port->base + pcie->hw->port_refclk); return 0; } +static void __iomem *port_rid2sid_addr(struct apple_pcie_port *port, int idx) +{ + return port->base + port->pcie->hw->port_rid2sid + 4 * idx; +} + static u32 apple_pcie_rid2sid_write(struct apple_pcie_port *port, int idx, u32 val) { - writel_relaxed(val, port->base + PORT_RID2SID(idx)); + writel_relaxed(val, port_rid2sid_addr(port, idx)); /* Read back to ensure completion of the write */ - return readl_relaxed(port->base + PORT_RID2SID(idx)); + return readl_relaxed(port_rid2sid_addr(port, idx)); } static int apple_pcie_setup_port(struct apple_pcie *pcie, @@ -528,7 +576,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, if (!port) return -ENOMEM; - port->sid_map = devm_bitmap_zalloc(pcie->dev, MAX_RID2SID, GFP_KERNEL); + port->sid_map = devm_bitmap_zalloc(pcie->dev, pcie->hw->max_rid2sid, GFP_KERNEL); if (!port->sid_map) return -ENOMEM; @@ -572,7 +620,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, usleep_range(100, 200); /* Deassert PERST# */ - rmw_set(PORT_PERST_OFF, port->base + PORT_PERST); + rmw_set(PORT_PERST_OFF, port->base + pcie->hw->port_perst); gpiod_set_value_cansleep(reset, 0); /* Wait for 100ms after PERST# deassertion (PCIe r5.0, 6.6.1) */ @@ -585,7 +633,11 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, return ret; } - rmw_clear(PORT_REFCLK_CGDIS, port->base + PORT_REFCLK); + if (pcie->hw->port_refclk) + rmw_clear(PORT_REFCLK_CGDIS, port->base + pcie->hw->port_refclk); + else + rmw_set(PHY_LANE_CFG_REFCLKCGEN, port->phy + PHY_LANE_CFG); + rmw_clear(PORT_APPCLK_CGDIS, port->base + PORT_APPCLK); ret = apple_pcie_port_setup_irq(port); @@ -593,7 +645,7 @@ static int apple_pcie_setup_port(struct apple_pcie *pcie, return ret; /* Reset all RID/SID mappings, and check for RAZ/WI registers */ - for (i = 0; i < MAX_RID2SID; i++) { + for (i = 0; i < pcie->hw->max_rid2sid; i++) { if (apple_pcie_rid2sid_write(port, i, 0xbad1d) != 0xbad1d) break; apple_pcie_rid2sid_write(port, i, 0); @@ -741,7 +793,7 @@ static void apple_pcie_disable_device(struct pci_host_bridge *bridge, struct pci for_each_set_bit(idx, port->sid_map, port->sid_map_sz) { u32 val; - val = readl_relaxed(port->base + PORT_RID2SID(idx)); + val = readl_relaxed(port_rid2sid_addr(port, idx)); if ((val & 0xffff) == rid) { apple_pcie_rid2sid_write(port, idx, 0); bitmap_release_region(port->sid_map, idx, 0); @@ -792,6 +844,9 @@ static int apple_pcie_probe(struct platform_device *pdev) return -ENOMEM; pcie->dev = dev; + pcie->hw = of_device_get_match_data(dev); + if (!pcie->hw) + return -ENODEV; pcie->base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); @@ -808,7 +863,7 @@ static int apple_pcie_probe(struct platform_device *pdev) } static const struct of_device_id apple_pcie_of_match[] = { - { .compatible = "apple,pcie" }, + { .compatible = "apple,pcie", .data = &t8103_hw }, { } }; MODULE_DEVICE_TABLE(of, apple_pcie_of_match); From 4e639f11d6e06d9b33d29e0ae2c57b993b44ee48 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 1 Apr 2025 10:17:13 +0100 Subject: [PATCH 051/147] PCI: apple: Add T602x PCIe support This version of the hardware moved around a bunch of registers, so we avoid the old compatible for these and introduce register offset structures to handle the differences. Signed-off-by: Hector Martin Signed-off-by: Alyssa Rosenzweig Signed-off-by: Marc Zyngier Signed-off-by: Manivannan Sadhasivam Tested-by: Janne Grunau Reviewed-by: Rob Herring (Arm) Reviewed-by: Manivannan Sadhasivam Acked-by: Alyssa Rosenzweig Link: https://patch.msgid.link/20250401091713.2765724-14-maz@kernel.org --- drivers/pci/controller/pcie-apple.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 1ffab0c068e3..1211ca957c41 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -124,6 +124,13 @@ #define PORT_TUNSTAT_PERST_ACK_PEND BIT(1) #define PORT_PREFMEM_ENABLE 0x00994 +/* T602x (M2-pro and co) */ +#define PORT_T602X_MSIADDR 0x016c +#define PORT_T602X_MSIADDR_HI 0x0170 +#define PORT_T602X_PERST 0x082c +#define PORT_T602X_RID2SID 0x3000 +#define PORT_T602X_MSIMAP 0x3800 + #define PORT_MSIMAP_ENABLE BIT(31) #define PORT_MSIMAP_TARGET GENMASK(7, 0) @@ -158,6 +165,18 @@ static const struct hw_info t8103_hw = { .max_rid2sid = 64, }; +static const struct hw_info t602x_hw = { + .phy_lane_ctl = 0, + .port_msiaddr = PORT_T602X_MSIADDR, + .port_msiaddr_hi = PORT_T602X_MSIADDR_HI, + .port_refclk = 0, + .port_perst = PORT_T602X_PERST, + .port_rid2sid = PORT_T602X_RID2SID, + .port_msimap = PORT_T602X_MSIMAP, + /* 16 on t602x, guess for autodetect on future HW */ + .max_rid2sid = 512, +}; + struct apple_pcie { struct mutex lock; struct device *dev; @@ -425,6 +444,7 @@ static int apple_pcie_port_setup_irq(struct apple_pcie_port *port) /* Disable all interrupts */ writel_relaxed(~0, port->base + PORT_INTMSK); writel_relaxed(~0, port->base + PORT_INTSTAT); + writel_relaxed(~0, port->base + PORT_LINKCMDSTS); irq_set_chained_handler_and_data(irq, apple_port_irq_handler, port); @@ -863,6 +883,7 @@ static int apple_pcie_probe(struct platform_device *pdev) } static const struct of_device_id apple_pcie_of_match[] = { + { .compatible = "apple,t6020-pcie", .data = &t602x_hw }, { .compatible = "apple,pcie", .data = &t8103_hw }, { } }; From 8fe743b5eba0abfbee39fe27b12acfb0df9b8a2d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Apr 2025 22:16:32 +0200 Subject: [PATCH 052/147] PCI: Add CONFIG_MMU dependency It turns out that there are no platforms that have PCI but don't have an MMU, so adding a Kconfig dependency on CONFIG_PCI simplifies build testing kernels for those platforms a lot, and avoids a lot of inadvertent build regressions. Add a dependency for CONFIG_PCI and remove all the ones for PCI specific device drivers that are currently marked not having it. There are a few platforms that have an optional MMU, but they usually cannot have PCI at all. The one exception is Coldfire MCF54xx, but this is mainly for historic reasons, and anyone using those chips should really use the MMU these days. Link: https://lore.kernel.org/lkml/a41f1b20-a76c-43d8-8c36-f12744327a54@app.fastmail.com/ Signed-off-by: Arnd Bergmann Signed-off-by: Bjorn Helgaas Reviewed-by: Martin K. Petersen # SCSI Reviewed-by: Thomas Zimmermann Acked-by: Alex Deucher Link: https://patch.msgid.link/20250423202215.3315550-1-arnd@kernel.org --- drivers/accel/qaic/Kconfig | 1 - drivers/firewire/Kconfig | 2 +- drivers/gpu/drm/Kconfig | 2 +- drivers/gpu/drm/amd/amdgpu/Kconfig | 3 +-- drivers/gpu/drm/ast/Kconfig | 2 +- drivers/gpu/drm/gma500/Kconfig | 2 +- drivers/gpu/drm/hisilicon/hibmc/Kconfig | 1 - drivers/gpu/drm/loongson/Kconfig | 2 +- drivers/gpu/drm/mgag200/Kconfig | 2 +- drivers/gpu/drm/nouveau/Kconfig | 3 +-- drivers/gpu/drm/qxl/Kconfig | 2 +- drivers/gpu/drm/radeon/Kconfig | 2 +- drivers/gpu/drm/tiny/Kconfig | 2 +- drivers/gpu/drm/vmwgfx/Kconfig | 2 +- drivers/gpu/drm/xe/Kconfig | 2 +- drivers/net/ethernet/broadcom/Kconfig | 1 - drivers/pci/Kconfig | 1 + drivers/pci/pci.c | 4 ++-- drivers/scsi/bnx2fc/Kconfig | 1 - drivers/scsi/bnx2i/Kconfig | 1 - drivers/vfio/pci/Kconfig | 2 +- 21 files changed, 17 insertions(+), 23 deletions(-) diff --git a/drivers/accel/qaic/Kconfig b/drivers/accel/qaic/Kconfig index a9f866230058..5e405a19c157 100644 --- a/drivers/accel/qaic/Kconfig +++ b/drivers/accel/qaic/Kconfig @@ -8,7 +8,6 @@ config DRM_ACCEL_QAIC depends on DRM_ACCEL depends on PCI && HAS_IOMEM depends on MHI_BUS - depends on MMU select CRC32 help Enables driver for Qualcomm's Cloud AI accelerator PCIe cards that are diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 905c82e26ce7..a5f5e250223a 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -83,7 +83,7 @@ config FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST config FIREWIRE_OHCI tristate "OHCI-1394 controllers" - depends on PCI && FIREWIRE && MMU + depends on PCI && FIREWIRE help Enable this driver if you have a FireWire controller based on the OHCI specification. For all practical purposes, this diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 2cba2b6ebe1c..6e95d204597e 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -462,7 +462,7 @@ source "drivers/gpu/drm/imagination/Kconfig" config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" - depends on DRM && PCI && MMU && HYPERV + depends on DRM && PCI && HYPERV select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_SHMEM_HELPER diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 1a11cab741ac..058e3b3ad520 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -2,7 +2,7 @@ config DRM_AMDGPU tristate "AMD GPU" - depends on DRM && PCI && MMU + depends on DRM && PCI depends on !UML select FW_LOADER select DRM_CLIENT @@ -68,7 +68,6 @@ config DRM_AMDGPU_CIK config DRM_AMDGPU_USERPTR bool "Always enable userptr write support" depends on DRM_AMDGPU - depends on MMU select HMM_MIRROR select MMU_NOTIFIER help diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig index da0663542e8a..242fbccdf844 100644 --- a/drivers/gpu/drm/ast/Kconfig +++ b/drivers/gpu/drm/ast/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_AST tristate "AST server chips" - depends on DRM && PCI && MMU + depends on DRM && PCI select DRM_CLIENT_SELECTION select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/gma500/Kconfig b/drivers/gpu/drm/gma500/Kconfig index aa2ea128aa2f..a2acaa699dd5 100644 --- a/drivers/gpu/drm/gma500/Kconfig +++ b/drivers/gpu/drm/gma500/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_GMA500 tristate "Intel GMA500/600/3600/3650 KMS Framebuffer" - depends on DRM && PCI && X86 && MMU && HAS_IOPORT + depends on DRM && PCI && X86 && HAS_IOPORT select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig index 98d77d74999d..d1f3f5793f34 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig @@ -2,7 +2,6 @@ config DRM_HISI_HIBMC tristate "DRM Support for Hisilicon Hibmc" depends on DRM && PCI - depends on MMU select DRM_CLIENT_SELECTION select DRM_DISPLAY_HELPER select DRM_DISPLAY_DP_HELPER diff --git a/drivers/gpu/drm/loongson/Kconfig b/drivers/gpu/drm/loongson/Kconfig index 552edfec7afb..d739d51cf54c 100644 --- a/drivers/gpu/drm/loongson/Kconfig +++ b/drivers/gpu/drm/loongson/Kconfig @@ -2,7 +2,7 @@ config DRM_LOONGSON tristate "DRM support for Loongson Graphics" - depends on DRM && PCI && MMU + depends on DRM && PCI depends on LOONGARCH || MIPS || COMPILE_TEST select DRM_CLIENT_SELECTION select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig index 412dcbea0e2d..a962ae564a75 100644 --- a/drivers/gpu/drm/mgag200/Kconfig +++ b/drivers/gpu/drm/mgag200/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_MGAG200 tristate "Matrox G200" - depends on DRM && PCI && MMU + depends on DRM && PCI select DRM_CLIENT_SELECTION select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 7b3e979c51ec..d1587639ebb0 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_NOUVEAU tristate "Nouveau (NVIDIA) cards" - depends on DRM && PCI && MMU + depends on DRM && PCI select IOMMU_API select FW_LOADER select FW_CACHE if PM_SLEEP @@ -94,7 +94,6 @@ config DRM_NOUVEAU_SVM bool "(EXPERIMENTAL) Enable SVM (Shared Virtual Memory) support" depends on DEVICE_PRIVATE depends on DRM_NOUVEAU - depends on MMU depends on STAGING select HMM_MIRROR select MMU_NOTIFIER diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig index 69427eb8bed2..d8f24bcae34b 100644 --- a/drivers/gpu/drm/qxl/Kconfig +++ b/drivers/gpu/drm/qxl/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_QXL tristate "QXL virtual GPU" - depends on DRM && PCI && MMU && HAS_IOPORT + depends on DRM && PCI && HAS_IOPORT select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_TTM diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index f51bace9555d..c479f0c0dd5c 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -2,7 +2,7 @@ config DRM_RADEON tristate "ATI Radeon" - depends on DRM && PCI && MMU + depends on DRM && PCI depends on AGP || !AGP select FW_LOADER select DRM_CLIENT_SELECTION diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index 54c84c9801c1..6ca12fe7f57a 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -37,7 +37,7 @@ config DRM_BOCHS config DRM_CIRRUS_QEMU tristate "Cirrus driver for QEMU emulated device" - depends on DRM && PCI && MMU + depends on DRM && PCI select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_SHMEM_HELPER diff --git a/drivers/gpu/drm/vmwgfx/Kconfig b/drivers/gpu/drm/vmwgfx/Kconfig index 6c3c2922ae8b..aab646b91ca9 100644 --- a/drivers/gpu/drm/vmwgfx/Kconfig +++ b/drivers/gpu/drm/vmwgfx/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config DRM_VMWGFX tristate "DRM driver for VMware Virtual GPU" - depends on DRM && PCI && MMU + depends on DRM && PCI depends on (X86 && HYPERVISOR_GUEST) || ARM64 select DRM_CLIENT_SELECTION select DRM_TTM diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig index 5c2f459a2925..2dec62737ff6 100644 --- a/drivers/gpu/drm/xe/Kconfig +++ b/drivers/gpu/drm/xe/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_XE tristate "Intel Xe Graphics" - depends on DRM && PCI && MMU && (m || (y && KUNIT=y)) + depends on DRM && PCI && (m || (y && KUNIT=y)) select INTERVAL_TREE # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index eeec8bf17cf4..aa43984a05cf 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -96,7 +96,6 @@ config BNX2 config CNIC tristate "QLogic CNIC support" depends on PCI && (IPV6 || IPV6=n) - depends on MMU select BNX2 select UIO help diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index da28295b4aac..9c0e4aaf4e8c 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -21,6 +21,7 @@ config GENERIC_PCI_IOMAP menuconfig PCI bool "PCI support" depends on HAVE_PCI + depends on MMU help This option enables support for the PCI local bus, including support for PCI-X and the foundations for PCI Express support. diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d7c9f64ea24..60a20a0ac41f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4257,7 +4257,7 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address) #ifndef pci_remap_iospace int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) { -#if defined(PCI_IOBASE) && defined(CONFIG_MMU) +#if defined(PCI_IOBASE) unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start; if (!(res->flags & IORESOURCE_IO)) @@ -4290,7 +4290,7 @@ EXPORT_SYMBOL(pci_remap_iospace); */ void pci_unmap_iospace(struct resource *res) { -#if defined(PCI_IOBASE) && defined(CONFIG_MMU) +#if defined(PCI_IOBASE) unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start; vunmap_range(vaddr, vaddr + resource_size(res)); diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig index ecdc0f0f4f4e..3cf7e08df809 100644 --- a/drivers/scsi/bnx2fc/Kconfig +++ b/drivers/scsi/bnx2fc/Kconfig @@ -5,7 +5,6 @@ config SCSI_BNX2X_FCOE depends on (IPV6 || IPV6=n) depends on LIBFC depends on LIBFCOE - depends on MMU select NETDEVICES select ETHERNET select NET_VENDOR_BROADCOM diff --git a/drivers/scsi/bnx2i/Kconfig b/drivers/scsi/bnx2i/Kconfig index 0cc06c2ce0b8..75ace2302fed 100644 --- a/drivers/scsi/bnx2i/Kconfig +++ b/drivers/scsi/bnx2i/Kconfig @@ -4,7 +4,6 @@ config SCSI_BNX2_ISCSI depends on NET depends on PCI depends on (IPV6 || IPV6=n) - depends on MMU select SCSI_ISCSI_ATTRS select NETDEVICES select ETHERNET diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index c3bcb6911c53..2b0172f54665 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only menu "VFIO support for PCI devices" - depends on PCI && MMU + depends on PCI config VFIO_PCI_CORE tristate From bfa4477751e9909bb121eca860f44d1b4259d871 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 22 Apr 2025 17:05:31 -0600 Subject: [PATCH 053/147] PM: runtime: Define pm_runtime_put cleanup helper Define a cleanup helper for use with __free to automatically drop the device usage count when the pointer goes out of scope. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Link: https://patch.msgid.link/20250422230534.2295291-2-alex.williamson@redhat.com --- include/linux/pm_runtime.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 7fb5a459847e..69d4b2929ee6 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -466,6 +466,8 @@ static inline int pm_runtime_put(struct device *dev) return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_ASYNC); } +DEFINE_FREE(pm_runtime_put, struct device *, if (_T) pm_runtime_put(_T)) + /** * __pm_runtime_put_autosuspend - Drop device usage counter and queue autosuspend if 0. * @dev: Target device. From 0a0829b1fd76cb6110cc049a60e634a51969e488 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 22 Apr 2025 17:05:32 -0600 Subject: [PATCH 054/147] PCI: Increment PM usage counter when probing reset methods We can get different results probing reset methods for a device depending on its power state. For example, reading the PM control register of a device in D3cold will always indicate NoSoftRst+ because we get ~0 data when the config read fails on PCI, preventing us from correctly probing PM reset support. Increment the PM usage counter before any probes and use the cleanup __free facility to automatically drop the usage counter out of scope. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250422230534.2295291-3-alex.williamson@redhat.com --- drivers/pci/pci-sysfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c6cda56ca52c..71a36f57ef57 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1475,6 +1475,9 @@ static ssize_t reset_method_store(struct device *dev, return count; } + pm_runtime_get_sync(dev); + struct device *pmdev __free(pm_runtime_put) = dev; + if (sysfs_streq(buf, "default")) { pci_init_reset_methods(pdev); return count; From 22282967585ac9e5d88d92d804cc3e5b19c47a97 Mon Sep 17 00:00:00 2001 From: Rick Wertenbroek Date: Wed, 23 Apr 2025 11:56:43 +0200 Subject: [PATCH 055/147] Documentation: Fix path for NVMe PCI endpoint target driver The path for the driver points to an non-existent file. Update path with the correct file: drivers/nvme/target/pci-epf.c Signed-off-by: Rick Wertenbroek Signed-off-by: Bjorn Helgaas Reviewed-by: Damien Le Moal Link: https://patch.msgid.link/20250423095643.490495-1-rick.wertenbroek@gmail.com --- Documentation/PCI/endpoint/pci-nvme-function.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/PCI/endpoint/pci-nvme-function.rst b/Documentation/PCI/endpoint/pci-nvme-function.rst index df57b8e7d066..a68015317f7f 100644 --- a/Documentation/PCI/endpoint/pci-nvme-function.rst +++ b/Documentation/PCI/endpoint/pci-nvme-function.rst @@ -8,6 +8,6 @@ PCI NVMe Function The PCI NVMe endpoint function implements a PCI NVMe controller using the NVMe subsystem target core code. The driver for this function resides with the NVMe -subsystem as drivers/nvme/target/nvmet-pciep.c. +subsystem as drivers/nvme/target/pci-epf.c. See Documentation/nvme/nvme-pci-endpoint-target.rst for more details. From a733e711278182840b4c9a0329294daa5cc34048 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Mon, 17 Mar 2025 15:30:26 +0530 Subject: [PATCH 056/147] dt-bindings: PCI: qcom: Add MHI registers for IPQ9574 The MHI registers are present in IPQ5332, IPQ6018, IPQ8074 and IPQ9574 SoCs. Hence, add the MHI registers to the binding to allow these registers to be defined in devicetree. Signed-off-by: Varadarajan Narayanan [mani: commit message rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20250317100029.881286-2-quic_varada@quicinc.com --- Documentation/devicetree/bindings/pci/qcom,pcie.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index e20f142316cc..9cc26d782258 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -175,14 +175,16 @@ allOf: properties: reg: minItems: 5 - maxItems: 5 + maxItems: 6 reg-names: + minItems: 5 items: - const: dbi # DesignWare PCIe registers - const: elbi # External local bus interface registers - const: atu # ATU address space - const: parf # Qualcomm specific registers - const: config # PCIe configuration space + - const: mhi # MHI registers - if: properties: From 7d9b5d6115532cf90a789ed6afd3f4c70ebbd827 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 17 Apr 2025 08:35:09 +0800 Subject: [PATCH 057/147] PCI: dw-rockchip: Remove PCIE_L0S_ENTRY check from rockchip_pcie_link_up() rockchip_pcie_link_up() currently has two issues: 1. Value 0x11 of PCIE_L0S_ENTRY corresponds to L0 state, not L0S. So the naming is wrong from the very beginning. 2. Checking for value 0x11 treats other states like L0S and L1 as link down, which is wrong. Hence, remove the PCIE_L0S_ENTRY check and also its definition. This allows adding ASPM support in the successive commits. Fixes: 0e898eb8df4e ("PCI: rockchip-dwc: Add Rockchip RK356X host controller driver") Signed-off-by: Shawn Lin [mani: commit message rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org Link: https://patch.msgid.link/1744850111-236269-1-git-send-email-shawn.lin@rock-chips.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index c624b7ebd118..21dc99c9d95c 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -44,7 +44,6 @@ #define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) #define PCIE_RDLH_LINK_UP_CHGED BIT(1) #define PCIE_LINK_REQ_RST_NOT_INT BIT(2) -#define PCIE_L0S_ENTRY 0x11 #define PCIE_CLIENT_GENERAL_CONTROL 0x0 #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c @@ -177,8 +176,7 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); u32 val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP && - (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY) + if ((val & PCIE_LINKUP) == PCIE_LINKUP) return 1; return 0; From 198e69cc4150aba1e7af740a2111ace6a267779e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 17 Apr 2025 08:35:10 +0800 Subject: [PATCH 058/147] PCI: dw-rockchip: Enable ASPM L0s capability for both RC and EP modes L0s capability isn't enabled on all Rockchip SoCs by default, so enable it in order to make ASPM L0s work on Rockchip platforms. Testing the L0s for a long time revealed that the default N_FTS value of 210 in the hardware doesn't work stable and causes LTSSM to switch between L0s and Recovery states. This leads to long exit latency and also causes link down sometimes. So override the value to the max 255, which seems to work fine under both PHYs used on Rockchip platforms. Signed-off-by: Shawn Lin [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/1744850111-236269-2-git-send-email-shawn.lin@rock-chips.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 21dc99c9d95c..e4519c020ea9 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -182,6 +182,21 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) return 0; } +static void rockchip_pcie_enable_l0s(struct dw_pcie *pci) +{ + u32 cap, lnkcap; + + /* Enable L0S capability for all SoCs */ + cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + if (cap) { + lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP); + lnkcap |= PCI_EXP_LNKCAP_ASPM_L0S; + dw_pcie_dbi_ro_wr_en(pci); + dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap); + dw_pcie_dbi_ro_wr_dis(pci); + } +} + static int rockchip_pcie_start_link(struct dw_pcie *pci) { struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); @@ -231,6 +246,8 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp) irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler, rockchip); + rockchip_pcie_enable_l0s(pci); + return 0; } @@ -271,6 +288,8 @@ static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) struct dw_pcie *pci = to_dw_pcie_from_ep(ep); enum pci_barno bar; + rockchip_pcie_enable_l0s(pci); + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); }; @@ -599,6 +618,10 @@ static int rockchip_pcie_probe(struct platform_device *pdev) rockchip->pci.ops = &dw_pcie_ops; rockchip->data = data; + /* Default N_FTS value (210) is broken, override it to 255 */ + rockchip->pci.n_fts[0] = 255; /* Gen1 */ + rockchip->pci.n_fts[1] = 255; /* Gen2+ */ + ret = rockchip_pcie_resource_get(pdev, rockchip); if (ret) return ret; From d4a5d7e6d91f6e53c8bf6ec72b7ee6c51f781695 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 14 Apr 2025 09:28:29 +0800 Subject: [PATCH 059/147] PCI: dw-rockchip: Move rockchip_pcie_ep_hide_broken_ats_cap_rk3588() to dw_pcie_ep_ops::init() In the case of PERST# deassert, non-sticky registers will get reset to their hardware default state and EXT_CAP registers are one among them. But since the broken ATS cap is hidden only in dw_pcie_ep_ops::pre_init() callback which is not gettting called during PERST# deassert, it results in the capability getting advertised again. So move it to dw_pcie_ep_ops::init() to fix it. Suggested-by: Niklas Cassel Signed-off-by: Shawn Lin [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Tested-by: Niklas Cassel Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/1744594109-209312-1-git-send-email-shawn.lin@rock-chips.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index e4519c020ea9..7790a9f33e48 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -278,17 +278,13 @@ static void rockchip_pcie_ep_hide_broken_ats_cap_rk3588(struct dw_pcie_ep *ep) dev_err(dev, "failed to hide ATS capability\n"); } -static void rockchip_pcie_ep_pre_init(struct dw_pcie_ep *ep) -{ - rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep); -} - static void rockchip_pcie_ep_init(struct dw_pcie_ep *ep) { struct dw_pcie *pci = to_dw_pcie_from_ep(ep); enum pci_barno bar; rockchip_pcie_enable_l0s(pci); + rockchip_pcie_ep_hide_broken_ats_cap_rk3588(ep); for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) dw_pcie_ep_reset_bar(pci, bar); @@ -359,7 +355,6 @@ rockchip_pcie_get_features(struct dw_pcie_ep *ep) static const struct dw_pcie_ep_ops rockchip_pcie_ep_ops = { .init = rockchip_pcie_ep_init, - .pre_init = rockchip_pcie_ep_pre_init, .raise_irq = rockchip_pcie_raise_irq, .get_features = rockchip_pcie_get_features, }; From 9c03e30e3ade32136fed5a4ab7872dcb205687d3 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:08 +0800 Subject: [PATCH 060/147] PCI: imx6: Skip link up workaround for newer platforms The current link setup procedure has one workaround to detect the devices behind PCIe switches on some i.MX6 platforms. But this workaround is not needed on recent i.MX7 platforms. So skip the workaround for platforms that do not set the flag and start LTSSM directly. Also, change the flag name from IMX_PCIE_FLAG_IMX_SPEED_CHANGE to IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND to match the usecase. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-2-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 34 +++++++++++---------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 5f267dd261b5..a4c0714c6468 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -91,7 +91,7 @@ enum imx_pcie_variants { }; #define IMX_PCIE_FLAG_IMX_PHY BIT(0) -#define IMX_PCIE_FLAG_IMX_SPEED_CHANGE BIT(1) +#define IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND BIT(1) #define IMX_PCIE_FLAG_SUPPORTS_SUSPEND BIT(2) #define IMX_PCIE_FLAG_HAS_PHYDRV BIT(3) #define IMX_PCIE_FLAG_HAS_APP_RESET BIT(4) @@ -860,6 +860,12 @@ static int imx_pcie_start_link(struct dw_pcie *pci) u32 tmp; int ret; + if (!(imx_pcie->drvdata->flags & + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND)) { + imx_pcie_ltssm_enable(dev); + return 0; + } + /* * Force Gen1 operation when starting the link. In case the link is * started in Gen2 mode, there is a possibility the devices on the @@ -896,22 +902,10 @@ static int imx_pcie_start_link(struct dw_pcie *pci) dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp); dw_pcie_dbi_ro_wr_dis(pci); - if (imx_pcie->drvdata->flags & - IMX_PCIE_FLAG_IMX_SPEED_CHANGE) { - - /* - * On i.MX7, DIRECT_SPEED_CHANGE behaves differently - * from i.MX6 family when no link speed transition - * occurs and we go Gen1 -> yep, Gen1. The difference - * is that, in such case, it will not be cleared by HW - * which will cause the following code to report false - * failure. - */ - ret = imx_pcie_wait_for_speed_change(imx_pcie); - if (ret) { - dev_err(dev, "Failed to bring link up!\n"); - goto err_reset_phy; - } + ret = imx_pcie_wait_for_speed_change(imx_pcie); + if (ret) { + dev_err(dev, "Failed to bring link up!\n"); + goto err_reset_phy; } /* Make sure link training is finished as well! */ @@ -1649,7 +1643,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6Q] = { .variant = IMX6Q, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | IMX_PCIE_FLAG_BROKEN_SUSPEND | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .dbi_length = 0x200, @@ -1665,7 +1659,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6SX] = { .variant = IMX6SX, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .gpr = "fsl,imx6q-iomuxc-gpr", .ltssm_off = IOMUXC_GPR12, @@ -1680,7 +1674,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6QP] = { .variant = IMX6QP, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_SPEED_CHANGE_WORKAROUND | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .dbi_length = 0x200, .gpr = "fsl,imx6q-iomuxc-gpr", From 4a4be0c088e3029a482ef8ac98bb2acb94af960e Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:09 +0800 Subject: [PATCH 061/147] PCI: imx6: Call dw_pcie_wait_for_link() from start_link() callback only when required Since the DWC driver is already calling dw_pcie_wait_for_link() after calling the start_link() callback, remove the redundant dw_pcie_wait_for_link() call from imx_pcie_start_link(). It is still required to call this function for controllers supporting Gen 2 and higher link speeds. Suggested-by: Manivannan Sadhasivam Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Frank Li Link: https://patch.msgid.link/20250416081314.3929794-3-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index a4c0714c6468..c5871c3d4194 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -881,11 +881,11 @@ static int imx_pcie_start_link(struct dw_pcie *pci) /* Start LTSSM. */ imx_pcie_ltssm_enable(dev); - ret = dw_pcie_wait_for_link(pci); - if (ret) - goto err_reset_phy; - if (pci->max_link_speed > 1) { + ret = dw_pcie_wait_for_link(pci); + if (ret) + goto err_reset_phy; + /* Allow faster modes after the link is up */ dw_pcie_dbi_ro_wr_en(pci); tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); @@ -907,17 +907,10 @@ static int imx_pcie_start_link(struct dw_pcie *pci) dev_err(dev, "Failed to bring link up!\n"); goto err_reset_phy; } - - /* Make sure link training is finished as well! */ - ret = dw_pcie_wait_for_link(pci); - if (ret) - goto err_reset_phy; } else { dev_info(dev, "Link: Only Gen1 is enabled\n"); } - tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA); - dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS); return 0; err_reset_phy: From 47f54a902dcd3b756e8e761f2c4c742af57dfff0 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:10 +0800 Subject: [PATCH 062/147] PCI: imx6: Toggle the core reset for i.MX95 PCIe Add toggling core reset for i.MX95 to align with PHY's power-up sequence. Note that the register is named as IMX95_PCIE_COLD_RST in hardware, though it is used to reset the PCIe core. Signed-off-by: Richard Zhu Signed-off-by: Manivannan Sadhasivam [mani: subject and description rewording] Reviewed-by: Manivannan Sadhasivam Reviewed-by: Frank Li Link: https://patch.msgid.link/20250416081314.3929794-4-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index c5871c3d4194..7c60b712480a 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -71,6 +71,9 @@ #define IMX95_SID_MASK GENMASK(5, 0) #define IMX95_MAX_LUT 32 +#define IMX95_PCIE_RST_CTRL 0x3010 +#define IMX95_PCIE_COLD_RST BIT(0) + #define to_imx_pcie(x) dev_get_drvdata((x)->dev) enum imx_pcie_variants { @@ -773,6 +776,43 @@ static int imx7d_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert) return 0; } +static int imx95_pcie_core_reset(struct imx_pcie *imx_pcie, bool assert) +{ + u32 val; + + if (assert) { + /* + * From i.MX95 PCIe PHY perspective, the COLD reset toggle + * should be complete after power-up by the following sequence. + * > 10us(at power-up) + * > 10ns(warm reset) + * |<------------>| + * ______________ + * phy_reset ____/ \________________ + * ____________ + * ref_clk_en_______________________/ + * Toggle COLD reset aligned with this sequence for i.MX95 PCIe. + */ + regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST); + /* + * Make sure the write to IMX95_PCIE_RST_CTRL is flushed to the + * hardware by doing a read. Otherwise, there is no guarantee + * that the write has reached the hardware before udelay(). + */ + regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + &val); + udelay(15); + regmap_clear_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + IMX95_PCIE_COLD_RST); + regmap_read_bypassed(imx_pcie->iomuxc_gpr, IMX95_PCIE_RST_CTRL, + &val); + udelay(10); + } + + return 0; +} + static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie) { reset_control_assert(imx_pcie->pciephy_reset); @@ -1739,6 +1779,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .ltssm_mask = IMX95_PCIE_LTSSM_EN, .mode_off[0] = IMX95_PE0_GEN_CTRL_1, .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, + .core_reset = imx95_pcie_core_reset, .init_phy = imx95_pcie_init_phy, }, [IMX8MQ_EP] = { @@ -1792,6 +1833,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_off[0] = IMX95_PE0_GEN_CTRL_1, .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, .init_phy = imx95_pcie_init_phy, + .core_reset = imx95_pcie_core_reset, .epc_features = &imx95_pcie_epc_features, .mode = DW_PCIE_EP_TYPE, }, From ce0c43e855c7f652b6351110aaaabf9b521debd7 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:11 +0800 Subject: [PATCH 063/147] PCI: imx6: Add workaround for errata ERR051624 ERR051624: The Controller Without Vaux Cannot Exit L23 Ready Through Beacon or PERST# De-assertion When the auxiliary power is not available, the controller cannot exit from L23 Ready with beacon or PERST# de-assertion when main power is not removed. So the workaround is to set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1. This workaround is required irrespective of whether Vaux is supplied to the link partner or not. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-5-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7c60b712480a..016b86add959 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -48,6 +48,8 @@ #define IMX95_PCIE_SS_RW_REG_0 0xf0 #define IMX95_PCIE_REF_CLKEN BIT(23) #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) +#define IMX95_PCIE_SS_RW_REG_1 0xf4 +#define IMX95_PCIE_SYS_AUX_PWR_DET BIT(31) #define IMX95_PE0_GEN_CTRL_1 0x1050 #define IMX95_PCIE_DEVICE_TYPE GENMASK(3, 0) @@ -227,6 +229,19 @@ static unsigned int imx_pcie_grp_offset(const struct imx_pcie *imx_pcie) static int imx95_pcie_init_phy(struct imx_pcie *imx_pcie) { + /* + * ERR051624: The Controller Without Vaux Cannot Exit L23 Ready + * Through Beacon or PERST# De-assertion + * + * When the auxiliary power is not available, the controller + * cannot exit from L23 Ready with beacon or PERST# de-assertion + * when main power is not removed. + * + * Workaround: Set SS_RW_REG_1[SYS_AUX_PWR_DET] to 1. + */ + regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_1, + IMX95_PCIE_SYS_AUX_PWR_DET); + regmap_update_bits(imx_pcie->iomuxc_gpr, IMX95_PCIE_SS_RW_REG_0, IMX95_PCIE_PHY_CR_PARA_SEL, From 744a1c20ce933dcaca0f161fe7da115902a2f343 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:12 +0800 Subject: [PATCH 064/147] PCI: imx6: Add workaround for errata ERR051586 ERR051586: Compliance with 8GT/s Receiver Impedance ECN. The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] is 1 which makes receiver non-compliant with the ZRX-DC parameter for 2.5 GT/s when operating at 8 GT/s or higher. It causes unnecessary timeout in L1. So the workaround is to set GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] to 0. Add this workaround in the dw_pcie_host_ops::post_init() callback for i.MX95 platforms. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-6-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 016b86add959..7dcc9d88740d 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -110,6 +110,7 @@ enum imx_pcie_variants { */ #define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9) #define IMX_PCIE_FLAG_HAS_LUT BIT(10) +#define IMX_PCIE_FLAG_8GT_ECN_ERR051586 BIT(11) #define imx_check_flag(pci, val) (pci->drvdata->flags & val) @@ -1256,6 +1257,32 @@ static void imx_pcie_host_exit(struct dw_pcie_rp *pp) regulator_disable(imx_pcie->vpcie); } +static void imx_pcie_host_post_init(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct imx_pcie *imx_pcie = to_imx_pcie(pci); + u32 val; + + if (imx_pcie->drvdata->flags & IMX_PCIE_FLAG_8GT_ECN_ERR051586) { + /* + * ERR051586: Compliance with 8GT/s Receiver Impedance ECN + * + * The default value of GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] + * is 1 which makes receiver non-compliant with the ZRX-DC + * parameter for 2.5 GT/s when operating at 8 GT/s or higher. + * It causes unnecessary timeout in L1. + * + * Workaround: Program GEN3_RELATED_OFF[GEN3_ZRXDC_NONCOMPL] + * to 0. + */ + dw_pcie_dbi_ro_wr_en(pci); + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF); + val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL; + dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val); + dw_pcie_dbi_ro_wr_dis(pci); + } +} + /* * In old DWC implementations, PCIE_ATU_INHIBIT_PAYLOAD in iATU Ctrl2 * register is reserved, so the generic DWC implementation of sending the @@ -1281,6 +1308,7 @@ static const struct dw_pcie_host_ops imx_pcie_host_ops = { static const struct dw_pcie_host_ops imx_pcie_host_dw_pme_ops = { .init = imx_pcie_host_init, .deinit = imx_pcie_host_exit, + .post_init = imx_pcie_host_post_init, }; static const struct dw_pcie_ops dw_pcie_ops = { @@ -1392,6 +1420,7 @@ static int imx_add_pcie_ep(struct imx_pcie *imx_pcie, dev_err(dev, "failed to initialize endpoint\n"); return ret; } + imx_pcie_host_post_init(pp); ret = dw_pcie_ep_init_registers(ep); if (ret) { @@ -1789,6 +1818,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .variant = IMX95, .flags = IMX_PCIE_FLAG_HAS_SERDES | IMX_PCIE_FLAG_HAS_LUT | + IMX_PCIE_FLAG_8GT_ECN_ERR051586 | IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .ltssm_off = IMX95_PE0_GEN_CTRL_3, .ltssm_mask = IMX95_PCIE_LTSSM_EN, @@ -1842,6 +1872,7 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX95_EP] = { .variant = IMX95_EP, .flags = IMX_PCIE_FLAG_HAS_SERDES | + IMX_PCIE_FLAG_8GT_ECN_ERR051586 | IMX_PCIE_FLAG_SUPPORT_64BIT, .ltssm_off = IMX95_PE0_GEN_CTRL_3, .ltssm_mask = IMX95_PCIE_LTSSM_EN, From 047e8b6b3bc3e6b25bfa12896a39d9fb82b591be Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:13 +0800 Subject: [PATCH 065/147] PCI: imx6: Add PLL lock check for i.MX95 SoC PLL lock is required to ensure that the PLL clock is stable before enabling the controller in i.MX95 SoC. Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-7-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 7dcc9d88740d..4cff66794990 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -45,6 +45,9 @@ #define IMX95_PCIE_PHY_GEN_CTRL 0x0 #define IMX95_PCIE_REF_USE_PAD BIT(17) +#define IMX95_PCIE_PHY_MPLLA_CTRL 0x10 +#define IMX95_PCIE_PHY_MPLL_STATE BIT(30) + #define IMX95_PCIE_SS_RW_REG_0 0xf0 #define IMX95_PCIE_REF_CLKEN BIT(23) #define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9) @@ -132,6 +135,7 @@ struct imx_pcie_drvdata { int (*init_phy)(struct imx_pcie *pcie); int (*enable_ref_clk)(struct imx_pcie *pcie, bool enable); int (*core_reset)(struct imx_pcie *pcie, bool assert); + int (*wait_pll_lock)(struct imx_pcie *pcie); const struct dw_pcie_host_ops *ops; }; @@ -479,6 +483,23 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie) dev_err(dev, "PCIe PLL lock timeout\n"); } +static int imx95_pcie_wait_for_phy_pll_lock(struct imx_pcie *imx_pcie) +{ + u32 val; + struct device *dev = imx_pcie->pci->dev; + + if (regmap_read_poll_timeout(imx_pcie->iomuxc_gpr, + IMX95_PCIE_PHY_MPLLA_CTRL, val, + val & IMX95_PCIE_PHY_MPLL_STATE, + PHY_PLL_LOCK_WAIT_USLEEP_MAX, + PHY_PLL_LOCK_WAIT_TIMEOUT)) { + dev_err(dev, "PCIe PLL lock timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int imx_setup_phy_mpll(struct imx_pcie *imx_pcie) { unsigned long phy_rate = 0; @@ -1225,6 +1246,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp) goto err_phy_off; } + if (imx_pcie->drvdata->wait_pll_lock) { + ret = imx_pcie->drvdata->wait_pll_lock(imx_pcie); + if (ret < 0) + goto err_phy_off; + } + imx_setup_phy_mpll(imx_pcie); return 0; @@ -1826,6 +1853,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, .core_reset = imx95_pcie_core_reset, .init_phy = imx95_pcie_init_phy, + .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, }, [IMX8MQ_EP] = { .variant = IMX8MQ_EP, @@ -1880,6 +1908,7 @@ static const struct imx_pcie_drvdata drvdata[] = { .mode_mask[0] = IMX95_PCIE_DEVICE_TYPE, .init_phy = imx95_pcie_init_phy, .core_reset = imx95_pcie_core_reset, + .wait_pll_lock = imx95_pcie_wait_for_phy_pll_lock, .epc_features = &imx95_pcie_epc_features, .mode = DW_PCIE_EP_TYPE, }, From e4d66131caaf18d7c3c69914513f4be0519ddaaf Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Wed, 16 Apr 2025 16:13:14 +0800 Subject: [PATCH 066/147] PCI: imx6: Save and restore the LUT setting during suspend/resume for i.MX95 SoC The look up table (LUT) setting would be lost during the PCIe suspend on i.MX95 SoC. So to ensure proper functionality after resume, save it during suspend and restore it while resuming. Fixes: 9d6b1bd6b3c8 ("PCI: imx6: Add i.MX8MQ, i.MX8Q and i.MX95 PM support") Signed-off-by: Richard Zhu [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Frank Li Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250416081314.3929794-8-hongxing.zhu@nxp.com --- drivers/pci/controller/dwc/pci-imx6.c | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 4cff66794990..5a38cfaf989b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -139,6 +139,11 @@ struct imx_pcie_drvdata { const struct dw_pcie_host_ops *ops; }; +struct imx_lut_data { + u32 data1; + u32 data2; +}; + struct imx_pcie { struct dw_pcie *pci; struct gpio_desc *reset_gpiod; @@ -158,6 +163,8 @@ struct imx_pcie { struct regulator *vph; void __iomem *phy_base; + /* LUT data for pcie */ + struct imx_lut_data luts[IMX95_MAX_LUT]; /* power domain for pcie */ struct device *pd_pcie; /* power domain for pcie phy */ @@ -1484,6 +1491,42 @@ static void imx_pcie_msi_save_restore(struct imx_pcie *imx_pcie, bool save) } } +static void imx_pcie_lut_save(struct imx_pcie *imx_pcie) +{ + u32 data1, data2; + int i; + + for (i = 0; i < IMX95_MAX_LUT; i++) { + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, + IMX95_PEO_LUT_RWA | i); + regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, &data1); + regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, &data2); + if (data1 & IMX95_PE0_LUT_VLD) { + imx_pcie->luts[i].data1 = data1; + imx_pcie->luts[i].data2 = data2; + } else { + imx_pcie->luts[i].data1 = 0; + imx_pcie->luts[i].data2 = 0; + } + } +} + +static void imx_pcie_lut_restore(struct imx_pcie *imx_pcie) +{ + int i; + + for (i = 0; i < IMX95_MAX_LUT; i++) { + if ((imx_pcie->luts[i].data1 & IMX95_PE0_LUT_VLD) == 0) + continue; + + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA1, + imx_pcie->luts[i].data1); + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_DATA2, + imx_pcie->luts[i].data2); + regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_LUT_ACSCTRL, i); + } +} + static int imx_pcie_suspend_noirq(struct device *dev) { struct imx_pcie *imx_pcie = dev_get_drvdata(dev); @@ -1492,6 +1535,8 @@ static int imx_pcie_suspend_noirq(struct device *dev) return 0; imx_pcie_msi_save_restore(imx_pcie, true); + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) + imx_pcie_lut_save(imx_pcie); if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) { /* * The minimum for a workaround would be to set PERST# and to @@ -1536,6 +1581,8 @@ static int imx_pcie_resume_noirq(struct device *dev) if (ret) return ret; } + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) + imx_pcie_lut_restore(imx_pcie); imx_pcie_msi_save_restore(imx_pcie, false); return 0; From c2f61b8479b2abcd9e20f8bd4c46e54bb7f5286f Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 27 Apr 2025 20:53:14 +0800 Subject: [PATCH 067/147] PCI: dw-rockchip: Remove unused PCIE_CLIENT_GENERAL_DEBUG definition The PCIE_CLIENT_GENERAL_DEBUG register offset is defined but never used in the driver. It's presence adds noise to the register map. Remove this unused definition to keep the register list minimal and aligned with actual hardware usage. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250427125316.99627-2-18255117159@163.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 7790a9f33e48..e7d33d545d5b 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -47,7 +47,6 @@ #define PCIE_CLIENT_GENERAL_CONTROL 0x0 #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c -#define PCIE_CLIENT_GENERAL_DEBUG 0x104 #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 #define PCIE_CLIENT_LTSSM_STATUS 0x300 #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) From ae8ed2b091ee8bd92da365d3332eebf159de8e0f Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 27 Apr 2025 20:53:15 +0800 Subject: [PATCH 068/147] PCI: dw-rockchip: Reorganize register and bitfield definitions Register definitions were scattered with ambiguous names (e.g., PCIE_RDLH_LINK_UP_CHGED in PCIE_CLIENT_INTR_STATUS_MISC) and lacked hierarchical grouping. Group registers and their associated bitfields logically. This improves maintainability and aligns the code with hardware documentation. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250427125316.99627-3-18255117159@163.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index e7d33d545d5b..a778f4f61595 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -33,24 +33,37 @@ #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev) -#define PCIE_CLIENT_RC_MODE HIWORD_UPDATE_BIT(0x40) -#define PCIE_CLIENT_EP_MODE HIWORD_UPDATE(0xf0, 0x0) -#define PCIE_CLIENT_ENABLE_LTSSM HIWORD_UPDATE_BIT(0xc) -#define PCIE_CLIENT_DISABLE_LTSSM HIWORD_UPDATE(0x0c, 0x8) -#define PCIE_CLIENT_INTR_STATUS_MISC 0x10 -#define PCIE_CLIENT_INTR_MASK_MISC 0x24 -#define PCIE_SMLH_LINKUP BIT(16) -#define PCIE_RDLH_LINKUP BIT(17) -#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) -#define PCIE_RDLH_LINK_UP_CHGED BIT(1) -#define PCIE_LINK_REQ_RST_NOT_INT BIT(2) -#define PCIE_CLIENT_GENERAL_CONTROL 0x0 +/* General Control Register */ +#define PCIE_CLIENT_GENERAL_CON 0x0 +#define PCIE_CLIENT_RC_MODE HIWORD_UPDATE_BIT(0x40) +#define PCIE_CLIENT_EP_MODE HIWORD_UPDATE(0xf0, 0x0) +#define PCIE_CLIENT_ENABLE_LTSSM HIWORD_UPDATE_BIT(0xc) +#define PCIE_CLIENT_DISABLE_LTSSM HIWORD_UPDATE(0x0c, 0x8) + +/* Interrupt Status Register Related to Legacy Interrupt */ #define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 + +/* Interrupt Status Register Related to Miscellaneous Operation */ +#define PCIE_CLIENT_INTR_STATUS_MISC 0x10 +#define PCIE_RDLH_LINK_UP_CHGED BIT(1) +#define PCIE_LINK_REQ_RST_NOT_INT BIT(2) + +/* Interrupt Mask Register Related to Legacy Interrupt */ #define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c + +/* Interrupt Mask Register Related to Miscellaneous Operation */ +#define PCIE_CLIENT_INTR_MASK_MISC 0x24 + +/* Hot Reset Control Register */ #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 +#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) + +/* LTSSM Status Register */ #define PCIE_CLIENT_LTSSM_STATUS 0x300 -#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) -#define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) +#define PCIE_SMLH_LINKUP BIT(16) +#define PCIE_RDLH_LINKUP BIT(17) +#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) +#define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) struct rockchip_pcie { struct dw_pcie pci; @@ -161,13 +174,13 @@ static u32 rockchip_pcie_get_ltssm(struct rockchip_pcie *rockchip) static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip) { rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); } static void rockchip_pcie_disable_ltssm(struct rockchip_pcie *rockchip) { rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DISABLE_LTSSM, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); } static int rockchip_pcie_link_up(struct dw_pcie *pci) @@ -516,7 +529,7 @@ static int rockchip_pcie_configure_rc(struct platform_device *pdev, rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); pp = &rockchip->pci.pp; pp->ops = &rockchip_pcie_host_ops; @@ -562,7 +575,7 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, - PCIE_CLIENT_GENERAL_CONTROL); + PCIE_CLIENT_GENERAL_CON); rockchip->pci.ep.ops = &rockchip_pcie_ep_ops; rockchip->pci.ep.page_size = SZ_64K; From 5e5a3bf48eed8d90bc5c5b710466f24663231f0a Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 27 Apr 2025 20:53:16 +0800 Subject: [PATCH 069/147] PCI: dw-rockchip: Use rockchip_pcie_link_up() to check link up instead of open coding Some of the callers of rockchip_pcie_link_up() are open coding the rockchip_pcie_link_up() function, leading to code duplication. So switch them to use rockchip_pcie_link_up() function. Also, use the FIELD_GET() macro to simplify the link up check in rockchip_pcie_link_up(). Signed-off-by: Hans Zhang <18255117159@163.com> [mani: subject and description rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250427125316.99627-4-18255117159@163.com --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index a778f4f61595..bfc47dab32e5 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -8,6 +8,7 @@ * Author: Simon Xue */ +#include #include #include #include @@ -60,9 +61,8 @@ /* LTSSM Status Register */ #define PCIE_CLIENT_LTSSM_STATUS 0x300 -#define PCIE_SMLH_LINKUP BIT(16) -#define PCIE_RDLH_LINKUP BIT(17) -#define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) +#define PCIE_LINKUP 0x3 +#define PCIE_LINKUP_MASK GENMASK(17, 16) #define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) struct rockchip_pcie { @@ -188,10 +188,7 @@ static int rockchip_pcie_link_up(struct dw_pcie *pci) struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); u32 val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP) - return 1; - - return 0; + return FIELD_GET(PCIE_LINKUP_MASK, val) == PCIE_LINKUP; } static void rockchip_pcie_enable_l0s(struct dw_pcie *pci) @@ -450,7 +447,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg) struct dw_pcie *pci = &rockchip->pci; struct dw_pcie_rp *pp = &pci->pp; struct device *dev = pci->dev; - u32 reg, val; + u32 reg; reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); @@ -459,8 +456,7 @@ static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg) dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm(rockchip)); if (reg & PCIE_RDLH_LINK_UP_CHGED) { - val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP) { + if (rockchip_pcie_link_up(pci)) { dev_dbg(dev, "Received Link up event. Starting enumeration!\n"); /* Rescan the bus to enumerate endpoint devices */ pci_lock_rescan_remove(); @@ -477,7 +473,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) struct rockchip_pcie *rockchip = arg; struct dw_pcie *pci = &rockchip->pci; struct device *dev = pci->dev; - u32 reg, val; + u32 reg; reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); @@ -491,8 +487,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) } if (reg & PCIE_RDLH_LINK_UP_CHGED) { - val = rockchip_pcie_get_ltssm(rockchip); - if ((val & PCIE_LINKUP) == PCIE_LINKUP) { + if (rockchip_pcie_link_up(pci)) { dev_dbg(dev, "link up\n"); dw_pcie_ep_linkup(&pci->ep); } From 5e2664f9e108f66046869ed4990043421919465f Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Mon, 14 Apr 2025 15:42:41 +0800 Subject: [PATCH 070/147] PCI: ls-gen4: Use to_delayed_work() Use to_delayed_work() instead of open-coding it. Signed-off-by: Chen Ni Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250414074241.3954081-1-nichen@iscas.ac.cn --- drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index 5af22bee913b..09dff6bf824f 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -174,8 +174,7 @@ static int ls_g4_pcie_interrupt_init(struct mobiveil_pcie *mv_pci) static void ls_g4_pcie_reset(struct work_struct *work) { - struct delayed_work *dwork = container_of(work, struct delayed_work, - work); + struct delayed_work *dwork = to_delayed_work(work); struct ls_g4_pcie *pcie = container_of(dwork, struct ls_g4_pcie, dwork); struct mobiveil_pcie *mv_pci = &pcie->pci; u16 ctrl; From 286ed198b899739862456f451eda884558526a9d Mon Sep 17 00:00:00 2001 From: Diederik de Haas Date: Thu, 17 Apr 2025 16:21:18 +0200 Subject: [PATCH 071/147] PCI: dw-rockchip: Fix PHY function call sequence in rockchip_pcie_phy_deinit() The documentation for the phy_power_off() function explicitly says that it must be called before phy_exit(). Hence, follow the same rule in rockchip_pcie_phy_deinit(). Fixes: 0e898eb8df4e ("PCI: rockchip-dwc: Add Rockchip RK356X host controller driver") Signed-off-by: Diederik de Haas [mani: commit message change] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Reviewed-by: Dragan Simic Acked-by: Shawn Lin Cc: stable@vger.kernel.org # v5.15+ Link: https://patch.msgid.link/20250417142138.1377451-1-didi.debian@cknow.org --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index bfc47dab32e5..3c6ab71c996e 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -431,8 +431,8 @@ static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip) static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip) { - phy_exit(rockchip->phy); phy_power_off(rockchip->phy); + phy_exit(rockchip->phy); } static const struct dw_pcie_ops dw_pcie_ops = { From af3c6eacce0c464f28fe0e3d365b3860aba07931 Mon Sep 17 00:00:00 2001 From: Wenbin Yao Date: Tue, 22 Apr 2025 18:36:23 +0800 Subject: [PATCH 072/147] PCI: dwc: Make link training more robust by setting PORT_LOGIC_LINK_WIDTH to one lane As per DWC PCIe registers description 4.30a, section 1.13.43, NUM_OF_LANES named as PORT_LOGIC_LINK_WIDTH in PCIe DWC driver, is referred to as the "Predetermined Number of Lanes" in PCIe r6.0, sec 4.2.7.2.1, which explains the conditions required to enter Polling.Configuration: Next state is Polling.Configuration after at least 1024 TS1 Ordered Sets were transmitted, and all Lanes that detected a Receiver during Detect receive eight consecutive training sequences ... Otherwise, after a 24 ms timeout the next state is: Polling.Configuration if, (i) Any Lane, which detected a Receiver during Detect, received eight consecutive training sequences ... and a minimum of 1024 TS1 Ordered Sets are transmitted after receiving one TS1 or TS2 Ordered Set. And (ii) At least a predetermined set of Lanes that detected a Receiver during Detect have detected an exit from Electrical Idle at least once since entering Polling.Active. Note: This may prevent one or more bad Receivers or Transmitters from holding up a valid Link from being configured, and allow for additional training in Polling.Configuration. The exact set of predetermined Lanes is implementation specific. Note: Any Lane that receives eight consecutive TS1 or TS2 Ordered Sets should have detected an exit from Electrical Idle at least once since entering Polling.Active. In a PCIe link supporting multiple lanes, if PORT_LOGIC_LINK_WIDTH is set to lane width the hardware supports, all lanes that detect a receiver during the Detect phase must receive eight consecutive training sequences. Otherwise, LTSSM will not enter Polling.Configuration and link training will fail. Therefore, always set PORT_LOGIC_LINK_WIDTH to 1, regardless of the number of lanes the port actually supports, to make link up more robust. This setting will not affect the intended link width if all lanes are functional. Additionally, the link can still be established with at least one lane if other lanes are faulty. Co-developed-by: Qiang Yu Signed-off-by: Qiang Yu Signed-off-by: Wenbin Yao [mani: subject change] Signed-off-by: Manivannan Sadhasivam [bhelgaas: update PCIe spec citation, format quote] Signed-off-by: Bjorn Helgaas Tested-by: Niklas Cassel Link: https://patch.msgid.link/20250422103623.462277-1-quic_wenbyao@quicinc.com --- drivers/pci/controller/dwc/pcie-designware.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..be348b341e3c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -797,22 +797,19 @@ static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes) /* Set link width speed control register */ lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL); lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK; + lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES; switch (num_lanes) { case 1: plc |= PORT_LINK_MODE_1_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES; break; case 2: plc |= PORT_LINK_MODE_2_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES; break; case 4: plc |= PORT_LINK_MODE_4_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES; break; case 8: plc |= PORT_LINK_MODE_8_LANES; - lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES; break; default: dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes); From ed798ff1c52f6fe232ce2e24e68fb63f5470ab97 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Mon, 7 Apr 2025 20:43:31 +0800 Subject: [PATCH 073/147] PCI: tegra194: Create debugfs directory only when CONFIG_PCIEASPM is enabled Previously, the debugfs directory was unconditionally created in tegra_pcie_config_rp() regardless of the CONFIG_PCIEASPM setting. This led to unnecessary directory creation when ASPM support was disabled since only ASPM state count was exposed through debugfs. Hence, move the debugfs directory creation into init_debugfs() which is conditionally compiled based on CONFIG_PCIEASPM. This ensures that both the directory and 'aspm_state_cnt' entry are only created when ASPM is enabled and avoids cluttering debugfs with empty directories when ASPM is disabled. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: subject and description change] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Christophe JAILLET Link: https://patch.msgid.link/20250407124331.69459-1-18255117159@163.com --- drivers/pci/controller/dwc/pcie-tegra194.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 5103995cd6c7..bc419688527a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -713,7 +713,16 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie) static void init_debugfs(struct tegra_pcie_dw *pcie) { - debugfs_create_devm_seqfile(pcie->dev, "aspm_state_cnt", pcie->debugfs, + struct device *dev = pcie->dev; + char *name; + + name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node); + if (!name) + return; + + pcie->debugfs = debugfs_create_dir(name, NULL); + + debugfs_create_devm_seqfile(dev, "aspm_state_cnt", pcie->debugfs, aspm_state_cnt); } #else @@ -1634,7 +1643,6 @@ static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie) static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) { struct device *dev = pcie->dev; - char *name; int ret; pm_runtime_enable(dev); @@ -1664,13 +1672,6 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) goto fail_host_init; } - name = devm_kasprintf(dev, GFP_KERNEL, "%pOFP", dev->of_node); - if (!name) { - ret = -ENOMEM; - goto fail_host_init; - } - - pcie->debugfs = debugfs_create_dir(name, NULL); init_debugfs(pcie); return ret; From f3efb9569b4a21354ef2caf7ab0608a3e14cc6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 5 May 2025 14:54:12 +0300 Subject: [PATCH 074/147] PCI: Fix lock symmetry in pci_slot_unlock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit a4e772898f8b ("PCI: Add missing bridge lock to pci_bus_lock()") made the lock function to call depend on dev->subordinate but left pci_slot_unlock() unmodified creating locking asymmetry compared with pci_slot_lock(). Because of the asymmetric lock handling, the same bridge device is unlocked twice. First pci_bus_unlock() unlocks bus->self and then pci_slot_unlock() will unconditionally unlock the same bridge device. Move pci_dev_unlock() inside an else branch to match the logic in pci_slot_lock(). Fixes: a4e772898f8b ("PCI: Add missing bridge lock to pci_bus_lock()") Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Reviewed-by: Dave Jiang Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250505115412.37628-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d7c9f64ea24..26507aa906d7 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5542,7 +5542,8 @@ static void pci_slot_unlock(struct pci_slot *slot) continue; if (dev->subordinate) pci_bus_unlock(dev->subordinate); - pci_dev_unlock(dev); + else + pci_dev_unlock(dev); } } From 4d4c10f763d7808fbade28d83d237411603bca05 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 23 Apr 2025 23:31:32 -0500 Subject: [PATCH 075/147] PCI: Explicitly put devices into D0 when initializing AMD BIOS team has root caused an issue that NVMe storage failed to come back from suspend to a lack of a call to _REG when NVMe device was probed. 112a7f9c8edbf ("PCI/ACPI: Call _REG when transitioning D-states") added support for calling _REG when transitioning D-states, but this only works if the device actually "transitions" D-states. 967577b062417 ("PCI/PM: Keep runtime PM enabled for unbound PCI devices") added support for runtime PM on PCI devices, but never actually 'explicitly' sets the device to D0. To make sure that devices are in D0 and that platform methods such as _REG are called, explicitly set all devices into D0 during initialization. Fixes: 967577b062417 ("PCI/PM: Keep runtime PM enabled for unbound PCI devices") Signed-off-by: Mario Limonciello Signed-off-by: Bjorn Helgaas Tested-by: Denis Benato Tested-By: Yijun Shen Tested-By: David Perry Reviewed-by: Rafael J. Wysocki Link: https://patch.msgid.link/20250424043232.1848107-1-superm1@kernel.org --- drivers/pci/pci-driver.c | 6 ------ drivers/pci/pci.c | 13 ++++++++++--- drivers/pci/pci.h | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index c8bd71a739f7..082918ce03d8 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -555,12 +555,6 @@ static void pci_pm_default_resume(struct pci_dev *pci_dev) pci_enable_wake(pci_dev, PCI_D0, false); } -static void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev) -{ - pci_power_up(pci_dev); - pci_update_current_state(pci_dev, PCI_D0); -} - static void pci_pm_default_resume_early(struct pci_dev *pci_dev) { pci_pm_power_up_and_verify_state(pci_dev); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d7c9f64ea24..cd51c6454d1b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3192,6 +3192,12 @@ void pci_d3cold_disable(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_d3cold_disable); +void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev) +{ + pci_power_up(pci_dev); + pci_update_current_state(pci_dev, PCI_D0); +} + /** * pci_pm_init - Initialize PM functions of given PCI device * @dev: PCI device to handle. @@ -3202,9 +3208,6 @@ void pci_pm_init(struct pci_dev *dev) u16 status; u16 pmc; - pm_runtime_forbid(&dev->dev); - pm_runtime_set_active(&dev->dev); - pm_runtime_enable(&dev->dev); device_enable_async_suspend(&dev->dev); dev->wakeup_prepared = false; @@ -3266,6 +3269,10 @@ void pci_pm_init(struct pci_dev *dev) pci_read_config_word(dev, PCI_STATUS, &status); if (status & PCI_STATUS_IMM_READY) dev->imm_ready = 1; + pci_pm_power_up_and_verify_state(dev); + pm_runtime_forbid(&dev->dev); + pm_runtime_set_active(&dev->dev); + pm_runtime_enable(&dev->dev); } static unsigned long pci_ea_flags(struct pci_dev *dev, u8 prop) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..49165b739138 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -148,6 +148,7 @@ void pci_dev_adjust_pme(struct pci_dev *dev); void pci_dev_complete_resume(struct pci_dev *pci_dev); void pci_config_pm_runtime_get(struct pci_dev *dev); void pci_config_pm_runtime_put(struct pci_dev *dev); +void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev); void pci_pm_init(struct pci_dev *dev); void pci_ea_init(struct pci_dev *dev); void pci_msi_init(struct pci_dev *dev); From 2612378d442aad23448053c47f34eb17f6209e67 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Mon, 28 Apr 2025 20:42:30 +0800 Subject: [PATCH 076/147] PCI: dwc: ep: Use FIELD_GET() where applicable Use FIELD_GET() to simplify the code extracting the register values. No functional change intended. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: commit message fixup] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250428124230.112648-1-18255117159@163.com --- drivers/pci/controller/dwc/pcie-designware-ep.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1a0bf9341542..f3daf46b5e63 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -256,11 +256,11 @@ static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie *pci, return offset; reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> PCI_REBAR_CTRL_NBAR_SHIFT; + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) { reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - bar_index = reg & PCI_REBAR_CTRL_BAR_IDX; + bar_index = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, reg); if (bar_index == bar) return offset; } @@ -875,8 +875,7 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) if (offset) { reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> - PCI_REBAR_CTRL_NBAR_SHIFT; + nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, reg); /* * PCIe r6.0, sec 7.8.6.2 require us to support at least one @@ -897,7 +896,7 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) * is why RESBAR_CAP_REG is written here. */ val = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); - bar = val & PCI_REBAR_CTRL_BAR_IDX; + bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val); if (ep->epf_bar[bar]) pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val); else From 9a5f8c7a81cde01738d4fa25624669a3d6f859e3 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 5 May 2025 17:01:37 -0500 Subject: [PATCH 077/147] dt-bindings: PCI: Convert v3,v360epc-pci to DT schema Convert the v3,v360epc-pci binding to DT schema format. Add "clocks" which was not documented and is required. Drop "syscon" which was documented, but is not used. Drop the "v3,v360epc-pci" compatible by itself as this device is only used on the Arm Integrator/AP and not likely going to be used anywhere else at this point. Signed-off-by: Rob Herring (Arm) Signed-off-by: Manivannan Sadhasivam Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20250505220139.2202164-1-robh@kernel.org --- .../bindings/pci/v3,v360epc-pci.yaml | 100 ++++++++++++++++++ .../bindings/pci/v3-v360epc-pci.txt | 76 ------------- MAINTAINERS | 2 +- 3 files changed, 101 insertions(+), 77 deletions(-) create mode 100644 Documentation/devicetree/bindings/pci/v3,v360epc-pci.yaml delete mode 100644 Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt diff --git a/Documentation/devicetree/bindings/pci/v3,v360epc-pci.yaml b/Documentation/devicetree/bindings/pci/v3,v360epc-pci.yaml new file mode 100644 index 000000000000..38cac88f17bf --- /dev/null +++ b/Documentation/devicetree/bindings/pci/v3,v360epc-pci.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/v3,v360epc-pci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: V3 Semiconductor V360 EPC PCI bridge + +maintainers: + - Linus Walleij + +description: + This bridge is found in the ARM Integrator/AP (Application Platform) + +allOf: + - $ref: /schemas/pci/pci-host-bridge.yaml# + +properties: + compatible: + items: + - const: arm,integrator-ap-pci + - const: v3,v360epc-pci + + reg: + items: + - description: V3 host bridge controller + - description: Configuration space + + clocks: + maxItems: 1 + + dma-ranges: + maxItems: 2 + description: + The inbound ranges must be aligned to a 1MB boundary, and may be 1MB, 2MB, + 4MB, 8MB, 16MB, 32MB, 64MB, 128MB, 256MB, 512MB, 1GB or 2GB in size. The + memory should be marked as pre-fetchable. + + interrupts: + description: Bus Error IRQ + maxItems: 1 + + ranges: + description: + The non-prefetchable and prefetchable memory windows must each be exactly + 256MB (0x10000000) in size. The prefetchable memory window must be + immediately adjacent to the non-prefetchable memory window. + +required: + - compatible + - reg + - clocks + - dma-ranges + - "#interrupt-cells" + - interrupt-map + - interrupt-map-mask + +unevaluatedProperties: false + +examples: + - | + pci@62000000 { + compatible = "arm,integrator-ap-pci", "v3,v360epc-pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0x62000000 0x10000>, <0x61000000 0x01000000>; + device_type = "pci"; + interrupt-parent = <&pic>; + interrupts = <17>; /* Bus error IRQ */ + clocks = <&pciclk>; + ranges = <0x01000000 0 0x00000000 0x60000000 0 0x01000000>, /* 16 MiB @ LB 60000000 */ + <0x02000000 0 0x40000000 0x40000000 0 0x10000000>, /* 256 MiB @ LB 40000000 1:1 */ + <0x42000000 0 0x50000000 0x50000000 0 0x10000000>; /* 256 MiB @ LB 50000000 1:1 */ + dma-ranges = <0x02000000 0 0x20000000 0x20000000 0 0x20000000>, /* EBI: 512 MB @ LB 20000000 1:1 */ + <0x02000000 0 0x80000000 0x80000000 0 0x40000000>; /* CM alias: 1GB @ LB 80000000 */ + interrupt-map-mask = <0xf800 0 0 0x7>; + interrupt-map = + /* IDSEL 9 */ + <0x4800 0 0 1 &pic 13>, /* INT A on slot 9 is irq 13 */ + <0x4800 0 0 2 &pic 14>, /* INT B on slot 9 is irq 14 */ + <0x4800 0 0 3 &pic 15>, /* INT C on slot 9 is irq 15 */ + <0x4800 0 0 4 &pic 16>, /* INT D on slot 9 is irq 16 */ + /* IDSEL 10 */ + <0x5000 0 0 1 &pic 14>, /* INT A on slot 10 is irq 14 */ + <0x5000 0 0 2 &pic 15>, /* INT B on slot 10 is irq 15 */ + <0x5000 0 0 3 &pic 16>, /* INT C on slot 10 is irq 16 */ + <0x5000 0 0 4 &pic 13>, /* INT D on slot 10 is irq 13 */ + /* IDSEL 11 */ + <0x5800 0 0 1 &pic 15>, /* INT A on slot 11 is irq 15 */ + <0x5800 0 0 2 &pic 16>, /* INT B on slot 11 is irq 16 */ + <0x5800 0 0 3 &pic 13>, /* INT C on slot 11 is irq 13 */ + <0x5800 0 0 4 &pic 14>, /* INT D on slot 11 is irq 14 */ + /* IDSEL 12 */ + <0x6000 0 0 1 &pic 16>, /* INT A on slot 12 is irq 16 */ + <0x6000 0 0 2 &pic 13>, /* INT B on slot 12 is irq 13 */ + <0x6000 0 0 3 &pic 14>, /* INT C on slot 12 is irq 14 */ + <0x6000 0 0 4 &pic 15>; /* INT D on slot 12 is irq 15 */ + }; +... diff --git a/Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt b/Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt deleted file mode 100644 index 11063293f761..000000000000 --- a/Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt +++ /dev/null @@ -1,76 +0,0 @@ -V3 Semiconductor V360 EPC PCI bridge - -This bridge is found in the ARM Integrator/AP (Application Platform) - -Required properties: -- compatible: should be one of: - "v3,v360epc-pci" - "arm,integrator-ap-pci", "v3,v360epc-pci" -- reg: should contain two register areas: - first the base address of the V3 host bridge controller, 64KB - second the configuration area register space, 16MB -- interrupts: should contain a reference to the V3 error interrupt - as routed on the system. -- bus-range: see pci.txt -- ranges: this follows the standard PCI bindings in the IEEE Std - 1275-1994 (see pci.txt) with the following restriction: - - The non-prefetchable and prefetchable memory windows must - each be exactly 256MB (0x10000000) in size. - - The prefetchable memory window must be immediately adjacent - to the non-prefetcable memory window -- dma-ranges: three ranges for the inbound memory region. The ranges must - be aligned to a 1MB boundary, and may be 1MB, 2MB, 4MB, 8MB, 16MB, 32MB, - 64MB, 128MB, 256MB, 512MB, 1GB or 2GB in size. The memory should be marked - as pre-fetchable. Two ranges are supported by the hardware. - -Integrator-specific required properties: -- syscon: should contain a link to the syscon device node, since - on the Integrator, some registers in the syscon are required to - operate the V3 host bridge. - -Example: - -pci: pciv3@62000000 { - compatible = "arm,integrator-ap-pci", "v3,v360epc-pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - reg = <0x62000000 0x10000>, <0x61000000 0x01000000>; - interrupt-parent = <&pic>; - interrupts = <17>; /* Bus error IRQ */ - clocks = <&pciclk>; - bus-range = <0x00 0xff>; - ranges = 0x01000000 0 0x00000000 /* I/O space @00000000 */ - 0x60000000 0 0x01000000 /* 16 MiB @ LB 60000000 */ - 0x02000000 0 0x40000000 /* non-prefectable memory @40000000 */ - 0x40000000 0 0x10000000 /* 256 MiB @ LB 40000000 1:1 */ - 0x42000000 0 0x50000000 /* prefetchable memory @50000000 */ - 0x50000000 0 0x10000000>; /* 256 MiB @ LB 50000000 1:1 */ - dma-ranges = <0x02000000 0 0x20000000 /* EBI memory space */ - 0x20000000 0 0x20000000 /* 512 MB @ LB 20000000 1:1 */ - 0x02000000 0 0x80000000 /* Core module alias memory */ - 0x80000000 0 0x40000000>; /* 1GB @ LB 80000000 */ - interrupt-map-mask = <0xf800 0 0 0x7>; - interrupt-map = < - /* IDSEL 9 */ - 0x4800 0 0 1 &pic 13 /* INT A on slot 9 is irq 13 */ - 0x4800 0 0 2 &pic 14 /* INT B on slot 9 is irq 14 */ - 0x4800 0 0 3 &pic 15 /* INT C on slot 9 is irq 15 */ - 0x4800 0 0 4 &pic 16 /* INT D on slot 9 is irq 16 */ - /* IDSEL 10 */ - 0x5000 0 0 1 &pic 14 /* INT A on slot 10 is irq 14 */ - 0x5000 0 0 2 &pic 15 /* INT B on slot 10 is irq 15 */ - 0x5000 0 0 3 &pic 16 /* INT C on slot 10 is irq 16 */ - 0x5000 0 0 4 &pic 13 /* INT D on slot 10 is irq 13 */ - /* IDSEL 11 */ - 0x5800 0 0 1 &pic 15 /* INT A on slot 11 is irq 15 */ - 0x5800 0 0 2 &pic 16 /* INT B on slot 11 is irq 16 */ - 0x5800 0 0 3 &pic 13 /* INT C on slot 11 is irq 13 */ - 0x5800 0 0 4 &pic 14 /* INT D on slot 11 is irq 14 */ - /* IDSEL 12 */ - 0x6000 0 0 1 &pic 16 /* INT A on slot 12 is irq 16 */ - 0x6000 0 0 2 &pic 13 /* INT B on slot 12 is irq 13 */ - 0x6000 0 0 3 &pic 14 /* INT C on slot 12 is irq 14 */ - 0x6000 0 0 4 &pic 15 /* INT D on slot 12 is irq 15 */ - >; -}; diff --git a/MAINTAINERS b/MAINTAINERS index 9764b87ea304..c4d000317b84 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18568,7 +18568,7 @@ PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC M: Linus Walleij L: linux-pci@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/pci/v3-v360epc-pci.txt +F: Documentation/devicetree/bindings/pci/v3,v360epc-pci.yaml F: drivers/pci/controller/pci-v3-semi.c PCI DRIVER FOR XILINX VERSAL CPM From f46bfb1d3c6a601caad90eb3c11a1e1e17cccb1a Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 11 May 2025 00:07:08 +0800 Subject: [PATCH 078/147] PCI: dwc: Return bool from link up check PCIe link status check is supposed to return a boolean to indicate whether the link is up or not. So, modify the link_up callbacks and dw_pcie_link_up() function to return bool instead of int. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: commit message reword] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250510160710.392122-2-18255117159@163.com --- drivers/pci/controller/dwc/pci-dra7xx.c | 4 ++-- drivers/pci/controller/dwc/pci-exynos.c | 4 ++-- drivers/pci/controller/dwc/pci-keystone.c | 5 ++--- drivers/pci/controller/dwc/pci-meson.c | 6 +++--- drivers/pci/controller/dwc/pcie-armada8k.c | 6 +++--- drivers/pci/controller/dwc/pcie-designware.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 4 ++-- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 2 +- drivers/pci/controller/dwc/pcie-histb.c | 9 +++------ drivers/pci/controller/dwc/pcie-keembay.c | 2 +- drivers/pci/controller/dwc/pcie-kirin.c | 7 ++----- drivers/pci/controller/dwc/pcie-qcom-ep.c | 2 +- drivers/pci/controller/dwc/pcie-qcom.c | 4 ++-- drivers/pci/controller/dwc/pcie-rcar-gen4.c | 2 +- drivers/pci/controller/dwc/pcie-spear13xx.c | 7 ++----- drivers/pci/controller/dwc/pcie-tegra194.c | 4 ++-- drivers/pci/controller/dwc/pcie-uniphier.c | 2 +- drivers/pci/controller/dwc/pcie-visconti.c | 4 ++-- 18 files changed, 33 insertions(+), 43 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c index 33d6bf460ffe..58f7d04ff37f 100644 --- a/drivers/pci/controller/dwc/pci-dra7xx.c +++ b/drivers/pci/controller/dwc/pci-dra7xx.c @@ -118,12 +118,12 @@ static u64 dra7xx_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 cpu_addr) return cpu_addr & DRA7XX_CPU_TO_BUS_ADDR; } -static int dra7xx_pcie_link_up(struct dw_pcie *pci) +static bool dra7xx_pcie_link_up(struct dw_pcie *pci) { struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci); u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); - return !!(reg & LINK_UP); + return reg & LINK_UP; } static void dra7xx_pcie_stop_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index ace736b025b1..1f0e98d07109 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -209,12 +209,12 @@ static struct pci_ops exynos_pci_ops = { .write = exynos_pcie_wr_own_conf, }; -static int exynos_pcie_link_up(struct dw_pcie *pci) +static bool exynos_pcie_link_up(struct dw_pcie *pci) { struct exynos_pcie *ep = to_exynos_pcie(pci); u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP); - return (val & PCIE_ELBI_XMLH_LINKUP); + return val & PCIE_ELBI_XMLH_LINKUP; } static int exynos_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 76a37368ae4f..968464530e3d 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -492,13 +492,12 @@ static struct pci_ops ks_pcie_ops = { * @pci: A pointer to the dw_pcie structure which holds the DesignWare PCIe host * controller driver information. */ -static int ks_pcie_link_up(struct dw_pcie *pci) +static bool ks_pcie_link_up(struct dw_pcie *pci) { u32 val; val = dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); - val &= PORT_LOGIC_LTSSM_STATE_MASK; - return (val == PORT_LOGIC_LTSSM_STATE_L0); + return (val & PORT_LOGIC_LTSSM_STATE_MASK) == PORT_LOGIC_LTSSM_STATE_L0; } static void ks_pcie_stop_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index db9482a113e9..787469d1b396 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -335,7 +335,7 @@ static struct pci_ops meson_pci_ops = { .write = pci_generic_config_write, }; -static int meson_pcie_link_up(struct dw_pcie *pci) +static bool meson_pcie_link_up(struct dw_pcie *pci) { struct meson_pcie *mp = to_meson_pcie(pci); struct device *dev = pci->dev; @@ -363,7 +363,7 @@ static int meson_pcie_link_up(struct dw_pcie *pci) dev_dbg(dev, "speed_okay\n"); if (smlh_up && rdlh_up && ltssm_up && speed_okay) - return 1; + return true; cnt++; @@ -371,7 +371,7 @@ static int meson_pcie_link_up(struct dw_pcie *pci) } while (cnt < WAIT_LINKUP_TIMEOUT); dev_err(dev, "error: wait linkup timeout\n"); - return 0; + return false; } static int meson_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c index b5c599ccaacf..c2650fd0d458 100644 --- a/drivers/pci/controller/dwc/pcie-armada8k.c +++ b/drivers/pci/controller/dwc/pcie-armada8k.c @@ -139,7 +139,7 @@ static int armada8k_pcie_setup_phys(struct armada8k_pcie *pcie) return ret; } -static int armada8k_pcie_link_up(struct dw_pcie *pci) +static bool armada8k_pcie_link_up(struct dw_pcie *pci) { u32 reg; u32 mask = PCIE_GLB_STS_RDLH_LINK_UP | PCIE_GLB_STS_PHY_LINK_UP; @@ -147,10 +147,10 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci) reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_STATUS_REG); if ((reg & mask) == mask) - return 1; + return true; dev_dbg(pci->dev, "No link detected (Global-Status: 0x%08x).\n", reg); - return 0; + return false; } static int armada8k_pcie_start_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..b3615d125942 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -711,7 +711,7 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci) } EXPORT_SYMBOL_GPL(dw_pcie_wait_for_link); -int dw_pcie_link_up(struct dw_pcie *pci) +bool dw_pcie_link_up(struct dw_pcie *pci) { u32 val; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 56aafdbcdaca..4dd16aa4b39e 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -462,7 +462,7 @@ struct dw_pcie_ops { size_t size, u32 val); void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg, size_t size, u32 val); - int (*link_up)(struct dw_pcie *pcie); + bool (*link_up)(struct dw_pcie *pcie); enum dw_pcie_ltssm (*get_ltssm)(struct dw_pcie *pcie); int (*start_link)(struct dw_pcie *pcie); void (*stop_link)(struct dw_pcie *pcie); @@ -537,7 +537,7 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val); u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size); void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val); void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); -int dw_pcie_link_up(struct dw_pcie *pci); +bool dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 3c6ab71c996e..ae171a545df6 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -183,7 +183,7 @@ static void rockchip_pcie_disable_ltssm(struct rockchip_pcie *rockchip) PCIE_CLIENT_GENERAL_CON); } -static int rockchip_pcie_link_up(struct dw_pcie *pci) +static bool rockchip_pcie_link_up(struct dw_pcie *pci) { struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); u32 val = rockchip_pcie_get_ltssm(rockchip); diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 1f2f4c28a949..a52071589377 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -151,7 +151,7 @@ static struct pci_ops histb_pci_ops = { .write = histb_pcie_wr_own_conf, }; -static int histb_pcie_link_up(struct dw_pcie *pci) +static bool histb_pcie_link_up(struct dw_pcie *pci) { struct histb_pcie *hipcie = to_histb_pcie(pci); u32 regval; @@ -160,11 +160,8 @@ static int histb_pcie_link_up(struct dw_pcie *pci) regval = histb_pcie_readl(hipcie, PCIE_SYS_STAT0); status = histb_pcie_readl(hipcie, PCIE_SYS_STAT4); status &= PCIE_LTSSM_STATE_MASK; - if ((regval & PCIE_XMLH_LINK_UP) && (regval & PCIE_RDLH_LINK_UP) && - (status == PCIE_LTSSM_STATE_ACTIVE)) - return 1; - - return 0; + return ((regval & PCIE_XMLH_LINK_UP) && (regval & PCIE_RDLH_LINK_UP) && + (status == PCIE_LTSSM_STATE_ACTIVE)); } static int histb_pcie_start_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index 278205db60a2..67dd3337b447 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -101,7 +101,7 @@ static void keembay_pcie_ltssm_set(struct keembay_pcie *pcie, bool enable) writel(val, pcie->apb_base + PCIE_REGS_PCIE_APP_CNTRL); } -static int keembay_pcie_link_up(struct dw_pcie *pci) +static bool keembay_pcie_link_up(struct dw_pcie *pci) { struct keembay_pcie *pcie = dev_get_drvdata(pci->dev); u32 val; diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d0e6a3811b00..91559c8b1866 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -586,16 +586,13 @@ static void kirin_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false); } -static int kirin_pcie_link_up(struct dw_pcie *pci) +static bool kirin_pcie_link_up(struct dw_pcie *pci) { struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci); u32 val; regmap_read(kirin_pcie->apb, PCIE_APB_PHY_STATUS0, &val); - if ((val & PCIE_LINKUP_ENABLE) == PCIE_LINKUP_ENABLE) - return 1; - - return 0; + return (val & PCIE_LINKUP_ENABLE) == PCIE_LINKUP_ENABLE; } static int kirin_pcie_start_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 46b1c6d19974..b3f7f42fa852 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -261,7 +261,7 @@ static void qcom_pcie_ep_configure_tcsr(struct qcom_pcie_ep *pcie_ep) } } -static int qcom_pcie_dw_link_up(struct dw_pcie *pci) +static bool qcom_pcie_dw_link_up(struct dw_pcie *pci) { struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); u32 reg; diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index dc98ae63362d..ba0dd1717a58 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1221,12 +1221,12 @@ static int qcom_pcie_post_init_2_9_0(struct qcom_pcie *pcie) return 0; } -static int qcom_pcie_link_up(struct dw_pcie *pci) +static bool qcom_pcie_link_up(struct dw_pcie *pci) { u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA); - return !!(val & PCI_EXP_LNKSTA_DLLLA); + return val & PCI_EXP_LNKSTA_DLLLA; } static int qcom_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index fc872dd35029..ccb94f4a215f 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -87,7 +87,7 @@ struct rcar_gen4_pcie { #define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw) /* Common */ -static int rcar_gen4_pcie_link_up(struct dw_pcie *dw) +static bool rcar_gen4_pcie_link_up(struct dw_pcie *dw) { struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw); u32 val, mask; diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c index ff986ced56b2..01794a9d3ad2 100644 --- a/drivers/pci/controller/dwc/pcie-spear13xx.c +++ b/drivers/pci/controller/dwc/pcie-spear13xx.c @@ -110,15 +110,12 @@ static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pc MSI_CTRL_INT, &app_reg->int_mask); } -static int spear13xx_pcie_link_up(struct dw_pcie *pci) +static bool spear13xx_pcie_link_up(struct dw_pcie *pci) { struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci); struct pcie_app_reg __iomem *app_reg = spear13xx_pcie->app_base; - if (readl(&app_reg->app_status_1) & XMLH_LINK_UP) - return 1; - - return 0; + return readl(&app_reg->app_status_1) & XMLH_LINK_UP; } static int spear13xx_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index 5103995cd6c7..55c47318e65a 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1027,12 +1027,12 @@ retry_link: return 0; } -static int tegra_pcie_dw_link_up(struct dw_pcie *pci) +static bool tegra_pcie_dw_link_up(struct dw_pcie *pci) { struct tegra_pcie_dw *pcie = to_tegra_pcie(pci); u32 val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA); - return !!(val & PCI_EXP_LNKSTA_DLLLA); + return val & PCI_EXP_LNKSTA_DLLLA; } static void tegra_pcie_dw_stop_link(struct dw_pcie *pci) diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c index 5757ca3803c9..9d05b3a0579e 100644 --- a/drivers/pci/controller/dwc/pcie-uniphier.c +++ b/drivers/pci/controller/dwc/pcie-uniphier.c @@ -135,7 +135,7 @@ static int uniphier_pcie_wait_rc(struct uniphier_pcie *pcie) return 0; } -static int uniphier_pcie_link_up(struct dw_pcie *pci) +static bool uniphier_pcie_link_up(struct dw_pcie *pci) { struct uniphier_pcie *pcie = to_uniphier_pcie(pci); u32 val, mask; diff --git a/drivers/pci/controller/dwc/pcie-visconti.c b/drivers/pci/controller/dwc/pcie-visconti.c index 318c278e65c8..cdeac6177143 100644 --- a/drivers/pci/controller/dwc/pcie-visconti.c +++ b/drivers/pci/controller/dwc/pcie-visconti.c @@ -121,13 +121,13 @@ static u32 visconti_mpu_readl(struct visconti_pcie *pcie, u32 reg) return readl_relaxed(pcie->mpu_base + reg); } -static int visconti_pcie_link_up(struct dw_pcie *pci) +static bool visconti_pcie_link_up(struct dw_pcie *pci) { struct visconti_pcie *pcie = dev_get_drvdata(pci->dev); void __iomem *addr = pcie->ulreg_base; u32 val = readl_relaxed(addr + PCIE_UL_REG_V_PHY_ST_02); - return !!(val & PCIE_UL_S_L0); + return val & PCIE_UL_S_L0; } static int visconti_pcie_start_link(struct dw_pcie *pci) From 0a9d6a3d0fd1650b9ee00bc8150828e19cadaf23 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 11 May 2025 00:07:09 +0800 Subject: [PATCH 079/147] PCI: mobiveil: Return bool from link up check PCIe link status check is supposed to return a boolean to indicate whether the link is up or not. So update ls_g4_pcie_link_up() to return bool and also simplify the LTSSM state check. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: commit message rewording] Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250510160710.392122-3-18255117159@163.com --- drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 9 ++------- drivers/pci/controller/mobiveil/pcie-mobiveil.h | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index 5af22bee913b..1cf014051296 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -53,18 +53,13 @@ static inline void ls_g4_pcie_pf_writel(struct ls_g4_pcie *pcie, iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off); } -static int ls_g4_pcie_link_up(struct mobiveil_pcie *pci) +static bool ls_g4_pcie_link_up(struct mobiveil_pcie *pci) { struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); u32 state; state = ls_g4_pcie_pf_readl(pcie, PCIE_PF_DBG); - state = state & PF_DBG_LTSSM_MASK; - - if (state == PF_DBG_LTSSM_L0) - return 1; - - return 0; + return (state & PF_DBG_LTSSM_MASK) == PF_DBG_LTSSM_L0; } static void ls_g4_pcie_disable_interrupt(struct ls_g4_pcie *pcie) diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h index e63abb887ee3..662f17f9bf65 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h @@ -160,7 +160,7 @@ struct mobiveil_root_port { }; struct mobiveil_pab_ops { - int (*link_up)(struct mobiveil_pcie *pcie); + bool (*link_up)(struct mobiveil_pcie *pcie); }; struct mobiveil_pcie { From 1a176b25f5d6f00c6c44729c006379b9a6dbc703 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Sun, 11 May 2025 00:07:10 +0800 Subject: [PATCH 080/147] PCI: cadence: Simplify J721e link status check Replace explicit if-else condition with direct return statement in j721e_pcie_link_up(). This reduces code verbosity while maintaining the same logic for detecting PCIe link completion. Signed-off-by: Hans Zhang <18255117159@163.com> Signed-off-by: Manivannan Sadhasivam Reviewed-by: Manivannan Sadhasivam Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250510160710.392122-4-18255117159@163.com --- drivers/pci/controller/cadence/pci-j721e.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index ef1cfdae33bb..bea1944a7eb2 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -153,11 +153,7 @@ static bool j721e_pcie_link_up(struct cdns_pcie *cdns_pcie) u32 reg; reg = j721e_pcie_user_readl(pcie, J721E_PCIE_USER_LINKSTATUS); - reg &= LINK_STATUS; - if (reg == LINK_UP_DL_COMPLETED) - return true; - - return false; + return (reg & LINK_STATUS) == LINK_UP_DL_COMPLETED; } static const struct cdns_pcie_ops j721e_pcie_ops = { From 2389d8dc38fee18176c49e9c4804f5ecc55807fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 22 Apr 2025 14:55:47 +0300 Subject: [PATCH 081/147] PCI/bwctrl: Replace lbms_count with PCI_LINK_LBMS_SEEN flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe BW controller counted LBMS assertions for the purposes of the Target Speed quirk (pcie_failed_link_retrain()). It was also a plan to expose the LBMS count through sysfs to allow better diagnosing link related issues. Lukas Wunner suggested, however, that adding a trace event would be better for diagnostics purposes, leaving only pcie_failed_link_retrain() as a user of the lbms_count. The logic in pcie_failed_link_retrain() does not require keeping count of LBMS assertions, so replace lbms_count with a simple flag in pci_dev's priv_flags. The reduced complexity allows removing pcie_bwctrl_lbms_rwsem. Since pcie_failed_link_retrain() runs before bwctrl is probed during boot, the LBMS in Link Status register still has to be checked by the quirk. The priv_flags numbering is not continuous because hotplug code added a few flags to fill numbers 4-5 (hotplug and bwctrl changes are routed through in different branches). Suggested-by: Lukas Wunner Signed-off-by: Ilpo Järvinen [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas [kwilczynski: squashed a fix to resolve build failures from https://lore.kernel.org/all/20250508090036.1528-1-ilpo.jarvinen@linux.intel.com] Signed-off-by: Krzysztof Wilczyński Reviewed-by: Lukas Wunner Link: https://patch.msgid.link/20250422115548.1483-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/hotplug/pciehp_ctrl.c | 2 +- drivers/pci/pci.c | 2 +- drivers/pci/pci.h | 10 ++--- drivers/pci/pcie/bwctrl.c | 73 ++++++++----------------------- drivers/pci/quirks.c | 10 ++--- 5 files changed, 26 insertions(+), 71 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index d603a7aa7483..bcc938d4420f 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -131,7 +131,7 @@ static void remove_board(struct controller *ctrl, bool safe_removal) INDICATOR_NOOP); /* Don't carry LBMS indications across */ - pcie_reset_lbms_count(ctrl->pcie->port); + pcie_reset_lbms(ctrl->pcie->port); } static int pciehp_enable_slot(struct controller *ctrl); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d7c9f64ea24..3d94cf33c1b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4757,7 +4757,7 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) * to track link speed or width changes made by hardware itself * in attempt to correct unreliable link operation. */ - pcie_reset_lbms_count(pdev); + pcie_reset_lbms(pdev); return rc; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..887811fbe722 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -557,6 +557,7 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) #define PCI_DPC_RECOVERED 1 #define PCI_DPC_RECOVERING 2 #define PCI_DEV_REMOVED 3 +#define PCI_LINK_LBMS_SEEN 6 static inline void pci_dev_assign_added(struct pci_dev *dev) { @@ -824,14 +825,9 @@ static inline void pcie_ecrc_get_policy(char *str) { } #endif #ifdef CONFIG_PCIEPORTBUS -void pcie_reset_lbms_count(struct pci_dev *port); -int pcie_lbms_count(struct pci_dev *port, unsigned long *val); +void pcie_reset_lbms(struct pci_dev *port); #else -static inline void pcie_reset_lbms_count(struct pci_dev *port) {} -static inline int pcie_lbms_count(struct pci_dev *port, unsigned long *val) -{ - return -EOPNOTSUPP; -} +static inline void pcie_reset_lbms(struct pci_dev *port) {} #endif struct pci_dev_reset_methods { diff --git a/drivers/pci/pcie/bwctrl.c b/drivers/pci/pcie/bwctrl.c index d8d2aa85a229..f31fbbd51490 100644 --- a/drivers/pci/pcie/bwctrl.c +++ b/drivers/pci/pcie/bwctrl.c @@ -38,24 +38,14 @@ /** * struct pcie_bwctrl_data - PCIe bandwidth controller * @set_speed_mutex: Serializes link speed changes - * @lbms_count: Count for LBMS (since last reset) * @cdev: Thermal cooling device associated with the port */ struct pcie_bwctrl_data { struct mutex set_speed_mutex; - atomic_t lbms_count; struct thermal_cooling_device *cdev; }; -/* - * Prevent port removal during LBMS count accessors and Link Speed changes. - * - * These have to be differentiated because pcie_bwctrl_change_speed() calls - * pcie_retrain_link() which uses LBMS count reset accessor on success - * (using just one rwsem triggers "possible recursive locking detected" - * warning). - */ -static DECLARE_RWSEM(pcie_bwctrl_lbms_rwsem); +/* Prevent port removal during Link Speed changes. */ static DECLARE_RWSEM(pcie_bwctrl_setspeed_rwsem); static bool pcie_valid_speed(enum pci_bus_speed speed) @@ -202,15 +192,14 @@ int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req, static void pcie_bwnotif_enable(struct pcie_device *srv) { - struct pcie_bwctrl_data *data = srv->port->link_bwctrl; struct pci_dev *port = srv->port; u16 link_status; int ret; - /* Count LBMS seen so far as one */ + /* Note if LBMS has been seen so far */ ret = pcie_capability_read_word(port, PCI_EXP_LNKSTA, &link_status); if (ret == PCIBIOS_SUCCESSFUL && link_status & PCI_EXP_LNKSTA_LBMS) - atomic_inc(&data->lbms_count); + set_bit(PCI_LINK_LBMS_SEEN, &port->priv_flags); pcie_capability_set_word(port, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_LBMIE | PCI_EXP_LNKCTL_LABIE); @@ -233,7 +222,6 @@ static void pcie_bwnotif_disable(struct pci_dev *port) static irqreturn_t pcie_bwnotif_irq(int irq, void *context) { struct pcie_device *srv = context; - struct pcie_bwctrl_data *data = srv->port->link_bwctrl; struct pci_dev *port = srv->port; u16 link_status, events; int ret; @@ -247,7 +235,7 @@ static irqreturn_t pcie_bwnotif_irq(int irq, void *context) return IRQ_NONE; if (events & PCI_EXP_LNKSTA_LBMS) - atomic_inc(&data->lbms_count); + set_bit(PCI_LINK_LBMS_SEEN, &port->priv_flags); pcie_capability_write_word(port, PCI_EXP_LNKSTA, events); @@ -262,31 +250,10 @@ static irqreturn_t pcie_bwnotif_irq(int irq, void *context) return IRQ_HANDLED; } -void pcie_reset_lbms_count(struct pci_dev *port) +void pcie_reset_lbms(struct pci_dev *port) { - struct pcie_bwctrl_data *data; - - guard(rwsem_read)(&pcie_bwctrl_lbms_rwsem); - data = port->link_bwctrl; - if (data) - atomic_set(&data->lbms_count, 0); - else - pcie_capability_write_word(port, PCI_EXP_LNKSTA, - PCI_EXP_LNKSTA_LBMS); -} - -int pcie_lbms_count(struct pci_dev *port, unsigned long *val) -{ - struct pcie_bwctrl_data *data; - - guard(rwsem_read)(&pcie_bwctrl_lbms_rwsem); - data = port->link_bwctrl; - if (!data) - return -ENOTTY; - - *val = atomic_read(&data->lbms_count); - - return 0; + clear_bit(PCI_LINK_LBMS_SEEN, &port->priv_flags); + pcie_capability_write_word(port, PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_LBMS); } static int pcie_bwnotif_probe(struct pcie_device *srv) @@ -308,18 +275,16 @@ static int pcie_bwnotif_probe(struct pcie_device *srv) return ret; scoped_guard(rwsem_write, &pcie_bwctrl_setspeed_rwsem) { - scoped_guard(rwsem_write, &pcie_bwctrl_lbms_rwsem) { - port->link_bwctrl = data; + port->link_bwctrl = data; - ret = request_irq(srv->irq, pcie_bwnotif_irq, - IRQF_SHARED, "PCIe bwctrl", srv); - if (ret) { - port->link_bwctrl = NULL; - return ret; - } - - pcie_bwnotif_enable(srv); + ret = request_irq(srv->irq, pcie_bwnotif_irq, + IRQF_SHARED, "PCIe bwctrl", srv); + if (ret) { + port->link_bwctrl = NULL; + return ret; } + + pcie_bwnotif_enable(srv); } pci_dbg(port, "enabled with IRQ %d\n", srv->irq); @@ -339,13 +304,11 @@ static void pcie_bwnotif_remove(struct pcie_device *srv) pcie_cooling_device_unregister(data->cdev); scoped_guard(rwsem_write, &pcie_bwctrl_setspeed_rwsem) { - scoped_guard(rwsem_write, &pcie_bwctrl_lbms_rwsem) { - pcie_bwnotif_disable(srv->port); + pcie_bwnotif_disable(srv->port); - free_irq(srv->irq, srv); + free_irq(srv->irq, srv); - srv->port->link_bwctrl = NULL; - } + srv->port->link_bwctrl = NULL; } } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8d610c17e0f2..64ac1ee944d3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -38,14 +38,10 @@ static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta) { - unsigned long count; - int ret; + if (test_bit(PCI_LINK_LBMS_SEEN, &dev->priv_flags)) + return true; - ret = pcie_lbms_count(dev, &count); - if (ret < 0) - return lnksta & PCI_EXP_LNKSTA_LBMS; - - return count > 0; + return lnksta & PCI_EXP_LNKSTA_LBMS; } /* From 132833405e61463d47d6badff1b8080b09b5808e Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:39 +0530 Subject: [PATCH 082/147] PCI: Add debugfs support for exposing PTM context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precision Time Management (PTM) mechanism defined in PCIe spec r6.0, sec 6.21 allows precise coordination of timing information across multiple components in a PCIe hierarchy with independent local time clocks. PCI core already supports enabling PTM in the root port and endpoint devices through PTM Extended Capability registers. But the PTM context supported by the PTM capable components such as Root Complex (RC) and Endpoint (EP) controllers were not exposed as of now. Part of the reason is that the spec doesn't define how the context information is exposed to the software and left it to the vendor implementation. So there is no standardized way to get access to the context information and each vendor have defined their own way. This commit adds debugfs support to expose the PTM context to userspace from both PCIe RC and EP controllers. Since the context information is exposed in a vendor specific way, the debugfs interface allows the controller drivers to implement callbacks for each attribute, to be called by the generic PTM driver. The Controller drivers are expected to call pcie_ptm_create_debugfs() to create the debugfs attributes for the PTM context and call pcie_ptm_destroy_debugfs() to destroy them. The drivers should also populate the relevant callbacks in the 'struct pcie_ptm_ops' structure based on the controller implementation. Below PTM context are exposed through debugfs: PCIe RC ======= 1. PTM Local clock 2. PTM T2 timestamp 3. PTM T3 timestamp 4. PTM Context valid PCIe EP ======= 1. PTM Local clock 2. PTM T1 timestamp 3. PTM T4 timestamp 4. PTM Master clock 5. PTM Context update Signed-off-by: Manivannan Sadhasivam [kwilczynski: fix overflow issue reported by Dan Carpenter from https://lore.kernel.org/linux-pci/b41c1754-c6b7-4805-9f14-7c643d6c5304@suswa.mountain] Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-1-02d26d51400b@linaro.org --- Documentation/ABI/testing/debugfs-pcie-ptm | 70 +++++ MAINTAINERS | 1 + drivers/pci/pcie/ptm.c | 300 +++++++++++++++++++++ include/linux/pci.h | 45 ++++ 4 files changed, 416 insertions(+) create mode 100644 Documentation/ABI/testing/debugfs-pcie-ptm diff --git a/Documentation/ABI/testing/debugfs-pcie-ptm b/Documentation/ABI/testing/debugfs-pcie-ptm new file mode 100644 index 000000000000..602d41363571 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-pcie-ptm @@ -0,0 +1,70 @@ +What: /sys/kernel/debug/pcie_ptm_*/local_clock +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RO) PTM local clock in nanoseconds. Applicable for both Root + Complex and Endpoint controllers. + +What: /sys/kernel/debug/pcie_ptm_*/master_clock +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RO) PTM master clock in nanoseconds. Applicable only for + Endpoint controllers. + +What: /sys/kernel/debug/pcie_ptm_*/t1 +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RO) PTM T1 timestamp in nanoseconds. Applicable only for + Endpoint controllers. + +What: /sys/kernel/debug/pcie_ptm_*/t2 +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RO) PTM T2 timestamp in nanoseconds. Applicable only for + Root Complex controllers. + +What: /sys/kernel/debug/pcie_ptm_*/t3 +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RO) PTM T3 timestamp in nanoseconds. Applicable only for + Root Complex controllers. + +What: /sys/kernel/debug/pcie_ptm_*/t4 +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RO) PTM T4 timestamp in nanoseconds. Applicable only for + Endpoint controllers. + +What: /sys/kernel/debug/pcie_ptm_*/context_update +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RW) Control the PTM context update mode. Applicable only for + Endpoint controllers. + + Following values are supported: + + * auto = PTM context auto update trigger for every 10ms + + * manual = PTM context manual update. Writing 'manual' to this + file triggers PTM context update (default) + +What: /sys/kernel/debug/pcie_ptm_*/context_valid +Date: May 2025 +Contact: Manivannan Sadhasivam +Description: + (RW) Control the PTM context validity (local clock timing). + Applicable only for Root Complex controllers. PTM context is + invalidated by hardware if the Root Complex enters low power + mode or changes link frequency. + + Following values are supported: + + * 0 = PTM context invalid (default) + + * 1 = PTM context valid diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..cecd5141b0ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18641,6 +18641,7 @@ Q: https://patchwork.kernel.org/project/linux-pci/list/ B: https://bugzilla.kernel.org C: irc://irc.oftc.net/linux-pci T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git +F: Documentation/ABI/testing/debugfs-pcie-ptm F: Documentation/devicetree/bindings/pci/ F: drivers/pci/controller/ F: drivers/pci/pci-bridge-emul.c diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c index 7cfb6c0d5dcb..ee5f615a9023 100644 --- a/drivers/pci/pcie/ptm.c +++ b/drivers/pci/pcie/ptm.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -252,3 +253,302 @@ bool pcie_ptm_enabled(struct pci_dev *dev) return dev->ptm_enabled; } EXPORT_SYMBOL(pcie_ptm_enabled); + +static ssize_t context_update_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct pci_ptm_debugfs *ptm_debugfs = file->private_data; + char buf[7]; + int ret; + u8 mode; + + if (!ptm_debugfs->ops->context_update_write) + return -EOPNOTSUPP; + + if (count < 1 || count >= sizeof(buf)) + return -EINVAL; + + ret = copy_from_user(buf, ubuf, count); + if (ret) + return -EFAULT; + + buf[count] = '\0'; + + if (sysfs_streq(buf, "auto")) + mode = PCIE_PTM_CONTEXT_UPDATE_AUTO; + else if (sysfs_streq(buf, "manual")) + mode = PCIE_PTM_CONTEXT_UPDATE_MANUAL; + else + return -EINVAL; + + mutex_lock(&ptm_debugfs->lock); + ret = ptm_debugfs->ops->context_update_write(ptm_debugfs->pdata, mode); + mutex_unlock(&ptm_debugfs->lock); + if (ret) + return ret; + + return count; +} + +static ssize_t context_update_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct pci_ptm_debugfs *ptm_debugfs = file->private_data; + char buf[8]; /* Extra space for NULL termination at the end */ + ssize_t pos; + u8 mode; + + if (!ptm_debugfs->ops->context_update_read) + return -EOPNOTSUPP; + + mutex_lock(&ptm_debugfs->lock); + ptm_debugfs->ops->context_update_read(ptm_debugfs->pdata, &mode); + mutex_unlock(&ptm_debugfs->lock); + + if (mode == PCIE_PTM_CONTEXT_UPDATE_AUTO) + pos = scnprintf(buf, sizeof(buf), "auto\n"); + else + pos = scnprintf(buf, sizeof(buf), "manual\n"); + + return simple_read_from_buffer(ubuf, count, ppos, buf, pos); +} + +static const struct file_operations context_update_fops = { + .open = simple_open, + .read = context_update_read, + .write = context_update_write, +}; + +static int context_valid_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + bool valid; + int ret; + + if (!ptm_debugfs->ops->context_valid_read) + return -EOPNOTSUPP; + + mutex_lock(&ptm_debugfs->lock); + ret = ptm_debugfs->ops->context_valid_read(ptm_debugfs->pdata, &valid); + mutex_unlock(&ptm_debugfs->lock); + if (ret) + return ret; + + *val = valid; + + return 0; +} + +static int context_valid_set(void *data, u64 val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + int ret; + + if (!ptm_debugfs->ops->context_valid_write) + return -EOPNOTSUPP; + + mutex_lock(&ptm_debugfs->lock); + ret = ptm_debugfs->ops->context_valid_write(ptm_debugfs->pdata, !!val); + mutex_unlock(&ptm_debugfs->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(context_valid_fops, context_valid_get, + context_valid_set, "%llu\n"); + +static int local_clock_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + u64 clock; + int ret; + + if (!ptm_debugfs->ops->local_clock_read) + return -EOPNOTSUPP; + + ret = ptm_debugfs->ops->local_clock_read(ptm_debugfs->pdata, &clock); + if (ret) + return ret; + + *val = clock; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(local_clock_fops, local_clock_get, NULL, "%llu\n"); + +static int master_clock_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + u64 clock; + int ret; + + if (!ptm_debugfs->ops->master_clock_read) + return -EOPNOTSUPP; + + ret = ptm_debugfs->ops->master_clock_read(ptm_debugfs->pdata, &clock); + if (ret) + return ret; + + *val = clock; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(master_clock_fops, master_clock_get, NULL, "%llu\n"); + +static int t1_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + u64 clock; + int ret; + + if (!ptm_debugfs->ops->t1_read) + return -EOPNOTSUPP; + + ret = ptm_debugfs->ops->t1_read(ptm_debugfs->pdata, &clock); + if (ret) + return ret; + + *val = clock; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(t1_fops, t1_get, NULL, "%llu\n"); + +static int t2_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + u64 clock; + int ret; + + if (!ptm_debugfs->ops->t2_read) + return -EOPNOTSUPP; + + ret = ptm_debugfs->ops->t2_read(ptm_debugfs->pdata, &clock); + if (ret) + return ret; + + *val = clock; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(t2_fops, t2_get, NULL, "%llu\n"); + +static int t3_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + u64 clock; + int ret; + + if (!ptm_debugfs->ops->t3_read) + return -EOPNOTSUPP; + + ret = ptm_debugfs->ops->t3_read(ptm_debugfs->pdata, &clock); + if (ret) + return ret; + + *val = clock; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(t3_fops, t3_get, NULL, "%llu\n"); + +static int t4_get(void *data, u64 *val) +{ + struct pci_ptm_debugfs *ptm_debugfs = data; + u64 clock; + int ret; + + if (!ptm_debugfs->ops->t4_read) + return -EOPNOTSUPP; + + ret = ptm_debugfs->ops->t4_read(ptm_debugfs->pdata, &clock); + if (ret) + return ret; + + *val = clock; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(t4_fops, t4_get, NULL, "%llu\n"); + +#define pcie_ptm_create_debugfs_file(pdata, mode, attr) \ + do { \ + if (ops->attr##_visible && ops->attr##_visible(pdata)) \ + debugfs_create_file(#attr, mode, ptm_debugfs->debugfs, \ + ptm_debugfs, &attr##_fops); \ + } while (0) + +/* + * pcie_ptm_create_debugfs() - Create debugfs entries for the PTM context + * @dev: PTM capable component device + * @pdata: Private data of the PTM capable component device + * @ops: PTM callback structure + * + * Create debugfs entries for exposing the PTM context of the PTM capable + * components such as Root Complex and Endpoint controllers. + * + * Return: Pointer to 'struct pci_ptm_debugfs' if success, NULL otherwise. + */ +struct pci_ptm_debugfs *pcie_ptm_create_debugfs(struct device *dev, void *pdata, + const struct pcie_ptm_ops *ops) +{ + struct pci_ptm_debugfs *ptm_debugfs; + char *dirname; + int ret; + + /* Caller must provide check_capability() callback */ + if (!ops->check_capability) + return NULL; + + /* Check for PTM capability before creating debugfs attrbutes */ + ret = ops->check_capability(pdata); + if (!ret) { + dev_dbg(dev, "PTM capability not present\n"); + return NULL; + } + + ptm_debugfs = kzalloc(sizeof(*ptm_debugfs), GFP_KERNEL); + if (!ptm_debugfs) + return NULL; + + dirname = devm_kasprintf(dev, GFP_KERNEL, "pcie_ptm_%s", dev_name(dev)); + if (!dirname) + return NULL; + + ptm_debugfs->debugfs = debugfs_create_dir(dirname, NULL); + ptm_debugfs->pdata = pdata; + ptm_debugfs->ops = ops; + mutex_init(&ptm_debugfs->lock); + + pcie_ptm_create_debugfs_file(pdata, 0644, context_update); + pcie_ptm_create_debugfs_file(pdata, 0644, context_valid); + pcie_ptm_create_debugfs_file(pdata, 0444, local_clock); + pcie_ptm_create_debugfs_file(pdata, 0444, master_clock); + pcie_ptm_create_debugfs_file(pdata, 0444, t1); + pcie_ptm_create_debugfs_file(pdata, 0444, t2); + pcie_ptm_create_debugfs_file(pdata, 0444, t3); + pcie_ptm_create_debugfs_file(pdata, 0444, t4); + + return ptm_debugfs; +} +EXPORT_SYMBOL_GPL(pcie_ptm_create_debugfs); + +/* + * pcie_ptm_destroy_debugfs() - Destroy debugfs entries for the PTM context + * @ptm_debugfs: Pointer to the PTM debugfs struct + */ +void pcie_ptm_destroy_debugfs(struct pci_ptm_debugfs *ptm_debugfs) +{ + if (!ptm_debugfs) + return; + + mutex_destroy(&ptm_debugfs->lock); + debugfs_remove_recursive(ptm_debugfs->debugfs); +} +EXPORT_SYMBOL_GPL(pcie_ptm_destroy_debugfs); diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..01a29076604f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1856,6 +1856,39 @@ static inline bool pci_aer_available(void) { return false; } bool pci_ats_disabled(void); +#define PCIE_PTM_CONTEXT_UPDATE_AUTO 0 +#define PCIE_PTM_CONTEXT_UPDATE_MANUAL 1 + +struct pcie_ptm_ops { + int (*check_capability)(void *drvdata); + int (*context_update_write)(void *drvdata, u8 mode); + int (*context_update_read)(void *drvdata, u8 *mode); + int (*context_valid_write)(void *drvdata, bool valid); + int (*context_valid_read)(void *drvdata, bool *valid); + int (*local_clock_read)(void *drvdata, u64 *clock); + int (*master_clock_read)(void *drvdata, u64 *clock); + int (*t1_read)(void *drvdata, u64 *clock); + int (*t2_read)(void *drvdata, u64 *clock); + int (*t3_read)(void *drvdata, u64 *clock); + int (*t4_read)(void *drvdata, u64 *clock); + + bool (*context_update_visible)(void *drvdata); + bool (*context_valid_visible)(void *drvdata); + bool (*local_clock_visible)(void *drvdata); + bool (*master_clock_visible)(void *drvdata); + bool (*t1_visible)(void *drvdata); + bool (*t2_visible)(void *drvdata); + bool (*t3_visible)(void *drvdata); + bool (*t4_visible)(void *drvdata); +}; + +struct pci_ptm_debugfs { + struct dentry *debugfs; + const struct pcie_ptm_ops *ops; + struct mutex lock; + void *pdata; +}; + #ifdef CONFIG_PCIE_PTM int pci_enable_ptm(struct pci_dev *dev, u8 *granularity); void pci_disable_ptm(struct pci_dev *dev); @@ -1868,6 +1901,18 @@ static inline bool pcie_ptm_enabled(struct pci_dev *dev) { return false; } #endif +#if IS_ENABLED(CONFIG_DEBUG_FS) && IS_ENABLED(CONFIG_PCIE_PTM) +struct pci_ptm_debugfs *pcie_ptm_create_debugfs(struct device *dev, void *pdata, + const struct pcie_ptm_ops *ops); +void pcie_ptm_destroy_debugfs(struct pci_ptm_debugfs *ptm_debugfs); +#else +static inline struct pci_ptm_debugfs +*pcie_ptm_create_debugfs(struct device *dev, void *pdata, + const struct pcie_ptm_ops *ops) { return NULL; } +static inline void +pcie_ptm_destroy_debugfs(struct pci_ptm_debugfs *ptm_debugfs) { } +#endif + void pci_cfg_access_lock(struct pci_dev *dev); bool pci_cfg_access_trylock(struct pci_dev *dev); void pci_cfg_access_unlock(struct pci_dev *dev); From 87a9d0cd6748b658a0c8f8c957c3260ed901f094 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:40 +0530 Subject: [PATCH 083/147] PCI: dwc: Pass DWC PCIe mode to dwc_pcie_debugfs_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upcoming PTM debugfs interface relies on the DWC PCIe mode to expose the relevant debugfs attributes to userspace. So pass the mode to dwc_pcie_debugfs_init() API from host and ep drivers and save it in 'struct dw_pcie::mode'. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-2-02d26d51400b@linaro.org --- drivers/pci/controller/dwc/pcie-designware-debugfs.c | 4 +++- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.h | 6 ++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c index 9e6f4d00f262..896c387450ca 100644 --- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c +++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c @@ -651,7 +651,7 @@ void dwc_pcie_debugfs_deinit(struct dw_pcie *pci) debugfs_remove_recursive(pci->debugfs->debug_dir); } -void dwc_pcie_debugfs_init(struct dw_pcie *pci) +void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode) { char dirname[DWC_DEBUGFS_BUF_MAX]; struct device *dev = pci->dev; @@ -674,4 +674,6 @@ void dwc_pcie_debugfs_init(struct dw_pcie *pci) err); dwc_pcie_ltssm_debugfs_init(pci, dir); + + pci->mode = mode; } diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1a0bf9341542..6ee14694372c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -1013,7 +1013,7 @@ int dw_pcie_ep_init_registers(struct dw_pcie_ep *ep) dw_pcie_ep_init_non_sticky_registers(pci); - dwc_pcie_debugfs_init(pci); + dwc_pcie_debugfs_init(pci, DW_PCIE_EP_TYPE); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index ecc33f6789e3..17c78a334651 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -567,7 +567,7 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (pp->ops->post_init) pp->ops->post_init(pp); - dwc_pcie_debugfs_init(pci); + dwc_pcie_debugfs_init(pci, DW_PCIE_RC_TYPE); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 56aafdbcdaca..7f58c94b5b1e 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -503,6 +503,7 @@ struct dw_pcie { struct gpio_desc *pe_rst; bool suspended; struct debugfs_info *debugfs; + enum dw_pcie_device_mode mode; /* * If iATU input addresses are offset from CPU physical addresses, @@ -871,10 +872,11 @@ dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no) #endif #ifdef CONFIG_PCIE_DW_DEBUGFS -void dwc_pcie_debugfs_init(struct dw_pcie *pci); +void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode); void dwc_pcie_debugfs_deinit(struct dw_pcie *pci); #else -static inline void dwc_pcie_debugfs_init(struct dw_pcie *pci) +static inline void dwc_pcie_debugfs_init(struct dw_pcie *pci, + enum dw_pcie_device_mode mode) { } static inline void dwc_pcie_debugfs_deinit(struct dw_pcie *pci) From 852a1fdd34a82d719bd67a55111f13a72891a868 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:41 +0530 Subject: [PATCH 084/147] PCI: dwc: Add debugfs support for PTM context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synopsys Designware PCIe IPs support PTM capability as defined in the PCIe spec r6.0, sec 6.21. The PTM context information is exposed through Vendor Specific Extended Capability (VSEC) registers on supported controller implementation. Hence, add support for exposing these context information to userspace through the debugfs interface for the DWC controllers (both RC and EP). Currently, only Qcom controllers are supported. For adding support for other DWC vendor controllers, dwc_pcie_ptm_vsec_ids[] needs to be extended. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-3-02d26d51400b@linaro.org --- .../controller/dwc/pcie-designware-debugfs.c | 248 ++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.c | 14 + drivers/pci/controller/dwc/pcie-designware.h | 18 ++ 3 files changed, 280 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-debugfs.c b/drivers/pci/controller/dwc/pcie-designware-debugfs.c index 896c387450ca..c67601096c48 100644 --- a/drivers/pci/controller/dwc/pcie-designware-debugfs.c +++ b/drivers/pci/controller/dwc/pcie-designware-debugfs.c @@ -642,11 +642,257 @@ static void dwc_pcie_ltssm_debugfs_init(struct dw_pcie *pci, struct dentry *dir) &dwc_pcie_ltssm_status_ops); } +static int dw_pcie_ptm_check_capability(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + pci->ptm_vsec_offset = dw_pcie_find_ptm_capability(pci); + + return pci->ptm_vsec_offset; +} + +static int dw_pcie_ptm_context_update_write(void *drvdata, u8 mode) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + if (mode == PCIE_PTM_CONTEXT_UPDATE_AUTO) { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val |= PTM_REQ_AUTO_UPDATE_ENABLED; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } else if (mode == PCIE_PTM_CONTEXT_UPDATE_MANUAL) { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val &= ~PTM_REQ_AUTO_UPDATE_ENABLED; + val |= PTM_REQ_START_UPDATE; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } else { + return -EINVAL; + } + + return 0; +} + +static int dw_pcie_ptm_context_update_read(void *drvdata, u8 *mode) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + if (FIELD_GET(PTM_REQ_AUTO_UPDATE_ENABLED, val)) + *mode = PCIE_PTM_CONTEXT_UPDATE_AUTO; + else + /* + * PTM_REQ_START_UPDATE is a self clearing register bit. So if + * PTM_REQ_AUTO_UPDATE_ENABLED is not set, then it implies that + * manual update is used. + */ + *mode = PCIE_PTM_CONTEXT_UPDATE_MANUAL; + + return 0; +} + +static int dw_pcie_ptm_context_valid_write(void *drvdata, bool valid) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + if (valid) { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val |= PTM_RES_CCONTEXT_VALID; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } else { + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + val &= ~PTM_RES_CCONTEXT_VALID; + dw_pcie_writel_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL, val); + } + + return 0; +} + +static int dw_pcie_ptm_context_valid_read(void *drvdata, bool *valid) +{ + struct dw_pcie *pci = drvdata; + u32 val; + + val = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_RES_REQ_CTRL); + *valid = !!FIELD_GET(PTM_RES_CCONTEXT_VALID, val); + + return 0; +} + +static int dw_pcie_ptm_local_clock_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_LOCAL_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_master_clock_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_MASTER_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t1_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t2_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T1_T2_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t3_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static int dw_pcie_ptm_t4_read(void *drvdata, u64 *clock) +{ + struct dw_pcie *pci = drvdata; + u32 msb, lsb; + + do { + msb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB); + lsb = dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_LSB); + } while (msb != dw_pcie_readl_dbi(pci, pci->ptm_vsec_offset + PTM_T3_T4_MSB)); + + *clock = ((u64) msb) << 32 | lsb; + + return 0; +} + +static bool dw_pcie_ptm_context_update_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_context_valid_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_RC_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_local_clock_visible(void *drvdata) +{ + /* PTM local clock is always visible */ + return true; +} + +static bool dw_pcie_ptm_master_clock_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t1_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t2_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_RC_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t3_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_RC_TYPE) ? true : false; +} + +static bool dw_pcie_ptm_t4_visible(void *drvdata) +{ + struct dw_pcie *pci = drvdata; + + return (pci->mode == DW_PCIE_EP_TYPE) ? true : false; +} + +const struct pcie_ptm_ops dw_pcie_ptm_ops = { + .check_capability = dw_pcie_ptm_check_capability, + .context_update_write = dw_pcie_ptm_context_update_write, + .context_update_read = dw_pcie_ptm_context_update_read, + .context_valid_write = dw_pcie_ptm_context_valid_write, + .context_valid_read = dw_pcie_ptm_context_valid_read, + .local_clock_read = dw_pcie_ptm_local_clock_read, + .master_clock_read = dw_pcie_ptm_master_clock_read, + .t1_read = dw_pcie_ptm_t1_read, + .t2_read = dw_pcie_ptm_t2_read, + .t3_read = dw_pcie_ptm_t3_read, + .t4_read = dw_pcie_ptm_t4_read, + .context_update_visible = dw_pcie_ptm_context_update_visible, + .context_valid_visible = dw_pcie_ptm_context_valid_visible, + .local_clock_visible = dw_pcie_ptm_local_clock_visible, + .master_clock_visible = dw_pcie_ptm_master_clock_visible, + .t1_visible = dw_pcie_ptm_t1_visible, + .t2_visible = dw_pcie_ptm_t2_visible, + .t3_visible = dw_pcie_ptm_t3_visible, + .t4_visible = dw_pcie_ptm_t4_visible, +}; + void dwc_pcie_debugfs_deinit(struct dw_pcie *pci) { if (!pci->debugfs) return; + pcie_ptm_destroy_debugfs(pci->ptm_debugfs); dwc_pcie_rasdes_debugfs_deinit(pci); debugfs_remove_recursive(pci->debugfs->debug_dir); } @@ -676,4 +922,6 @@ void dwc_pcie_debugfs_init(struct dw_pcie *pci, enum dw_pcie_device_mode mode) dwc_pcie_ltssm_debugfs_init(pci, dir); pci->mode = mode; + pci->ptm_debugfs = pcie_ptm_create_debugfs(pci->dev, pci, + &dw_pcie_ptm_ops); } diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 97d76d3dc066..4a9b1ebda679 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -54,6 +54,14 @@ static const char * const dw_pcie_core_rsts[DW_PCIE_NUM_CORE_RSTS] = { [DW_PCIE_PWR_RST] = "pwr", }; +static const struct dwc_pcie_vsec_id dwc_pcie_ptm_vsec_ids[] = { + { .vendor_id = PCI_VENDOR_ID_QCOM, /* EP */ + .vsec_id = 0x03, .vsec_rev = 0x1 }, + { .vendor_id = PCI_VENDOR_ID_QCOM, /* RC */ + .vsec_id = 0x04, .vsec_rev = 0x1 }, + { } +}; + static int dw_pcie_get_clocks(struct dw_pcie *pci) { int i, ret; @@ -330,6 +338,12 @@ u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci) } EXPORT_SYMBOL_GPL(dw_pcie_find_rasdes_capability); +u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci) +{ + return dw_pcie_find_vsec_capability(pci, dwc_pcie_ptm_vsec_ids); +} +EXPORT_SYMBOL_GPL(dw_pcie_find_ptm_capability); + int dw_pcie_read(void __iomem *addr, int size, u32 *val) { if (!IS_ALIGNED((uintptr_t)addr, size)) { diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 7f58c94b5b1e..4d41274a6937 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -260,6 +260,21 @@ #define PCIE_RAS_DES_EVENT_COUNTER_DATA 0xc +/* PTM register definitions */ +#define PTM_RES_REQ_CTRL 0x8 +#define PTM_RES_CCONTEXT_VALID BIT(0) +#define PTM_REQ_AUTO_UPDATE_ENABLED BIT(0) +#define PTM_REQ_START_UPDATE BIT(1) + +#define PTM_LOCAL_LSB 0x10 +#define PTM_LOCAL_MSB 0x14 +#define PTM_T1_T2_LSB 0x18 +#define PTM_T1_T2_MSB 0x1c +#define PTM_T3_T4_LSB 0x28 +#define PTM_T3_T4_MSB 0x2c +#define PTM_MASTER_LSB 0x38 +#define PTM_MASTER_MSB 0x3c + /* * The default address offset between dbi_base and atu_base. Root controller * drivers are not required to initialize atu_base if the offset matches this @@ -504,6 +519,8 @@ struct dw_pcie { bool suspended; struct debugfs_info *debugfs; enum dw_pcie_device_mode mode; + u16 ptm_vsec_offset; + struct pci_ptm_debugfs *ptm_debugfs; /* * If iATU input addresses are offset from CPU physical addresses, @@ -531,6 +548,7 @@ void dw_pcie_version_detect(struct dw_pcie *pci); u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap); u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap); u16 dw_pcie_find_rasdes_capability(struct dw_pcie *pci); +u16 dw_pcie_find_ptm_capability(struct dw_pcie *pci); int dw_pcie_read(void __iomem *addr, int size, u32 *val); int dw_pcie_write(void __iomem *addr, int size, u32 val); From 5fbfae69e78d242c5efb2a4b62eeea883af145ee Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 5 May 2025 19:54:42 +0530 Subject: [PATCH 085/147] PCI: qcom-ep: Mask PTM_UPDATING interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When PTM is enabled, PTM_UPDATING interrupt will be fired for each PTM context update, which will be once every 10ms in the case of auto context update. Since the interrupt is not strictly needed for making use of PTM, mask it to avoid the overhead of processing it. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/20250505-pcie-ptm-v4-4-02d26d51400b@linaro.org --- drivers/pci/controller/dwc/pcie-qcom-ep.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 46b1c6d19974..9270429501ae 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -60,6 +60,7 @@ #define PARF_DEVICE_TYPE 0x1000 #define PARF_BDF_TO_SID_CFG 0x2c00 #define PARF_INT_ALL_5_MASK 0x2dcc +#define PARF_INT_ALL_3_MASK 0x2e18 /* PARF_INT_ALL_{STATUS/CLEAR/MASK} register fields */ #define PARF_INT_ALL_LINK_DOWN BIT(1) @@ -132,6 +133,9 @@ /* PARF_INT_ALL_5_MASK fields */ #define PARF_INT_ALL_5_MHI_RAM_DATA_PARITY_ERR BIT(0) +/* PARF_INT_ALL_3_MASK fields */ +#define PARF_INT_ALL_3_PTM_UPDATING BIT(4) + /* ELBI registers */ #define ELBI_SYS_STTS 0x08 #define ELBI_CS2_ENABLE 0xa4 @@ -497,6 +501,10 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_5_MASK); } + val = readl_relaxed(pcie_ep->parf + PARF_INT_ALL_3_MASK); + val &= ~PARF_INT_ALL_3_PTM_UPDATING; + writel_relaxed(val, pcie_ep->parf + PARF_INT_ALL_3_MASK); + ret = dw_pcie_ep_init_registers(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to complete initialization: %d\n", ret); From 3be5fa236649da6404f1bca1491bf02d4b0d5cce Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 25 Apr 2025 11:24:21 +0200 Subject: [PATCH 086/147] Revert "iommu/amd: Prevent binding other PCI drivers to IOMMU PCI devices" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 991de2e59090 ("PCI, x86: Implement pcibios_alloc_irq() and pcibios_free_irq()") changed IRQ handling on PCI driver probing. It inadvertently broke resume from system sleep on AMD platforms: https://lore.kernel.org/r/20150926164651.GA3640@pd.tnic/ This was fixed by two independent commits: * 8affb487d4a4 ("x86/PCI: Don't alloc pcibios-irq when MSI is enabled") * cbbc00be2ce3 ("iommu/amd: Prevent binding other PCI drivers to IOMMU PCI devices") The breaking change and one of these two fixes were subsequently reverted: * fe25d078874f ("Revert "x86/PCI: Don't alloc pcibios-irq when MSI is enabled"") * 6c777e8799a9 ("Revert "PCI, x86: Implement pcibios_alloc_irq() and pcibios_free_irq()"") This rendered the second fix unnecessary, so revert it as well. It used the match_driver flag in struct pci_dev, which is internal to the PCI core and not supposed to be touched by arbitrary drivers. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Signed-off-by: Krzysztof Wilczyński Acked-by: Joerg Roedel Link: https://patch.msgid.link/9a3ddff5cc49512044f963ba0904347bd404094d.1745572340.git.lukas@wunner.de --- drivers/iommu/amd/init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index dd9e26b7b718..33b6e12c7d24 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -2030,9 +2030,6 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) if (!iommu->dev) return -ENODEV; - /* Prevent binding other PCI device drivers to IOMMU devices */ - iommu->dev->match_driver = false; - /* ACPI _PRT won't have an IRQ for IOMMU */ iommu->dev->irq_managed = 1; From ce45dc4bb22e96b59a07e19b67e915d99dd5281b Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 25 Apr 2025 11:24:22 +0200 Subject: [PATCH 087/147] PCI: Limit visibility of match_driver flag to PCI core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 58d9a38f6fac ("PCI: Skip attaching driver in device_add()"), PCI enumeration is split into two steps: In the first step, all devices are published in sysfs with device_add(). In the second step, drivers are bound to the devices with device_attach(). To delay driver binding until the second step, a "bool match_driver" in struct pci_dev is used. Instead of a bool, use a bit in the "unsigned long priv_flags" to shrink struct pci_dev a little and prevent use of the bool outside the PCI core (as has happened with commit cbbc00be2ce3 ("iommu/amd: Prevent binding other PCI drivers to IOMMU PCI devices")). Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Signed-off-by: Krzysztof Wilczyński Link: https://patch.msgid.link/d22a9e5b81d6bd8dd1837607d6156679b3b1199c.1745572340.git.lukas@wunner.de --- drivers/pci/bus.c | 4 +++- drivers/pci/pci-driver.c | 2 +- drivers/pci/pci.h | 11 +++++++++++ drivers/pci/probe.c | 1 - include/linux/pci.h | 2 -- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index b6851101ac36..69048869ef1c 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -369,7 +369,9 @@ void pci_bus_add_device(struct pci_dev *dev) pdev->name); } - dev->match_driver = !dn || of_device_is_available(dn); + if (!dn || of_device_is_available(dn)) + pci_dev_allow_binding(dev); + retval = device_attach(&dev->dev); if (retval < 0 && retval != -EPROBE_DEFER) pci_warn(dev, "device attach failed (%d)\n", retval); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index c8bd71a739f7..0c5bdb8c2c07 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1507,7 +1507,7 @@ static int pci_bus_match(struct device *dev, const struct device_driver *drv) struct pci_driver *pci_drv; const struct pci_device_id *found_id; - if (!pci_dev->match_driver) + if (pci_dev_binding_disallowed(pci_dev)) return 0; pci_drv = (struct pci_driver *)to_pci_driver(drv); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..de5d4ef943b2 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -557,6 +557,7 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) #define PCI_DPC_RECOVERED 1 #define PCI_DPC_RECOVERING 2 #define PCI_DEV_REMOVED 3 +#define PCI_DEV_ALLOW_BINDING 7 static inline void pci_dev_assign_added(struct pci_dev *dev) { @@ -580,6 +581,16 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev) return test_and_set_bit(PCI_DEV_REMOVED, &dev->priv_flags); } +static inline void pci_dev_allow_binding(struct pci_dev *dev) +{ + set_bit(PCI_DEV_ALLOW_BINDING, &dev->priv_flags); +} + +static inline bool pci_dev_binding_disallowed(struct pci_dev *dev) +{ + return !test_bit(PCI_DEV_ALLOW_BINDING, &dev->priv_flags); +} + #ifdef CONFIG_PCIEAER #include diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 08971fca0819..4b8693ec9e4c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2711,7 +2711,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) pci_set_msi_domain(dev); /* Notifier could use PCI capabilities */ - dev->match_driver = false; ret = device_add(&dev->dev); WARN_ON(ret < 0); diff --git a/include/linux/pci.h b/include/linux/pci.h index d26e6611bd00..053d9dd494d4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -423,8 +423,6 @@ struct pci_dev { struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ struct resource driver_exclusive_resource; /* driver exclusive resource ranges */ - bool match_driver; /* Skip attaching driver */ - unsigned int transparent:1; /* Subtractive decode bridge */ unsigned int io_window:1; /* Bridge has I/O window */ unsigned int pref_window:1; /* Bridge has pref mem window */ From 6ade6e81f898f7f533207b23849ac8cc0ea8c755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Wed, 14 May 2025 16:28:21 +0300 Subject: [PATCH 088/147] PCI: Update Link Speed after retraining MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe Link Retraining can alter Link Speed. pcie_retrain_link() that performs the Link Training is called from bwctrl and ASPM driver. While bwctrl listens for Link Bandwidth Management Status (LBMS) to pick up changes in Link Speed, there is a race between pcie_reset_lbms() clearing LBMS after the Link Training and pcie_bwnotif_irq() reading the Link Status register. If LBMS is already cleared when the irq handler reads the register, the interrupt handler will return early with IRQ_NONE and won't update the Link Speed. When Link Speed update originates from bwctrl, pcie_bwctrl_change_speed() ensures Link Speed is updated after the retraining. ASPM driver, however, calls pcie_retrain_link() but does not update the Link Speed after retraining which can result in stale Link Speed. Also, it is possible to have ASPM support with CONFIG_PCIEPORTBUS=n in which case bwctrl will not be built in (and thus won't update the Link Speed at all). To ensure Link Speed is not left stale after Link Training, move the call to pcie_update_link_speed() from pcie_bwctrl_change_speed() into pcie_retrain_link(). Suggested-by: Lukas Wunner Signed-off-by: Ilpo Järvinen Signed-off-by: Krzysztof Wilczyński Reviewed-by: Lukas Wunner Link: https://lore.kernel.org/linux-pci/aBCjpfyYmlkJ12AZ@wunner.de Link: https://lore.kernel.org/r/20250514132821.15705-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/pci.c | 17 +++++++++++++++++ drivers/pci/pcie/bwctrl.c | 13 +------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 3d94cf33c1b6..eb0c55078d5e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4718,6 +4718,11 @@ static int pcie_wait_for_link_status(struct pci_dev *pdev, * @pdev: Device whose link to retrain. * @use_lt: Use the LT bit if TRUE, or the DLLLA bit if FALSE, for status. * + * Trigger retraining of the PCIe Link and wait for the completion of the + * retraining. As link retraining is known to asserts LBMS and may change + * the Link Speed, LBMS is cleared after the retraining and the Link Speed + * of the subordinate bus is updated. + * * Retrain completion status is retrieved from the Link Status Register * according to @use_lt. It is not verified whether the use of the DLLLA * bit is valid. @@ -4758,6 +4763,18 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) * in attempt to correct unreliable link operation. */ pcie_reset_lbms(pdev); + + /* + * Ensure the Link Speed updates after retraining in case the Link + * Speed was changed because of the retraining. While the bwctrl's + * IRQ handler normally picks up the new Link Speed, clearing LBMS + * races with the IRQ handler reading the Link Status register and + * can result in the handler returning early without updating the + * Link Speed. + */ + if (pdev->subordinate) + pcie_update_link_speed(pdev->subordinate); + return rc; } diff --git a/drivers/pci/pcie/bwctrl.c b/drivers/pci/pcie/bwctrl.c index f31fbbd51490..36f939f23d34 100644 --- a/drivers/pci/pcie/bwctrl.c +++ b/drivers/pci/pcie/bwctrl.c @@ -117,18 +117,7 @@ static int pcie_bwctrl_change_speed(struct pci_dev *port, u16 target_speed, bool if (ret != PCIBIOS_SUCCESSFUL) return pcibios_err_to_errno(ret); - ret = pcie_retrain_link(port, use_lt); - if (ret < 0) - return ret; - - /* - * Ensure link speed updates also with platforms that have problems - * with notifications. - */ - if (port->subordinate) - pcie_update_link_speed(port->subordinate); - - return 0; + return pcie_retrain_link(port, use_lt); } /** From db8266017e0a703809c83453112c8d5ceb4f03af Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Fri, 16 May 2025 10:59:39 +0100 Subject: [PATCH 089/147] dt-bindings: PCI: microchip,pcie-host: Fix DMA coherency property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PolarFire SoC may be configured in a way that requires non-coherent DMA handling. On RISC-V, buses are coherent by default & the dma-noncoherent property is required to denote buses or devices that are non-coherent. For some reason, instead of adding dma-noncoherent to the binding the pointless, NOP, property dma-coherent was. Swap dma-coherent for dma-noncoherent. Fixes: 04aa999eb96fd ("dt-bindings: PCI: microchip,pcie-host: Allow dma-noncoherent") Signed-off-by: Conor Dooley Signed-off-by: Krzysztof Wilczyński Link: https://lore.kernel.org/r/20250516-datebook-senator-ff7a1c30cbd5@spud --- Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml index 1aadfdee868f..47b0bad690d5 100644 --- a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml +++ b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml @@ -50,7 +50,7 @@ properties: items: pattern: '^fic[0-3]$' - dma-coherent: true + dma-noncoherent: true ranges: minItems: 1 From 51f6aec99cb0493b6c288ba55bed2ef9fb6242ca Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Mon, 19 May 2025 13:29:55 +0200 Subject: [PATCH 090/147] PCI: Remove hybrid devres nature from request functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All functions based on __pci_request_region() and its release counter part support "hybrid mode", where the functions become managed if the PCI device was enabled with pcim_enable_device(). Removing this undesirable feature requires to remove all users who activated their device with that function and use one of the affected request functions. These users were: ASoC alsa cardreader cirrus i2c mmc mtd mtd mxser net spi vdpa vmwgfx all of which have been ported to always-managed pcim_ functions by now. The hybrid nature can, thus, be removed from the aforementioned PCI functions. Remove all function guards and documentation in pci.c related to the hybrid redirection. Adjust the visibility of pcim_release_region(). Signed-off-by: Philipp Stanner Signed-off-by: Krzysztof Wilczyński Reviewed-by: Andy Shevchenko Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://lore.kernel.org/r/20250519112959.25487-3-phasta@kernel.org --- drivers/pci/devres.c | 39 ++++++++++++--------------------------- drivers/pci/pci.c | 42 ------------------------------------------ drivers/pci/pci.h | 1 - 3 files changed, 12 insertions(+), 70 deletions(-) diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index 0317c56ac27d..dde109095428 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -6,30 +6,13 @@ /* * On the state of PCI's devres implementation: * - * The older devres API for PCI has two significant problems: + * The older PCI devres API has one significant problem: * - * 1. It is very strongly tied to the statically allocated mapping table in - * struct pcim_iomap_devres below. This is mostly solved in the sense of the - * pcim_ functions in this file providing things like ranged mapping by - * bypassing this table, whereas the functions that were present in the old - * API still enter the mapping addresses into the table for users of the old - * API. - * - * 2. The region-request-functions in pci.c do become managed IF the device has - * been enabled with pcim_enable_device() instead of pci_enable_device(). - * This resulted in the API becoming inconsistent: Some functions have an - * obviously managed counter-part (e.g., pci_iomap() <-> pcim_iomap()), - * whereas some don't and are never managed, while others don't and are - * _sometimes_ managed (e.g. pci_request_region()). - * - * Consequently, in the new API, region requests performed by the pcim_ - * functions are automatically cleaned up through the devres callback - * pcim_addr_resource_release(). - * - * Users of pcim_enable_device() + pci_*region*() are redirected in - * pci.c to the managed functions here in this file. This isn't exactly - * perfect, but the only alternative way would be to port ALL drivers - * using said combination to pcim_ functions. + * It is very strongly tied to the statically allocated mapping table in struct + * pcim_iomap_devres below. This is mostly solved in the sense of the pcim_ + * functions in this file providing things like ranged mapping by bypassing + * this table, whereas the functions that were present in the old API still + * enter the mapping addresses into the table for users of the old API. * * TODO: * Remove the legacy table entirely once all calls to pcim_iomap_table() in @@ -89,10 +72,12 @@ static inline void pcim_addr_devres_clear(struct pcim_addr_devres *res) /* * The following functions, __pcim_*_region*, exist as counterparts to the - * versions from pci.c - which, unfortunately, can be in "hybrid mode", i.e., - * sometimes managed, sometimes not. + * versions from pci.c - which, unfortunately, were in the past in "hybrid + * mode", i.e., sometimes managed, sometimes not. * - * To separate the APIs cleanly, we define our own, simplified versions here. + * To separate the APIs cleanly, we defined our own, simplified versions here. + * + * TODO: unify those functions with the counterparts in pci.c */ /** @@ -893,7 +878,7 @@ int pcim_request_region_exclusive(struct pci_dev *pdev, int bar, const char *nam * Release a region manually that was previously requested by * pcim_request_region(). */ -void pcim_release_region(struct pci_dev *pdev, int bar) +static void pcim_release_region(struct pci_dev *pdev, int bar) { struct pcim_addr_devres res_searched; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4d7c9f64ea24..fe241fabe0f3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3937,16 +3937,6 @@ void pci_release_region(struct pci_dev *pdev, int bar) if (!pci_bar_index_is_valid(bar)) return; - /* - * This is done for backwards compatibility, because the old PCI devres - * API had a mode in which the function became managed if it had been - * enabled with pcim_enable_device() instead of pci_enable_device(). - */ - if (pci_is_managed(pdev)) { - pcim_release_region(pdev, bar); - return; - } - if (pci_resource_len(pdev, bar) == 0) return; if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) @@ -3984,13 +3974,6 @@ static int __pci_request_region(struct pci_dev *pdev, int bar, if (!pci_bar_index_is_valid(bar)) return -EINVAL; - if (pci_is_managed(pdev)) { - if (exclusive == IORESOURCE_EXCLUSIVE) - return pcim_request_region_exclusive(pdev, bar, name); - - return pcim_request_region(pdev, bar, name); - } - if (pci_resource_len(pdev, bar) == 0) return 0; @@ -4027,11 +4010,6 @@ err_out: * * Returns 0 on success, or %EBUSY on error. A warning * message is also printed on failure. - * - * NOTE: - * This is a "hybrid" function: It's normally unmanaged, but becomes managed - * when pcim_enable_device() has been called in advance. This hybrid feature is - * DEPRECATED! If you want managed cleanup, use the pcim_* functions instead. */ int pci_request_region(struct pci_dev *pdev, int bar, const char *name) { @@ -4084,11 +4062,6 @@ err_out: * @name: Name of the driver requesting the resources * * Returns: 0 on success, negative error code on failure. - * - * NOTE: - * This is a "hybrid" function: It's normally unmanaged, but becomes managed - * when pcim_enable_device() has been called in advance. This hybrid feature is - * DEPRECATED! If you want managed cleanup, use the pcim_* functions instead. */ int pci_request_selected_regions(struct pci_dev *pdev, int bars, const char *name) @@ -4104,11 +4077,6 @@ EXPORT_SYMBOL(pci_request_selected_regions); * @name: name of the driver requesting the resources * * Returns: 0 on success, negative error code on failure. - * - * NOTE: - * This is a "hybrid" function: It's normally unmanaged, but becomes managed - * when pcim_enable_device() has been called in advance. This hybrid feature is - * DEPRECATED! If you want managed cleanup, use the pcim_* functions instead. */ int pci_request_selected_regions_exclusive(struct pci_dev *pdev, int bars, const char *name) @@ -4144,11 +4112,6 @@ EXPORT_SYMBOL(pci_release_regions); * * Returns 0 on success, or %EBUSY on error. A warning * message is also printed on failure. - * - * NOTE: - * This is a "hybrid" function: It's normally unmanaged, but becomes managed - * when pcim_enable_device() has been called in advance. This hybrid feature is - * DEPRECATED! If you want managed cleanup, use the pcim_* functions instead. */ int pci_request_regions(struct pci_dev *pdev, const char *name) { @@ -4173,11 +4136,6 @@ EXPORT_SYMBOL(pci_request_regions); * * Returns 0 on success, or %EBUSY on error. A warning message is also * printed on failure. - * - * NOTE: - * This is a "hybrid" function: It's normally unmanaged, but becomes managed - * when pcim_enable_device() has been called in advance. This hybrid feature is - * DEPRECATED! If you want managed cleanup, use the pcim_* functions instead. */ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *name) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..8c3e5fb2443a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1062,7 +1062,6 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev) int pcim_intx(struct pci_dev *dev, int enable); int pcim_request_region_exclusive(struct pci_dev *pdev, int bar, const char *name); -void pcim_release_region(struct pci_dev *pdev, int bar); /* * Config Address for PCI Configuration Mechanism #1 From b4fb90fb930193bf391b0fd8e9e4fa63b347e3ed Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Mon, 19 May 2025 13:29:56 +0200 Subject: [PATCH 091/147] Documentation/driver-api: Update pcim_enable_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcim_enable_device() is not related anymore to switching the mode of operation of any functions. It merely sets up a devres callback for automatically disabling the PCI device on driver detach. Adjust the function's documentation. Signed-off-by: Philipp Stanner Signed-off-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250519112959.25487-4-phasta@kernel.org --- Documentation/driver-api/driver-model/devres.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 601f1a74d34d..3d56f94ac2ee 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -391,7 +391,7 @@ PCI devm_pci_remap_cfgspace() : ioremap PCI configuration space devm_pci_remap_cfg_resource() : ioremap PCI configuration space resource - pcim_enable_device() : after success, some PCI ops become managed + pcim_enable_device() : after success, the PCI device gets disabled automatically on driver detach pcim_iomap() : do iomap() on a single BAR pcim_iomap_regions() : do request_region() and iomap() on multiple BARs pcim_iomap_table() : array of mapped addresses indexed by BAR From 8e9987485d9ae233fdd5b3f8e6857d28bcfe6a04 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Mon, 19 May 2025 13:29:57 +0200 Subject: [PATCH 092/147] PCI: Remove pcim_request_region_exclusive() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcim_request_region_exclusive() was only needed for redirecting the relatively exotic exclusive request functions in pci.c in case of them operating in managed mode. The managed nature has been removed from those functions and no one else uses pcim_request_region_exclusive(). Remove pcim_request_region_exclusive(). Signed-off-by: Philipp Stanner Signed-off-by: Krzysztof Wilczyński Reviewed-by: Andy Shevchenko Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://lore.kernel.org/r/20250519112959.25487-5-phasta@kernel.org --- drivers/pci/devres.c | 18 ------------------ drivers/pci/pci.h | 2 -- 2 files changed, 20 deletions(-) diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index dde109095428..9f74cfd025fc 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -852,24 +852,6 @@ int pcim_request_region(struct pci_dev *pdev, int bar, const char *name) } EXPORT_SYMBOL(pcim_request_region); -/** - * pcim_request_region_exclusive - Request a PCI BAR exclusively - * @pdev: PCI device to request region for - * @bar: Index of BAR to request - * @name: Name of the driver requesting the resource - * - * Returns: 0 on success, a negative error code on failure. - * - * Request region specified by @bar exclusively. - * - * The region will automatically be released on driver detach. If desired, - * release manually only with pcim_release_region(). - */ -int pcim_request_region_exclusive(struct pci_dev *pdev, int bar, const char *name) -{ - return _pcim_request_region(pdev, bar, name, IORESOURCE_EXCLUSIVE); -} - /** * pcim_release_region - Release a PCI BAR * @pdev: PCI device to operate on diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8c3e5fb2443a..cfc9e71a4d84 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1060,8 +1060,6 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev) #endif int pcim_intx(struct pci_dev *dev, int enable); -int pcim_request_region_exclusive(struct pci_dev *pdev, int bar, - const char *name); /* * Config Address for PCI Configuration Mechanism #1 From 85826c11e77bb8bd18fbdae9bd04e51b4711c6f7 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Mon, 19 May 2025 13:29:58 +0200 Subject: [PATCH 093/147] PCI: Remove exclusive requests flags from _pcim_request_region() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcim_request_region_exclusive(), the only user in PCI devres that needed exclusive region requests, has been removed. All features related to exclusive requests can, therefore, be removed, too. Remove them. Signed-off-by: Philipp Stanner [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250519112959.25487-6-phasta@kernel.org --- drivers/pci/devres.c | 46 +++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index 9f74cfd025fc..c8713571a7b8 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -808,31 +808,6 @@ err: } EXPORT_SYMBOL(pcim_iomap_regions); -static int _pcim_request_region(struct pci_dev *pdev, int bar, const char *name, - int request_flags) -{ - int ret; - struct pcim_addr_devres *res; - - if (!pci_bar_index_is_valid(bar)) - return -EINVAL; - - res = pcim_addr_devres_alloc(pdev); - if (!res) - return -ENOMEM; - res->type = PCIM_ADDR_DEVRES_TYPE_REGION; - res->bar = bar; - - ret = __pcim_request_region(pdev, bar, name, request_flags); - if (ret != 0) { - pcim_addr_devres_free(res); - return ret; - } - - devres_add(&pdev->dev, res); - return 0; -} - /** * pcim_request_region - Request a PCI BAR * @pdev: PCI device to request region for @@ -848,7 +823,26 @@ static int _pcim_request_region(struct pci_dev *pdev, int bar, const char *name, */ int pcim_request_region(struct pci_dev *pdev, int bar, const char *name) { - return _pcim_request_region(pdev, bar, name, 0); + int ret; + struct pcim_addr_devres *res; + + if (!pci_bar_index_is_valid(bar)) + return -EINVAL; + + res = pcim_addr_devres_alloc(pdev); + if (!res) + return -ENOMEM; + res->type = PCIM_ADDR_DEVRES_TYPE_REGION; + res->bar = bar; + + ret = __pcim_request_region(pdev, bar, name, 0); + if (ret != 0) { + pcim_addr_devres_free(res); + return ret; + } + + devres_add(&pdev->dev, res); + return 0; } EXPORT_SYMBOL(pcim_request_region); From bcfc67157e413cbb41d363f8ee961a01130d0a73 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Mon, 19 May 2025 13:29:59 +0200 Subject: [PATCH 094/147] PCI: Remove redundant set of request functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the demangling of the hybrid devres functions within PCI was implemented, it was necessary to implement several PCI functions a second time to avoid cyclic calls, since the hybrid functions in pci.c call the managed functions in devres.c, which in turn can be directly used outside of PCI and needed request infrastructure, too. Therefore, __pcim_request_region_range(), __pci_release_region_range() and wrappers around them were implemented. The hybrid nature has recently been removed from all functions in pci.c. Therefore, the functions in devres.c can now directly use their counterparts in pci.c without causing a call-cycle. Remove __pcim_request_region_range(), __pcim_request_region_range() and the wrappers. Use the corresponding request functions from pci.c in devres.c Signed-off-by: Philipp Stanner Signed-off-by: Krzysztof Wilczyński Reviewed-by: Andy Shevchenko Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://lore.kernel.org/r/20250519112959.25487-7-phasta@kernel.org --- drivers/pci/devres.c | 110 ++----------------------------------------- 1 file changed, 5 insertions(+), 105 deletions(-) diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index c8713571a7b8..9f4190501395 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -70,106 +70,6 @@ static inline void pcim_addr_devres_clear(struct pcim_addr_devres *res) res->bar = -1; } -/* - * The following functions, __pcim_*_region*, exist as counterparts to the - * versions from pci.c - which, unfortunately, were in the past in "hybrid - * mode", i.e., sometimes managed, sometimes not. - * - * To separate the APIs cleanly, we defined our own, simplified versions here. - * - * TODO: unify those functions with the counterparts in pci.c - */ - -/** - * __pcim_request_region_range - Request a ranged region - * @pdev: PCI device the region belongs to - * @bar: BAR the range is within - * @offset: offset from the BAR's start address - * @maxlen: length in bytes, beginning at @offset - * @name: name of the driver requesting the resource - * @req_flags: flags for the request, e.g., for kernel-exclusive requests - * - * Returns: 0 on success, a negative error code on failure. - * - * Request a range within a device's PCI BAR. Sanity check the input. - */ -static int __pcim_request_region_range(struct pci_dev *pdev, int bar, - unsigned long offset, - unsigned long maxlen, - const char *name, int req_flags) -{ - resource_size_t start = pci_resource_start(pdev, bar); - resource_size_t len = pci_resource_len(pdev, bar); - unsigned long dev_flags = pci_resource_flags(pdev, bar); - - if (start == 0 || len == 0) /* Unused BAR. */ - return 0; - if (len <= offset) - return -EINVAL; - - start += offset; - len -= offset; - - if (len > maxlen && maxlen != 0) - len = maxlen; - - if (dev_flags & IORESOURCE_IO) { - if (!request_region(start, len, name)) - return -EBUSY; - } else if (dev_flags & IORESOURCE_MEM) { - if (!__request_mem_region(start, len, name, req_flags)) - return -EBUSY; - } else { - /* That's not a device we can request anything on. */ - return -ENODEV; - } - - return 0; -} - -static void __pcim_release_region_range(struct pci_dev *pdev, int bar, - unsigned long offset, - unsigned long maxlen) -{ - resource_size_t start = pci_resource_start(pdev, bar); - resource_size_t len = pci_resource_len(pdev, bar); - unsigned long flags = pci_resource_flags(pdev, bar); - - if (len <= offset || start == 0) - return; - - if (len == 0 || maxlen == 0) /* This an unused BAR. Do nothing. */ - return; - - start += offset; - len -= offset; - - if (len > maxlen) - len = maxlen; - - if (flags & IORESOURCE_IO) - release_region(start, len); - else if (flags & IORESOURCE_MEM) - release_mem_region(start, len); -} - -static int __pcim_request_region(struct pci_dev *pdev, int bar, - const char *name, int flags) -{ - unsigned long offset = 0; - unsigned long len = pci_resource_len(pdev, bar); - - return __pcim_request_region_range(pdev, bar, offset, len, name, flags); -} - -static void __pcim_release_region(struct pci_dev *pdev, int bar) -{ - unsigned long offset = 0; - unsigned long len = pci_resource_len(pdev, bar); - - __pcim_release_region_range(pdev, bar, offset, len); -} - static void pcim_addr_resource_release(struct device *dev, void *resource_raw) { struct pci_dev *pdev = to_pci_dev(dev); @@ -177,11 +77,11 @@ static void pcim_addr_resource_release(struct device *dev, void *resource_raw) switch (res->type) { case PCIM_ADDR_DEVRES_TYPE_REGION: - __pcim_release_region(pdev, res->bar); + pci_release_region(pdev, res->bar); break; case PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING: pci_iounmap(pdev, res->baseaddr); - __pcim_release_region(pdev, res->bar); + pci_release_region(pdev, res->bar); break; case PCIM_ADDR_DEVRES_TYPE_MAPPING: pci_iounmap(pdev, res->baseaddr); @@ -720,7 +620,7 @@ void __iomem *pcim_iomap_region(struct pci_dev *pdev, int bar, res->type = PCIM_ADDR_DEVRES_TYPE_REGION_MAPPING; res->bar = bar; - ret = __pcim_request_region(pdev, bar, name, 0); + ret = pci_request_region(pdev, bar, name); if (ret != 0) goto err_region; @@ -734,7 +634,7 @@ void __iomem *pcim_iomap_region(struct pci_dev *pdev, int bar, return res->baseaddr; err_iomap: - __pcim_release_region(pdev, bar); + pci_release_region(pdev, bar); err_region: pcim_addr_devres_free(res); @@ -835,7 +735,7 @@ int pcim_request_region(struct pci_dev *pdev, int bar, const char *name) res->type = PCIM_ADDR_DEVRES_TYPE_REGION; res->bar = bar; - ret = __pcim_request_region(pdev, bar, name, 0); + ret = pci_request_region(pdev, bar, name); if (ret != 0) { pcim_addr_devres_free(res); return ret; From 90ffe1f093e85ebb70212909607e0c0517aa65a5 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Mon, 19 May 2025 13:30:00 +0200 Subject: [PATCH 095/147] PCI: Remove hybrid-devres usage warnings from kernel-doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci/iomap.c still contains warnings about those functions not behaving in a managed manner if pcim_enable_device() was called. Since all hybrid behavior that users could know about has been removed by now, those explicit warnings are no longer necessary. Remove the hybrid-devres usage warnings from the kernel-doc. Signed-off-by: Philipp Stanner [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński Reviewed-by: Andy Shevchenko Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://lore.kernel.org/r/20250519112959.25487-8-phasta@kernel.org --- drivers/pci/iomap.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/pci/iomap.c b/drivers/pci/iomap.c index fe706ed946df..ea86c282a386 100644 --- a/drivers/pci/iomap.c +++ b/drivers/pci/iomap.c @@ -25,10 +25,6 @@ * * @maxlen specifies the maximum length to map. If you want to get access to * the complete BAR from offset to the end, pass %0 here. - * - * NOTE: - * This function is never managed, even if you initialized with - * pcim_enable_device(). * */ void __iomem *pci_iomap_range(struct pci_dev *dev, int bar, @@ -76,10 +72,6 @@ EXPORT_SYMBOL(pci_iomap_range); * * @maxlen specifies the maximum length to map. If you want to get access to * the complete BAR from offset to the end, pass %0 here. - * - * NOTE: - * This function is never managed, even if you initialized with - * pcim_enable_device(). * */ void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar, @@ -127,10 +119,6 @@ EXPORT_SYMBOL_GPL(pci_iomap_wc_range); * * @maxlen specifies the maximum length to map. If you want to get access to * the complete BAR without checking for its length first, pass %0 here. - * - * NOTE: - * This function is never managed, even if you initialized with - * pcim_enable_device(). If you need automatic cleanup, use pcim_iomap(). * */ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) { @@ -152,10 +140,6 @@ EXPORT_SYMBOL(pci_iomap); * * @maxlen specifies the maximum length to map. If you want to get access to * the complete BAR without checking for its length first, pass %0 here. - * - * NOTE: - * This function is never managed, even if you initialized with - * pcim_enable_device(). * */ void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen) { From 1d79596e86613727006161439f3781e74bdb9fac Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 6 May 2025 11:51:39 +0200 Subject: [PATCH 096/147] PCI: dwc: ep: Fix errno typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix errno typo in kernel-doc comments. Fixes: 7cbebc86c72a ("PCI: dwc: ep: Add Kernel-doc comments for APIs") Signed-off-by: Niklas Cassel Signed-off-by: Krzysztof Wilczyński Reviewed-by: Frank Li Link: https://lore.kernel.org/r/20250506095138.482485-2-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-designware-ep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index f3daf46b5e63..845862f1a1cb 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -671,7 +671,7 @@ static const struct pci_epc_ops epc_ops = { * @ep: DWC EP device * @func_no: Function number of the endpoint * - * Return: 0 if success, errono otherwise. + * Return: 0 if success, errno otherwise. */ int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no) { @@ -690,7 +690,7 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq); * @func_no: Function number of the endpoint * @interrupt_num: Interrupt number to be raised * - * Return: 0 if success, errono otherwise. + * Return: 0 if success, errno otherwise. */ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u8 interrupt_num) From 003d15b30f3690b14315822439edc2c3f823c6cd Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 7 May 2025 19:09:47 +0900 Subject: [PATCH 097/147] PCI: rcar-gen4: Document how to obtain platform firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renesas R-Car V4H (r8a779g0) has PCIe controller, and it requires specific firmware downloading. So, add a document about the firmware how to get. Signed-off-by: Yoshihiro Shimoda [kwilczynski: commit log, refactor the document content and then add this new file to a correct index under the top-level PCI documentation] Signed-off-by: Krzysztof Wilczyński Reviewed-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20250507100947.608875-1-yoshihiro.shimoda.uh@renesas.com --- Documentation/PCI/controller/index.rst | 10 ++++++ .../PCI/controller/rcar-pcie-firmware.rst | 32 +++++++++++++++++++ Documentation/PCI/index.rst | 1 + MAINTAINERS | 1 + 4 files changed, 44 insertions(+) create mode 100644 Documentation/PCI/controller/index.rst create mode 100644 Documentation/PCI/controller/rcar-pcie-firmware.rst diff --git a/Documentation/PCI/controller/index.rst b/Documentation/PCI/controller/index.rst new file mode 100644 index 000000000000..c2ce9ccdcfa0 --- /dev/null +++ b/Documentation/PCI/controller/index.rst @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================================== +PCI Native Host Bridge and Endpoint Drivers +=========================================== + +.. toctree:: + :maxdepth: 2 + + rcar-pcie-firmware diff --git a/Documentation/PCI/controller/rcar-pcie-firmware.rst b/Documentation/PCI/controller/rcar-pcie-firmware.rst new file mode 100644 index 000000000000..67d3bf66e315 --- /dev/null +++ b/Documentation/PCI/controller/rcar-pcie-firmware.rst @@ -0,0 +1,32 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================================= +Firmware of PCIe controller for Renesas R-Car V4H +================================================= + +Renesas R-Car V4H (r8a779g0) has a PCIe controller, requiring a specific +firmware download during startup. + +However, Renesas currently cannot distribute the firmware free of charge. + +The firmware file "104_PCIe_fw_addr_data_ver1.05.txt" (note that the file name +might be different between different datasheet revisions) can be found in the +datasheet encoded as text, and as such, the file's content must be converted +back to binary form. This can be achieved using the following example script: + +.. code-block:: sh + + $ awk '/^\s*0x[0-9A-Fa-f]{4}\s+0x[0-9A-Fa-f]{4}/ { print substr($2,5,2) substr($2,3,2) }' \ + 104_PCIe_fw_addr_data_ver1.05.txt | \ + xxd -p -r > rcar_gen4_pcie.bin + +Once the text content has been converted into a binary firmware file, verify +its checksum as follows: + +.. code-block:: sh + + $ sha1sum rcar_gen4_pcie.bin + 1d0bd4b189b4eb009f5d564b1f93a79112994945 rcar_gen4_pcie.bin + +The resulting binary file called "rcar_gen4_pcie.bin" should be placed in the +"/lib/firmware" directory before the driver runs. diff --git a/Documentation/PCI/index.rst b/Documentation/PCI/index.rst index 5e7c4e6e726b..5d720d2a415e 100644 --- a/Documentation/PCI/index.rst +++ b/Documentation/PCI/index.rst @@ -17,5 +17,6 @@ PCI Bus Subsystem pci-error-recovery pcieaer-howto endpoint/index + controller/index boot-interrupts tph diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..ceceb4ecdb3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18531,6 +18531,7 @@ M: Yoshihiro Shimoda L: linux-pci@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Maintained +F: Documentation/PCI/controller/rcar-pcie-firmware.rst F: Documentation/devicetree/bindings/pci/*rcar* F: drivers/pci/controller/*rcar* F: drivers/pci/controller/dwc/*rcar* From dfc970ad61973111932fc282ebab8d825056d5ab Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Thu, 22 May 2025 10:46:27 +0200 Subject: [PATCH 098/147] PCI: Remove function pcim_intx() prototype from pci.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The subsystem-internal header pci.h still contains the function prototype of pcim_intx(), which has since been made public in the global header. Remove the redundant function prototype. Signed-off-by: Philipp Stanner [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20250522084626.150148-2-phasta@kernel.org --- drivers/pci/pci.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index cfc9e71a4d84..2dd7fa93d95b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1059,8 +1059,6 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev) } #endif -int pcim_intx(struct pci_dev *dev, int enable); - /* * Config Address for PCI Configuration Mechanism #1 * From 631b2af2f35737750af284be22e63da56bf20139 Mon Sep 17 00:00:00 2001 From: Zhe Qiao Date: Wed, 30 Apr 2025 14:06:03 +0800 Subject: [PATCH 099/147] PCI/ACPI: Fix allocated memory release on error in pci_acpi_scan_root() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the pci_acpi_scan_root() function, when creating a PCI bus fails, we need to free up the previously allocated memory, which can avoid invalid memory usage and save resources. Fixes: 789befdfa389 ("arm64: PCI: Migrate ACPI related functions to pci-acpi.c") Signed-off-by: Zhe Qiao [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20250430060603.381504-1-qiaozhe@iscas.ac.cn --- drivers/pci/pci-acpi.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index af370628e583..b78e0e417324 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1676,24 +1676,19 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) return NULL; root_ops = kzalloc(sizeof(*root_ops), GFP_KERNEL); - if (!root_ops) { - kfree(ri); - return NULL; - } + if (!root_ops) + goto free_ri; ri->cfg = pci_acpi_setup_ecam_mapping(root); - if (!ri->cfg) { - kfree(ri); - kfree(root_ops); - return NULL; - } + if (!ri->cfg) + goto free_root_ops; root_ops->release_info = pci_acpi_generic_release_info; root_ops->prepare_resources = pci_acpi_root_prepare_resources; root_ops->pci_ops = (struct pci_ops *)&ri->cfg->ops->pci_ops; bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg); if (!bus) - return NULL; + goto free_cfg; /* If we must preserve the resource configuration, claim now */ host = pci_find_host_bridge(bus); @@ -1710,6 +1705,14 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) pcie_bus_configure_settings(child); return bus; + +free_cfg: + pci_ecam_free(ri->cfg); +free_root_ops: + kfree(root_ops); +free_ri: + kfree(ri); + return NULL; } void pcibios_add_bus(struct pci_bus *bus) From a424b598e6a6c1e69a2bb801d6fd16e805ab2c38 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:07 -0500 Subject: [PATCH 100/147] PCI/DPC: Initialize aer_err_info before using it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the struct aer_err_info "info" was allocated on the stack without being initialized, so it contained junk except for the fields we explicitly set later. Initialize "info" at declaration so it starts as all zeros. Fixes: 8aefa9b0d910 ("PCI/DPC: Print AER status in DPC event handling") Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-2-helgaas@kernel.org --- drivers/pci/pcie/dpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index df42f15c9829..3daaf61c79c9 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -258,7 +258,7 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev, void dpc_process_error(struct pci_dev *pdev) { u16 cap = pdev->dpc_cap, status, source, reason, ext_reason; - struct aer_err_info info; + struct aer_err_info info = {}; pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &source); From a0b62cc310239c7f1323fb20bd3789f21bdd8615 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:08 -0500 Subject: [PATCH 101/147] PCI/DPC: Log Error Source ID only when valid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DPC Error Source ID is only valid when the DPC Trigger Reason indicates that DPC was triggered due to reception of an ERR_NONFATAL or ERR_FATAL Message (PCIe r6.0, sec 7.9.14.5). When DPC was triggered by ERR_NONFATAL (PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE) or ERR_FATAL (PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) from a downstream device, log the Error Source ID (decoded into domain/bus/device/function). Don't print the source otherwise, since it's not valid. For DPC trigger due to reception of ERR_NONFATAL or ERR_FATAL, the dmesg logging changes: - pci 0000:00:01.0: DPC: containment event, status:0x000d source:0x0200 - pci 0000:00:01.0: DPC: ERR_FATAL detected + pci 0000:00:01.0: DPC: containment event, status:0x000d, ERR_FATAL received from 0000:02:00.0 and when DPC triggered for other reasons, where DPC Error Source ID is undefined, e.g., unmasked uncorrectable error: - pci 0000:00:01.0: DPC: containment event, status:0x0009 source:0x0200 - pci 0000:00:01.0: DPC: unmasked uncorrectable error detected + pci 0000:00:01.0: DPC: containment event, status:0x0009: unmasked uncorrectable error detected Previously the "containment event" message was at KERN_INFO and the "%s detected" message was at KERN_WARNING. Now the single message is at KERN_WARNING. Fixes: 26e515713342 ("PCI: Add Downstream Port Containment driver") Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Jonathan Cameron Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20250522232339.1525671-3-helgaas@kernel.org --- drivers/pci/pcie/dpc.c | 64 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 3daaf61c79c9..9d85f1b3b761 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -261,37 +261,45 @@ void dpc_process_error(struct pci_dev *pdev) struct aer_err_info info = {}; pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &status); - pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, &source); - - pci_info(pdev, "containment event, status:%#06x source:%#06x\n", - status, source); reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN; - ext_reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT; - pci_warn(pdev, "%s detected\n", - (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR) ? - "unmasked uncorrectable error" : - (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE) ? - "ERR_NONFATAL" : - (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) ? - "ERR_FATAL" : - (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) ? - "RP PIO error" : - (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER) ? - "software trigger" : - "reserved error"); - /* show RP PIO error detail information */ - if (pdev->dpc_rp_extensions && - reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT && - ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) - dpc_process_rp_pio_error(pdev); - else if (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR && - dpc_get_aer_uncorrect_severity(pdev, &info) && - aer_get_device_error_info(pdev, &info)) { - aer_print_error(pdev, &info); - pci_aer_clear_nonfatal_status(pdev); - pci_aer_clear_fatal_status(pdev); + switch (reason) { + case PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR: + pci_warn(pdev, "containment event, status:%#06x: unmasked uncorrectable error detected\n", + status); + if (dpc_get_aer_uncorrect_severity(pdev, &info) && + aer_get_device_error_info(pdev, &info)) { + aer_print_error(pdev, &info); + pci_aer_clear_nonfatal_status(pdev); + pci_aer_clear_fatal_status(pdev); + } + break; + case PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE: + case PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE: + pci_read_config_word(pdev, cap + PCI_EXP_DPC_SOURCE_ID, + &source); + pci_warn(pdev, "containment event, status:%#06x, %s received from %04x:%02x:%02x.%d\n", + status, + (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) ? + "ERR_FATAL" : "ERR_NONFATAL", + pci_domain_nr(pdev->bus), PCI_BUS_NUM(source), + PCI_SLOT(source), PCI_FUNC(source)); + break; + case PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT: + ext_reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT; + pci_warn(pdev, "containment event, status:%#06x: %s detected\n", + status, + (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) ? + "RP PIO error" : + (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER) ? + "software trigger" : + "reserved error"); + /* show RP PIO error detail information */ + if (ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO && + pdev->dpc_rp_extensions) + dpc_process_rp_pio_error(pdev); + break; } } From 6fc4dae74afcf29ef82afbaaa9b082893871eda4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:09 -0500 Subject: [PATCH 102/147] PCI/AER: Factor COR/UNCOR error handling out from aer_isr_one_error() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aer_isr_one_error() duplicates the Error Source ID logging and AER error processing for Correctable Errors and Uncorrectable Errors. Factor out the duplicated code to aer_isr_one_error_type(). aer_isr_one_error() doesn't need the struct aer_rpc pointer, so pass it the Root Port or RCEC pci_dev pointer instead. Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-4-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index a1cf8c7ef628..568229288ca3 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1273,17 +1273,32 @@ static inline void aer_process_err_devices(struct aer_err_info *e_info) } /** - * aer_isr_one_error - consume an error detected by Root Port - * @rpc: pointer to the Root Port which holds an error + * aer_isr_one_error_type - consume a Correctable or Uncorrectable Error + * detected by Root Port or RCEC + * @root: pointer to Root Port or RCEC that signaled AER interrupt + * @info: pointer to AER error info + */ +static void aer_isr_one_error_type(struct pci_dev *root, + struct aer_err_info *info) +{ + aer_print_port_info(root, info); + + if (find_source_device(root, info)) + aer_process_err_devices(info); +} + +/** + * aer_isr_one_error - consume error(s) signaled by an AER interrupt from + * Root Port or RCEC + * @root: pointer to Root Port or RCEC that signaled AER interrupt * @e_src: pointer to an error source */ -static void aer_isr_one_error(struct aer_rpc *rpc, +static void aer_isr_one_error(struct pci_dev *root, struct aer_err_source *e_src) { - struct pci_dev *pdev = rpc->rpd; struct aer_err_info e_info; - pci_rootport_aer_stats_incr(pdev, e_src); + pci_rootport_aer_stats_incr(root, e_src); /* * There is a possibility that both correctable error and @@ -1297,10 +1312,8 @@ static void aer_isr_one_error(struct aer_rpc *rpc, e_info.multi_error_valid = 1; else e_info.multi_error_valid = 0; - aer_print_port_info(pdev, &e_info); - if (find_source_device(pdev, &e_info)) - aer_process_err_devices(&e_info); + aer_isr_one_error_type(root, &e_info); } if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { @@ -1316,10 +1329,7 @@ static void aer_isr_one_error(struct aer_rpc *rpc, else e_info.multi_error_valid = 0; - aer_print_port_info(pdev, &e_info); - - if (find_source_device(pdev, &e_info)) - aer_process_err_devices(&e_info); + aer_isr_one_error_type(root, &e_info); } } @@ -1340,7 +1350,7 @@ static irqreturn_t aer_isr(int irq, void *context) return IRQ_NONE; while (kfifo_get(&rpc->aer_fifo, &e_src)) - aer_isr_one_error(rpc, &e_src); + aer_isr_one_error(rpc->rpd, &e_src); return IRQ_HANDLED; } From 6a1eda745967a1e84f6e4cae14c118c97319891e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:10 -0500 Subject: [PATCH 103/147] PCI/AER: Consolidate Error Source ID logging in aer_isr_one_error_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we decoded the AER Error Source ID in aer_isr_one_error_type(), then again in find_source_device() if we didn't find any devices with errors logged in their AER Capabilities. Consolidate this so we only decode and log the Error Source ID once in aer_isr_one_error_type(). Add a "found" parameter so we can add a note when we didn't find any downstream devices with errors logged in their AER Capability. This changes the dmesg logging when we found no devices with errors logged: - pci 0000:00:01.0: AER: Correctable error message received from 0000:02:00.0 - pci 0000:00:01.0: AER: found no error details for 0000:02:00.0 + pci 0000:00:01.0: AER: Correctable error message received from 0000:02:00.0 (no details found) Signed-off-by: Bjorn Helgaas Reviewed-by: Jonathan Cameron Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Link: https://patch.msgid.link/20250522232339.1525671-5-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 568229288ca3..fe6d323306a0 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -733,16 +733,17 @@ out: info->severity, info->tlp_header_valid, &info->tlp); } -static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) +static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info, + bool found) { u8 bus = info->id >> 8; u8 devfn = info->id & 0xff; - pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d\n", + pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d%s\n", info->multi_error_valid ? "Multiple " : "", aer_error_severity_string[info->severity], pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), - PCI_FUNC(devfn)); + PCI_FUNC(devfn), found ? "" : " (no details found"); } #ifdef CONFIG_ACPI_APEI_PCIEAER @@ -926,15 +927,8 @@ static bool find_source_device(struct pci_dev *parent, else pci_walk_bus(parent->subordinate, find_device_iter, e_info); - if (!e_info->error_dev_num) { - u8 bus = e_info->id >> 8; - u8 devfn = e_info->id & 0xff; - - pci_info(parent, "found no error details for %04x:%02x:%02x.%d\n", - pci_domain_nr(parent->bus), bus, PCI_SLOT(devfn), - PCI_FUNC(devfn)); + if (!e_info->error_dev_num) return false; - } return true; } @@ -1281,9 +1275,11 @@ static inline void aer_process_err_devices(struct aer_err_info *e_info) static void aer_isr_one_error_type(struct pci_dev *root, struct aer_err_info *info) { - aer_print_port_info(root, info); + bool found; - if (find_source_device(root, info)) + found = find_source_device(root, info); + aer_print_port_info(root, info, found); + if (found) aer_process_err_devices(info); } From f40bd2865501437bf5dfc7167be7b5c8f536b323 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:11 -0500 Subject: [PATCH 104/147] PCI/AER: Extract bus/dev/fn in aer_print_port_info() with PCI_BUS_NUM(), etc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use PCI_BUS_NUM(), PCI_SLOT(), PCI_FUNC() to extract the bus number, device, and function number directly from the Error Source ID. There's no need to shift and mask it explicitly. Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-6-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index fe6d323306a0..18005615d376 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -736,14 +736,14 @@ out: static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info, bool found) { - u8 bus = info->id >> 8; - u8 devfn = info->id & 0xff; + u16 source = info->id; pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d%s\n", info->multi_error_valid ? "Multiple " : "", aer_error_severity_string[info->severity], - pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn), - PCI_FUNC(devfn), found ? "" : " (no details found"); + pci_domain_nr(dev->bus), PCI_BUS_NUM(source), + PCI_SLOT(source), PCI_FUNC(source), + found ? "" : " (no details found"); } #ifdef CONFIG_ACPI_APEI_PCIEAER From 99c3fd0de8eb4e35459aaac5c1aa315a1a6843a6 Mon Sep 17 00:00:00 2001 From: Jon Pan-Doh Date: Thu, 22 May 2025 18:21:12 -0500 Subject: [PATCH 105/147] PCI/AER: Rename aer_print_port_info() to aer_print_source() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename aer_print_port_info() to aer_print_source() to be more descriptive. This logs the Error Source ID logged by a Root Port or Root Complex Event Collector when it receives an ERR_COR, ERR_NONFATAL, or ERR_FATAL Message. [bhelgaas: aer_print_rp_info() -> aer_print_source()] Signed-off-by: Jon Pan-Doh Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-7-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 18005615d376..8b23ef90345b 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -733,8 +733,8 @@ out: info->severity, info->tlp_header_valid, &info->tlp); } -static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info, - bool found) +static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info, + bool found) { u16 source = info->id; @@ -1278,7 +1278,7 @@ static void aer_isr_one_error_type(struct pci_dev *root, bool found; found = find_source_device(root, info); - aer_print_port_info(root, info, found); + aer_print_source(root, info, found); if (found) aer_process_err_devices(info); } From ca2426a570ab4bdf6185aea034ee09184420bd0d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:13 -0500 Subject: [PATCH 106/147] PCI/AER: Move aer_print_source() earlier in file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move aer_print_source() earlier in the file so a future change can use it from aer_print_error(), where it's easier to rate limit it. Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-8-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 8b23ef90345b..c0481550363b 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -696,6 +696,19 @@ static void __aer_print_error(struct pci_dev *dev, pci_dev_aer_stats_incr(dev, info); } +static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info, + bool found) +{ + u16 source = info->id; + + pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d%s\n", + info->multi_error_valid ? "Multiple " : "", + aer_error_severity_string[info->severity], + pci_domain_nr(dev->bus), PCI_BUS_NUM(source), + PCI_SLOT(source), PCI_FUNC(source), + found ? "" : " (no details found"); +} + void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { int layer, agent; @@ -733,19 +746,6 @@ out: info->severity, info->tlp_header_valid, &info->tlp); } -static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info, - bool found) -{ - u16 source = info->id; - - pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d%s\n", - info->multi_error_valid ? "Multiple " : "", - aer_error_severity_string[info->severity], - pci_domain_nr(dev->bus), PCI_BUS_NUM(source), - PCI_SLOT(source), PCI_FUNC(source), - found ? "" : " (no details found"); -} - #ifdef CONFIG_ACPI_APEI_PCIEAER int cper_severity_to_aer(int cper_severity) { From 57964ba39057a76f3485437347bb4219be9c5b52 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:14 -0500 Subject: [PATCH 107/147] PCI/AER: Initialize aer_err_info before using it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the struct aer_err_info "e_info" was allocated on the stack without being initialized, so it contained junk except for the fields we explicitly set later. Initialize "e_info" at declaration with a designated initializer list, which initializes the other members to zero. Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-9-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index c0481550363b..109f5e0ade8a 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -1290,9 +1290,9 @@ static void aer_isr_one_error_type(struct pci_dev *root, * @e_src: pointer to an error source */ static void aer_isr_one_error(struct pci_dev *root, - struct aer_err_source *e_src) + struct aer_err_source *e_src) { - struct aer_err_info e_info; + u32 status = e_src->status; pci_rootport_aer_stats_incr(root, e_src); @@ -1300,30 +1300,25 @@ static void aer_isr_one_error(struct pci_dev *root, * There is a possibility that both correctable error and * uncorrectable error being logged. Report correctable error first. */ - if (e_src->status & PCI_ERR_ROOT_COR_RCV) { - e_info.id = ERR_COR_ID(e_src->id); - e_info.severity = AER_CORRECTABLE; - - if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV) - e_info.multi_error_valid = 1; - else - e_info.multi_error_valid = 0; + if (status & PCI_ERR_ROOT_COR_RCV) { + int multi = status & PCI_ERR_ROOT_MULTI_COR_RCV; + struct aer_err_info e_info = { + .id = ERR_COR_ID(e_src->id), + .severity = AER_CORRECTABLE, + .multi_error_valid = multi ? 1 : 0, + }; aer_isr_one_error_type(root, &e_info); } - if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { - e_info.id = ERR_UNCOR_ID(e_src->id); - - if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) - e_info.severity = AER_FATAL; - else - e_info.severity = AER_NONFATAL; - - if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV) - e_info.multi_error_valid = 1; - else - e_info.multi_error_valid = 0; + if (status & PCI_ERR_ROOT_UNCOR_RCV) { + int fatal = status & PCI_ERR_ROOT_FATAL_RCV; + int multi = status & PCI_ERR_ROOT_MULTI_UNCOR_RCV; + struct aer_err_info e_info = { + .id = ERR_UNCOR_ID(e_src->id), + .severity = fatal ? AER_FATAL : AER_NONFATAL, + .multi_error_valid = multi ? 1 : 0, + }; aer_isr_one_error_type(root, &e_info); } From ad9839137cf9fb0f0c2d531bd04bc4382e6f2de9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:15 -0500 Subject: [PATCH 108/147] PCI/AER: Simplify pci_print_aer() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify pci_print_aer() by initializing the struct aer_err_info "info" with a designated initializer list (it was previously initialized with memset()) and using pci_name(). Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-10-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 109f5e0ade8a..dc5f4bebd613 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -766,7 +766,10 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, { int layer, agent, tlp_header_valid = 0; u32 status, mask; - struct aer_err_info info; + struct aer_err_info info = { + .severity = aer_severity, + .first_error = PCI_ERR_CAP_FEP(aer->cap_control), + }; if (aer_severity == AER_CORRECTABLE) { status = aer->cor_status; @@ -777,14 +780,11 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, tlp_header_valid = status & AER_LOG_TLP_MASKS; } - layer = AER_GET_LAYER_ERROR(aer_severity, status); - agent = AER_GET_AGENT(aer_severity, status); - - memset(&info, 0, sizeof(info)); - info.severity = aer_severity; info.status = status; info.mask = mask; - info.first_error = PCI_ERR_CAP_FEP(aer->cap_control); + + layer = AER_GET_LAYER_ERROR(aer_severity, status); + agent = AER_GET_AGENT(aer_severity, status); pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); __aer_print_error(dev, &info); @@ -798,7 +798,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, if (tlp_header_valid) pcie_print_tlp_log(dev, &aer->header_log, dev_fmt(" ")); - trace_aer_event(dev_name(&dev->dev), (status & ~mask), + trace_aer_event(pci_name(dev), (status & ~mask), aer_severity, tlp_header_valid, &aer->header_log); } EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL"); From 88a7765e62b9e4c79c7ca2c7b749ae04f54a5668 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:16 -0500 Subject: [PATCH 109/147] PCI/AER: Update statistics before ratelimiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two AER logging entry points: - aer_print_error() is used by DPC (dpc_process_error()) and native AER handling (aer_process_err_devices()). - pci_print_aer() is used by GHES (aer_recover_work_func()) and CXL (cxl_handle_rdport_errors()) Both use __aer_print_error() to print the AER error bits. Previously __aer_print_error() also incremented the AER statistics via pci_dev_aer_stats_incr(). Call pci_dev_aer_stats_incr() early in the entry points instead of in __aer_print_error() so we update the statistics even if the actual printing of error bits is rate limited by a future change. Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-11-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index dc5f4bebd613..53f460bb7e6c 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -693,7 +693,6 @@ static void __aer_print_error(struct pci_dev *dev, aer_printk(level, dev, " [%2d] %-22s%s\n", i, errmsg, info->first_error == i ? " (First)" : ""); } - pci_dev_aer_stats_incr(dev, info); } static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info, @@ -715,6 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) int id = pci_dev_id(dev); const char *level; + pci_dev_aer_stats_incr(dev, info); + if (!info->status) { pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", aer_error_severity_string[info->severity]); @@ -783,6 +784,8 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, info.status = status; info.mask = mask; + pci_dev_aer_stats_incr(dev, &info); + layer = AER_GET_LAYER_ERROR(aer_severity, status); agent = AER_GET_AGENT(aer_severity, status); From 6bb4befbd65fa7f99688fb707e376637e5acfe36 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:17 -0500 Subject: [PATCH 110/147] PCI/AER: Trace error event before ratelimiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As with the AER statistics, we always want to emit trace events, even if the actual dmesg logging is rate limited. Call trace_aer_event() immediately after pci_dev_aer_stats_incr() so both happen before ratelimiting. Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-12-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 53f460bb7e6c..636bcd92afa1 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -715,6 +715,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) const char *level; pci_dev_aer_stats_incr(dev, info); + trace_aer_event(pci_name(dev), (info->status & ~info->mask), + info->severity, info->tlp_header_valid, &info->tlp); if (!info->status) { pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", @@ -742,9 +744,6 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) out: if (info->id && info->error_dev_num > 1 && info->id == id) pci_err(dev, " Error of this Agent is reported first\n"); - - trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), - info->severity, info->tlp_header_valid, &info->tlp); } #ifdef CONFIG_ACPI_APEI_PCIEAER @@ -785,6 +784,8 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, info.mask = mask; pci_dev_aer_stats_incr(dev, &info); + trace_aer_event(pci_name(dev), (status & ~mask), + aer_severity, tlp_header_valid, &aer->header_log); layer = AER_GET_LAYER_ERROR(aer_severity, status); agent = AER_GET_AGENT(aer_severity, status); @@ -800,9 +801,6 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, if (tlp_header_valid) pcie_print_tlp_log(dev, &aer->header_log, dev_fmt(" ")); - - trace_aer_event(pci_name(dev), (status & ~mask), - aer_severity, tlp_header_valid, &aer->header_log); } EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL"); From c8f6791e33a7757025285db26f3b382cdcb7f7cd Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Thu, 22 May 2025 18:21:18 -0500 Subject: [PATCH 111/147] PCI/AER: Check log level once and remember it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reporting an AER error, we check its type multiple times to determine the log level for each message. Do this check only in the top-level functions (aer_isr_one_error(), pci_print_aer()) and save the level in struct aer_err_info. [bhelgaas: save log level in struct aer_err_info instead of passing it as a parameter] Signed-off-by: Karolina Stolarek Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-13-helgaas@kernel.org --- drivers/pci/pci.h | 1 + drivers/pci/pcie/aer.c | 21 ++++++++++----------- drivers/pci/pcie/dpc.c | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b81e99cd4b62..705f9ef58acc 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev) struct aer_err_info { struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; int error_dev_num; + const char *level; /* printk level */ unsigned int id:16; diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 636bcd92afa1..f80c78846a14 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -669,21 +669,18 @@ static void pci_rootport_aer_stats_incr(struct pci_dev *pdev, } } -static void __aer_print_error(struct pci_dev *dev, - struct aer_err_info *info) +static void __aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { const char **strings; unsigned long status = info->status & ~info->mask; - const char *level, *errmsg; + const char *level = info->level; + const char *errmsg; int i; - if (info->severity == AER_CORRECTABLE) { + if (info->severity == AER_CORRECTABLE) strings = aer_correctable_error_string; - level = KERN_WARNING; - } else { + else strings = aer_uncorrectable_error_string; - level = KERN_ERR; - } for_each_set_bit(i, &status, 32) { errmsg = strings[i]; @@ -712,7 +709,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { int layer, agent; int id = pci_dev_id(dev); - const char *level; + const char *level = info->level; pci_dev_aer_stats_incr(dev, info); trace_aer_event(pci_name(dev), (info->status & ~info->mask), @@ -727,8 +724,6 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) layer = AER_GET_LAYER_ERROR(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status); - level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR; - aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n", aer_error_severity_string[info->severity], aer_error_layer[layer], aer_agent_string[agent]); @@ -774,9 +769,11 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, if (aer_severity == AER_CORRECTABLE) { status = aer->cor_status; mask = aer->cor_mask; + info.level = KERN_WARNING; } else { status = aer->uncor_status; mask = aer->uncor_mask; + info.level = KERN_ERR; tlp_header_valid = status & AER_LOG_TLP_MASKS; } @@ -1306,6 +1303,7 @@ static void aer_isr_one_error(struct pci_dev *root, struct aer_err_info e_info = { .id = ERR_COR_ID(e_src->id), .severity = AER_CORRECTABLE, + .level = KERN_WARNING, .multi_error_valid = multi ? 1 : 0, }; @@ -1318,6 +1316,7 @@ static void aer_isr_one_error(struct pci_dev *root, struct aer_err_info e_info = { .id = ERR_UNCOR_ID(e_src->id), .severity = fatal ? AER_FATAL : AER_NONFATAL, + .level = KERN_ERR, .multi_error_valid = multi ? 1 : 0, }; diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 9d85f1b3b761..6c98fabdba57 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -252,6 +252,7 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev, else info->severity = AER_NONFATAL; + info->level = KERN_ERR; return 1; } From 82013ff394ea58fced098a1fdc001b46cc3dd5ee Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:19 -0500 Subject: [PATCH 112/147] PCI/ERR: Add printk level to pcie_print_tlp_log() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aer_print_error() produces output at a printk level (KERN_ERR/KERN_WARNING/ etc) that depends on the kind of error, and it calls pcie_print_tlp_log(), which previously always produced output at KERN_ERR. Add a "level" parameter so aer_print_error() can control the level of the pcie_print_tlp_log() output to match. Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-14-helgaas@kernel.org --- drivers/pci/pci.h | 3 ++- drivers/pci/pcie/aer.c | 5 +++-- drivers/pci/pcie/dpc.c | 2 +- drivers/pci/pcie/tlp.c | 6 ++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 705f9ef58acc..1a9bfc708757 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -613,7 +613,8 @@ int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2, struct pcie_tlp_log *log); unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc); void pcie_print_tlp_log(const struct pci_dev *dev, - const struct pcie_tlp_log *log, const char *pfx); + const struct pcie_tlp_log *log, const char *level, + const char *pfx); #endif /* CONFIG_PCIEAER */ #ifdef CONFIG_PCIEPORTBUS diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index f80c78846a14..f0936759ba8b 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -734,7 +734,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) __aer_print_error(dev, info); if (info->tlp_header_valid) - pcie_print_tlp_log(dev, &info->tlp, dev_fmt(" ")); + pcie_print_tlp_log(dev, &info->tlp, level, dev_fmt(" ")); out: if (info->id && info->error_dev_num > 1 && info->id == id) @@ -797,7 +797,8 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, aer->uncor_severity); if (tlp_header_valid) - pcie_print_tlp_log(dev, &aer->header_log, dev_fmt(" ")); + pcie_print_tlp_log(dev, &aer->header_log, info.level, + dev_fmt(" ")); } EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL"); diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 6c98fabdba57..7ae1590ea1da 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -222,7 +222,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev) dpc_tlp_log_len(pdev), pdev->subordinate->flit_mode, &tlp_log); - pcie_print_tlp_log(pdev, &tlp_log, dev_fmt("")); + pcie_print_tlp_log(pdev, &tlp_log, KERN_ERR, dev_fmt("")); if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1) goto clear_status; diff --git a/drivers/pci/pcie/tlp.c b/drivers/pci/pcie/tlp.c index 890d5391d7f5..71f8fc9ea2ed 100644 --- a/drivers/pci/pcie/tlp.c +++ b/drivers/pci/pcie/tlp.c @@ -98,12 +98,14 @@ int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2, * pcie_print_tlp_log - Print TLP Header / Prefix Log contents * @dev: PCIe device * @log: TLP Log structure + * @level: Printk log level * @pfx: String prefix * * Prints TLP Header and Prefix Log information held by @log. */ void pcie_print_tlp_log(const struct pci_dev *dev, - const struct pcie_tlp_log *log, const char *pfx) + const struct pcie_tlp_log *log, const char *level, + const char *pfx) { /* EE_PREFIX_STR fits the extended DW space needed for the Flit mode */ char buf[11 * PCIE_STD_MAX_TLP_HEADERLOG + 1]; @@ -130,6 +132,6 @@ void pcie_print_tlp_log(const struct pci_dev *dev, } } - pci_err(dev, "%sTLP Header%s: %s\n", pfx, + dev_printk(level, &dev->dev, "%sTLP Header%s: %s\n", pfx, log->flit ? " (Flit)" : "", buf); } From 36c5932074aaedebf905374dba2399a529215aa1 Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Thu, 22 May 2025 18:21:20 -0500 Subject: [PATCH 113/147] PCI/AER: Reduce pci_print_aer() correctable error level to KERN_WARNING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some existing logs in pci_print_aer() log with error severity by default. Convert them to use KERN_WARNING for correctable errors and KERN_ERR for uncorrectable errors. [bhelgaas: commit log] Signed-off-by: Karolina Stolarek Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Ilpo Järvinen Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-15-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index f0936759ba8b..16779f281b2f 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -787,14 +787,15 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, layer = AER_GET_LAYER_ERROR(aer_severity, status); agent = AER_GET_AGENT(aer_severity, status); - pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); + aer_printk(info.level, dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", + status, mask); __aer_print_error(dev, &info); - pci_err(dev, "aer_layer=%s, aer_agent=%s\n", - aer_error_layer[layer], aer_agent_string[agent]); + aer_printk(info.level, dev, "aer_layer=%s, aer_agent=%s\n", + aer_error_layer[layer], aer_agent_string[agent]); if (aer_severity != AER_CORRECTABLE) - pci_err(dev, "aer_uncor_severity: 0x%08x\n", - aer->uncor_severity); + aer_printk(info.level, dev, "aer_uncor_severity: 0x%08x\n", + aer->uncor_severity); if (tlp_header_valid) pcie_print_tlp_log(dev, &aer->header_log, info.level, From 09683a6184ad6fd635831402316651392b56cc3a Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Thu, 22 May 2025 18:21:21 -0500 Subject: [PATCH 114/147] PCI/AER: Rename struct aer_stats to aer_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update name to reflect the broader definition of structs/variables that are stored (e.g. ratelimits). This is a preparatory patch for adding rate limit support. [bhelgaas: "aer_report" -> "aer_info"] Signed-off-by: Karolina Stolarek Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20250522232339.1525671-16-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 46 +++++++++++++++++++++--------------------- include/linux/pci.h | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 16779f281b2f..787a953fb331 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -54,8 +54,8 @@ struct aer_rpc { DECLARE_KFIFO(aer_fifo, struct aer_err_source, AER_ERROR_SOURCES_MAX); }; -/* AER stats for the device */ -struct aer_stats { +/* AER info for the device */ +struct aer_info { /* * Fields for all AER capable devices. They indicate the errors @@ -377,7 +377,7 @@ void pci_aer_init(struct pci_dev *dev) if (!dev->aer_cap) return; - dev->aer_stats = kzalloc(sizeof(struct aer_stats), GFP_KERNEL); + dev->aer_info = kzalloc(sizeof(*dev->aer_info), GFP_KERNEL); /* * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER, @@ -398,8 +398,8 @@ void pci_aer_init(struct pci_dev *dev) void pci_aer_exit(struct pci_dev *dev) { - kfree(dev->aer_stats); - dev->aer_stats = NULL; + kfree(dev->aer_info); + dev->aer_info = NULL; } #define AER_AGENT_RECEIVER 0 @@ -537,10 +537,10 @@ static const char *aer_agent_string[] = { { \ unsigned int i; \ struct pci_dev *pdev = to_pci_dev(dev); \ - u64 *stats = pdev->aer_stats->stats_array; \ + u64 *stats = pdev->aer_info->stats_array; \ size_t len = 0; \ \ - for (i = 0; i < ARRAY_SIZE(pdev->aer_stats->stats_array); i++) {\ + for (i = 0; i < ARRAY_SIZE(pdev->aer_info->stats_array); i++) { \ if (strings_array[i]) \ len += sysfs_emit_at(buf, len, "%s %llu\n", \ strings_array[i], \ @@ -551,7 +551,7 @@ static const char *aer_agent_string[] = { i, stats[i]); \ } \ len += sysfs_emit_at(buf, len, "TOTAL_%s %llu\n", total_string, \ - pdev->aer_stats->total_field); \ + pdev->aer_info->total_field); \ return len; \ } \ static DEVICE_ATTR_RO(name) @@ -572,7 +572,7 @@ aer_stats_dev_attr(aer_dev_nonfatal, dev_nonfatal_errs, char *buf) \ { \ struct pci_dev *pdev = to_pci_dev(dev); \ - return sysfs_emit(buf, "%llu\n", pdev->aer_stats->field); \ + return sysfs_emit(buf, "%llu\n", pdev->aer_info->field); \ } \ static DEVICE_ATTR_RO(name) @@ -599,7 +599,7 @@ static umode_t aer_stats_attrs_are_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct pci_dev *pdev = to_pci_dev(dev); - if (!pdev->aer_stats) + if (!pdev->aer_info) return 0; if ((a == &dev_attr_aer_rootport_total_err_cor.attr || @@ -623,25 +623,25 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev, unsigned long status = info->status & ~info->mask; int i, max = -1; u64 *counter = NULL; - struct aer_stats *aer_stats = pdev->aer_stats; + struct aer_info *aer_info = pdev->aer_info; - if (!aer_stats) + if (!aer_info) return; switch (info->severity) { case AER_CORRECTABLE: - aer_stats->dev_total_cor_errs++; - counter = &aer_stats->dev_cor_errs[0]; + aer_info->dev_total_cor_errs++; + counter = &aer_info->dev_cor_errs[0]; max = AER_MAX_TYPEOF_COR_ERRS; break; case AER_NONFATAL: - aer_stats->dev_total_nonfatal_errs++; - counter = &aer_stats->dev_nonfatal_errs[0]; + aer_info->dev_total_nonfatal_errs++; + counter = &aer_info->dev_nonfatal_errs[0]; max = AER_MAX_TYPEOF_UNCOR_ERRS; break; case AER_FATAL: - aer_stats->dev_total_fatal_errs++; - counter = &aer_stats->dev_fatal_errs[0]; + aer_info->dev_total_fatal_errs++; + counter = &aer_info->dev_fatal_errs[0]; max = AER_MAX_TYPEOF_UNCOR_ERRS; break; } @@ -653,19 +653,19 @@ static void pci_dev_aer_stats_incr(struct pci_dev *pdev, static void pci_rootport_aer_stats_incr(struct pci_dev *pdev, struct aer_err_source *e_src) { - struct aer_stats *aer_stats = pdev->aer_stats; + struct aer_info *aer_info = pdev->aer_info; - if (!aer_stats) + if (!aer_info) return; if (e_src->status & PCI_ERR_ROOT_COR_RCV) - aer_stats->rootport_total_cor_errs++; + aer_info->rootport_total_cor_errs++; if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) { if (e_src->status & PCI_ERR_ROOT_FATAL_RCV) - aer_stats->rootport_total_fatal_errs++; + aer_info->rootport_total_fatal_errs++; else - aer_stats->rootport_total_nonfatal_errs++; + aer_info->rootport_total_nonfatal_errs++; } } diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..81a81dbfc873 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -346,7 +346,7 @@ struct pci_dev { u8 hdr_type; /* PCI header type (`multi' flag masked out) */ #ifdef CONFIG_PCIEAER u16 aer_cap; /* AER capability offset */ - struct aer_stats *aer_stats; /* AER stats for this device */ + struct aer_info *aer_info; /* AER info for this device */ #endif #ifdef CONFIG_PCIEPORTBUS struct rcec_ea *rcec_ea; /* RCEC cached endpoint association */ From 94bc15c3484aa1dbbd01aee8f9eaa5dc347a01a8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:22 -0500 Subject: [PATCH 115/147] PCI/AER: Convert aer_get_device_error_info(), aer_print_error() to index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously aer_get_device_error_info() and aer_print_error() took a pointer to struct aer_err_info and a pointer to a pci_dev. Typically the pci_dev was one of the elements of the aer_err_info.dev[] array (DPC was an exception, where the dev[] array was unused). Convert aer_get_device_error_info() and aer_print_error() to take an index into the aer_err_info.dev[] array instead. A future patch will add per-device ratelimit information, so the index makes it convenient to find the ratelimit associated with the device. To accommodate DPC, set info->dev[0] to the DPC port before using these interfaces. Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-17-helgaas@kernel.org --- drivers/pci/pci.h | 4 ++-- drivers/pci/pcie/aer.c | 33 +++++++++++++++++++++++---------- drivers/pci/pcie/dpc.c | 8 ++++++-- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 1a9bfc708757..e1a28215967f 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -605,8 +605,8 @@ struct aer_err_info { struct pcie_tlp_log tlp; /* TLP Header */ }; -int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info); -void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); +int aer_get_device_error_info(struct aer_err_info *info, int i); +void aer_print_error(struct aer_err_info *info, int i); int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2, unsigned int tlp_len, bool flit, diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 787a953fb331..ab99bc1b8542 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -705,12 +705,18 @@ static void aer_print_source(struct pci_dev *dev, struct aer_err_info *info, found ? "" : " (no details found"); } -void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) +void aer_print_error(struct aer_err_info *info, int i) { - int layer, agent; - int id = pci_dev_id(dev); + struct pci_dev *dev; + int layer, agent, id; const char *level = info->level; + if (WARN_ON_ONCE(i >= AER_MAX_MULTI_ERR_DEVICES)) + return; + + dev = info->dev[i]; + id = pci_dev_id(dev); + pci_dev_aer_stats_incr(dev, info); trace_aer_event(pci_name(dev), (info->status & ~info->mask), info->severity, info->tlp_header_valid, &info->tlp); @@ -1193,19 +1199,26 @@ EXPORT_SYMBOL_GPL(aer_recover_queue); /** * aer_get_device_error_info - read error status from dev and store it to info - * @dev: pointer to the device expected to have an error record * @info: pointer to structure to store the error record + * @i: index into info->dev[] * * Return: 1 on success, 0 on error. * * Note that @info is reused among all error devices. Clear fields properly. */ -int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) +int aer_get_device_error_info(struct aer_err_info *info, int i) { - int type = pci_pcie_type(dev); - int aer = dev->aer_cap; + struct pci_dev *dev; + int type, aer; u32 aercc; + if (i >= AER_MAX_MULTI_ERR_DEVICES) + return 0; + + dev = info->dev[i]; + aer = dev->aer_cap; + type = pci_pcie_type(dev); + /* Must reset in this function */ info->status = 0; info->tlp_header_valid = 0; @@ -1257,11 +1270,11 @@ static inline void aer_process_err_devices(struct aer_err_info *e_info) /* Report all before handling them, to not lose records by reset etc. */ for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { - if (aer_get_device_error_info(e_info->dev[i], e_info)) - aer_print_error(e_info->dev[i], e_info); + if (aer_get_device_error_info(e_info, i)) + aer_print_error(e_info, i); } for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) { - if (aer_get_device_error_info(e_info->dev[i], e_info)) + if (aer_get_device_error_info(e_info, i)) handle_error_source(e_info->dev[i], e_info); } } diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index 7ae1590ea1da..fc18349614d7 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -253,6 +253,10 @@ static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev, info->severity = AER_NONFATAL; info->level = KERN_ERR; + + info->dev[0] = dev; + info->error_dev_num = 1; + return 1; } @@ -270,8 +274,8 @@ void dpc_process_error(struct pci_dev *pdev) pci_warn(pdev, "containment event, status:%#06x: unmasked uncorrectable error detected\n", status); if (dpc_get_aer_uncorrect_severity(pdev, &info) && - aer_get_device_error_info(pdev, &info)) { - aer_print_error(pdev, &info); + aer_get_device_error_info(&info, 0)) { + aer_print_error(&info, 0); pci_aer_clear_nonfatal_status(pdev); pci_aer_clear_fatal_status(pdev); } From d72bae423004aa7b4d94c34a7fd0b48b64305a08 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 22 May 2025 18:21:23 -0500 Subject: [PATCH 116/147] PCI/AER: Simplify add_error_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return -ENOSPC error early so the usual path through add_error_device() is the straightline code. Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-18-helgaas@kernel.org --- drivers/pci/pcie/aer.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index ab99bc1b8542..5d62b82b5bc1 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -816,12 +816,15 @@ EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL"); */ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) { - if (e_info->error_dev_num < AER_MAX_MULTI_ERR_DEVICES) { - e_info->dev[e_info->error_dev_num] = pci_dev_get(dev); - e_info->error_dev_num++; - return 0; - } - return -ENOSPC; + int i = e_info->error_dev_num; + + if (i >= AER_MAX_MULTI_ERR_DEVICES) + return -ENOSPC; + + e_info->dev[i] = pci_dev_get(dev); + e_info->error_dev_num++; + + return 0; } /** From a57f2bfb4a5863f83087867c0e671f2418212d23 Mon Sep 17 00:00:00 2001 From: Jon Pan-Doh Date: Thu, 22 May 2025 18:21:24 -0500 Subject: [PATCH 117/147] PCI/AER: Ratelimit correctable and non-fatal error logging Spammy devices can flood kernel logs with AER errors and slow/stall execution. Add per-device ratelimits for AER correctable and non-fatal uncorrectable errors that use the kernel defaults (10 per 5s). Logging of fatal errors is not ratelimited. There are two AER logging entry points: - aer_print_error() is used by DPC and native AER - pci_print_aer() is used by GHES and CXL The native AER aer_print_error() case includes a loop that may log details from multiple devices, which are ratelimited individually. If we log details for any device, we also log the Error Source ID from the Root Port or RCEC. If no such device details are found, we still log the Error Source from the ERR_* Message, ratelimited by the Root Port or RCEC that received it. The DPC aer_print_error() case is not ratelimited, since this only happens for fatal errors. The CXL pci_print_aer() case is ratelimited by the Error Source device. The GHES pci_print_aer() case is via aer_recover_work_func(), which searches for the Error Source device. If the device is not found, there's no per-device ratelimit, so we use a system-wide ratelimit that covers all error types (correctable, non-fatal, and fatal). Sargun at Meta reported internally that a flood of AER errors causes RCU CPU stall warnings and CSD-lock warnings. Tested using aer-inject[1]. Sent 11 AER errors. Observed 10 errors logged while AER stats (cat /sys/bus/pci/devices//aer_dev_correctable) show true count of 11. [1] https://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/aer-inject.git [bhelgaas: commit log, factor out trace_aer_event() and aer_print_rp_info() changes to previous patches, enable Error Source logging if any downstream detail will be printed, don't ratelimit fatal errors, "aer_report" -> "aer_info", "cor_log_ratelimit" -> "correctable_ratelimit", "uncor_log_ratelimit" -> "nonfatal_ratelimit"] Reported-by: Sargun Dhillon Signed-off-by: Jon Pan-Doh Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-19-helgaas@kernel.org --- drivers/pci/pci.h | 4 ++- drivers/pci/pcie/aer.c | 66 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e1a28215967f..3023c68fe485 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -587,13 +587,15 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev) struct aer_err_info { struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; + int ratelimit_print[AER_MAX_MULTI_ERR_DEVICES]; int error_dev_num; const char *level; /* printk level */ unsigned int id:16; unsigned int severity:2; /* 0:NONFATAL | 1:FATAL | 2:COR */ - unsigned int __pad1:5; + unsigned int root_ratelimit_print:1; /* 0=skip, 1=print */ + unsigned int __pad1:4; unsigned int multi_error_valid:1; unsigned int first_error:5; diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 5d62b82b5bc1..7886a9ad126c 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,10 @@ struct aer_info { u64 rootport_total_cor_errs; u64 rootport_total_fatal_errs; u64 rootport_total_nonfatal_errs; + + /* Ratelimits for errors */ + struct ratelimit_state correctable_ratelimit; + struct ratelimit_state nonfatal_ratelimit; }; #define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ @@ -379,6 +384,11 @@ void pci_aer_init(struct pci_dev *dev) dev->aer_info = kzalloc(sizeof(*dev->aer_info), GFP_KERNEL); + ratelimit_state_init(&dev->aer_info->correctable_ratelimit, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + ratelimit_state_init(&dev->aer_info->nonfatal_ratelimit, + DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); + /* * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER, * PCI_ERR_COR_MASK, and PCI_ERR_CAP. Root and Root Complex Event @@ -669,6 +679,18 @@ static void pci_rootport_aer_stats_incr(struct pci_dev *pdev, } } +static int aer_ratelimit(struct pci_dev *dev, unsigned int severity) +{ + switch (severity) { + case AER_NONFATAL: + return __ratelimit(&dev->aer_info->nonfatal_ratelimit); + case AER_CORRECTABLE: + return __ratelimit(&dev->aer_info->correctable_ratelimit); + default: + return 1; /* Don't ratelimit fatal errors */ + } +} + static void __aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { const char **strings; @@ -721,6 +743,9 @@ void aer_print_error(struct aer_err_info *info, int i) trace_aer_event(pci_name(dev), (info->status & ~info->mask), info->severity, info->tlp_header_valid, &info->tlp); + if (!info->ratelimit_print[i]) + return; + if (!info->status) { pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n", aer_error_severity_string[info->severity]); @@ -790,6 +815,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, trace_aer_event(pci_name(dev), (status & ~mask), aer_severity, tlp_header_valid, &aer->header_log); + if (!aer_ratelimit(dev, info.severity)) + return; + layer = AER_GET_LAYER_ERROR(aer_severity, status); agent = AER_GET_AGENT(aer_severity, status); @@ -824,6 +852,18 @@ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev) e_info->dev[i] = pci_dev_get(dev); e_info->error_dev_num++; + /* + * Ratelimit AER log messages. "dev" is either the source + * identified by the root's Error Source ID or it has an unmasked + * error logged in its own AER Capability. Messages are emitted + * when "ratelimit_print[i]" is non-zero. If we will print detail + * for a downstream device, make sure we print the Error Source ID + * from the root as well. + */ + if (aer_ratelimit(dev, e_info->severity)) { + e_info->ratelimit_print[i] = 1; + e_info->root_ratelimit_print = 1; + } return 0; } @@ -918,7 +958,7 @@ static int find_device_iter(struct pci_dev *dev, void *data) * e_info->error_dev_num and e_info->dev[], based on the given information. */ static bool find_source_device(struct pci_dev *parent, - struct aer_err_info *e_info) + struct aer_err_info *e_info) { struct pci_dev *dev = parent; int result; @@ -1144,9 +1184,10 @@ static void aer_recover_work_func(struct work_struct *work) pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus, entry.devfn); if (!pdev) { - pr_err("no pci_dev for %04x:%02x:%02x.%x\n", - entry.domain, entry.bus, - PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); + pr_err_ratelimited("%04x:%02x:%02x.%x: no pci_dev found\n", + entry.domain, entry.bus, + PCI_SLOT(entry.devfn), + PCI_FUNC(entry.devfn)); continue; } pci_print_aer(pdev, entry.severity, entry.regs); @@ -1294,7 +1335,22 @@ static void aer_isr_one_error_type(struct pci_dev *root, bool found; found = find_source_device(root, info); - aer_print_source(root, info, found); + + /* + * If we're going to log error messages, we've already set + * "info->root_ratelimit_print" and "info->ratelimit_print[i]" to + * non-zero (which enables printing) because this is either an + * ERR_FATAL or we found a device with an error logged in its AER + * Capability. + * + * If we didn't find the Error Source device, at least log the + * Requester ID from the ERR_* Message received by the Root Port or + * RCEC, ratelimited by the RP or RCEC. + */ + if (info->root_ratelimit_print || + (!found && aer_ratelimit(root, info->severity))) + aer_print_source(root, info, found); + if (found) aer_process_err_devices(info); } From 24816cc298ee9cc01003b10b888427faada4403d Mon Sep 17 00:00:00 2001 From: Jon Pan-Doh Date: Thu, 22 May 2025 18:21:25 -0500 Subject: [PATCH 118/147] PCI/AER: Add ratelimits to PCI AER Documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ratelimits section for rationale and defaults. [bhelgaas: note fatal errors are not ratelimited] Signed-off-by: Karolina Stolarek Signed-off-by: Jon Pan-Doh Signed-off-by: Bjorn Helgaas Tested-by: Krzysztof Wilczyński Reviewed-by: Kuppuswamy Sathyanarayanan Acked-by: Paul E. McKenney Link: https://patch.msgid.link/20250522232339.1525671-20-helgaas@kernel.org --- Documentation/PCI/pcieaer-howto.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/PCI/pcieaer-howto.rst b/Documentation/PCI/pcieaer-howto.rst index f013f3b27c82..6fb31516fff1 100644 --- a/Documentation/PCI/pcieaer-howto.rst +++ b/Documentation/PCI/pcieaer-howto.rst @@ -85,6 +85,18 @@ In the example, 'Requester ID' means the ID of the device that sent the error message to the Root Port. Please refer to PCIe specs for other fields. +AER Ratelimits +-------------- + +Since error messages can be generated for each transaction, we may see +large volumes of errors reported. To prevent spammy devices from flooding +the console/stalling execution, messages are throttled by device and error +type (correctable vs. non-fatal uncorrectable). Fatal errors, including +DPC errors, are not ratelimited. + +AER uses the default ratelimit of DEFAULT_RATELIMIT_BURST (10 events) over +DEFAULT_RATELIMIT_INTERVAL (5 seconds). + AER Statistics / Counters ------------------------- From b4fe7398def6df344442b884d2288f80205cbd2d Mon Sep 17 00:00:00 2001 From: Jon Pan-Doh Date: Thu, 22 May 2025 18:21:26 -0500 Subject: [PATCH 119/147] PCI/AER: Add sysfs attributes for log ratelimits Allow userspace to read/write log ratelimits per device (including enable/disable). Create aer/ sysfs directory to store them and any future AER configs. The new sysfs files are: /sys/bus/pci/devices/*/aer/correctable_ratelimit_burst /sys/bus/pci/devices/*/aer/correctable_ratelimit_interval_ms /sys/bus/pci/devices/*/aer/nonfatal_ratelimit_burst /sys/bus/pci/devices/*/aer/nonfatal_ratelimit_interval_ms The default values are ratelimit_burst=10, ratelimit_interval_ms=5000, so if we try to emit more than 10 messages in a 5 second period, some are suppressed. Update AER sysfs ABI filename to reflect the broader scope of AER sysfs attributes (e.g. stats and ratelimits). Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats -> sysfs-bus-pci-devices-aer Tested using aer-inject[1]. Configured correctable log ratelimit to 5. Sent 6 AER errors. Observed 5 errors logged while AER stats (cat /sys/bus/pci/devices//aer_dev_correctable) shows 6. Disabled ratelimiting and sent 6 more AER errors. Observed all 6 errors logged and accounted in AER stats (12 total errors). [1] https://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/aer-inject.git [bhelgaas: note fatal errors are not ratelimited, "aer_report" -> "aer_info", replace ratelimit_log_enable toggle with *_ratelimit_interval_ms] Signed-off-by: Karolina Stolarek Signed-off-by: Jon Pan-Doh Signed-off-by: Bjorn Helgaas Reviewed-by: Kuppuswamy Sathyanarayanan Link: https://patch.msgid.link/20250522232339.1525671-21-helgaas@kernel.org --- ...es-aer_stats => sysfs-bus-pci-devices-aer} | 44 ++++++++ Documentation/PCI/pcieaer-howto.rst | 5 +- drivers/pci/pci-sysfs.c | 1 + drivers/pci/pci.h | 1 + drivers/pci/pcie/aer.c | 105 ++++++++++++++++++ 5 files changed, 155 insertions(+), 1 deletion(-) rename Documentation/ABI/testing/{sysfs-bus-pci-devices-aer_stats => sysfs-bus-pci-devices-aer} (72%) diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats b/Documentation/ABI/testing/sysfs-bus-pci-devices-aer similarity index 72% rename from Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats rename to Documentation/ABI/testing/sysfs-bus-pci-devices-aer index d1f67bb81d5d..5ed284523956 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-aer @@ -117,3 +117,47 @@ Date: July 2018 KernelVersion: 4.19.0 Contact: linux-pci@vger.kernel.org, rajatja@google.com Description: Total number of ERR_NONFATAL messages reported to rootport. + +PCIe AER ratelimits +------------------- + +These attributes show up under all the devices that are AER capable. +They represent configurable ratelimits of logs per error type. + +See Documentation/PCI/pcieaer-howto.rst for more info on ratelimits. + +What: /sys/bus/pci/devices//aer/correctable_ratelimit_interval_ms +Date: May 2025 +KernelVersion: 6.16.0 +Contact: linux-pci@vger.kernel.org +Description: Writing 0 disables AER correctable error log ratelimiting. + Writing a positive value sets the ratelimit interval in ms. + Default is DEFAULT_RATELIMIT_INTERVAL (5000 ms). + +What: /sys/bus/pci/devices//aer/correctable_ratelimit_burst +Date: May 2025 +KernelVersion: 6.16.0 +Contact: linux-pci@vger.kernel.org +Description: Ratelimit burst for correctable error logs. Writing a value + changes the number of errors (burst) allowed per interval + before ratelimiting. Reading gets the current ratelimit + burst. Default is DEFAULT_RATELIMIT_BURST (10). + +What: /sys/bus/pci/devices//aer/nonfatal_ratelimit_interval_ms +Date: May 2025 +KernelVersion: 6.16.0 +Contact: linux-pci@vger.kernel.org +Description: Writing 0 disables AER non-fatal uncorrectable error log + ratelimiting. Writing a positive value sets the ratelimit + interval in ms. Default is DEFAULT_RATELIMIT_INTERVAL + (5000 ms). + +What: /sys/bus/pci/devices//aer/nonfatal_ratelimit_burst +Date: May 2025 +KernelVersion: 6.16.0 +Contact: linux-pci@vger.kernel.org +Description: Ratelimit burst for non-fatal uncorrectable error logs. + Writing a value changes the number of errors (burst) + allowed per interval before ratelimiting. Reading gets the + current ratelimit burst. Default is DEFAULT_RATELIMIT_BURST + (10). diff --git a/Documentation/PCI/pcieaer-howto.rst b/Documentation/PCI/pcieaer-howto.rst index 6fb31516fff1..4b71e2f43ca7 100644 --- a/Documentation/PCI/pcieaer-howto.rst +++ b/Documentation/PCI/pcieaer-howto.rst @@ -97,12 +97,15 @@ DPC errors, are not ratelimited. AER uses the default ratelimit of DEFAULT_RATELIMIT_BURST (10 events) over DEFAULT_RATELIMIT_INTERVAL (5 seconds). +Ratelimits are exposed in the form of sysfs attributes and configurable. +See Documentation/ABI/testing/sysfs-bus-pci-devices-aer. + AER Statistics / Counters ------------------------- When PCIe AER errors are captured, the counters / statistics are also exposed in the form of sysfs attributes which are documented at -Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats +Documentation/ABI/testing/sysfs-bus-pci-devices-aer. Developer Guide =============== diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c6cda56ca52c..278de99b00ce 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -1805,6 +1805,7 @@ const struct attribute_group *pci_dev_attr_groups[] = { &pcie_dev_attr_group, #ifdef CONFIG_PCIEAER &aer_stats_attr_group, + &aer_attr_group, #endif #ifdef CONFIG_PCIEASPM &aspm_ctrl_attr_group, diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 3023c68fe485..eca2812cfd25 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -965,6 +965,7 @@ void pci_no_aer(void); void pci_aer_init(struct pci_dev *dev); void pci_aer_exit(struct pci_dev *dev); extern const struct attribute_group aer_stats_attr_group; +extern const struct attribute_group aer_attr_group; void pci_aer_clear_fatal_status(struct pci_dev *dev); int pci_aer_clear_status(struct pci_dev *dev); int pci_aer_raw_clear_status(struct pci_dev *dev); diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 7886a9ad126c..70ac66188367 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -627,6 +627,111 @@ const struct attribute_group aer_stats_attr_group = { .is_visible = aer_stats_attrs_are_visible, }; +/* + * Ratelimit interval + * <=0: disabled with ratelimit.interval = 0 + * >0: enabled with ratelimit.interval in ms + */ +#define aer_ratelimit_interval_attr(name, ratelimit) \ + static ssize_t \ + name##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ + { \ + struct pci_dev *pdev = to_pci_dev(dev); \ + \ + return sysfs_emit(buf, "%d\n", \ + pdev->aer_info->ratelimit.interval); \ + } \ + \ + static ssize_t \ + name##_store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct pci_dev *pdev = to_pci_dev(dev); \ + int interval; \ + \ + if (!capable(CAP_SYS_ADMIN)) \ + return -EPERM; \ + \ + if (kstrtoint(buf, 0, &interval) < 0) \ + return -EINVAL; \ + \ + if (interval <= 0) \ + interval = 0; \ + else \ + interval = msecs_to_jiffies(interval); \ + \ + pdev->aer_info->ratelimit.interval = interval; \ + \ + return count; \ + } \ + static DEVICE_ATTR_RW(name); + +#define aer_ratelimit_burst_attr(name, ratelimit) \ + static ssize_t \ + name##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ + { \ + struct pci_dev *pdev = to_pci_dev(dev); \ + \ + return sysfs_emit(buf, "%d\n", \ + pdev->aer_info->ratelimit.burst); \ + } \ + \ + static ssize_t \ + name##_store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct pci_dev *pdev = to_pci_dev(dev); \ + int burst; \ + \ + if (!capable(CAP_SYS_ADMIN)) \ + return -EPERM; \ + \ + if (kstrtoint(buf, 0, &burst) < 0) \ + return -EINVAL; \ + \ + pdev->aer_info->ratelimit.burst = burst; \ + \ + return count; \ + } \ + static DEVICE_ATTR_RW(name); + +#define aer_ratelimit_attrs(name) \ + aer_ratelimit_interval_attr(name##_ratelimit_interval_ms, \ + name##_ratelimit) \ + aer_ratelimit_burst_attr(name##_ratelimit_burst, \ + name##_ratelimit) + +aer_ratelimit_attrs(correctable) +aer_ratelimit_attrs(nonfatal) + +static struct attribute *aer_attrs[] = { + &dev_attr_correctable_ratelimit_interval_ms.attr, + &dev_attr_correctable_ratelimit_burst.attr, + &dev_attr_nonfatal_ratelimit_interval_ms.attr, + &dev_attr_nonfatal_ratelimit_burst.attr, + NULL +}; + +static umode_t aer_attrs_are_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct pci_dev *pdev = to_pci_dev(dev); + + if (!pdev->aer_info) + return 0; + + return a->mode; +} + +const struct attribute_group aer_attr_group = { + .name = "aer", + .attrs = aer_attrs, + .is_visible = aer_attrs_are_visible, +}; + static void pci_dev_aer_stats_incr(struct pci_dev *pdev, struct aer_err_info *info) { From 8b926f237743f020518162c62b93cb7107a2b5eb Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 9 Apr 2025 11:53:13 -0700 Subject: [PATCH 120/147] PCI/pwrctrl: Cancel outstanding rescan work when unregistering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's possible to trigger use-after-free here by: (a) forcing rescan_work_func() to take a long time and (b) utilizing a pwrctrl driver that may be unloaded for some reason Cancel outstanding work to ensure it is finished before we allow our data structures to be cleaned up. [bhelgaas: tidy commit log] Fixes: 8f62819aaace ("PCI/pwrctl: Rescan bus on a separate thread") Signed-off-by: Brian Norris Signed-off-by: Brian Norris Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Acked-by: Bartosz Golaszewski Cc: Konrad Dybcio Link: https://patch.msgid.link/20250409115313.1.Ia319526ed4ef06bec3180378c9a008340cec9658@changeid --- drivers/pci/pwrctrl/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 9cc7e2b7f2b5..6bdbfed584d6 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -101,6 +101,8 @@ EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); */ void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl) { + cancel_work_sync(&pwrctrl->work); + /* * We don't have to delete the link here. Typically, this function * is only called when the power control device is being detached. If From 13bbf6a5f065f235bba69f6c21272d992ed5d5d0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 2 Apr 2025 15:26:31 +0200 Subject: [PATCH 121/147] PCI/pwrctrl: Rename pwrctrl Kconfig symbols and slot module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commits b88cbaaa6fa1 ("PCI/pwrctrl: Rename pwrctl files to pwrctrl") and 3f925cd62874 ("PCI/pwrctrl: Rename pwrctrl functions and structures") renamed the "pwrctl" framework to "pwrctrl" for consistency reasons. Rename also the Kconfig symbols so that they reflect the new name while adding entries for the deprecated ones. The old symbols can be removed once everything that depends on them has been updated. Note that no deprecated symbol is added for the new slot driver to avoid having to add a user visible option. Rename the new slot module to reflect the framework name and match the other pwrctrl modules. Signed-off-by: Johan Hovold Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Acked-by: Manivannan Sadhasivam Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250402132634.18065-2-johan+linaro@kernel.org --- drivers/pci/pwrctrl/Kconfig | 22 ++++++++++++++++------ drivers/pci/pwrctrl/Makefile | 8 ++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index 990cab67d413..6956c1854811 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -1,19 +1,19 @@ # SPDX-License-Identifier: GPL-2.0-only -config HAVE_PWRCTL +config HAVE_PWRCTRL bool -config PCI_PWRCTL +config PCI_PWRCTRL tristate -config PCI_PWRCTL_PWRSEQ +config PCI_PWRCTRL_PWRSEQ tristate select POWER_SEQUENCING - select PCI_PWRCTL + select PCI_PWRCTRL -config PCI_PWRCTL_SLOT +config PCI_PWRCTRL_SLOT tristate "PCI Power Control driver for PCI slots" - select PCI_PWRCTL + select PCI_PWRCTRL help Say Y here to enable the PCI Power Control driver to control the power state of PCI slots. @@ -21,3 +21,13 @@ config PCI_PWRCTL_SLOT This is a generic driver that controls the power state of different PCI slots. The voltage regulators powering the rails of the PCI slots are expected to be defined in the devicetree node of the PCI bridge. + +# deprecated +config HAVE_PWRCTL + bool + select HAVE_PWRCTRL + +# deprecated +config PCI_PWRCTL_PWRSEQ + tristate + select PCI_PWRCTRL_PWRSEQ diff --git a/drivers/pci/pwrctrl/Makefile b/drivers/pci/pwrctrl/Makefile index ddfb12c5aadf..a4e5808d7850 100644 --- a/drivers/pci/pwrctrl/Makefile +++ b/drivers/pci/pwrctrl/Makefile @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctrl-core.o +obj-$(CONFIG_PCI_PWRCTRL) += pci-pwrctrl-core.o pci-pwrctrl-core-y := core.o -obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctrl-pwrseq.o +obj-$(CONFIG_PCI_PWRCTRL_PWRSEQ) += pci-pwrctrl-pwrseq.o -obj-$(CONFIG_PCI_PWRCTL_SLOT) += pci-pwrctl-slot.o -pci-pwrctl-slot-y := slot.o +obj-$(CONFIG_PCI_PWRCTRL_SLOT) += pci-pwrctrl-slot.o +pci-pwrctrl-slot-y := slot.o From 52ddd0265bca80be19438f184cc9ce0bf4cf5a4f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 2 Apr 2025 15:26:32 +0200 Subject: [PATCH 122/147] wifi: ath11k: switch to PCI_PWRCTRL_PWRSEQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI_PWRCTRL_PWRSEQ and HAVE_PWRCTRL symbols have been renamed to reflect the pwrctrl framework name. Switch to the non-deprecated symbols. Signed-off-by: Johan Hovold Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Acked-by: Jeff Johnson # drivers/net/wireless/ath/... Acked-by: Manivannan Sadhasivam Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250402132634.18065-3-johan+linaro@kernel.org --- drivers/net/wireless/ath/ath11k/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 2e935d381b6b..659ef134ef16 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -24,7 +24,7 @@ config ATH11K_PCI select MHI_BUS select QRTR select QRTR_MHI - select PCI_PWRCTL_PWRSEQ if HAVE_PWRCTL + select PCI_PWRCTRL_PWRSEQ if HAVE_PWRCTRL help This module adds support for PCIE bus From d5fc1909349e1999427c86de31e98c4fa6e0b721 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 2 Apr 2025 15:26:33 +0200 Subject: [PATCH 123/147] wifi: ath12k: switch to PCI_PWRCTRL_PWRSEQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI_PWRCTRL_PWRSEQ and HAVE_PWRCTRL symbols have been renamed to reflect the pwrctrl framework name. Switch to the non-deprecated symbols. Signed-off-by: Johan Hovold Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Acked-by: Jeff Johnson # drivers/net/wireless/ath/... Acked-by: Manivannan Sadhasivam Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250402132634.18065-4-johan+linaro@kernel.org --- drivers/net/wireless/ath/ath12k/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig index 52a1bb19e3da..2d1eb22deda7 100644 --- a/drivers/net/wireless/ath/ath12k/Kconfig +++ b/drivers/net/wireless/ath/ath12k/Kconfig @@ -7,7 +7,7 @@ config ATH12K select MHI_BUS select QRTR select QRTR_MHI - select PCI_PWRCTL_PWRSEQ if HAVE_PWRCTL + select PCI_PWRCTRL_PWRSEQ if HAVE_PWRCTRL help Enable support for Qualcomm Technologies Wi-Fi 7 (IEEE 802.11be) family of chipsets, for example WCN7850 and From 46bc169f6f07eca9a7d2346c703ea59bff385e22 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 2 Apr 2025 15:26:34 +0200 Subject: [PATCH 124/147] arm64: Kconfig: switch to HAVE_PWRCTRL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HAVE_PWRCTRL symbol has been renamed to reflect the pwrctrl framework name. Switch to the non-deprecated symbol. Signed-off-by: Johan Hovold Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Acked-by: Bartosz Golaszewski Link: https://patch.msgid.link/20250402132634.18065-5-johan+linaro@kernel.org --- arch/arm64/Kconfig.platforms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 8b76821f190f..a541bb029aa4 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -269,7 +269,7 @@ config ARCH_QCOM bool "Qualcomm Platforms" select GPIOLIB select PINCTRL - select HAVE_PWRCTL if PCI + select HAVE_PWRCTRL if PCI help This enables support for the ARMv8 based Qualcomm chipsets. From 793908d60b8745c386b9f4e29eb702f74ceb0886 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 24 Apr 2025 10:34:04 +0200 Subject: [PATCH 125/147] PCI: endpoint: Retain fixed-size BAR size as well as aligned size When allocating space for an endpoint function on a BAR with a fixed size, the size saved in 'struct pci_epf_bar.size' should be the fixed size as expected by pci_epc_set_bar(). However, if pci_epf_alloc_space() increased the allocation size to accommodate iATU alignment requirements, it previously saved the larger aligned size in .size, which broke pci_epc_set_bar(). To solve this, keep the fixed BAR size in .size and save the aligned size in a new .aligned_size for use when deallocating it. Fixes: 2a9a801620ef ("PCI: endpoint: Add support to specify alignment for buffers allocated to BARs") Signed-off-by: Jerome Brunet [mani: commit message fixup] Signed-off-by: Manivannan Sadhasivam [bhelgaas: more specific subject, commit log, wrap comment to match file] Signed-off-by: Bjorn Helgaas Reviewed-by: Niklas Cassel Link: https://patch.msgid.link/20250424-pci-ep-size-alignment-v5-1-2d4ec2af23f5@baylibre.com --- drivers/pci/endpoint/pci-epf-core.c | 22 +++++++++++++++------- include/linux/pci-epf.h | 3 +++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c index 394395c7f8de..577a9e490115 100644 --- a/drivers/pci/endpoint/pci-epf-core.c +++ b/drivers/pci/endpoint/pci-epf-core.c @@ -236,12 +236,13 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar, } dev = epc->dev.parent; - dma_free_coherent(dev, epf_bar[bar].size, addr, + dma_free_coherent(dev, epf_bar[bar].aligned_size, addr, epf_bar[bar].phys_addr); epf_bar[bar].phys_addr = 0; epf_bar[bar].addr = NULL; epf_bar[bar].size = 0; + epf_bar[bar].aligned_size = 0; epf_bar[bar].barno = 0; epf_bar[bar].flags = 0; } @@ -264,7 +265,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, enum pci_epc_interface_type type) { u64 bar_fixed_size = epc_features->bar[bar].fixed_size; - size_t align = epc_features->align; + size_t aligned_size, align = epc_features->align; struct pci_epf_bar *epf_bar; dma_addr_t phys_addr; struct pci_epc *epc; @@ -285,12 +286,18 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, return NULL; } size = bar_fixed_size; + } else { + /* BAR size must be power of two */ + size = roundup_pow_of_two(size); } - if (align) - size = ALIGN(size, align); - else - size = roundup_pow_of_two(size); + /* + * Allocate enough memory to accommodate the iATU alignment + * requirement. In most cases, this will be the same as .size but + * it might be different if, for example, the fixed size of a BAR + * is smaller than align. + */ + aligned_size = align ? ALIGN(size, align) : size; if (type == PRIMARY_INTERFACE) { epc = epf->epc; @@ -301,7 +308,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, } dev = epc->dev.parent; - space = dma_alloc_coherent(dev, size, &phys_addr, GFP_KERNEL); + space = dma_alloc_coherent(dev, aligned_size, &phys_addr, GFP_KERNEL); if (!space) { dev_err(dev, "failed to allocate mem space\n"); return NULL; @@ -310,6 +317,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar, epf_bar[bar].phys_addr = phys_addr; epf_bar[bar].addr = space; epf_bar[bar].size = size; + epf_bar[bar].aligned_size = aligned_size; epf_bar[bar].barno = bar; if (upper_32_bits(size) || epc_features->bar[bar].only_64bit) epf_bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h index 879d19cebd4f..749cee0bcf2c 100644 --- a/include/linux/pci-epf.h +++ b/include/linux/pci-epf.h @@ -114,6 +114,8 @@ struct pci_epf_driver { * @phys_addr: physical address that should be mapped to the BAR * @addr: virtual address corresponding to the @phys_addr * @size: the size of the address space present in BAR + * @aligned_size: the size actually allocated to accommodate the iATU alignment + * requirement * @barno: BAR number * @flags: flags that are set for the BAR */ @@ -121,6 +123,7 @@ struct pci_epf_bar { dma_addr_t phys_addr; void *addr; size_t size; + size_t aligned_size; enum pci_barno barno; int flags; }; From e5327a655636e2ffb93d65f44777d9481aab3715 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 24 Apr 2025 10:34:05 +0200 Subject: [PATCH 126/147] PCI: endpoint: pci-epf-vntb: Simplify ctrl/SPAD space allocation When allocating the shared ctrl/SPAD space, epf_ntb_config_spad_bar_alloc() should not try to handle the size quirks for underlying BAR, whether it is fixed size or alignment. This is already handled by pci_epf_alloc_space(). Also, when handling the alignment, this allocates more space than necessary. For example, with a SPAD size of 1024B and a ctrl size of 308B, the space necessary is 1332B. If the alignment is 1MB, epf_ntb_config_spad_bar_alloc() tries to allocate 2MB where 1MB would have been more than enough. Drop the handling of the BAR size quirks and let pci_epf_alloc_space() handle that. Just make sure the 32bits SPAD register are aligned on 32bits. Signed-off-by: Jerome Brunet Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250424-pci-ep-size-alignment-v5-2-2d4ec2af23f5@baylibre.com --- drivers/pci/endpoint/functions/pci-epf-vntb.c | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c index 874cb097b093..e4da3fdb0007 100644 --- a/drivers/pci/endpoint/functions/pci-epf-vntb.c +++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c @@ -408,11 +408,9 @@ static void epf_ntb_config_spad_bar_free(struct epf_ntb *ntb) */ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb) { - size_t align; enum pci_barno barno; struct epf_ntb_ctrl *ctrl; u32 spad_size, ctrl_size; - u64 size; struct pci_epf *epf = ntb->epf; struct device *dev = &epf->dev; u32 spad_count; @@ -422,31 +420,13 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb) epf->func_no, epf->vfunc_no); barno = ntb->epf_ntb_bar[BAR_CONFIG]; - size = epc_features->bar[barno].fixed_size; - align = epc_features->align; - - if ((!IS_ALIGNED(size, align))) - return -EINVAL; - spad_count = ntb->spad_count; - ctrl_size = sizeof(struct epf_ntb_ctrl); + ctrl_size = ALIGN(sizeof(struct epf_ntb_ctrl), sizeof(u32)); spad_size = 2 * spad_count * sizeof(u32); - if (!align) { - ctrl_size = roundup_pow_of_two(ctrl_size); - spad_size = roundup_pow_of_two(spad_size); - } else { - ctrl_size = ALIGN(ctrl_size, align); - spad_size = ALIGN(spad_size, align); - } - - if (!size) - size = ctrl_size + spad_size; - else if (size < ctrl_size + spad_size) - return -EINVAL; - - base = pci_epf_alloc_space(epf, size, barno, epc_features, 0); + base = pci_epf_alloc_space(epf, ctrl_size + spad_size, + barno, epc_features, 0); if (!base) { dev_err(dev, "Config/Status/SPAD alloc region fail\n"); return -ENOMEM; From 810276362bad172d063d1f6be1cc2cb425b90103 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:14 +0200 Subject: [PATCH 127/147] PCI: dwc: ep: Correct PBA offset in .set_msix() callback While dw_pcie_ep_set_msix() writes the Table Size field correctly (N-1), the calculation of the PBA offset is wrong because it calculates space for (N-1) entries instead of N. This results in the following QEMU error when using PCI passthrough on a device which relies on the PCI endpoint subsystem: failed to add PCI capability 0x11[0x50]@0xb0: table & pba overlap, or they don't fit in BARs, or don't align Fix the calculation of PBA offset in the MSI-X capability. [bhelgaas: more specific subject and commit log] Fixes: 83153d9f36e2 ("PCI: endpoint: Fix ->set_msix() to take BIR and offset as arguments") Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Wilfred Mallawa Reviewed-by: Damien Le Moal Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250514074313.283156-9-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-designware-ep.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 1a0bf9341542..24026f3f3413 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -585,6 +585,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; u32 val, reg; + u16 actual_interrupts = interrupts + 1; ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); if (!ep_func || !ep_func->msix_cap) @@ -595,7 +596,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, reg = ep_func->msix_cap + PCI_MSIX_FLAGS; val = dw_pcie_ep_readw_dbi(ep, func_no, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; + val |= interrupts; /* 0's based value */ dw_pcie_writew_dbi(pci, reg, val); reg = ep_func->msix_cap + PCI_MSIX_TABLE; @@ -603,7 +604,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, dw_pcie_ep_writel_dbi(ep, func_no, reg, val); reg = ep_func->msix_cap + PCI_MSIX_PBA; - val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; dw_pcie_ep_writel_dbi(ep, func_no, reg, val); dw_pcie_dbi_ro_wr_dis(pci); From c8bcb01352a86bc5592403904109c22b66bd916e Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:15 +0200 Subject: [PATCH 128/147] PCI: cadence-ep: Correct PBA offset in .set_msix() callback While cdns_pcie_ep_set_msix() writes the Table Size field correctly (N-1), the calculation of the PBA offset is wrong because it calculates space for (N-1) entries instead of N. This results in the following QEMU error when using PCI passthrough on a device which relies on the PCI endpoint subsystem: failed to add PCI capability 0x11[0x50]@0xb0: table & pba overlap, or they don't fit in BARs, or don't align Fix the calculation of PBA offset in the MSI-X capability. [bhelgaas: more specific subject and commit log] Fixes: 3ef5d16f50f8 ("PCI: cadence: Add MSI-X support to Endpoint driver") Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Wilfred Mallawa Reviewed-by: Damien Le Moal Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250514074313.283156-10-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 599ec4b1223e..112ae200b393 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -292,13 +292,14 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, struct cdns_pcie *pcie = &ep->pcie; u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; u32 val, reg; + u16 actual_interrupts = interrupts + 1; fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); reg = cap + PCI_MSIX_FLAGS; val = cdns_pcie_ep_fn_readw(pcie, fn, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; + val |= interrupts; /* 0's based value */ cdns_pcie_ep_fn_writew(pcie, fn, reg, val); /* Set MSI-X BAR and offset */ @@ -308,7 +309,7 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, /* Set PBA BAR and offset. BAR must match MSI-X BAR */ reg = cap + PCI_MSIX_PBA; - val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; cdns_pcie_ep_fn_writel(pcie, fn, reg, val); return 0; From f7f15fc53245385e39ef0aab4310d1682fd3c079 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:16 +0200 Subject: [PATCH 129/147] PCI: endpoint: Align pci_epc_get_msi(), pci_epc_ops::get_msi() return value encoding The kdoc for API pci_epc_get_msi() says: "Invoke to get the number of MSI interrupts allocated by the RC" The kdoc for the callback pci_epc_ops::get_msi() says: "ops to get the number of MSI interrupts allocated by the RC from the MSI capability register" pci_epc_ops::get_msi() does however return the number of interrupts in the encoding as defined by the Multiple Message Enable (MME) field of the MSI Capability structure. Nowhere in the kdoc does it say that the returned number of interrupts is in MME encoding. It is very confusing that the API pci_epc_get_msi() and the callback function pci_epc_ops::get_msi() don't return the same value. Clean up the API and the callback function to have the same semantics, i.e. return the number of interrupts, regardless of the internal encoding of that value. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Damien Le Moal Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-11-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/controller/pcie-rcar-ep.c | 2 +- drivers/pci/controller/pcie-rockchip-ep.c | 4 ++-- drivers/pci/endpoint/pci-epc-core.c | 2 -- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 112ae200b393..78b4d009cd04 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -262,7 +262,7 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) */ mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags); - return mme; + return 1 << mme; } static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 24026f3f3413..03597551f4cd 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -532,7 +532,7 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) val = FIELD_GET(PCI_MSI_FLAGS_QSIZE, val); - return val; + return 1 << val; } static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index c5e0d025bc43..9da39a4617b6 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -280,7 +280,7 @@ static int rcar_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) if (!(flags & MSICAP0_MSIE)) return -EINVAL; - return ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); + return 1 << ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET); } static int rcar_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 85ea36df2f59..85ca7d9b4c77 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -340,8 +340,8 @@ static int rockchip_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) if (!(flags & ROCKCHIP_PCIE_EP_MSI_CTRL_ME)) return -EINVAL; - return ((flags & ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK) >> - ROCKCHIP_PCIE_EP_MSI_CTRL_MME_OFFSET); + return 1 << ((flags & ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK) >> + ROCKCHIP_PCIE_EP_MSI_CTRL_MME_OFFSET); } static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index beabea00af91..cc1456bd188e 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -293,8 +293,6 @@ int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) if (interrupt < 0) return 0; - interrupt = 1 << interrupt; - return interrupt; } EXPORT_SYMBOL_GPL(pci_epc_get_msi); From 0917ed8f16b646c5e3cc481ccfa4709286b76691 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:17 +0200 Subject: [PATCH 130/147] PCI: endpoint: Align pci_epc_get_msix(), pci_epc_ops::get_msix() return value encoding The kdoc for pci_epc_get_msix() says: "Invoke to get the number of MSI-X interrupts allocated by the RC" The kdoc for the callback pci_epc_ops->get_msix() says: "ops to get the number of MSI-X interrupts allocated by the RC from the MSI-X capability register" pci_epc_ops::get_msix() does however return the number of interrupts in the encoding as defined by the Table Size field. Nowhere in the kdoc does it say that the returned number of interrupts is in Table Size encoding. It is very confusing that the API pci_epc_get_msix() and the callback function pci_epc_ops::get_msix() don't return the same value. Clean up the API and the callback function to have the same semantics, i.e. return the number of interrupts, regardless of the internal encoding of that value. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Damien Le Moal Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-12-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 2 +- drivers/pci/controller/dwc/pcie-designware-ep.c | 2 +- drivers/pci/endpoint/pci-epc-core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 78b4d009cd04..569cb7481d45 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -281,7 +281,7 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) val &= PCI_MSIX_FLAGS_QSIZE; - return val; + return val + 1; } static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 03597551f4cd..307c862588a4 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -575,7 +575,7 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) val &= PCI_MSIX_FLAGS_QSIZE; - return val; + return val + 1; } static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index cc1456bd188e..092b14918b46 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -355,7 +355,7 @@ int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) if (interrupt < 0) return 0; - return interrupt + 1; + return interrupt; } EXPORT_SYMBOL_GPL(pci_epc_get_msix); From f62da6e7270c2db5aef8a8b14f465896961a9372 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:18 +0200 Subject: [PATCH 131/147] PCI: endpoint: Align pci_epc_set_msi(), pci_epc_ops::set_msi() nr_irqs encoding The kdoc for pci_epc_set_msi() says: "Invoke to set the required number of MSI interrupts." The kdoc for the callback pci_epc_ops::set_msi() says: "ops to set the requested number of MSI interrupts in the MSI capability register" pci_epc_ops::set_msi() does however expect the parameter 'interrupts' to be in the encoding as defined by the Multiple Message Capable (MMC) field of the MSI capability structure. Nowhere in the kdoc does it say that the number of interrupts should be in MMC encoding. It is very confusing that the API pci_epc_set_msi() and the callback function pci_epc_ops::set_msi() both take a parameter named 'interrupts', but they expect completely different encodings. Clean up the API and the callback function to have the same semantics, i.e. the parameter represents the number of interrupts, regardless of the internal encoding of that value. Also rename the parameter 'interrupts' to 'nr_irqs', in both the wrapper function and the callback function, such that the name is unambiguous. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-13-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 3 ++- drivers/pci/controller/dwc/pcie-designware-ep.c | 5 +++-- drivers/pci/controller/pcie-rcar-ep.c | 6 +++--- drivers/pci/controller/pcie-rockchip-ep.c | 5 +++-- drivers/pci/endpoint/pci-epc-core.c | 11 ++++------- include/linux/pci-epc.h | 5 ++--- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 569cb7481d45..f09f29ed27ed 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -220,10 +220,11 @@ static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, clear_bit(r, &ep->ob_region_map); } -static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc) +static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; + u8 mmc = order_base_2(nr_irqs); u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET; u16 flags; diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 307c862588a4..230e82674591 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -536,11 +536,12 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) } static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u8 interrupts) + u8 nr_irqs) { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; + u8 mmc = order_base_2(nr_irqs); u32 val, reg; ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); @@ -550,7 +551,7 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, reg = ep_func->msi_cap + PCI_MSI_FLAGS; val = dw_pcie_ep_readw_dbi(ep, func_no, reg); val &= ~PCI_MSI_FLAGS_QMASK; - val |= FIELD_PREP(PCI_MSI_FLAGS_QMASK, interrupts); + val |= FIELD_PREP(PCI_MSI_FLAGS_QMASK, mmc); dw_pcie_dbi_ro_wr_en(pci); dw_pcie_ep_writew_dbi(ep, func_no, reg, val); dw_pcie_dbi_ro_wr_dis(pci); diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index 9da39a4617b6..a8a966844cf3 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -256,15 +256,15 @@ static void rcar_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn, clear_bit(atu_index + 1, ep->ib_window_map); } -static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, - u8 interrupts) +static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 nr_irqs) { struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc); struct rcar_pcie *pcie = &ep->pcie; + u8 mmc = order_base_2(nr_irqs); u32 flags; flags = rcar_pci_read_reg(pcie, MSICAP(fn)); - flags |= interrupts << MSICAP0_MMESCAP_OFFSET; + flags |= mmc << MSICAP0_MMESCAP_OFFSET; rcar_pci_write_reg(pcie, flags, MSICAP(fn)); return 0; diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 85ca7d9b4c77..a0a85080c31d 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -308,10 +308,11 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, } static int rockchip_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, - u8 multi_msg_cap) + u8 nr_irqs) { struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); struct rockchip_pcie *rockchip = &ep->rockchip; + u8 mmc = order_base_2(nr_irqs); u32 flags; flags = rockchip_pcie_read(rockchip, @@ -319,7 +320,7 @@ static int rockchip_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, ROCKCHIP_PCIE_EP_MSI_CTRL_REG); flags &= ~ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_MASK; flags |= - (multi_msg_cap << ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET) | + (mmc << ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET) | (PCI_MSI_FLAGS_64BIT << ROCKCHIP_PCIE_EP_MSI_FLAGS_OFFSET); flags &= ~ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP; rockchip_pcie_write(rockchip, flags, diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 092b14918b46..ea698551f9d8 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -302,28 +302,25 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msi); * @epc: the EPC device on which MSI has to be configured * @func_no: the physical endpoint function number in the EPC device * @vfunc_no: the virtual endpoint function number in the physical function - * @interrupts: number of MSI interrupts required by the EPF + * @nr_irqs: number of MSI interrupts required by the EPF * * Invoke to set the required number of MSI interrupts. */ -int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 interrupts) +int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 nr_irqs) { int ret; - u8 encode_int; if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; - if (interrupts < 1 || interrupts > 32) + if (nr_irqs < 1 || nr_irqs > 32) return -EINVAL; if (!epc->ops->set_msi) return 0; - encode_int = order_base_2(interrupts); - mutex_lock(&epc->lock); - ret = epc->ops->set_msi(epc, func_no, vfunc_no, encode_int); + ret = epc->ops->set_msi(epc, func_no, vfunc_no, nr_irqs); mutex_unlock(&epc->lock); return ret; diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index 82837008b56f..15d10c07c9f1 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -100,7 +100,7 @@ struct pci_epc_ops { void (*unmap_addr)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t addr); int (*set_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u8 interrupts); + u8 nr_irqs); int (*get_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int (*set_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 interrupts, enum pci_barno, u32 offset); @@ -286,8 +286,7 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u64 pci_addr, size_t size); void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr); -int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u8 interrupts); +int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 nr_irqs); int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 interrupts, enum pci_barno, u32 offset); From de0321bcc5fdd83631f0c2a6fdebfe0ad4e23449 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 14 May 2025 09:43:19 +0200 Subject: [PATCH 132/147] PCI: endpoint: Align pci_epc_set_msix(), pci_epc_ops::set_msix() nr_irqs encoding The kdoc for pci_epc_set_msix() says: "Invoke to set the required number of MSI-X interrupts." The kdoc for the callback pci_epc_ops->set_msix() says: "ops to set the requested number of MSI-X interrupts in the MSI-X capability register" pci_epc_ops::set_msix() does however expect the parameter 'interrupts' to be in the encoding as defined by the Table Size field. Nowhere in the kdoc does it say that the number of interrupts should be in Table Size encoding. It is very confusing that the API pci_epc_set_msix() and the callback function pci_epc_ops::set_msix() both take a parameter named 'interrupts', but they expect completely different encodings. Clean up the API and the callback function to have the same semantics, i.e. the parameter represents the number of interrupts, regardless of the internal encoding of that value. Also rename the parameter 'interrupts' to 'nr_irqs', in both the wrapper function and the callback function, such that the name is unambiguous. [bhelgaas: more specific subject] Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Cc: stable+noautosel@kernel.org # this is simply a cleanup Link: https://patch.msgid.link/20250514074313.283156-14-cassel@kernel.org --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 8 +++----- drivers/pci/controller/dwc/pcie-designware-ep.c | 7 +++---- drivers/pci/endpoint/pci-epc-core.c | 11 +++++------ include/linux/pci-epc.h | 6 +++--- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index f09f29ed27ed..0e9ebe956e7a 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -286,21 +286,19 @@ static int cdns_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) } static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, - u16 interrupts, enum pci_barno bir, - u32 offset) + u16 nr_irqs, enum pci_barno bir, u32 offset) { struct cdns_pcie_ep *ep = epc_get_drvdata(epc); struct cdns_pcie *pcie = &ep->pcie; u32 cap = CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET; u32 val, reg; - u16 actual_interrupts = interrupts + 1; fn = cdns_pcie_get_fn_from_vfn(pcie, fn, vfn); reg = cap + PCI_MSIX_FLAGS; val = cdns_pcie_ep_fn_readw(pcie, fn, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; /* 0's based value */ + val |= nr_irqs - 1; /* encoded as N-1 */ cdns_pcie_ep_fn_writew(pcie, fn, reg, val); /* Set MSI-X BAR and offset */ @@ -310,7 +308,7 @@ static int cdns_pcie_ep_set_msix(struct pci_epc *epc, u8 fn, u8 vfn, /* Set PBA BAR and offset. BAR must match MSI-X BAR */ reg = cap + PCI_MSIX_PBA; - val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (nr_irqs * PCI_MSIX_ENTRY_SIZE)) | bir; cdns_pcie_ep_fn_writel(pcie, fn, reg, val); return 0; diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 230e82674591..6770318c0636 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -580,13 +580,12 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) } static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno bir, u32 offset) + u16 nr_irqs, enum pci_barno bir, u32 offset) { struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie_ep_func *ep_func; u32 val, reg; - u16 actual_interrupts = interrupts + 1; ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no); if (!ep_func || !ep_func->msix_cap) @@ -597,7 +596,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, reg = ep_func->msix_cap + PCI_MSIX_FLAGS; val = dw_pcie_ep_readw_dbi(ep, func_no, reg); val &= ~PCI_MSIX_FLAGS_QSIZE; - val |= interrupts; /* 0's based value */ + val |= nr_irqs - 1; /* encoded as N-1 */ dw_pcie_writew_dbi(pci, reg, val); reg = ep_func->msix_cap + PCI_MSIX_TABLE; @@ -605,7 +604,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, dw_pcie_ep_writel_dbi(ep, func_no, reg, val); reg = ep_func->msix_cap + PCI_MSIX_PBA; - val = (offset + (actual_interrupts * PCI_MSIX_ENTRY_SIZE)) | bir; + val = (offset + (nr_irqs * PCI_MSIX_ENTRY_SIZE)) | bir; dw_pcie_ep_writel_dbi(ep, func_no, reg, val); dw_pcie_dbi_ro_wr_dis(pci); diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index ea698551f9d8..ca7f19cc973a 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -361,29 +361,28 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msix); * @epc: the EPC device on which MSI-X has to be configured * @func_no: the physical endpoint function number in the EPC device * @vfunc_no: the virtual endpoint function number in the physical function - * @interrupts: number of MSI-X interrupts required by the EPF + * @nr_irqs: number of MSI-X interrupts required by the EPF * @bir: BAR where the MSI-X table resides * @offset: Offset pointing to the start of MSI-X table * * Invoke to set the required number of MSI-X interrupts. */ -int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno bir, u32 offset) +int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 nr_irqs, + enum pci_barno bir, u32 offset) { int ret; if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; - if (interrupts < 1 || interrupts > 2048) + if (nr_irqs < 1 || nr_irqs > 2048) return -EINVAL; if (!epc->ops->set_msix) return 0; mutex_lock(&epc->lock); - ret = epc->ops->set_msix(epc, func_no, vfunc_no, interrupts - 1, bir, - offset); + ret = epc->ops->set_msix(epc, func_no, vfunc_no, nr_irqs, bir, offset); mutex_unlock(&epc->lock); return ret; diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index 15d10c07c9f1..4286bfdbfdfa 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -103,7 +103,7 @@ struct pci_epc_ops { u8 nr_irqs); int (*get_msi)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int (*set_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno, u32 offset); + u16 nr_irqs, enum pci_barno, u32 offset); int (*get_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int (*raise_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, unsigned int type, u16 interrupt_num); @@ -288,8 +288,8 @@ void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr); int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 nr_irqs); int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no); -int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, - u16 interrupts, enum pci_barno, u32 offset); +int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u16 nr_irqs, + enum pci_barno, u32 offset); int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no); int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr, u8 interrupt_num, From 16b2da850f6f79bf9013516ce78b27a8abb10359 Mon Sep 17 00:00:00 2001 From: Hans Zhang <18255117159@163.com> Date: Tue, 1 Apr 2025 22:50:23 +0800 Subject: [PATCH 133/147] PCI: cadence: Remove duplicate message code definitions The Cadence PCIe controller driver defines message codes in enum cdns_pcie_msg_code duplicating the existing PCIE_MSG_CODE_* definitions in drivers/pci/pci.h. The driver only uses ASSERT_INTA and DEASSERT_INTA codes from this enum. Remove the redundant Cadence-specific enum definitions and use the ones available in drivers/pci/pci.h. This helps in avoiding code duplication, maintaining consistency with the spec, and simplifying the code maintenance. Signed-off-by: Hans Zhang <18255117159@163.com> [mani: commit message rewording] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250401145023.22948-1-18255117159@163.com --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 5 +++-- drivers/pci/controller/cadence/pcie-cadence.h | 11 ----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 599ec4b1223e..12454142f3b3 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -12,6 +12,7 @@ #include #include "pcie-cadence.h" +#include "../../pci.h" #define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */ #define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1 @@ -337,10 +338,10 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, u8 intx, if (is_asserted) { ep->irq_pending |= BIT(intx); - msg_code = MSG_CODE_ASSERT_INTA + intx; + msg_code = PCIE_MSG_CODE_ASSERT_INTA + intx; } else { ep->irq_pending &= ~BIT(intx); - msg_code = MSG_CODE_DEASSERT_INTA + intx; + msg_code = PCIE_MSG_CODE_DEASSERT_INTA + intx; } spin_lock_irqsave(&ep->lock, flags); diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 39ee9945c903..3632d5c12c2a 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -250,17 +250,6 @@ struct cdns_pcie_rp_ib_bar { struct cdns_pcie; -enum cdns_pcie_msg_code { - MSG_CODE_ASSERT_INTA = 0x20, - MSG_CODE_ASSERT_INTB = 0x21, - MSG_CODE_ASSERT_INTC = 0x22, - MSG_CODE_ASSERT_INTD = 0x23, - MSG_CODE_DEASSERT_INTA = 0x24, - MSG_CODE_DEASSERT_INTB = 0x25, - MSG_CODE_DEASSERT_INTC = 0x26, - MSG_CODE_DEASSERT_INTD = 0x27, -}; - enum cdns_pcie_msg_routing { /* Route to Root Complex */ MSG_ROUTING_TO_RC, From b06d125e6280603a34d9064cd9c12748ca2edb04 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 8 May 2025 12:40:30 +0530 Subject: [PATCH 134/147] PCI/ERR: Remove misleading TODO regarding kernel panic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A PCI device is just another peripheral in a system. So failure to recover it, must not result in a kernel panic. So remove the TODO which is quite misleading. Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Reviewed-by: Wilfred Mallawa Link: https://patch.msgid.link/20250508-pcie-reset-slot-v4-1-7050093e2b50@linaro.org --- drivers/pci/pcie/err.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 31090770fffc..de6381c690f5 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -271,7 +271,6 @@ failed: pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT); - /* TODO: Should kernel panic here? */ pci_info(bridge, "device recovery failed\n"); return status; From d1c696dba120624256ab335ab8247f535b872309 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 8 May 2025 12:40:32 +0530 Subject: [PATCH 135/147] PCI: host-common: Convert to library for host controller drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This common library will be used as a placeholder for helper functions shared by the host controller drivers. This avoids placing the host controller drivers specific helpers in drivers/pci/*.c, to avoid enlarging the kernel image on platforms that do not use host controller drivers at all (like x86/ACPI platforms). Suggested-by: Lukas Wunner Signed-off-by: Manivannan Sadhasivam Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250508-pcie-reset-slot-v4-3-7050093e2b50@linaro.org --- drivers/pci/controller/Kconfig | 8 ++++---- drivers/pci/controller/dwc/pcie-hisi.c | 1 + drivers/pci/controller/pci-host-common.c | 6 ++++-- drivers/pci/controller/pci-host-common.h | 16 ++++++++++++++++ drivers/pci/controller/pci-host-generic.c | 2 ++ drivers/pci/controller/pci-thunder-ecam.c | 2 ++ drivers/pci/controller/pci-thunder-pem.c | 1 + drivers/pci/controller/pcie-apple.c | 2 ++ .../pci/controller/plda/pcie-microchip-host.c | 1 + include/linux/pci-ecam.h | 6 ------ 10 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 drivers/pci/controller/pci-host-common.h diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 9800b7681054..9bb8bf669a80 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -3,6 +3,10 @@ menu "PCI controller drivers" depends on PCI +config PCI_HOST_COMMON + tristate + select PCI_ECAM + config PCI_AARDVARK tristate "Aardvark PCIe controller" depends on (ARCH_MVEBU && ARM64) || COMPILE_TEST @@ -119,10 +123,6 @@ config PCI_FTPCI100 depends on OF default ARCH_GEMINI -config PCI_HOST_COMMON - tristate - select PCI_ECAM - config PCI_HOST_GENERIC tristate "Generic PCI host controller" depends on OF diff --git a/drivers/pci/controller/dwc/pcie-hisi.c b/drivers/pci/controller/dwc/pcie-hisi.c index 8904b5b85ee5..3c17897e56fc 100644 --- a/drivers/pci/controller/dwc/pcie-hisi.c +++ b/drivers/pci/controller/dwc/pcie-hisi.c @@ -15,6 +15,7 @@ #include #include #include "../../pci.h" +#include "../pci-host-common.h" #if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c index f441bfd6f96a..f93bc7034e69 100644 --- a/drivers/pci/controller/pci-host-common.c +++ b/drivers/pci/controller/pci-host-common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Generic PCI host driver common code + * Common library for PCI host controller drivers * * Copyright (C) 2014 ARM Limited * @@ -15,6 +15,8 @@ #include #include +#include "pci-host-common.h" + static void gen_pci_unmap_cfg(void *ptr) { pci_ecam_free((struct pci_config_window *)ptr); @@ -94,5 +96,5 @@ void pci_host_common_remove(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(pci_host_common_remove); -MODULE_DESCRIPTION("Generic PCI host common driver"); +MODULE_DESCRIPTION("Common library for PCI host controller drivers"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/controller/pci-host-common.h b/drivers/pci/controller/pci-host-common.h new file mode 100644 index 000000000000..d8be024ca68d --- /dev/null +++ b/drivers/pci/controller/pci-host-common.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Common library for PCI host controller drivers + * + * Copyright (C) 2014 ARM Limited + * + * Author: Will Deacon + */ + +#ifndef _PCI_HOST_COMMON_H +#define _PCI_HOST_COMMON_H + +int pci_host_common_probe(struct platform_device *pdev); +void pci_host_common_remove(struct platform_device *pdev); + +#endif diff --git a/drivers/pci/controller/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c index 4051b9b61dac..c1bc0d34348f 100644 --- a/drivers/pci/controller/pci-host-generic.c +++ b/drivers/pci/controller/pci-host-generic.c @@ -14,6 +14,8 @@ #include #include +#include "pci-host-common.h" + static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = { .bus_shift = 16, .pci_ops = { diff --git a/drivers/pci/controller/pci-thunder-ecam.c b/drivers/pci/controller/pci-thunder-ecam.c index 08161065a89c..b5b4a958e6a2 100644 --- a/drivers/pci/controller/pci-thunder-ecam.c +++ b/drivers/pci/controller/pci-thunder-ecam.c @@ -11,6 +11,8 @@ #include #include +#include "pci-host-common.h" + #if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) static void set_val(u32 v, int where, int size, u32 *val) diff --git a/drivers/pci/controller/pci-thunder-pem.c b/drivers/pci/controller/pci-thunder-pem.c index f1bd5de67997..5fa037fb61dc 100644 --- a/drivers/pci/controller/pci-thunder-pem.c +++ b/drivers/pci/controller/pci-thunder-pem.c @@ -14,6 +14,7 @@ #include #include #include "../pci.h" +#include "pci-host-common.h" #if defined(CONFIG_PCI_HOST_THUNDER_PEM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) diff --git a/drivers/pci/controller/pcie-apple.c b/drivers/pci/controller/pcie-apple.c index 18e11b9a7f46..edd4c8c683c6 100644 --- a/drivers/pci/controller/pcie-apple.c +++ b/drivers/pci/controller/pcie-apple.c @@ -29,6 +29,8 @@ #include #include +#include "pci-host-common.h" + #define CORE_RC_PHYIF_CTL 0x00024 #define CORE_RC_PHYIF_CTL_RUN BIT(0) #define CORE_RC_PHYIF_STAT 0x00028 diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c index 3fdfffdf0270..24bbf93b8051 100644 --- a/drivers/pci/controller/plda/pcie-microchip-host.c +++ b/drivers/pci/controller/plda/pcie-microchip-host.c @@ -23,6 +23,7 @@ #include #include "../../pci.h" +#include "../pci-host-common.h" #include "pcie-plda.h" #define MC_MAX_NUM_INBOUND_WINDOWS 8 diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 3a10f8cfc3ad..d930651473b4 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -93,10 +93,4 @@ extern const struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */ extern const struct pci_ecam_ops tegra194_pcie_ops; /* Tegra194 PCIe */ extern const struct pci_ecam_ops loongson_pci_ecam_ops; /* Loongson PCIe */ #endif - -#if IS_ENABLED(CONFIG_PCI_HOST_COMMON) -/* for DT-based PCI controllers that support ECAM */ -int pci_host_common_probe(struct platform_device *pdev); -void pci_host_common_remove(struct platform_device *pdev); -#endif #endif From d34719d0e81f5bf1750931562a36a6f3fa6512bc Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 6 May 2025 09:39:38 +0200 Subject: [PATCH 136/147] PCI: dw-rockchip: Replace PERST# sleep time with proper macro Replace the PERST# sleep time with the proper macro (PCIE_T_PVPERL_MS). No functional change. Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Tested-by: Laszlo Fiat Reviewed-by: Hans Zhang <18255117159@163.com> Reviewed-by: Wilfred Mallawa Link: https://patch.msgid.link/20250506073934.433176-9-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-dw-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index ae171a545df6..6089a6a9f252 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -22,6 +22,7 @@ #include #include +#include "../../pci.h" #include "pcie-designware.h" /* @@ -224,7 +225,7 @@ static int rockchip_pcie_start_link(struct dw_pcie *pci) * We need more extra time as before, rather than setting just * 100us as we don't know how long should the device need to reset. */ - msleep(100); + msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(rockchip->rst_gpio, 1); return 0; From ec49e253322bf29e721c6153d9e7be95eef33b33 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 6 May 2025 09:39:39 +0200 Subject: [PATCH 137/147] PCI: qcom: Replace PERST# sleep time with proper macro Replace the PERST# sleep time with the proper macro (PCIE_T_PVPERL_MS). No functional change. Signed-off-by: Niklas Cassel Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Wilfred Mallawa Reviewed-by: Hans Zhang <18255117159@163.com> Reviewed-by: Krishna Chaitanya Chundru Link: https://patch.msgid.link/20250506073934.433176-10-cassel@kernel.org --- drivers/pci/controller/dwc/pcie-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index ba0dd1717a58..a623ed0fbc2f 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -289,7 +289,7 @@ static void qcom_ep_reset_assert(struct qcom_pcie *pcie) static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) { /* Ensure that PERST has been asserted for at least 100 ms */ - msleep(100); + msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(pcie->reset, 0); usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500); } From 1c8a0ed2043c30cee97facd1eb8cff88b6c7ea4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 7 Apr 2025 13:12:14 +0300 Subject: [PATCH 138/147] PCI: Remove unused pci_printk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit include/linux/pci.h provides low-level pci_printk() interface that is not used since the commits fab874e12593 ("PCI/AER: Descope pci_printk() to aer_printk()") and 588021b28642 ("PCI: shpchp: Remove 'shpchp_debug' module parameter"). PCI logging should not use pci_printk() but pci_*() wrappers that follow the usual logging wrapper patterns. Remove pci_printk(). Signed-off-by: Ilpo Järvinen Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20250407101215.1376-1-ilpo.jarvinen@linux.intel.com --- include/linux/pci.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e8e3fd77e96..e293ad5d840d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2694,9 +2694,6 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type); #include -#define pci_printk(level, pdev, fmt, arg...) \ - dev_printk(level, &(pdev)->dev, fmt, ##arg) - #define pci_emerg(pdev, fmt, arg...) dev_emerg(&(pdev)->dev, fmt, ##arg) #define pci_alert(pdev, fmt, arg...) dev_alert(&(pdev)->dev, fmt, ##arg) #define pci_crit(pdev, fmt, arg...) dev_crit(&(pdev)->dev, fmt, ##arg) From af6e3defb11a1c67cd462485655b43b5d70524b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 12 May 2025 00:52:23 +0300 Subject: [PATCH 139/147] PCI: WARN (not BUG()) when we fail to assign optional resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resource fitting/assignment code checks if there's a remainder in add_list (aka. realloc_head in the inner functions) using BUG_ON(). This problem typically results in a mere PCI device resource assignment failure which does not warrant using BUG_ON(). The machine could well come up usable even if this condition occurs because the realloc_head relates to resources which are optional anyway. Change BUG_ON() to WARN_ON_ONCE() and free the list if it's not empty. [bhelgaas: subject] Reported-by: Tudor Ambarus Signed-off-by: Ilpo Järvinen Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Link: https://lore.kernel.org/linux-pci/5f103643-5e1c-43c6-b8fe-9617d3b5447c@linaro.org Link: https://lore.kernel.org/r/20250511215223.7131-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 54d6f4fa3ce1..a0d815557f5c 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2298,8 +2298,8 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus) /* Depth last, allocate resources and update the hardware. */ __pci_bus_assign_resources(bus, add_list, &fail_head); - if (add_list) - BUG_ON(!list_empty(add_list)); + if (WARN_ON_ONCE(add_list && !list_empty(add_list))) + free_list(add_list); tried_times++; /* Any device complain? */ @@ -2361,7 +2361,8 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) pci_bridge_distribute_available_resources(bridge, &add_list); __pci_bridge_assign_resources(bridge, &add_list, &fail_head); - BUG_ON(!list_empty(&add_list)); + if (WARN_ON_ONCE(!list_empty(&add_list))) + free_list(&add_list); tried_times++; if (list_empty(&fail_head)) @@ -2437,7 +2438,8 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) __pci_bus_size_bridges(bridge->subordinate, &added); __pci_bridge_assign_resources(bridge, &added, &failed); - BUG_ON(!list_empty(&added)); + if (WARN_ON_ONCE(!list_empty(&added))) + free_list(&added); if (!list_empty(&failed)) { ret = -ENOSPC; @@ -2493,6 +2495,7 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus) __pci_bus_size_bridges(dev->subordinate, &add_list); up_read(&pci_bus_sem); __pci_bus_assign_resources(bus, &add_list, NULL); - BUG_ON(!list_empty(&add_list)); + if (WARN_ON_ONCE(!list_empty(&add_list))) + free_list(&add_list); } EXPORT_SYMBOL_GPL(pci_assign_unassigned_bus_resources); From 75d7b40becfb9de11f9c2ff7138111eb48e76099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 4 Apr 2025 15:45:47 +0300 Subject: [PATCH 140/147] PCI: Remove unnecessary linesplit in __pci_setup_bridge() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to split the line in __pci_setup_bridge() as it is way shorter than the limit. Signed-off-by: Ilpo Järvinen Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Link: https://lore.kernel.org/r/20250404124547.51185-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a0d815557f5c..cc37cdb5e352 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -772,8 +772,7 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) { struct pci_dev *bridge = bus->self; - pci_info(bridge, "PCI bridge to %pR\n", - &bus->busn_res); + pci_info(bridge, "PCI bridge to %pR\n", &bus->busn_res); if (type & IORESOURCE_IO) pci_setup_bridge_io(bridge); From ae06c6197c9e53dcb115f1f7aad9e86aa465adae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= Date: Fri, 18 Apr 2025 04:52:51 +0000 Subject: [PATCH 141/147] =?UTF-8?q?MAINTAINERS:=20Update=20Krzysztof=20Wil?= =?UTF-8?q?czy=C5=84ski=20email=20address?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update my e-mail address and add relevant entries to the .mailmap file. [bhelgaas: drop maintainer status change] Signed-off-by: Krzysztof Wilczyński Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250418045251.7434-1-kwilczynski@kernel.org --- .mailmap | 2 ++ MAINTAINERS | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index 4f7cd8e23177..5224f3cc2d34 100644 --- a/.mailmap +++ b/.mailmap @@ -413,6 +413,8 @@ Krishna Manikandan Krzysztof Kozlowski Krzysztof Kozlowski Krzysztof Kozlowski +Krzysztof Wilczyński +Krzysztof Wilczyński Kshitiz Godara Kuninori Morimoto Kuogee Hsieh diff --git a/MAINTAINERS b/MAINTAINERS index 1f6514d55b17..d5d1a4aea0e8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18581,7 +18581,7 @@ F: drivers/pci/controller/pcie-xilinx-cpm.c PCI ENDPOINT SUBSYSTEM M: Manivannan Sadhasivam -M: Krzysztof Wilczyński +M: Krzysztof Wilczyński R: Kishon Vijay Abraham I L: linux-pci@vger.kernel.org S: Supported @@ -18632,7 +18632,7 @@ F: drivers/pci/controller/pci-xgene-msi.c PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS M: Lorenzo Pieralisi -M: Krzysztof Wilczyński +M: Krzysztof Wilczyński R: Manivannan Sadhasivam R: Rob Herring L: linux-pci@vger.kernel.org From f876904e44360449e64e2d38c428eba3a03d7a47 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 17 Apr 2025 18:14:05 +0530 Subject: [PATCH 142/147] PCI: cadence: Add support to build pcie-cadence library as a kernel module Currently, the Cadence PCIe controller driver can be built as a built-in module only. Since PCIe functionality is not a necessity for booting, add support to build the Cadence PCIe driver as a loadable module as well. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250417124408.2752248-2-s-vadapalli@ti.com --- drivers/pci/controller/cadence/Kconfig | 6 +++--- drivers/pci/controller/cadence/pcie-cadence-ep.c | 6 ++++++ drivers/pci/controller/cadence/pcie-cadence-host.c | 9 +++++++++ drivers/pci/controller/cadence/pcie-cadence.c | 12 ++++++++++++ drivers/pci/controller/cadence/pcie-cadence.h | 4 ++-- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig index 8a0044bb3989..82b58096eea0 100644 --- a/drivers/pci/controller/cadence/Kconfig +++ b/drivers/pci/controller/cadence/Kconfig @@ -4,16 +4,16 @@ menu "Cadence-based PCIe controllers" depends on PCI config PCIE_CADENCE - bool + tristate config PCIE_CADENCE_HOST - bool + tristate depends on OF select IRQ_DOMAIN select PCIE_CADENCE config PCIE_CADENCE_EP - bool + tristate depends on OF depends on PCI_ENDPOINT select PCIE_CADENCE diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 12454142f3b3..387c0c49333b 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -752,3 +753,8 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) return ret; } +EXPORT_SYMBOL_GPL(cdns_pcie_ep_setup); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cadence PCIe endpoint controller driver"); +MODULE_AUTHOR("Cyrille Pitchen "); diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c index 741e10a575ec..f04623f32d82 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -72,6 +73,7 @@ void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, return rc->cfg_base + (where & 0xfff); } +EXPORT_SYMBOL_GPL(cdns_pci_map_bus); static struct pci_ops cdns_pcie_host_ops = { .map_bus = cdns_pci_map_bus, @@ -495,6 +497,7 @@ int cdns_pcie_host_init(struct cdns_pcie_rc *rc) return cdns_pcie_host_init_address_translation(rc); } +EXPORT_SYMBOL_GPL(cdns_pcie_host_init); int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc) { @@ -519,6 +522,7 @@ int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc) return 0; } +EXPORT_SYMBOL_GPL(cdns_pcie_host_link_setup); int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) { @@ -572,3 +576,8 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) return pci_host_probe(bridge); } +EXPORT_SYMBOL_GPL(cdns_pcie_host_setup); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cadence PCIe host controller driver"); +MODULE_AUTHOR("Cyrille Pitchen "); diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c index 204e045aed8c..70a19573440e 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.c +++ b/drivers/pci/controller/cadence/pcie-cadence.c @@ -4,6 +4,7 @@ // Author: Cyrille Pitchen #include +#include #include #include "pcie-cadence.h" @@ -23,6 +24,7 @@ void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie) cdns_pcie_writel(pcie, CDNS_PCIE_LTSSM_CONTROL_CAP, ltssm_control_cap); } +EXPORT_SYMBOL_GPL(cdns_pcie_detect_quiet_min_delay_set); void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn, u32 r, bool is_io, @@ -100,6 +102,7 @@ void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 busnr, u8 fn, cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0); cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1); } +EXPORT_SYMBOL_GPL(cdns_pcie_set_outbound_region); void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 busnr, u8 fn, @@ -134,6 +137,7 @@ void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0); cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1); } +EXPORT_SYMBOL_GPL(cdns_pcie_set_outbound_region_for_normal_msg); void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) { @@ -146,6 +150,7 @@ void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r) cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0); cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0); } +EXPORT_SYMBOL_GPL(cdns_pcie_reset_outbound_region); void cdns_pcie_disable_phy(struct cdns_pcie *pcie) { @@ -156,6 +161,7 @@ void cdns_pcie_disable_phy(struct cdns_pcie *pcie) phy_exit(pcie->phy[i]); } } +EXPORT_SYMBOL_GPL(cdns_pcie_disable_phy); int cdns_pcie_enable_phy(struct cdns_pcie *pcie) { @@ -184,6 +190,7 @@ err_phy: return ret; } +EXPORT_SYMBOL_GPL(cdns_pcie_enable_phy); int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) { @@ -243,6 +250,7 @@ err_phy: return ret; } +EXPORT_SYMBOL_GPL(cdns_pcie_init_phy); static int cdns_pcie_suspend_noirq(struct device *dev) { @@ -271,3 +279,7 @@ const struct dev_pm_ops cdns_pcie_pm_ops = { NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_pcie_suspend_noirq, cdns_pcie_resume_noirq) }; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cadence PCIe controller driver"); +MODULE_AUTHOR("Cyrille Pitchen "); diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 3632d5c12c2a..033cade8bbf5 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -508,7 +508,7 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie) return true; } -#ifdef CONFIG_PCIE_CADENCE_HOST +#if IS_ENABLED(CONFIG_PCIE_CADENCE_HOST) int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc); int cdns_pcie_host_init(struct cdns_pcie_rc *rc); int cdns_pcie_host_setup(struct cdns_pcie_rc *rc); @@ -537,7 +537,7 @@ static inline void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int d } #endif -#ifdef CONFIG_PCIE_CADENCE_EP +#if IS_ENABLED(CONFIG_PCIE_CADENCE_EP) int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep); #else static inline int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) From 47f25da6c5ea55494f4de5ca1ecf6c456b4b3e2a Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Thu, 17 Apr 2025 18:14:06 +0530 Subject: [PATCH 143/147] PCI: cadence-host: Introduce cdns_pcie_host_disable() helper for cleanup Introduce the helper function cdns_pcie_host_disable() which will undo the configuration performed by cdns_pcie_host_setup(). Also, export it for use by existing callers of cdns_pcie_host_setup(), thereby allowing them to cleanup on their exit path. Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250417124408.2752248-3-s-vadapalli@ti.com --- .../controller/cadence/pcie-cadence-host.c | 104 ++++++++++++++++++ drivers/pci/controller/cadence/pcie-cadence.h | 5 + 2 files changed, 109 insertions(+) diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c index f04623f32d82..59a4631de79f 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-host.c +++ b/drivers/pci/controller/cadence/pcie-cadence-host.c @@ -152,6 +152,14 @@ static int cdns_pcie_retrain(struct cdns_pcie *pcie) return ret; } +static void cdns_pcie_host_disable_ptm_response(struct cdns_pcie *pcie) +{ + u32 val; + + val = cdns_pcie_readl(pcie, CDNS_PCIE_LM_PTM_CTRL); + cdns_pcie_writel(pcie, CDNS_PCIE_LM_PTM_CTRL, val & ~CDNS_PCIE_LM_TPM_CTRL_PTMRSEN); +} + static void cdns_pcie_host_enable_ptm_response(struct cdns_pcie *pcie) { u32 val; @@ -177,6 +185,26 @@ static int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc) return ret; } +static void cdns_pcie_host_deinit_root_port(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + u32 value, ctrl; + + cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, 0xffff); + cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0xff); + cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0xff); + cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, 0xffffffff); + cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, 0xffff); + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; + value = ~(CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS); + cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); +} + static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc) { struct cdns_pcie *pcie = &rc->pcie; @@ -393,6 +421,32 @@ static int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a, return resource_size(entry2->res) - resource_size(entry1->res); } +static void cdns_pcie_host_unmap_dma_ranges(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + enum cdns_pcie_rp_bar bar; + u32 value; + + /* Reset inbound configuration for all BARs which were being used */ + for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) { + if (rc->avail_ib_bar[bar]) + continue; + + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), 0); + cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), 0); + + if (bar == RP_NO_BAR) + continue; + + value = ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) | + LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) | + LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) | + LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) | + LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2)); + cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); + } +} + static int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc) { struct cdns_pcie *pcie = &rc->pcie; @@ -430,6 +484,29 @@ static int cdns_pcie_host_map_dma_ranges(struct cdns_pcie_rc *rc) return 0; } +static void cdns_pcie_host_deinit_address_translation(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc); + struct resource_entry *entry; + int r; + + cdns_pcie_host_unmap_dma_ranges(rc); + + /* + * Reset outbound region 0 which was reserved for configuration space + * accesses. + */ + cdns_pcie_reset_outbound_region(pcie, 0); + + /* Reset rest of the outbound regions */ + r = 1; + resource_list_for_each_entry(entry, &bridge->windows) { + cdns_pcie_reset_outbound_region(pcie, r); + r++; + } +} + static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) { struct cdns_pcie *pcie = &rc->pcie; @@ -487,6 +564,12 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) return cdns_pcie_host_map_dma_ranges(rc); } +static void cdns_pcie_host_deinit(struct cdns_pcie_rc *rc) +{ + cdns_pcie_host_deinit_address_translation(rc); + cdns_pcie_host_deinit_root_port(rc); +} + int cdns_pcie_host_init(struct cdns_pcie_rc *rc) { int err; @@ -499,6 +582,14 @@ int cdns_pcie_host_init(struct cdns_pcie_rc *rc) } EXPORT_SYMBOL_GPL(cdns_pcie_host_init); +static void cdns_pcie_host_link_disable(struct cdns_pcie_rc *rc) +{ + struct cdns_pcie *pcie = &rc->pcie; + + cdns_pcie_stop_link(pcie); + cdns_pcie_host_disable_ptm_response(pcie); +} + int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc) { struct cdns_pcie *pcie = &rc->pcie; @@ -524,6 +615,19 @@ int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc) } EXPORT_SYMBOL_GPL(cdns_pcie_host_link_setup); +void cdns_pcie_host_disable(struct cdns_pcie_rc *rc) +{ + struct pci_host_bridge *bridge; + + bridge = pci_host_bridge_from_priv(rc); + pci_stop_root_bus(bridge->bus); + pci_remove_root_bus(bridge->bus); + + cdns_pcie_host_deinit(rc); + cdns_pcie_host_link_disable(rc); +} +EXPORT_SYMBOL_GPL(cdns_pcie_host_disable); + int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) { struct device *dev = rc->pcie.dev; diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 033cade8bbf5..40ff5aadc94f 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -512,6 +512,7 @@ static inline bool cdns_pcie_link_up(struct cdns_pcie *pcie) int cdns_pcie_host_link_setup(struct cdns_pcie_rc *rc); int cdns_pcie_host_init(struct cdns_pcie_rc *rc); int cdns_pcie_host_setup(struct cdns_pcie_rc *rc); +void cdns_pcie_host_disable(struct cdns_pcie_rc *rc); void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, int where); #else @@ -530,6 +531,10 @@ static inline int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) return 0; } +static inline void cdns_pcie_host_disable(struct cdns_pcie_rc *rc) +{ +} + static inline void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { From 3a4b05c9bae485d230560278a659e0830f96e28f Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Thu, 17 Apr 2025 18:14:07 +0530 Subject: [PATCH 144/147] PCI: cadence-ep: Introduce cdns_pcie_ep_disable() helper for cleanup Introduce the helper function cdns_pcie_ep_disable() which will undo the configuration performed by cdns_pcie_ep_setup(). Also, export it for use by the existing callers of cdns_pcie_ep_setup(), thereby allowing them to cleanup on their exit path. Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250417124408.2752248-4-s-vadapalli@ti.com --- drivers/pci/controller/cadence/pcie-cadence-ep.c | 11 +++++++++++ drivers/pci/controller/cadence/pcie-cadence.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c index 387c0c49333b..26534b6f3a87 100644 --- a/drivers/pci/controller/cadence/pcie-cadence-ep.c +++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c @@ -646,6 +646,17 @@ static const struct pci_epc_ops cdns_pcie_epc_ops = { .get_features = cdns_pcie_ep_get_features, }; +void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep) +{ + struct device *dev = ep->pcie.dev; + struct pci_epc *epc = to_pci_epc(dev); + + pci_epc_deinit_notify(epc); + pci_epc_mem_free_addr(epc, ep->irq_phys_addr, ep->irq_cpu_addr, + SZ_128K); + pci_epc_mem_exit(epc); +} +EXPORT_SYMBOL_GPL(cdns_pcie_ep_disable); int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) { diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h index 40ff5aadc94f..a149845d341a 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.h +++ b/drivers/pci/controller/cadence/pcie-cadence.h @@ -544,11 +544,16 @@ static inline void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int d #if IS_ENABLED(CONFIG_PCIE_CADENCE_EP) int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep); +void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep); #else static inline int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) { return 0; } + +static inline void cdns_pcie_ep_disable(struct cdns_pcie_ep *ep) +{ +} #endif void cdns_pcie_detect_quiet_min_delay_set(struct cdns_pcie *pcie); From a2790bf81f0f7b0fb683204cd3bef07feecb9958 Mon Sep 17 00:00:00 2001 From: Siddharth Vadapalli Date: Thu, 17 Apr 2025 18:14:08 +0530 Subject: [PATCH 145/147] PCI: j721e: Add support to build as a loadable module The 'pci-j721e.c' driver is the application/glue/wrapper driver for the Cadence PCIe Controllers on TI SoCs. Implement support for building it as a loadable module. Signed-off-by: Siddharth Vadapalli Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20250417124408.2752248-5-s-vadapalli@ti.com --- drivers/pci/controller/cadence/Kconfig | 6 ++--- drivers/pci/controller/cadence/pci-j721e.c | 30 +++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig index 82b58096eea0..72d7d264d6c3 100644 --- a/drivers/pci/controller/cadence/Kconfig +++ b/drivers/pci/controller/cadence/Kconfig @@ -43,10 +43,10 @@ config PCIE_CADENCE_PLAT_EP different vendors SoCs. config PCI_J721E - bool + tristate config PCI_J721E_HOST - bool "TI J721E PCIe controller (host mode)" + tristate "TI J721E PCIe controller (host mode)" depends on ARCH_K3 || COMPILE_TEST depends on OF select PCIE_CADENCE_HOST @@ -57,7 +57,7 @@ config PCI_J721E_HOST core. config PCI_J721E_EP - bool "TI J721E PCIe controller (endpoint mode)" + tristate "TI J721E PCIe controller (endpoint mode)" depends on ARCH_K3 || COMPILE_TEST depends on OF depends on PCI_ENDPOINT diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index ef1cfdae33bb..b87bc26bbf06 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #define cdns_pcie_to_rc(p) container_of(p, struct cdns_pcie_rc, pcie) #define ENABLE_REG_SYS_2 0x108 +#define ENABLE_CLR_REG_SYS_2 0x308 #define STATUS_REG_SYS_2 0x508 #define STATUS_CLR_REG_SYS_2 0x708 #define LINK_DOWN BIT(1) @@ -116,6 +118,15 @@ static irqreturn_t j721e_pcie_link_irq_handler(int irq, void *priv) return IRQ_HANDLED; } +static void j721e_pcie_disable_link_irq(struct j721e_pcie *pcie) +{ + u32 reg; + + reg = j721e_pcie_intd_readl(pcie, ENABLE_CLR_REG_SYS_2); + reg |= pcie->linkdown_irq_regfield; + j721e_pcie_intd_writel(pcie, ENABLE_CLR_REG_SYS_2, reg); +} + static void j721e_pcie_config_link_irq(struct j721e_pcie *pcie) { u32 reg; @@ -633,9 +644,22 @@ static void j721e_pcie_remove(struct platform_device *pdev) struct j721e_pcie *pcie = platform_get_drvdata(pdev); struct cdns_pcie *cdns_pcie = pcie->cdns_pcie; struct device *dev = &pdev->dev; + struct cdns_pcie_ep *ep; + struct cdns_pcie_rc *rc; + + if (pcie->mode == PCI_MODE_RC) { + rc = container_of(cdns_pcie, struct cdns_pcie_rc, pcie); + cdns_pcie_host_disable(rc); + } else { + ep = container_of(cdns_pcie, struct cdns_pcie_ep, pcie); + cdns_pcie_ep_disable(ep); + } + + gpiod_set_value_cansleep(pcie->reset_gpio, 0); clk_disable_unprepare(pcie->refclk); cdns_pcie_disable_phy(cdns_pcie); + j721e_pcie_disable_link_irq(pcie); pm_runtime_put(dev); pm_runtime_disable(dev); } @@ -730,4 +754,8 @@ static struct platform_driver j721e_pcie_driver = { .pm = pm_sleep_ptr(&j721e_pcie_pm_ops), }, }; -builtin_platform_driver(j721e_pcie_driver); +module_platform_driver(j721e_pcie_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCIe controller driver for TI's J721E and related SoCs"); +MODULE_AUTHOR("Kishon Vijay Abraham I "); From 3c05e88413f7b7145795dc1ad56983e75bca07a7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Apr 2025 18:25:16 +0200 Subject: [PATCH 146/147] PCI: j721e: Fix host/endpoint dependencies The j721e driver has a single platform driver that can be built-in or a loadable module, but it calls two separate backend drivers depending on whether it is a host or endpoint. If the two modes are not the same, we can end up with a situation where the built-in pci-j721e driver tries to call the modular host or endpoint driver, which causes a link failure: ld.lld-21: error: undefined symbol: cdns_pcie_ep_setup >>> referenced by pci-j721e.c >>> drivers/pci/controller/cadence/pci-j721e.o:(j721e_pcie_probe) in archive vmlinux.a ld.lld-21: error: undefined symbol: cdns_pcie_host_setup >>> referenced by pci-j721e.c >>> drivers/pci/controller/cadence/pci-j721e.o:(j721e_pcie_probe) in archive vmlinux.a Rework the dependencies so that the 'select' is done by the common Kconfig symbol, based on which of the two are enabled. Effectively this means that having one built-in makes the other either built-in or disabled, but all configurations will now build. Signed-off-by: Arnd Bergmann Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Reviewed-by: Siddharth Vadapalli Link: https://patch.msgid.link/20250423162523.2060405-1-arnd@kernel.org --- drivers/pci/controller/cadence/Kconfig | 4 ++-- drivers/pci/controller/cadence/pci-j721e.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig index 72d7d264d6c3..666e16b6367f 100644 --- a/drivers/pci/controller/cadence/Kconfig +++ b/drivers/pci/controller/cadence/Kconfig @@ -44,12 +44,13 @@ config PCIE_CADENCE_PLAT_EP config PCI_J721E tristate + select PCIE_CADENCE_HOST if PCI_J721E_HOST != n + select PCIE_CADENCE_EP if PCI_J721E_EP != n config PCI_J721E_HOST tristate "TI J721E PCIe controller (host mode)" depends on ARCH_K3 || COMPILE_TEST depends on OF - select PCIE_CADENCE_HOST select PCI_J721E help Say Y here if you want to support the TI J721E PCIe platform @@ -61,7 +62,6 @@ config PCI_J721E_EP depends on ARCH_K3 || COMPILE_TEST depends on OF depends on PCI_ENDPOINT - select PCIE_CADENCE_EP select PCI_J721E help Say Y here if you want to support the TI J721E PCIe platform diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index b87bc26bbf06..f0051805f9e9 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -475,7 +475,7 @@ static int j721e_pcie_probe(struct platform_device *pdev) switch (mode) { case PCI_MODE_RC: - if (!IS_ENABLED(CONFIG_PCIE_CADENCE_HOST)) + if (!IS_ENABLED(CONFIG_PCI_J721E_HOST)) return -ENODEV; bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc)); @@ -494,7 +494,7 @@ static int j721e_pcie_probe(struct platform_device *pdev) pcie->cdns_pcie = cdns_pcie; break; case PCI_MODE_EP: - if (!IS_ENABLED(CONFIG_PCIE_CADENCE_EP)) + if (!IS_ENABLED(CONFIG_PCI_J721E_EP)) return -ENODEV; ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); From 308f8c7a626ecd5b9be67181ae67660e165a29b5 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 4 Jun 2025 17:38:30 +0530 Subject: [PATCH 147/147] MAINTAINERS: Update Manivannan Sadhasivam email address My Linaro email is going to bounce soon, so switch to the kernel.org alias and add relevant .mailmap entry. [bhelgaas: squash https://patch.msgid.link/20250604120833.32791-3-manivannan.sadhasivam@linaro.org] Signed-off-by: Manivannan Sadhasivam Signed-off-by: Bjorn Helgaas Acked-by: Neil Armstrong Link: https://patch.msgid.link/20250604120833.32791-2-manivannan.sadhasivam@linaro.org --- .mailmap | 1 + MAINTAINERS | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.mailmap b/.mailmap index 5224f3cc2d34..d6ea8d58694a 100644 --- a/.mailmap +++ b/.mailmap @@ -453,6 +453,7 @@ Maheshwar Ajja Malathi Gottam Manikanta Pubbisetty Manivannan Sadhasivam +Manivannan Sadhasivam Manoj Basapathi Marcin Nowakowski Marc Zyngier diff --git a/MAINTAINERS b/MAINTAINERS index d5d1a4aea0e8..f1a0769ed8ee 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2102,7 +2102,7 @@ F: arch/arm/plat-*/ ARM/ACTIONS SEMI ARCHITECTURE M: Andreas Färber -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-actions@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -2354,7 +2354,7 @@ F: arch/arm/boot/dts/intel/axm/ F: arch/arm/mach-axxia/ ARM/BITMAIN ARCHITECTURE -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/bitmain.yaml @@ -3021,7 +3021,7 @@ F: include/linux/soc/qcom/ F: include/soc/qcom/ ARM/RDA MICRO ARCHITECTURE -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-unisoc@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -3718,7 +3718,7 @@ F: Documentation/admin-guide/aoe/ F: drivers/block/aoe/ ATC260X PMIC MFD DRIVER -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam M: Cristian Ciocaltea L: linux-actions@lists.infradead.org S: Maintained @@ -6721,7 +6721,7 @@ S: Orphan F: drivers/mtd/nand/raw/denali* DESIGNWARE EDMA CORE IP DRIVER -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: dmaengine@vger.kernel.org S: Maintained F: drivers/dma/dw-edma/ @@ -8536,7 +8536,7 @@ S: Maintained F: drivers/edac/pnd2_edac.[ch] EDAC-QCOM -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-msm@vger.kernel.org L: linux-edac@vger.kernel.org S: Maintained @@ -14664,7 +14664,7 @@ F: drivers/hid/hid-mcp2221.c MCP251XFD SPI-CAN NETWORK DRIVER M: Marc Kleine-Budde -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam R: Thomas Kopp L: linux-can@vger.kernel.org S: Maintained @@ -15644,7 +15644,7 @@ F: arch/arm64/boot/dts/marvell/armada-3720-eDPU.dts F: arch/arm64/boot/dts/marvell/armada-3720-uDPU.* MHI BUS -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: mhi@lists.linux.dev L: linux-arm-msm@vger.kernel.org S: Maintained @@ -18545,7 +18545,7 @@ F: drivers/pci/controller/dwc/pci-exynos.c PCI DRIVER FOR SYNOPSYS DESIGNWARE M: Jingoo Han -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-pci@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml @@ -18580,7 +18580,7 @@ F: Documentation/devicetree/bindings/pci/xilinx-versal-cpm.yaml F: drivers/pci/controller/pcie-xilinx-cpm.c PCI ENDPOINT SUBSYSTEM -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam M: Krzysztof Wilczyński R: Kishon Vijay Abraham I L: linux-pci@vger.kernel.org @@ -18633,7 +18633,7 @@ F: drivers/pci/controller/pci-xgene-msi.c PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS M: Lorenzo Pieralisi M: Krzysztof Wilczyński -R: Manivannan Sadhasivam +M: Manivannan Sadhasivam R: Rob Herring L: linux-pci@vger.kernel.org S: Supported @@ -18779,7 +18779,7 @@ F: Documentation/devicetree/bindings/pci/microchip* F: drivers/pci/controller/plda/*microchip* PCIE DRIVER FOR QUALCOMM MSM -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-pci@vger.kernel.org L: linux-arm-msm@vger.kernel.org S: Maintained @@ -18815,7 +18815,7 @@ F: Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml F: drivers/pci/controller/plda/pcie-starfive.c PCIE ENDPOINT DRIVER FOR QUALCOMM -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-pci@vger.kernel.org L: linux-arm-msm@vger.kernel.org S: Maintained @@ -19933,7 +19933,7 @@ F: drivers/iommu/arm/arm-smmu/arm-smmu-qcom* F: drivers/iommu/msm_iommu* QUALCOMM IPC ROUTER (QRTR) DRIVER -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-msm@vger.kernel.org S: Maintained F: include/trace/events/qrtr.h @@ -19941,7 +19941,7 @@ F: include/uapi/linux/qrtr.h F: net/qrtr/ QUALCOMM IPCC MAILBOX DRIVER -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-msm@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -19975,7 +19975,7 @@ F: Documentation/devicetree/bindings/media/qcom,*-iris.yaml F: drivers/media/platform/qcom/iris/ QUALCOMM NAND CONTROLLER DRIVER -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-mtd@lists.infradead.org L: linux-arm-msm@vger.kernel.org S: Maintained @@ -22510,7 +22510,7 @@ F: Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml F: drivers/media/i2c/imx283.c SONY IMX290 SENSOR DRIVER -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -22519,7 +22519,7 @@ F: drivers/media/i2c/imx290.c SONY IMX296 SENSOR DRIVER M: Laurent Pinchart -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -24815,7 +24815,7 @@ S: Maintained F: drivers/ufs/host/ufs-mediatek* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER QUALCOMM HOOKS -M: Manivannan Sadhasivam +M: Manivannan Sadhasivam L: linux-arm-msm@vger.kernel.org L: linux-scsi@vger.kernel.org S: Maintained