Commit 29fa3bbd authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/dwc'

  - Use generic config space reader in qcom (Marc Gonzalez)

  - Stop calling IRQ handler cleanup in dwc driver for invalid MSI IRQs
    (Jisheng Zhang)

  - Free dwc MSI target page when freeing MSI (Jisheng Zhang)

  - Fix dwc MSI leak in host init error path (Jisheng Zhang)

  - Use managed host bridge alloc to simplify dwc (Jisheng Zhang)

  - Save dwc root pci_bus pointer for use by .remove() methods (Jisheng
    Zhang)

  - Allow imx6 asynchronous probing (Lucas Stach)

* pci/dwc:
  PCI: imx6: Allow asynchronous probing
  PCI: dwc: Save root bus for driver remove hooks
  PCI: dwc: Use devm_pci_alloc_host_bridge() to simplify code
  PCI: dwc: Free MSI in dw_pcie_host_init() error path
  PCI: dwc: Free MSI IRQ page in dw_pcie_free_msi()
  PCI: dwc: Fix dw_pcie_free_msi() if msi_irq is invalid
  PCI: qcom: Use default config space read function
parents 4014eb8b 1b8df7aa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1279,6 +1279,7 @@ static struct platform_driver imx6_pcie_driver = {
		.of_match_table = imx6_pcie_of_match,
		.suppress_bind_attrs = true,
		.pm = &imx6_pcie_pm_ops,
		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
	},
	.probe    = imx6_pcie_probe,
	.shutdown = imx6_pcie_shutdown,
+32 −28
Original line number Diff line number Diff line
@@ -298,25 +298,31 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)

void dw_pcie_free_msi(struct pcie_port *pp)
{
	if (pp->msi_irq) {
		irq_set_chained_handler(pp->msi_irq, NULL);
		irq_set_handler_data(pp->msi_irq, NULL);
	}

	irq_domain_remove(pp->msi_domain);
	irq_domain_remove(pp->irq_domain);

	if (pp->msi_page)
		__free_page(pp->msi_page);
}

void dw_pcie_msi_init(struct pcie_port *pp)
{
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
	struct device *dev = pci->dev;
	struct page *page;
	u64 msi_target;

	page = alloc_page(GFP_KERNEL);
	pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
	pp->msi_page = alloc_page(GFP_KERNEL);
	pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE,
				    DMA_FROM_DEVICE);
	if (dma_mapping_error(dev, pp->msi_data)) {
		dev_err(dev, "Failed to map MSI data\n");
		__free_page(page);
		__free_page(pp->msi_page);
		pp->msi_page = NULL;
		return;
	}
	msi_target = (u64)pp->msi_data;
@@ -335,7 +341,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
	struct device_node *np = dev->of_node;
	struct platform_device *pdev = to_platform_device(dev);
	struct resource_entry *win, *tmp;
	struct pci_bus *bus, *child;
	struct pci_bus *child;
	struct pci_host_bridge *bridge;
	struct resource *cfg_res;
	int ret;
@@ -352,7 +358,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
		dev_err(dev, "Missing *config* reg space\n");
	}

	bridge = pci_alloc_host_bridge(0);
	bridge = devm_pci_alloc_host_bridge(dev, 0);
	if (!bridge)
		return -ENOMEM;

@@ -363,7 +369,7 @@ int dw_pcie_host_init(struct pcie_port *pp)

	ret = devm_request_pci_bus_resources(dev, &bridge->windows);
	if (ret)
		goto error;
		return ret;

	/* Get the I/O and memory ranges from DT */
	resource_list_for_each_entry_safe(win, tmp, &bridge->windows) {
@@ -407,8 +413,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
						resource_size(pp->cfg));
		if (!pci->dbi_base) {
			dev_err(dev, "Error with ioremap\n");
			ret = -ENOMEM;
			goto error;
			return -ENOMEM;
		}
	}

@@ -419,8 +424,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
					pp->cfg0_base, pp->cfg0_size);
		if (!pp->va_cfg0_base) {
			dev_err(dev, "Error with ioremap in function\n");
			ret = -ENOMEM;
			goto error;
			return -ENOMEM;
		}
	}

