Commit 8c2b4e3c authored by Thierry Reding's avatar Thierry Reding Committed by Bjorn Helgaas

Revert "PCI: tegra: Do not allocate MSI target memory"

This reverts commit d7bd554f.

It turns out that Tegra20 has a bug in the implementation of the MSI
target address register (which is worked around by the existence of the
struct tegra_pcie_soc.msi_base_shift parameter) that restricts the MSI
target memory to the lower 32 bits of physical memory on that particular
generation. The offending patch causes a regression on TrimSlice, which
is a Tegra20-based device and has a PCI network interface card.

An initial, simpler fix was to change the MSI target address for Tegra20
only, but it was pointed out that the offending commit also prevents the
use of 32-bit only MSI capable devices, even on later chips. Technically
this was never guaranteed to work with the prior code in the first place
because the allocated page could have resided beyond the 4 GiB boundary,
but it is still possible that this could've introduced a regression.

The proper fix that was settled on is to select a fixed address within
the lowest 32 bits of physical address space that is otherwise unused,
but testing of that patch has provided mixed results that are not fully
understood yet.

Given all of the above and the relative urgency to get this fixed in
v4.13, revert the offending commit until a universal fix is found.

Fixes: d7bd554f ("PCI: tegra: Do not allocate MSI target memory")
Reported-by: default avatarTomasz Maciej Nowak <tmn505@gmail.com>
Reported-by: default avatarErik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Cc: stable@vger.kernel.org	# 4.13.x
parent b1f9e5e3
...@@ -233,6 +233,7 @@ struct tegra_msi { ...@@ -233,6 +233,7 @@ struct tegra_msi {
struct msi_controller chip; struct msi_controller chip;
DECLARE_BITMAP(used, INT_PCI_MSI_NR); DECLARE_BITMAP(used, INT_PCI_MSI_NR);
struct irq_domain *domain; struct irq_domain *domain;
unsigned long pages;
struct mutex lock; struct mutex lock;
u64 phys; u64 phys;
int irq; int irq;
...@@ -1529,22 +1530,9 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) ...@@ -1529,22 +1530,9 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie)
goto err; goto err;
} }
/* /* setup AFI/FPCI range */
* The PCI host bridge on Tegra contains some logic that intercepts msi->pages = __get_free_pages(GFP_KERNEL, 0);
* MSI writes, which means that the MSI target address doesn't have msi->phys = virt_to_phys((void *)msi->pages);
* 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 >> soc->msi_base_shift, AFI_MSI_FPCI_BAR_ST);
afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST); afi_writel(pcie, msi->phys, AFI_MSI_AXI_BAR_ST);
...@@ -1596,6 +1584,8 @@ static int tegra_pcie_disable_msi(struct tegra_pcie *pcie) ...@@ -1596,6 +1584,8 @@ 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_VEC6);
afi_writel(pcie, 0, AFI_MSI_EN_VEC7); afi_writel(pcie, 0, AFI_MSI_EN_VEC7);
free_pages(msi->pages, 0);
if (msi->irq > 0) if (msi->irq > 0)
free_irq(msi->irq, pcie); free_irq(msi->irq, pcie);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment