linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] iommu/tegra-smmu: A set of small fixes
@ 2019-12-20  0:29 Nicolin Chen
  2019-12-20  0:29 ` [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr Nicolin Chen
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Nicolin Chen @ 2019-12-20  0:29 UTC (permalink / raw)
  To: thierry.reding, joro; +Cc: jonathanh, linux-tegra, iommu, linux-kernel

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(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr
  2019-12-20  0:29 [PATCH 0/4] iommu/tegra-smmu: A set of small fixes Nicolin Chen
@ 2019-12-20  0:29 ` Nicolin Chen
  2020-01-10 14:34   ` Thierry Reding
  2019-12-20  0:29 ` [PATCH 2/4] iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK Nicolin Chen
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Nicolin Chen @ 2019-12-20  0:29 UTC (permalink / raw)
  To: thierry.reding, joro; +Cc: jonathanh, linux-tegra, iommu, linux-kernel

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.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/memory/tegra/tegra210.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
index a3918a96467f..eab4bc01c8bc 100644
--- a/drivers/memory/tegra/tegra210.c
+++ b/drivers/memory/tegra/tegra210.c
@@ -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,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK
  2019-12-20  0:29 [PATCH 0/4] iommu/tegra-smmu: A set of small fixes Nicolin Chen
  2019-12-20  0:29 ` [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr Nicolin Chen
@ 2019-12-20  0:29 ` Nicolin Chen
  2019-12-20  0:29 ` [PATCH 3/4] iommu/tegra-smmu: Fix iova->phys translation Nicolin Chen
  2019-12-20  0:29 ` [PATCH 4/4] iommu/tegra-smmu: Prevent race condition between map and unmap Nicolin Chen
  3 siblings, 0 replies; 6+ messages in thread
From: Nicolin Chen @ 2019-12-20  0:29 UTC (permalink / raw)
  To: thierry.reding, joro; +Cc: jonathanh, linux-tegra, iommu, linux-kernel

PAGE_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.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/iommu/tegra-smmu.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 63a147b623e6..5594b47a88bf 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -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;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] iommu/tegra-smmu: Fix iova->phys translation
  2019-12-20  0:29 [PATCH 0/4] iommu/tegra-smmu: A set of small fixes Nicolin Chen
  2019-12-20  0:29 ` [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr Nicolin Chen
  2019-12-20  0:29 ` [PATCH 2/4] iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK Nicolin Chen
@ 2019-12-20  0:29 ` Nicolin Chen
  2019-12-20  0:29 ` [PATCH 4/4] iommu/tegra-smmu: Prevent race condition between map and unmap Nicolin Chen
  3 siblings, 0 replies; 6+ messages in thread
From: Nicolin Chen @ 2019-12-20  0:29 UTC (permalink / raw)
  To: thierry.reding, joro; +Cc: jonathanh, linux-tegra, iommu, linux-kernel

IOVA 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.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/iommu/tegra-smmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 5594b47a88bf..3999ecb63cfa 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -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)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] iommu/tegra-smmu: Prevent race condition between map and unmap
  2019-12-20  0:29 [PATCH 0/4] iommu/tegra-smmu: A set of small fixes Nicolin Chen
                   ` (2 preceding siblings ...)
  2019-12-20  0:29 ` [PATCH 3/4] iommu/tegra-smmu: Fix iova->phys translation Nicolin Chen
@ 2019-12-20  0:29 ` Nicolin Chen
  3 siblings, 0 replies; 6+ messages in thread
From: Nicolin Chen @ 2019-12-20  0:29 UTC (permalink / raw)
  To: thierry.reding, joro; +Cc: jonathanh, linux-tegra, iommu, linux-kernel

When 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.

Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
---
 drivers/iommu/tegra-smmu.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 3999ecb63cfa..236bc6d6d238 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -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;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr
  2019-12-20  0:29 ` [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr Nicolin Chen
@ 2020-01-10 14:34   ` Thierry Reding
  0 siblings, 0 replies; 6+ messages in thread
From: Thierry Reding @ 2020-01-10 14:34 UTC (permalink / raw)
  To: Nicolin Chen; +Cc: joro, jonathanh, linux-tegra, iommu, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 414 bytes --]

On Thu, Dec 19, 2019 at 04:29:11PM -0800, Nicolin Chen wrote:
> 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.
> 
> Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
> ---
>  drivers/memory/tegra/tegra210.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Applied to for-5.6/memory, thanks.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-01-10 14:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-20  0:29 [PATCH 0/4] iommu/tegra-smmu: A set of small fixes Nicolin Chen
2019-12-20  0:29 ` [PATCH 1/4] memory: tegra: Correct reset value of xusb_hostr Nicolin Chen
2020-01-10 14:34   ` Thierry Reding
2019-12-20  0:29 ` [PATCH 2/4] iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK Nicolin Chen
2019-12-20  0:29 ` [PATCH 3/4] iommu/tegra-smmu: Fix iova->phys translation Nicolin Chen
2019-12-20  0:29 ` [PATCH 4/4] iommu/tegra-smmu: Prevent race condition between map and unmap Nicolin Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).