2020-09-11 07:20:45

by Nicolin Chen

[permalink] [raw]
Subject: [PATCH 0/3] iommu/tegra-smmu: Some small fixes

These are a series of small fixes for tegra-smmu driver.
They might not be critial bugs as current mainline does
not enable a lot of clients, but be nicer to have since
we are going to enable the DMA domain for other clients
in the near future.

Nicolin Chen (3):
iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK
iommu/tegra-smmu: Fix iova->phys translation
iommu/tegra-smmu: Allow to group clients in same swgroup

drivers/iommu/tegra-smmu.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)

--
2.17.1


2020-09-11 07:22:33

by Nicolin Chen

[permalink] [raw]
Subject: [PATCH 2/3] iommu/tegra-smmu: Fix iova->phys translation

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 <[email protected]>
---
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 789d21c01b77..50b962b0647e 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -795,7 +795,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

2020-09-11 07:22:50

by Nicolin Chen

[permalink] [raw]
Subject: [PATCH 3/3] iommu/tegra-smmu: Allow to group clients in same swgroup

There can be clients using the same swgroup in DT, for example i2c0
and i2c1. The current driver will add them to separate IOMMU groups,
though it has implemented device_group() callback which is to group
devices using different swgroups like DC and DCB.

All clients having the same swgroup should be also added to the same
IOMMU group so as to share an asid. Otherwise, the asid register may
get overwritten every time a new device is attached.

Signed-off-by: Nicolin Chen <[email protected]>
---
drivers/iommu/tegra-smmu.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 50b962b0647e..84fdee473873 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -23,6 +23,7 @@ struct tegra_smmu_group {
struct tegra_smmu *smmu;
const struct tegra_smmu_group_soc *soc;
struct iommu_group *group;
+ unsigned int swgroup;
};

struct tegra_smmu {
@@ -909,14 +910,14 @@ static struct iommu_group *tegra_smmu_group_get(struct tegra_smmu *smmu,
struct tegra_smmu_group *group;
struct iommu_group *grp;

+ /* Find group_soc associating with swgroup */
soc = tegra_smmu_find_group(smmu, swgroup);
- if (!soc)
- return NULL;

mutex_lock(&smmu->lock);

+ /* Find existing iommu_group associating with swgroup or group_soc */
list_for_each_entry(group, &smmu->groups, list)
- if (group->soc == soc) {
+ if ((group->swgroup == swgroup) || (soc && group->soc == soc)) {
grp = iommu_group_ref_get(group->group);
mutex_unlock(&smmu->lock);
return grp;
@@ -929,6 +930,7 @@ static struct iommu_group *tegra_smmu_group_get(struct tegra_smmu *smmu,
}

INIT_LIST_HEAD(&group->list);
+ group->swgroup = swgroup;
group->smmu = smmu;
group->soc = soc;

@@ -940,7 +942,8 @@ static struct iommu_group *tegra_smmu_group_get(struct tegra_smmu *smmu,
}

iommu_group_set_iommudata(group->group, group, tegra_smmu_group_release);
- iommu_group_set_name(group->group, soc->name);
+ if (soc)
+ iommu_group_set_name(group->group, soc->name);
list_add_tail(&group->list, &smmu->groups);
mutex_unlock(&smmu->lock);

--
2.17.1

2020-09-11 07:23:06

by Nicolin Chen

[permalink] [raw]
Subject: [PATCH 1/3] iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK

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 <[email protected]>
---
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 046add7acb61..789d21c01b77 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -130,6 +130,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;

@@ -726,7 +731,7 @@ __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;
}
@@ -790,7 +795,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)
@@ -1108,7 +1113,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

2020-09-24 10:24:43

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH 1/3] iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK

On Fri, Sep 11, 2020 at 12:16:41AM -0700, Nicolin Chen wrote:
> 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 <[email protected]>
> ---
> 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 046add7acb61..789d21c01b77 100644
> --- a/drivers/iommu/tegra-smmu.c
> +++ b/drivers/iommu/tegra-smmu.c
> @@ -130,6 +130,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;
>
> @@ -726,7 +731,7 @@ __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;
> }
> @@ -790,7 +795,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)
> @@ -1108,7 +1113,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;

checkpatch no longer warns about lines longer than 80 characters. The
new limit is 100, so you can fit this all on one line.

But either way:

Acked-by: Thierry Reding <[email protected]>


Attachments:
(No filename) (2.67 kB)
signature.asc (849.00 B)
Download all attachments

2020-09-24 10:25:05

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH 2/3] iommu/tegra-smmu: Fix iova->phys translation

On Fri, Sep 11, 2020 at 12:16:42AM -0700, Nicolin Chen wrote:
> 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 <[email protected]>
> ---
> 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 789d21c01b77..50b962b0647e 100644
> --- a/drivers/iommu/tegra-smmu.c
> +++ b/drivers/iommu/tegra-smmu.c
> @@ -795,7 +795,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)

Acked-by: Thierry Reding <[email protected]>


Attachments:
(No filename) (911.00 B)
signature.asc (849.00 B)
Download all attachments

2020-09-24 10:28:57

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH 3/3] iommu/tegra-smmu: Allow to group clients in same swgroup

On Fri, Sep 11, 2020 at 12:16:43AM -0700, Nicolin Chen wrote:
> There can be clients using the same swgroup in DT, for example i2c0
> and i2c1. The current driver will add them to separate IOMMU groups,
> though it has implemented device_group() callback which is to group
> devices using different swgroups like DC and DCB.
>
> All clients having the same swgroup should be also added to the same
> IOMMU group so as to share an asid. Otherwise, the asid register may
> get overwritten every time a new device is attached.
>
> Signed-off-by: Nicolin Chen <[email protected]>
> ---
> drivers/iommu/tegra-smmu.c | 11 +++++++----
> 1 file changed, 7 insertions(+), 4 deletions(-)

Makes sense:

Acked-by: Thierry Reding <[email protected]>


Attachments:
(No filename) (766.00 B)
signature.asc (849.00 B)
Download all attachments

2020-09-24 10:34:29

by Joerg Roedel

[permalink] [raw]
Subject: Re: [PATCH 0/3] iommu/tegra-smmu: Some small fixes

On Fri, Sep 11, 2020 at 12:16:40AM -0700, Nicolin Chen wrote:
> These are a series of small fixes for tegra-smmu driver.
> They might not be critial bugs as current mainline does
> not enable a lot of clients, but be nicer to have since
> we are going to enable the DMA domain for other clients
> in the near future.
>
> Nicolin Chen (3):
> iommu/tegra-smmu: Do not use PAGE_SHIFT and PAGE_MASK
> iommu/tegra-smmu: Fix iova->phys translation
> iommu/tegra-smmu: Allow to group clients in same swgroup
>
> drivers/iommu/tegra-smmu.c | 25 +++++++++++++++++--------
> 1 file changed, 17 insertions(+), 8 deletions(-)

Applied, thanks.