Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 804cb54c authored by Thierry Reding's avatar Thierry Reding Committed by Joerg Roedel
Browse files

iommu/tegra: smmu: Compute PFN mask at runtime



The SMMU on Tegra30 and Tegra114 supports addressing up to 4 GiB of
physical memory. On Tegra124 the addressable physical memory was
extended to 16 GiB. The page frame number stored in PTEs therefore
requires 20 or 22 bits, depending on SoC generation.

In order to cope with this, compute the proper value at runtime.

Reported-by: default avatarJoseph Lo <josephl@nvidia.com>
Cc: Hiroshi Doyu <hdoyu@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 836a8ac9
Loading
Loading
Loading
Loading
+10 −5
Original line number Original line Diff line number Diff line
@@ -6,6 +6,7 @@
 * published by the Free Software Foundation.
 * published by the Free Software Foundation.
 */
 */


#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/err.h>
#include <linux/iommu.h>
#include <linux/iommu.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
@@ -24,6 +25,8 @@ struct tegra_smmu {
	struct tegra_mc *mc;
	struct tegra_mc *mc;
	const struct tegra_smmu_soc *soc;
	const struct tegra_smmu_soc *soc;


	unsigned long pfn_mask;

	unsigned long *asids;
	unsigned long *asids;
	struct mutex lock;
	struct mutex lock;


@@ -105,8 +108,6 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
#define SMMU_PDE_SHIFT 22
#define SMMU_PDE_SHIFT 22
#define SMMU_PTE_SHIFT 12
#define SMMU_PTE_SHIFT 12


#define SMMU_PFN_MASK 0x000fffff

#define SMMU_PD_READABLE	(1 << 31)
#define SMMU_PD_READABLE	(1 << 31)
#define SMMU_PD_WRITABLE	(1 << 30)
#define SMMU_PD_WRITABLE	(1 << 30)
#define SMMU_PD_NONSECURE	(1 << 29)
#define SMMU_PD_NONSECURE	(1 << 29)
@@ -486,7 +487,7 @@ static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
		smmu_flush_tlb_section(smmu, as->id, iova);
		smmu_flush_tlb_section(smmu, as->id, iova);
		smmu_flush(smmu);
		smmu_flush(smmu);
	} else {
	} else {
		page = pfn_to_page(pd[pde] & SMMU_PFN_MASK);
		page = pfn_to_page(pd[pde] & smmu->pfn_mask);
		pt = page_address(page);
		pt = page_address(page);
	}
	}


@@ -508,7 +509,7 @@ static void as_put_pte(struct tegra_smmu_as *as, dma_addr_t iova)
	u32 *pd = page_address(as->pd), *pt;
	u32 *pd = page_address(as->pd), *pt;
	struct page *page;
	struct page *page;


	page = pfn_to_page(pd[pde] & SMMU_PFN_MASK);
	page = pfn_to_page(pd[pde] & as->smmu->pfn_mask);
	pt = page_address(page);
	pt = page_address(page);


	/*
	/*
@@ -583,7 +584,7 @@ static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain,
	u32 *pte;
	u32 *pte;


	pte = as_get_pte(as, iova, &page);
	pte = as_get_pte(as, iova, &page);
	pfn = *pte & SMMU_PFN_MASK;
	pfn = *pte & as->smmu->pfn_mask;


	return PFN_PHYS(pfn);
	return PFN_PHYS(pfn);
}
}
@@ -707,6 +708,10 @@ struct tegra_smmu *tegra_smmu_probe(struct device *dev,
	smmu->dev = dev;
	smmu->dev = dev;
	smmu->mc = mc;
	smmu->mc = mc;


	smmu->pfn_mask = BIT_MASK(mc->soc->num_address_bits - PAGE_SHIFT) - 1;
	dev_dbg(dev, "address bits: %u, PFN mask: %#lx\n",
		mc->soc->num_address_bits, smmu->pfn_mask);

	value = SMMU_PTC_CONFIG_ENABLE | SMMU_PTC_CONFIG_INDEX_MAP(0x3f);
	value = SMMU_PTC_CONFIG_ENABLE | SMMU_PTC_CONFIG_INDEX_MAP(0x3f);


	if (soc->supports_request_limit)
	if (soc->supports_request_limit)