aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVidya Sagar <vidyas@nvidia.com>2019-04-16 06:51:44 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2019-04-16 10:27:46 -0400
commit21e2079fe4938e84c0c5c0996cc03d63d5f9cacc (patch)
tree36c8ed8d066df3e601d0afd2a3f2d19d0f971be0
parent9e98c678c2d6ae3a17cb2de55d17f69dddaa231b (diff)
PCI: tegra: Use the DMA-API to get the MSI address
Since the upstream MSI memory writes are generated by downstream devices, it is logically correct to have MSI target memory coming from the DMA pool reserved for PCIe than from the general memory pool reserved for CPU access to avoid PCIe DMA addresses coinciding with MSI target address thereby raising unwanted MSI interrupts. Enforce this behaviour by retrieving the MSI address through the DMA API. Limit the MSI target address to 32-bits to make it work for PCIe endpoints that support only 32-bit MSI target address; endpoints that support 64-bit MSI target address work with 32-bit MSI target address too. Signed-off-by: Vidya Sagar <vidyas@nvidia.com> [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Robin Murphy <robin.murphy@arm.com> Reviewed-by: Thierry Reding <treding@nvidia.com> Acked-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/pci/controller/pci-tegra.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index f4f53d092e00..464ba2538d52 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -231,9 +231,9 @@ struct tegra_msi {
231 struct msi_controller chip; 231 struct msi_controller chip;
232 DECLARE_BITMAP(used, INT_PCI_MSI_NR); 232 DECLARE_BITMAP(used, INT_PCI_MSI_NR);
233 struct irq_domain *domain; 233 struct irq_domain *domain;
234 unsigned long pages;
235 struct mutex lock; 234 struct mutex lock;
236 u64 phys; 235 void *virt;
236 dma_addr_t phys;
237 int irq; 237 int irq;
238}; 238};
239 239
@@ -1536,7 +1536,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
1536 err = platform_get_irq_byname(pdev, "msi"); 1536 err = platform_get_irq_byname(pdev, "msi");
1537 if (err < 0) { 1537 if (err < 0) {
1538 dev_err(dev, "failed to get IRQ: %d\n", err); 1538 dev_err(dev, "failed to get IRQ: %d\n", err);
1539 goto err; 1539 goto free_irq_domain;
1540 } 1540 }
1541 1541
1542 msi->irq = err; 1542 msi->irq = err;
@@ -1545,17 +1545,35 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
1545 tegra_msi_irq_chip.name, pcie); 1545 tegra_msi_irq_chip.name, pcie);
1546 if (err < 0) { 1546 if (err < 0) {
1547 dev_err(dev, "failed to request IRQ: %d\n", err); 1547 dev_err(dev, "failed to request IRQ: %d\n", err);
1548 goto err; 1548 goto free_irq_domain;
1549 }
1550
1551 /* Though the PCIe controller can address >32-bit address space, to
1552 * facilitate endpoints that support only 32-bit MSI target address,
1553 * the mask is set to 32-bit to make sure that MSI target address is
1554 * always a 32-bit address
1555 */
1556 err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
1557 if (err < 0) {
1558 dev_err(dev, "failed to set DMA coherent mask: %d\n", err);
1559 goto free_irq;
1560 }
1561
1562 msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL,
1563 DMA_ATTR_NO_KERNEL_MAPPING);
1564 if (!msi->virt) {
1565 dev_err(dev, "failed to allocate DMA memory for MSI\n");
1566 err = -ENOMEM;
1567 goto free_irq;
1549 } 1568 }
1550 1569
1551 /* setup AFI/FPCI range */
1552 msi->pages = __get_free_pages(GFP_KERNEL, 0);
1553 msi->phys = virt_to_phys((void *)msi->pages);
1554 host->msi = &msi->chip; 1570 host->msi = &msi->chip;
1555 1571
1556 return 0; 1572 return 0;
1557 1573
1558err: 1574free_irq:
1575 free_irq(msi->irq, pcie);
1576free_irq_domain:
1559 irq_domain_remove(msi->domain); 1577 irq_domain_remove(msi->domain);
1560 return err; 1578 return err;
1561} 1579}
@@ -1592,7 +1610,8 @@ static void tegra_pcie_msi_teardown(struct tegra_pcie *pcie)
1592 struct tegra_msi *msi = &pcie->msi; 1610 struct tegra_msi *msi = &pcie->msi;
1593 unsigned int i, irq; 1611 unsigned int i, irq;
1594 1612
1595 free_pages(msi->pages, 0); 1613 dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys,
1614 DMA_ATTR_NO_KERNEL_MAPPING);
1596 1615
1597 if (msi->irq > 0) 1616 if (msi->irq > 0)
1598 free_irq(msi->irq, pcie); 1617 free_irq(msi->irq, pcie);