diff mbox series

[2/3] iommu/arm-smmu-v3: Make BTM optional for SVA

Message ID 20210122115257.2502526-3-jean-philippe@linaro.org (mailing list archive)
State New, archived
Headers show
Series iommu/arm-smmu-v3: TLB invalidation for SVA | expand

Commit Message

Jean-Philippe Brucker Jan. 22, 2021, 11:52 a.m. UTC
When BTM isn't supported by the SMMU, send invalidations on the
command queue.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     |  3 +++
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 14 +++++++++++---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 14 ++++++++++++++
 3 files changed, 28 insertions(+), 3 deletions(-)

Comments

Robin Murphy Jan. 22, 2021, 2:04 p.m. UTC | #1
On 2021-01-22 11:52, Jean-Philippe Brucker wrote:
> When BTM isn't supported by the SMMU, send invalidations on the
> command queue.
> 
> Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
> ---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h     |  3 +++
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 14 +++++++++++---
>   drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c     | 14 ++++++++++++++
>   3 files changed, 28 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index a6536c2b32d0..652d03ad8ae6 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -743,6 +743,9 @@ extern struct arm_smmu_ctx_desc quiet_cd;
>   int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
>   			    struct arm_smmu_ctx_desc *cd);
>   void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
> +void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
> +				 size_t granule, bool leaf,
> +				 struct arm_smmu_domain *smmu_domain);
>   bool arm_smmu_free_asid(struct arm_smmu_ctx_desc *cd);
>   int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid,
>   			    unsigned long iova, size_t size);
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> index 642ce2c225b5..ad8cf62a8f83 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
> @@ -16,6 +16,7 @@ struct arm_smmu_mmu_notifier {
>   	struct mmu_notifier		mn;
>   	struct arm_smmu_ctx_desc	*cd;
>   	bool				cleared;
> +	bool				tlb_inv_command;
>   	refcount_t			refs;
>   	struct list_head		list;
>   	struct arm_smmu_domain		*domain;
> @@ -182,9 +183,13 @@ static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn,
>   					 unsigned long start, unsigned long end)
>   {
>   	struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn);
> +	struct arm_smmu_domain *smmu_domain = smmu_mn->domain;
> +	size_t size = end - start + 1;
>   
> -	arm_smmu_atc_inv_domain(smmu_mn->domain, mm->pasid, start,
> -				end - start + 1);
> +	if (smmu_mn->tlb_inv_command)

Since we're going to be drilling down to smmu_domain->smmu->features in 
the invalidate call anyway, perhaps we could just test for BTM directly 
here?

Obviously that also proves my previous comment involved a reading 
comprehension failure and too much haste, so should be discounted. Sorry 
about that :)

Robin.

> +		arm_smmu_tlb_inv_range_asid(start, size, smmu_mn->cd->asid,
> +					    PAGE_SIZE, false, smmu_domain);
> +	arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, start, size);
>   }
>   
>   static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
> @@ -253,6 +258,9 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
>   	smmu_mn->domain = smmu_domain;
>   	smmu_mn->mn.ops = &arm_smmu_mmu_notifier_ops;
>   
> +	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM))
> +		smmu_mn->tlb_inv_command = true;
> +
>   	ret = mmu_notifier_register(&smmu_mn->mn, mm);
>   	if (ret) {
>   		kfree(smmu_mn);
> @@ -404,7 +412,7 @@ bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
>   	unsigned long reg, fld;
>   	unsigned long oas;
>   	unsigned long asid_bits;
> -	u32 feat_mask = ARM_SMMU_FEAT_BTM | ARM_SMMU_FEAT_COHERENCY;
> +	u32 feat_mask = ARM_SMMU_FEAT_COHERENCY;
>   
>   	if (vabits_actual == 52)
>   		feat_mask |= ARM_SMMU_FEAT_VAX;
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index a27b074d5c0c..db545834493b 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2018,6 +2018,20 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
>   	arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size);
>   }
>   
> +void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
> +				 size_t granule, bool leaf,
> +				 struct arm_smmu_domain *smmu_domain)
> +{
> +	struct arm_smmu_cmdq_ent cmd = {
> +		.opcode	= CMDQ_OP_TLBI_NH_VA,
> +		.tlbi = {
> +			.asid	= asid,
> +			.leaf	= leaf,
> +		},
> +	};
> +	arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
> +}
> +
>   static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
>   					 unsigned long iova, size_t granule,
>   					 void *cookie)
>
Jean-Philippe Brucker Jan. 22, 2021, 2:13 p.m. UTC | #2
On Fri, Jan 22, 2021 at 02:04:55PM +0000, Robin Murphy wrote:
> > @@ -182,9 +183,13 @@ static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn,
> >   					 unsigned long start, unsigned long end)
> >   {
> >   	struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn);
> > +	struct arm_smmu_domain *smmu_domain = smmu_mn->domain;
> > +	size_t size = end - start + 1;
> > -	arm_smmu_atc_inv_domain(smmu_mn->domain, mm->pasid, start,
> > -				end - start + 1);
> > +	if (smmu_mn->tlb_inv_command)
> 
> Since we're going to be drilling down to smmu_domain->smmu->features in the
> invalidate call anyway, perhaps we could just test for BTM directly here?

