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