From 6a878a54d0053ef21f3b829dc267487c2302b012 Mon Sep 17 00:00:00 2001 From: Sricharan Ramabadhran Date: Tue, 19 Sep 2023 15:59:48 +0530 Subject: PCI: qcom: Fix IPQ8074 enumeration PARF_SLV_ADDR_SPACE_SIZE_2_3_3 is used by qcom_pcie_post_init_2_3_3(). This PCIe slave address space size register offset is 0x358 but was incorrectly changed to 0x16c by 39171b33f652 ("PCI: qcom: Remove PCIE20_ prefix from register definitions"). This prevented access to slave address space registers like iATU, etc., so the IPQ8074 PCIe controller was not enumerated. Revert back to the correct 0x358 offset and remove the unused PARF_SLV_ADDR_SPACE_SIZE_2_3_3. Fixes: 39171b33f652 ("PCI: qcom: Remove PCIE20_ prefix from register definitions") Link: https://lore.kernel.org/r/20230919102948.1844909-1-quic_srichara@quicinc.com Tested-by: Robert Marko Signed-off-by: Sricharan Ramabadhran [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas Reviewed-by: Manivannan Sadhasivam Reviewed-by: Konrad Dybcio Cc: stable@vger.kernel.org # v6.4+ --- drivers/pci/controller/dwc/pcie-qcom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index e2f29404c84e..64420ecc24d1 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -43,7 +43,6 @@ #define PARF_PHY_REFCLK 0x4c #define PARF_CONFIG_BITS 0x50 #define PARF_DBI_BASE_ADDR 0x168 -#define PARF_SLV_ADDR_SPACE_SIZE_2_3_3 0x16c /* Register offset specific to IP ver 2.3.3 */ #define PARF_MHI_CLOCK_RESET_CTRL 0x174 #define PARF_AXI_MSTR_WR_ADDR_HALT 0x178 #define PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1a8 @@ -797,8 +796,7 @@ static int qcom_pcie_post_init_2_3_3(struct qcom_pcie *pcie) u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); u32 val; - writel(SLV_ADDR_SPACE_SZ, - pcie->parf + PARF_SLV_ADDR_SPACE_SIZE_2_3_3); + writel(SLV_ADDR_SPACE_SZ, pcie->parf + PARF_SLV_ADDR_SPACE_SIZE); val = readl(pcie->parf + PARF_PHY_CTRL); val &= ~PHY_TEST_PWR_DOWN; -- cgit v1.2.3 From 33efa29e825636a06d5711c9dfccf92726d2fc81 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Fri, 29 Sep 2023 10:10:48 -0700 Subject: PCI: of_property: Handle interrupt parsing failures of_pci_prop_intr_map() uses uninitialized addr_sz[] values if of_irq_parse_raw() fails, which leads to intermittent crashes. Clear addr_sz[] before use so we never use uninitialized elements. If no valid IRQs are parsed, don't bother adding the interrupt-map property. Fixes: 407d1a51921e ("PCI: Create device tree node for bridge") Link: https://lore.kernel.org/r/1696007448-42127-1-git-send-email-lizhi.hou@amd.com Reported-by: Jonathan Cameron Closes: https://lore.kernel.org/all/20230911154856.000076c3@Huawei.com/ Reported-by: Herve Codina Closes: https://lore.kernel.org/all/20230911171319.495bb837@bootlin.com/ Signed-off-by: Lizhi Hou [bhelgaas: commit log, add similar report from Herve] Signed-off-by: Bjorn Helgaas Reviewed-by: Herve Codina --- drivers/pci/of_property.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c index 710ec35ba4a1..c2c7334152bc 100644 --- a/drivers/pci/of_property.c +++ b/drivers/pci/of_property.c @@ -186,8 +186,8 @@ static int of_pci_prop_interrupts(struct pci_dev *pdev, static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs, struct device_node *np) { + u32 i, addr_sz[OF_PCI_MAX_INT_PIN] = { 0 }, map_sz = 0; struct of_phandle_args out_irq[OF_PCI_MAX_INT_PIN]; - u32 i, addr_sz[OF_PCI_MAX_INT_PIN], map_sz = 0; __be32 laddr[OF_PCI_ADDRESS_CELLS] = { 0 }; u32 int_map_mask[] = { 0xffff00, 0, 0, 7 }; struct device_node *pnode; @@ -213,33 +213,44 @@ static int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs, out_irq[i].args[0] = pin; ret = of_irq_parse_raw(laddr, &out_irq[i]); if (ret) { - pci_err(pdev, "parse irq %d failed, ret %d", pin, ret); + out_irq[i].np = NULL; + pci_dbg(pdev, "parse irq %d failed, ret %d", pin, ret); continue; } - ret = of_property_read_u32(out_irq[i].np, "#address-cells", - &addr_sz[i]); - if (ret) - addr_sz[i] = 0; + of_property_read_u32(out_irq[i].np, "#address-cells", + &addr_sz[i]); } list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { i = pci_swizzle_interrupt_pin(child, pin) - 1; + if (!out_irq[i].np) + continue; map_sz += 5 + addr_sz[i] + out_irq[i].args_count; } } + /* + * Parsing interrupt failed for all pins. In this case, it does not + * need to generate interrupt-map property. + */ + if (!map_sz) + return 0; + int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL); mapp = int_map; list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) { + i = pci_swizzle_interrupt_pin(child, pin) - 1; + if (!out_irq[i].np) + continue; + *mapp = (child->bus->number << 16) | (child->devfn << 8); mapp += OF_PCI_ADDRESS_CELLS; *mapp = pin; mapp++; - i = pci_swizzle_interrupt_pin(child, pin) - 1; *mapp = out_irq[i].np->phandle; mapp++; if (addr_sz[i]) { -- cgit v1.2.3 From f69977404700a3d33b1c4b492c2a44f17cb07af5 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Fri, 29 Sep 2023 10:10:17 -0700 Subject: PCI: of: Destroy changeset when adding PCI device node fails Previously of_pci_make_dev_node() leaked a cset if it failed to create a device node for the PCI device with of_changeset_create_node(). Destroy the cset if of_changeset_create_node() fails. Fixes: 407d1a51921e ("PCI: Create device tree node for bridge") Link: https://lore.kernel.org/r/1696007417-42059-1-git-send-email-lizhi.hou@amd.com Reported-by: Herve Codina Closes: https://lore.kernel.org/all/20230911171319.495bb837@bootlin.com/ Signed-off-by: Lizhi Hou [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas Reviewed-by: Herve Codina --- drivers/pci/of.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 2af64bcb7da3..51e3dd0ea5ab 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -657,30 +657,33 @@ void of_pci_make_dev_node(struct pci_dev *pdev) cset = kmalloc(sizeof(*cset), GFP_KERNEL); if (!cset) - goto failed; + goto out_free_name; of_changeset_init(cset); np = of_changeset_create_node(cset, ppnode, name); if (!np) - goto failed; - np->data = cset; + goto out_destroy_cset; ret = of_pci_add_properties(pdev, cset, np); if (ret) - goto failed; + goto out_free_node; ret = of_changeset_apply(cset); if (ret) - goto failed; + goto out_free_node; + np->data = cset; pdev->dev.of_node = np; kfree(name); return; -failed: - if (np) - of_node_put(np); +out_free_node: + of_node_put(np); +out_destroy_cset: + of_changeset_destroy(cset); + kfree(cset); +out_free_name: kfree(name); } #endif -- cgit v1.2.3 From c82458101d5490230d735caecce14c9c27b1010c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 18 Sep 2023 08:30:41 +0300 Subject: PCI/PM: Mark devices disconnected if upstream PCIe link is down on resume Mark Blakeney reported that when suspending system with a Thunderbolt dock connected and then unplugging the dock before resume (which is pretty normal flow with laptops), resuming takes long time. What happens is that the PCIe link from the root port to the PCIe switch inside the Thunderbolt device does not train (as expected, the link is unplugged): pcieport 0000:00:07.2: restoring config space at offset 0x24 (was 0x3bf12001, writing 0x3bf12001) pcieport 0000:00:07.0: waiting 100 ms for downstream link pcieport 0000:01:00.0: not ready 1023ms after resume; giving up However, at this point we still try to resume the devices below that unplugged link: pcieport 0000:01:00.0: Unable to change power state from D3cold to D0, device inaccessible ... pcieport 0000:01:00.0: restoring config space at offset 0x38 (was 0xffffffff, writing 0x0) ... pcieport 0000:02:02.0: waiting 100 ms for downstream link, after activation And this is the link from PCIe switch downstream port to the xHCI on the dock: xhci_hcd 0000:03:00.0: not ready 65535ms after resume; giving up xhci_hcd 0000:03:00.0: Unable to change power state from D3cold to D0, device inaccessible xhci_hcd 0000:03:00.0: restoring config space at offset 0x3c (was 0xffffffff, writing 0x1ff) This ends up slowing down the resume time considerably. For this reason mark these devices as disconnected if the link above them did not train properly. Fixes: e8b908146d44 ("PCI/PM: Increase wait time after resume") Link: https://lore.kernel.org/r/20230918053041.1018876-1-mika.westerberg@linux.intel.com Reported-by: Mark Blakeney Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217915 Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Lukas Wunner Cc: stable@vger.kernel.org # v6.4+ --- drivers/pci/pci-driver.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/pci') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index a79c110c7e51..51ec9e7e784f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -572,7 +572,19 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev) static void pci_pm_bridge_power_up_actions(struct pci_dev *pci_dev) { - pci_bridge_wait_for_secondary_bus(pci_dev, "resume"); + int ret; + + ret = pci_bridge_wait_for_secondary_bus(pci_dev, "resume"); + if (ret) { + /* + * The downstream link failed to come up, so mark the + * devices below as disconnected to make sure we don't + * attempt to resume them. + */ + pci_walk_bus(pci_dev->subordinate, pci_dev_set_disconnected, + NULL); + return; + } /* * When powering on a bridge from D3cold, the whole hierarchy may be -- cgit v1.2.3