diff options
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 22 |
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); |