From 057f1652feb9be78587dae53866371e7fcce81e9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 24 Oct 2025 14:41:40 -0500 Subject: [PATCH 1/2] Revert "PCI: qcom: Remove custom ASPM enablement code" This reverts commit a729c16646198872e345bf6c48dbe540ad8a9753. Prior to a729c1664619 ("PCI: qcom: Remove custom ASPM enablement code"), the qcom controller driver enabled ASPM, including L0s, L1, and L1 PM Substates, for all devices powered on at the time the controller driver enumerates them. ASPM was *not* enabled for devices powered on later by pwrctrl (unless the kernel was built with PCIEASPM_POWERSAVE or PCIEASPM_POWER_SUPERSAVE, or the user enabled ASPM via module parameter or sysfs). After f3ac2ff14834 ("PCI/ASPM: Enable all ClockPM and ASPM states for devicetree platforms"), the PCI core enabled all ASPM states for all devices whether powered on initially or by pwrctrl, so a729c1664619 was unnecessary and reverted. But f3ac2ff14834 was too aggressive and broke platforms that didn't support CLKREQ# or required device-specific configuration for L1 Substates, so df5192d9bb0e ("PCI/ASPM: Enable only L0s and L1 for devicetree platforms") enabled only L0s and L1. On Qualcomm platforms, this left L1 Substates disabled, which was a regression. Revert a729c1664619 so L1 Substates will be enabled on devices that are initially powered on. Devices powered on by pwrctrl will be addressed later. Fixes: df5192d9bb0e ("PCI/ASPM: Enable only L0s and L1 for devicetree platforms") Reported-by: Johan Hovold Closes: https://lore.kernel.org/lkml/aPuXZlaawFmmsLmX@hovoldconsulting.com/ Signed-off-by: Bjorn Helgaas Tested-by: Johan Hovold Reviewed-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20251024210514.1365996-1-helgaas@kernel.org --- drivers/pci/controller/dwc/pcie-qcom.c | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 805edbbfe7eb..e6d2a6b0c087 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -262,6 +262,7 @@ struct qcom_pcie_ops { int (*get_resources)(struct qcom_pcie *pcie); int (*init)(struct qcom_pcie *pcie); int (*post_init)(struct qcom_pcie *pcie); + void (*host_post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); void (*ltssm_enable)(struct qcom_pcie *pcie); int (*config_sid)(struct qcom_pcie *pcie); @@ -1094,6 +1095,25 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie) return 0; } +static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata) +{ + /* + * Downstream devices need to be in D0 state before enabling PCI PM + * substates. + */ + pci_set_power_state_locked(pdev, PCI_D0); + pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); + + return 0; +} + +static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie) +{ + struct dw_pcie_rp *pp = &pcie->pci->pp; + + pci_walk_bus(pp->bridge->bus, qcom_pcie_enable_aspm, NULL); +} + static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie) { struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0; @@ -1380,9 +1400,19 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp) pcie->cfg->ops->deinit(pcie); } +static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct qcom_pcie *pcie = to_qcom_pcie(pci); + + if (pcie->cfg->ops->host_post_init) + pcie->cfg->ops->host_post_init(pcie); +} + static const struct dw_pcie_host_ops qcom_pcie_dw_ops = { .init = qcom_pcie_host_init, .deinit = qcom_pcie_host_deinit, + .post_init = qcom_pcie_host_post_init, }; /* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */ @@ -1444,6 +1474,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .get_resources = qcom_pcie_get_resources_2_7_0, .init = qcom_pcie_init_2_7_0, .post_init = qcom_pcie_post_init_2_7_0, + .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, .config_sid = qcom_pcie_config_sid_1_9_0, @@ -1454,6 +1485,7 @@ static const struct qcom_pcie_ops ops_1_21_0 = { .get_resources = qcom_pcie_get_resources_2_7_0, .init = qcom_pcie_init_2_7_0, .post_init = qcom_pcie_post_init_2_7_0, + .host_post_init = qcom_pcie_host_post_init_2_7_0, .deinit = qcom_pcie_deinit_2_7_0, .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, }; From 437aa64c8e32b724fc6d60100ef0eb313d32c88f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Mon, 27 Oct 2025 15:24:23 +0200 Subject: [PATCH 2/2] PCI: Do not size non-existing prefetchable window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pbus_size_mem() should only be called for bridge windows that exist but __pci_bus_size_bridges() may point 'pref' to a resource that does not exist (has zero flags) in case of non-root buses. When prefetchable bridge window does not exist, the same non-prefetchable bridge window is sized more than once which may result in duplicating entries into the realloc_head list. Duplicated entries are shown in this log and trigger a WARN_ON() because realloc_head had residual entries after the resource assignment algorithm: pci 0000:00:03.0: [11ab:6820] type 01 class 0x060400 PCIe Root Port pci 0000:00:03.0: PCI bridge to [bus 00] pci 0000:00:03.0: bridge window [io 0x0000-0x0fff] pci 0000:00:03.0: bridge window [mem 0x00000000-0x000fffff] pci 0000:00:03.0: bridge window [mem 0x00200000-0x003fffff] to [bus 02] add_size 200000 add_align 200000 pci 0000:00:03.0: bridge window [mem 0x00200000-0x003fffff] to [bus 02] add_size 200000 add_align 200000 pci 0000:00:03.0: bridge window [mem 0xe0000000-0xe03fffff]: assigned pci 0000:00:03.0: PCI bridge to [bus 02] pci 0000:00:03.0: bridge window [mem 0xe0000000-0xe03fffff] ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at drivers/pci/setup-bus.c:2373 pci_assign_unassigned_root_bus_resources+0x1bc/0x234 Check resource flags of 'pref' and only size the prefetchable window if the resource has the IORESOURCE_PREFETCH flag. Fixes: ae88d0b9c57f ("PCI: Use pbus_select_window_for_type() during mem window sizing") Reported-by: Klaus Kudielka Closes: https://lore.kernel.org/r/51e8cf1c62b8318882257d6b5a9de7fdaaecc343.camel@gmail.com/ Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Tested-by: Klaus Kudielka Link: https://patch.msgid.link/20251027132423.8841-1-ilpo.jarvinen@linux.intel.com --- drivers/pci/setup-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 4a8735b275e4..3645f392a9fd 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1604,7 +1604,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) pbus_size_io(bus, realloc_head ? 0 : additional_io_size, additional_io_size, realloc_head); - if (pref) { + if (pref && (pref->flags & IORESOURCE_PREFETCH)) { pbus_size_mem(bus, IORESOURCE_MEM | IORESOURCE_PREFETCH | (pref->flags & IORESOURCE_MEM_64),