@@ -430,8 +434,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
						pp->cfg1_size);
		if (!pp->va_cfg1_base) {
			dev_err(dev, "Error with ioremap\n");
			ret = -ENOMEM;
			goto error;
			return -ENOMEM;
		}
	}

@@ -439,7 +442,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
	if (ret)
		pci->num_viewport = 2;

	if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_enabled()) {
	if (pci_msi_enabled()) {
		/*
		 * If a specific SoC driver needs to change the
		 * default number of vectors, it needs to implement
@@ -454,14 +457,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
			    pp->num_vectors == 0) {
				dev_err(dev,
					"Invalid number of vectors\n");
				goto error;
				return -EINVAL;
			}
		}

		if (!pp->ops->msi_host_init) {
			ret = dw_pcie_allocate_domains(pp);
			if (ret)
				goto error;
				return ret;

			if (pp->msi_irq)
				irq_set_chained_handler_and_data(pp->msi_irq,
@@ -470,14 +473,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
		} else {
			ret = pp->ops->msi_host_init(pp);
			if (ret < 0)
				goto error;
				return ret;
		}
	}

	if (pp->ops->host_init) {
		ret = pp->ops->host_init(pp);
		if (ret)
			goto error;
			goto err_free_msi;
	}

	pp->root_bus_nr = pp->busn->start;
@@ -491,24 +494,25 @@ int dw_pcie_host_init(struct pcie_port *pp)

	ret = pci_scan_root_bus_bridge(bridge);
	if (ret)
		goto error;
		goto err_free_msi;

	bus = bridge->bus;
	pp->root_bus = bridge->bus;

	if (pp->ops->scan_bus)
		pp->ops->scan_bus(pp);

	pci_bus_size_bridges(bus);
	pci_bus_assign_resources(bus);
	pci_bus_size_bridges(pp->root_bus);
	pci_bus_assign_resources(pp->root_bus);

	list_for_each_entry(child, &bus->children, node)
	list_for_each_entry(child, &pp->root_bus->children, node)
		pcie_bus_configure_settings(child);

	pci_bus_add_devices(bus);
	pci_bus_add_devices(pp->root_bus);
	return 0;

error:
	pci_free_host_bridge(bridge);
err_free_msi:
	if (pci_msi_enabled() && !pp->ops->msi_host_init)
		dw_pcie_free_msi(pp);
	return ret;
}

+2 −0
Original line number Diff line number Diff line
@@ -179,8 +179,10 @@ struct pcie_port {
	struct irq_domain	*irq_domain;
	struct irq_domain	*msi_domain;
	dma_addr_t		msi_data;
	struct page		*msi_page;
	u32			num_vectors;
	u32			irq_mask[MAX_MSI_CTRLS];
	struct pci_bus		*root_bus;
	raw_spinlock_t		lock;
	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
};
+6 −17
Original line number Diff line number Diff line
@@ -1129,25 +1129,8 @@ err_deinit:
	return ret;
}

static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
				 u32 *val)
{
	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);

	/* the device class is not reported correctly from the register */
	if (where == PCI_CLASS_REVISION && size == 4) {
		*val = readl(pci->dbi_base + PCI_CLASS_REVISION);
		*val &= 0xff;	/* keep revision id */
		*val |= PCI_CLASS_BRIDGE_PCI << 16;
		return PCIBIOS_SUCCESSFUL;
	}

	return dw_pcie_read(pci->dbi_base + where, size, val);
}

static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
	.host_init = qcom_pcie_host_init,
	.rd_own_conf = qcom_pcie_rd_own_conf,
};

/* Qcom IP rev.: 2.1.0	Synopsys IP rev.: 4.01a */
@@ -1309,6 +1292,12 @@ static const struct of_device_id qcom_pcie_match[] = {
	{ }
};

static void qcom_fixup_class(struct pci_dev *dev)
{
	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, PCI_ANY_ID, qcom_fixup_class);

static struct platform_driver qcom_pcie_driver = {
	.probe = qcom_pcie_probe,
	.driver = {