提交 21e2079f 编写于 作者: V Vidya Sagar 提交者: Lorenzo Pieralisi

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: NVidya Sagar <vidyas@nvidia.com>
[lorenzo.pieralisi@arm.com: updated commit log]
Signed-off-by: NLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: NRobin Murphy <robin.murphy@arm.com>
Reviewed-by: NThierry Reding <treding@nvidia.com>
Acked-by: NThierry Reding <treding@nvidia.com>
上级 9e98c678
......@@ -231,9 +231,9 @@ struct tegra_msi {
struct msi_controller chip;
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
struct irq_domain *domain;
unsigned long pages;
struct mutex lock;
u64 phys;
void *virt;
dma_addr_t phys;
int irq;
};
......@@ -1536,7 +1536,7 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
err = platform_get_irq_byname(pdev, "msi");
if (err < 0) {
dev_err(dev, "failed to get IRQ: %d\n", err);
goto err;
goto free_irq_domain;
}
msi->irq = err;
......@@ -1545,17 +1545,35 @@ static int tegra_pcie_msi_setup(struct tegra_pcie *pcie)
tegra_msi_irq_chip.name, pcie);
if (err < 0) {
dev_err(dev, "failed to request IRQ: %d\n", err);
goto err;
goto free_irq_domain;
}
/* Though the PCIe controller can address >32-bit address space, to
* facilitate endpoints that support only 32-bit MSI target address,
* the mask is set to 32-bit to make sure that MSI target address is
* always a 32-bit address
*/
err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (err < 0) {
dev_err(dev, "failed to set DMA coherent mask: %d\n", err);
goto free_irq;
}
msi->virt = dma_alloc_attrs(dev, PAGE_SIZE, &msi->phys, GFP_KERNEL,
DMA_ATTR_NO_KERNEL_MAPPING);
if (!msi->virt) {
dev_err(dev, "failed to allocate DMA memory for MSI\n");
err = -ENOMEM;
goto free_irq;
}
/* setup AFI/FPCI range */
msi->pages = __get_free_pages(GFP_KERNEL, 0);
msi->phys = virt_to_phys((void *)msi->pages);
host->msi = &msi->chip;
return 0;
err:
free_irq:
free_irq(msi->irq, pcie);
free_irq_domain:
irq_domain_remove(msi->domain);
return err;
}
......@@ -1592,7 +1610,8 @@ static void tegra_pcie_msi_teardown(struct tegra_pcie *pcie)
struct tegra_msi *msi = &pcie->msi;
unsigned int i, irq;
free_pages(msi->pages, 0);
dma_free_attrs(pcie->dev, PAGE_SIZE, msi->virt, msi->phys,
DMA_ATTR_NO_KERNEL_MAPPING);
if (msi->irq > 0)
free_irq(msi->irq, pcie);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册