Commit af95dc6f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents a5e0a4b1 c8245810
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -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;
+11 −8
Original line number Diff line number Diff line
@@ -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)
out_free_node:
	of_node_put(np);
out_destroy_cset:
	of_changeset_destroy(cset);
	kfree(cset);
out_free_name:
	kfree(name);
}
#endif
+18 −7
Original line number Diff line number Diff line
@@ -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",
		of_property_read_u32(out_irq[i].np, "#address-cells",
				     &addr_sz[i]);
		if (ret)
			addr_sz[i] = 0;
	}

	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]) {
+13 −1
Original line number Diff line number Diff line
@@ -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