Message ID | 13-v7-9597c885796c+d2-smmuv3_newapi_p2b_jgg@nvidia.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Update SMMUv3 to the modern iommu API (part 2b/3) | expand |
On Wed, May 08, 2024 at 03:57:21PM -0300, Jason Gunthorpe wrote: > If the STE doesn't point to the CD table we can upgrade it by > reprogramming the STE with the appropriate S1DSS. We may also need to turn > on ATS at the same time. > > Keep track if the installed STE is pointing at the cd_table and the ATS > state to trigger this path. > > Tested-by: Nicolin Chen <nicolinc@nvidia.com> > Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com> > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> > --- > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 49 ++++++++++++++++++++- > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +- > 2 files changed, 49 insertions(+), 3 deletions(-) > @@ -2819,6 +2851,19 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid, > arm_smmu_atc_inv_master(master, pasid); > arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid); > mutex_unlock(&arm_smmu_asid_lock); > + > + /* > + * When the last user of the CD table goes away downgrade the STE back > + * to a non-cd_table one. > + */ > + if (!arm_smmu_ssids_in_use(&master->cd_table)) { > + struct iommu_domain *sid_domain = > + iommu_get_domain_for_dev(master->dev); > + > + if (domain->type == IOMMU_DOMAIN_IDENTITY || > + domain->type == IOMMU_DOMAIN_BLOCKED) > + sid_domain->ops->attach_dev(sid_domain, dev); Should we check against sid_domain->type instead? Thanks Nicolin
On Mon, May 13, 2024 at 01:31:31AM -0700, Nicolin Chen wrote: > On Wed, May 08, 2024 at 03:57:21PM -0300, Jason Gunthorpe wrote: > > If the STE doesn't point to the CD table we can upgrade it by > > reprogramming the STE with the appropriate S1DSS. We may also need to turn > > on ATS at the same time. > > > > Keep track if the installed STE is pointing at the cd_table and the ATS > > state to trigger this path. > > > > Tested-by: Nicolin Chen <nicolinc@nvidia.com> > > Tested-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com> > > Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> > > --- > > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 49 ++++++++++++++++++++- > > drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +- > > 2 files changed, 49 insertions(+), 3 deletions(-) > > > @@ -2819,6 +2851,19 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid, > > arm_smmu_atc_inv_master(master, pasid); > > arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid); > > mutex_unlock(&arm_smmu_asid_lock); > > + > > + /* > > + * When the last user of the CD table goes away downgrade the STE back > > + * to a non-cd_table one. > > + */ > > + if (!arm_smmu_ssids_in_use(&master->cd_table)) { > > + struct iommu_domain *sid_domain = > > + iommu_get_domain_for_dev(master->dev); > > + > > + if (domain->type == IOMMU_DOMAIN_IDENTITY || > > + domain->type == IOMMU_DOMAIN_BLOCKED) > > + sid_domain->ops->attach_dev(sid_domain, dev); > > Should we check against sid_domain->type instead? Yes, I typo'd that after some edit Thanks, Jason
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 41d7a0664a445d..ccc10ad3ab996d 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -2435,6 +2435,9 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master, master->cd_table.in_ste = FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) == STRTAB_STE_0_CFG_S1_TRANS; + master->ste_ats_enabled = + FIELD_GET(STRTAB_STE_1_EATS, le64_to_cpu(target->data[1])) == + STRTAB_STE_1_EATS_TRANS; for (i = 0; i < master->num_streams; ++i) { u32 sid = master->streams[i].id; @@ -2765,10 +2768,36 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) return 0; } +static void arm_smmu_update_ste(struct arm_smmu_master *master, + struct iommu_domain *sid_domain, + bool want_ats) +{ + unsigned int s1dss = STRTAB_STE_1_S1DSS_TERMINATE; + struct arm_smmu_ste ste; + + if (master->cd_table.in_ste && master->ste_ats_enabled == want_ats) + return; + + if (sid_domain->type == IOMMU_DOMAIN_IDENTITY) + s1dss = STRTAB_STE_1_S1DSS_BYPASS; + else + WARN_ON(sid_domain->type != IOMMU_DOMAIN_BLOCKED); + + /* + * Change the STE into a cdtable one with SID IDENTITY/BLOCKED behavior + * using s1dss if necessary. The cd_table is already installed then + * the S1DSS is correct and this will just update the EATS. Otherwise + * it installs the entire thing. This will be hitless. + */ + arm_smmu_make_cdtable_ste(&ste, master, want_ats, s1dss); + arm_smmu_install_ste_for_dev(master, &ste); +} + int arm_smmu_set_pasid(struct arm_smmu_master *master, struct arm_smmu_domain *smmu_domain, ioasid_t pasid, const struct arm_smmu_cd *cd) { + struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev); struct attach_state state = { /* * For now the core code prevents calling this when a domain is @@ -2784,8 +2813,10 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master, if (smmu_domain->smmu != master->smmu) return -EINVAL; - if (!master->cd_table.in_ste) - return -ENODEV; + if (!master->cd_table.in_ste && + sid_domain->type != IOMMU_DOMAIN_IDENTITY && + sid_domain->type != IOMMU_DOMAIN_BLOCKED) + return -EINVAL; cdptr = arm_smmu_alloc_cd_ptr(master, pasid); if (!cdptr) @@ -2797,6 +2828,7 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master, goto out_unlock; arm_smmu_write_cd_entry(master, pasid, cdptr, cd); + arm_smmu_update_ste(master, sid_domain, state.want_ats); arm_smmu_attach_commit(master, &state); @@ -2819,6 +2851,19 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid, arm_smmu_atc_inv_master(master, pasid); arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid); mutex_unlock(&arm_smmu_asid_lock); + + /* + * When the last user of the CD table goes away downgrade the STE back + * to a non-cd_table one. + */ + if (!arm_smmu_ssids_in_use(&master->cd_table)) { + struct iommu_domain *sid_domain = + iommu_get_domain_for_dev(master->dev); + + if (domain->type == IOMMU_DOMAIN_IDENTITY || + domain->type == IOMMU_DOMAIN_BLOCKED) + sid_domain->ops->attach_dev(sid_domain, dev); + } } static void arm_smmu_attach_dev_ste(struct iommu_domain *domain, 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 71ecced1db0226..3c189a48e29757 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -705,7 +705,8 @@ struct arm_smmu_master { /* Locked by the iommu core using the group mutex */ struct arm_smmu_ctx_desc_cfg cd_table; unsigned int num_streams; - bool ats_enabled; + bool ats_enabled : 1; + bool ste_ats_enabled : 1; bool stall_enabled; bool sva_enabled; bool iopf_enabled;