Skip to content

Commit

Permalink
Merge tag 'pci-v6.6-fixes-2' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/pci/pci

Pull PCI fixes from Bjorn Helgaas:

 - Fix a qcom register offset that broke IPQ8074 PCIe controller
   enumeration (Sricharan Ramabadhran)

 - Handle interrupt parsing failures when creating a device tree node to
   avoid using uninitialized data (Lizhi Hou)

 - Clean up if adding PCI device node fails when creating a device tree
   node to avoid a memory leak (Lizhi Hou)

 - If a link is down, mark all downstream devices as "disconnected" so
   we don't wait for them on resume (Mika Westerberg)

* tag 'pci-v6.6-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci:
  PCI/PM: Mark devices disconnected if upstream PCIe link is down on resume
  PCI: of: Destroy changeset when adding PCI device node fails
  PCI: of_property: Handle interrupt parsing failures
  PCI: qcom: Fix IPQ8074 enumeration
  • Loading branch information
torvalds committed Oct 6, 2023
2 parents a5e0a4b + c824581 commit af95dc6
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 19 deletions.
4 changes: 1 addition & 3 deletions drivers/pci/controller/dwc/pcie-qcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
19 changes: 11 additions & 8 deletions drivers/pci/of.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 18 additions & 7 deletions drivers/pci/of_property.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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]) {
Expand Down
14 changes: 13 additions & 1 deletion drivers/pci/pci-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit af95dc6

Please sign in to comment.