iommu/tegra-smmu: A set of small fixes
cover iommu/tegra-smmu: A set of small fixes
Hi all,
This series of patches are some small fixes for tegra-smmu, mainly tested Tegra210 with downstream kernel. As we only enabled limited clients for Tegra210 on mainline tree, I am not sure how critical these fixes are, so not CCing stable tree.
Nicolin Chen (4):
memory: tegra: Correct reset value of xusb_hostr iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK iommu/tegra-smmu: Fix iova->phy translation iommu/tegra-smmu: Prevent race condition between map and unmap
drivers/iommu/tegra-smmu.c | 29 ++++++++++++++++++++++++----- drivers/memory/tegra/tegra210.c | 2 +- 2 files changed, 25 insertions(+), 6 deletions(-)
Signature · 1 line
2.17.1
PATCH 1/4 memory: tegra: Correct reset value of xusb_hostr
According to Tegra X1 (Tegra210) TRM, the reset value of xusb_hostr field (bit [7:0]) should be 0x7a. So this patch simply corrects it.
--- drivers/memory/tegra/tegra210.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/memory/tegra/tegra210.c +1 -1
@@ -436,7 +436,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { .reg = 0x37c, .shift = 0, .mask = 0xff, - .def = 0x39, + .def = 0x7a, }, }, { .id = 0x4b,
Signature · 1 line
2.17.1
Thierry Reding
AppliedRe: [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr
Quoted 7 lines · Nicolin Chen
According to Tegra X1 (Tegra210) TRM, the reset value of
xusb_hostrfield (bit [7:0]) should be0x7a. So this patch simply corrects it.Signed-off-by Nicolin Chen <[email protected]>--- drivers/memory/tegra/tegra210.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to for-5.6/memory, thanks.
Thierry
PATCH 2/4 iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK
In reply to Nicolin ChenPAGE_SHIFT and PAGE_MASK are defined corresponding to the page size for CPU virtual addresses, which means PAGE_SHIFT could be a number other than 12, but tegra-smmu maintains fixed 4KB IOVA pages and has fixed [21:12] bit range for PTE entries.
So this patch replaces all PAGE_SHIFT/PAGE_MASK references with the macros defined with SMMU_PTE_SHIFT.
--- drivers/iommu/tegra-smmu.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/iommu/tegra-smmu.c +10 -4
@@ -127,6 +127,11 @@ static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)#define SMMU_PDE_SHIFT 22#define SMMU_PTE_SHIFT 12 +#define SMMU_PAGE_MASK (~(SMMU_SIZE_PT-1)) +#define SMMU_OFFSET_IN_PAGE (x) ((unsigned long)(x) & ~SMMU_PAGE_MASK) +#define SMMU_PFN_PHYS (x) ((phys_addr_t)(x) << SMMU_PTE_SHIFT) +#define SMMU_PHYS_PFN (x) ((unsigned long)((x) >> SMMU_PTE_SHIFT)) +#define SMMU_PD_READABLE (1 << 31)#define SMMU_PD_WRITABLE (1 << 30)#define SMMU_PD_NONSECURE (1 << 29)
@@ -644,7 +649,7 @@ static void tegra_smmu_set_pte(struct tegra_smmu_as *as, unsigned long iova, u32 *pte, dma_addr_t pte_dma, u32 val) { struct tegra_smmu *smmu = as->smmu; -unsigned long offset =offset_in_page (pte); +unsigned long offset =SMMU_OFFSET_IN_PAGE (pte); *pte = val;
@@ -680,7 +685,7 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, pte_attrs |=SMMU_PTE_WRITABLE ;tegra_smmu_set_pte (as, iova, pte, pte_dma, -__phys_to_pfn (paddr) | pte_attrs); +SMMU_PHYS_PFN (paddr) | pte_attrs);return 0 ; }
@@ -716,7 +721,7 @@ static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain, pfn = *pte & as->smmu->pfn_mask; -return PFN_PHYS (pfn); +return SMMU_PFN_PHYS (pfn); }static struct tegra_smmu *tegra_smmu_find (struct device_node *np)
@@ -1034,7 +1039,8 @@ struct tegra_smmu *tegra_smmu_probe(struct device *dev, smmu->dev = dev; smmu->mc = mc; - smmu->pfn_mask =BIT_MASK (mc->soc->num_address_bits -PAGE_SHIFT ) -1 ; + smmu->pfn_mask = +BIT_MASK (mc->soc->num_address_bits -SMMU_PTE_SHIFT ) -1 ;dev_dbg (dev,"address bits: %u, PFN mask: %#lx\n" , mc->soc->num_address_bits, smmu->pfn_mask); smmu->tlb_mask = (smmu->soc->num_tlb_lines <<1 ) -1 ;
Signature · 1 line
2.17.1
PATCH 3/4 iommu/tegra-smmu: Fix iova->phys translation
In reply to Nicolin ChenIOVA might not be always 4KB aligned. So tegra_smmu_iova_to_phys function needs to add on the lower 12-bit offset from input iova.
--- drivers/iommu/tegra-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/tegra-smmu.c +1 -1
@@ -721,7 +721,7 @@ static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain, pfn = *pte & as->smmu->pfn_mask; -return SMMU_PFN_PHYS (pfn); +return SMMU_PFN_PHYS (pfn) +SMMU_OFFSET_IN_PAGE (iova); }static struct tegra_smmu *tegra_smmu_find (struct device_node *np)
Signature · 1 line
2.17.1
PATCH 4/4 iommu/tegra-smmu: Prevent race condition between map and unmap
In reply to Nicolin ChenWhen testing with ethernet downloading, "EMEM address decode error" happens due to race condition between map() and unmap() functions.
This patch adds a spin lock to protect content within as->[count] and as->pts[pde] references, since a function call might be atomic.
--- drivers/iommu/tegra-smmu.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/iommu/tegra-smmu.c +14 -1
@@ -37,6 +37,7 @@ struct tegra_smmu {unsigned long *asids;struct mutex lock; +spinlock_t as_lock;struct list_head list;
@@ -664,17 +665,23 @@ static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot, gfp_t gfp) { struct tegra_smmu_as *as = to_smmu_as(domain); +struct tegra_smmu *smmu = as->smmu; +unsigned long flags;dma_addr_t pte_dma;u32 pte_attrs;u32 *pte; +spin_lock_irqsave (&smmu->as_lock, flags); pte =as_get_pte (as, iova, &pte_dma); -if (!pte) +if (!pte) { +spin_unlock_irqrestore (&smmu->as_lock, flags);return -ENOMEM ; + }/* If we aren't overwriting a pre-existing entry, increment use */ if (*pte ==0 )tegra_smmu_pte_get_use (as, iova); +spin_unlock_irqrestore (&smmu->as_lock, flags); pte_attrs =SMMU_PTE_NONSECURE ;
@@ -694,6 +701,8 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size, struct iommu_iotlb_gather *gather) { struct tegra_smmu_as *as = to_smmu_as(domain); +struct tegra_smmu *smmu = as->smmu; +unsigned long flags;dma_addr_t pte_dma;u32 *pte;
@@ -702,7 +711,10 @@ static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,return 0 ;tegra_smmu_set_pte (as, iova, pte, pte_dma,0 ); + +spin_lock_irqsave (&smmu->as_lock, flags);tegra_smmu_pte_put_use (as, iova); +spin_unlock_irqrestore (&smmu->as_lock, flags);return size; }
@@ -1033,6 +1045,7 @@ struct tegra_smmu *tegra_smmu_probe(struct device *dev,INIT_LIST_HEAD (&smmu->groups);mutex_init (&smmu->lock); +spin_lock_init (&smmu->as_lock); smmu->regs = mc->regs; smmu->soc = soc;
Signature · 1 line
2.17.1