summaryrefslogtreecommitdiff
path: root/drivers/pci/host/pci-tegra.c
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2017-05-04 22:10:32 +0200
committerBjorn Helgaas <bhelgaas@google.com>2017-07-02 18:46:20 -0500
commitd7bd554f27c942e6b8b54100b4044f9be1038edf (patch)
tree022dae6e2bf8d18a5a305904cc8ab323a32b4ce2 /drivers/pci/host/pci-tegra.c
parentc016555091119b469fe49d1b1b359f0ae3fc6ed7 (diff)
PCI: tegra: Do not allocate MSI target memory
The PCI host bridge found on Tegra SoCs doesn't require the MSI target address to be backed by physical system memory. Writes are intercepted within the controller and never make it to the memory pointed to. Since no actual system memory is required, remove the allocation of a single page and hardcode the MSI target address with a special address that maps to the last 4 KiB page within the range that is reserved for system memory and memory-mapped I/O in the FPCI address map. Signed-off-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'drivers/pci/host/pci-tegra.c')
-rw-r--r--drivers/pci/host/pci-tegra.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 1d1d87e8bcbf..b3722b7709df 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -233,7 +233,6 @@ 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;
int irq;
@@ -1530,9 +1529,22 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie)
goto err;
}
- /* setup AFI/FPCI range */
- msi->pages = __get_free_pages(GFP_KERNEL, 0);
- msi->phys = virt_to_phys((void *)msi->pages);
+ /*
+ * The PCI host bridge on Tegra contains some logic that intercepts
+ * MSI writes, which means that the MSI target address doesn't have
+ * to point to actual physical memory. Rather than allocating one 4
+ * KiB page of system memory that's never used, we can simply pick
+ * an arbitrary address within an area reserved for system memory
+ * in the FPCI address map.
+ *
+ * However, in order to avoid confusion, we pick an address that
+ * doesn't map to physical memory. The FPCI address map reserves a
+ * 1012 GiB region for system memory and memory-mapped I/O. Since
+ * none of the Tegra SoCs that contain this PCI host bridge can
+ * address more than 16 GiB of system memory, the last 4 KiB of
+ * these 1012 GiB is a good candidate.
+ */
+ msi->phys = 0xfcfffff000;
afi_writel(pcie, msi->phys >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST);
afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST);
@@ -1584,8 +1596,6 @@ static int tegra_pcie_disable_msi(struct tegra_pcie *pcie)
afi_writel(pcie, 0, AFI_MSI_EN_VEC6);
afi_writel(pcie, 0, AFI_MSI_EN_VEC7);
- free_pages(msi->pages, 0);
-
if (msi->irq > 0)
free_irq(msi->irq, pcie);