Yes even with BTM enabled we'll still check features in atc_inv_domain(),
so this shortcut isn't useful.

Thanks,
Jean
diff mbox series

Patch

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index a6536c2b32d0..652d03ad8ae6 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -743,6 +743,9 @@  extern struct arm_smmu_ctx_desc quiet_cd;
 int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
 			    struct arm_smmu_ctx_desc *cd);
 void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
+void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
+				 size_t granule, bool leaf,
+				 struct arm_smmu_domain *smmu_domain);
 bool arm_smmu_free_asid(struct arm_smmu_ctx_desc *cd);
 int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, int ssid,
 			    unsigned long iova, size_t size);
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 642ce2c225b5..ad8cf62a8f83 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -16,6 +16,7 @@  struct arm_smmu_mmu_notifier {
 	struct mmu_notifier		mn;
 	struct arm_smmu_ctx_desc	*cd;
 	bool				cleared;
+	bool				tlb_inv_command;
 	refcount_t			refs;
 	struct list_head		list;
 	struct arm_smmu_domain		*domain;
@@ -182,9 +183,13 @@  static void arm_smmu_mm_invalidate_range(struct mmu_notifier *mn,
 					 unsigned long start, unsigned long end)
 {
 	struct arm_smmu_mmu_notifier *smmu_mn = mn_to_smmu(mn);
+	struct arm_smmu_domain *smmu_domain = smmu_mn->domain;
+	size_t size = end - start + 1;
 
-	arm_smmu_atc_inv_domain(smmu_mn->domain, mm->pasid, start,
-				end - start + 1);
+	if (smmu_mn->tlb_inv_command)
+		arm_smmu_tlb_inv_range_asid(start, size, smmu_mn->cd->asid,
+					    PAGE_SIZE, false, smmu_domain);
+	arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, start, size);
 }
 
 static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -253,6 +258,9 @@  arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
 	smmu_mn->domain = smmu_domain;
 	smmu_mn->mn.ops = &arm_smmu_mmu_notifier_ops;
 
+	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_BTM))
+		smmu_mn->tlb_inv_command = true;
+
 	ret = mmu_notifier_register(&smmu_mn->mn, mm);
 	if (ret) {
 		kfree(smmu_mn);
@@ -404,7 +412,7 @@  bool arm_smmu_sva_supported(struct arm_smmu_device *smmu)
 	unsigned long reg, fld;
 	unsigned long oas;
 	unsigned long asid_bits;
-	u32 feat_mask = ARM_SMMU_FEAT_BTM | ARM_SMMU_FEAT_COHERENCY;
+	u32 feat_mask = ARM_SMMU_FEAT_COHERENCY;
 
 	if (vabits_actual == 52)
 		feat_mask |= ARM_SMMU_FEAT_VAX;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index a27b074d5c0c..db545834493b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2018,6 +2018,20 @@  static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
 	arm_smmu_atc_inv_domain(smmu_domain, 0, iova, size);
 }
 
+void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
+				 size_t granule, bool leaf,
+				 struct arm_smmu_domain *smmu_domain)
+{
+	struct arm_smmu_cmdq_ent cmd = {
+		.opcode	= CMDQ_OP_TLBI_NH_VA,
+		.tlbi = {
+			.asid	= asid,
+			.leaf	= leaf,
+		},
+	};
+	arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
+}
+
 static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
 					 unsigned long iova, size_t granule,
 					 void *cookie)