Skip to content

Commit ac328da

Browse files
jgunthorpenvidia
authored andcommitted
iommu/arm-smmu-v3: Allow a PASID to be set when RID is IDENTITY/BLOCKED
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> Reviewed-by: Nicolin Chen <nicolinc@nvidia.com> Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/13-v9-5cd718286059+79186-smmuv3_newapi_p2b_jgg@nvidia.com Signed-off-by: Will Deacon <will@kernel.org> (cherry picked from commit 8ee9175) Signed-off-by: Koba Ko <kobak@nvidia.com>
1 parent 5d31699 commit ac328da

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,6 +2448,9 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
24482448
master->cd_table.in_ste =
24492449
FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) ==
24502450
STRTAB_STE_0_CFG_S1_TRANS;
2451+
master->ste_ats_enabled =
2452+
FIELD_GET(STRTAB_STE_1_EATS, le64_to_cpu(target->data[1])) ==
2453+
STRTAB_STE_1_EATS_TRANS;
24512454

24522455
for (i = 0; i < master->num_streams; ++i) {
24532456
u32 sid = master->streams[i].id;
@@ -2808,10 +2811,36 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
28082811
return 0;
28092812
}
28102813

2814+
static void arm_smmu_update_ste(struct arm_smmu_master *master,
2815+
struct iommu_domain *sid_domain,
2816+
bool ats_enabled)
2817+
{
2818+
unsigned int s1dss = STRTAB_STE_1_S1DSS_TERMINATE;
2819+
struct arm_smmu_ste ste;
2820+
2821+
if (master->cd_table.in_ste && master->ste_ats_enabled == ats_enabled)
2822+
return;
2823+
2824+
if (sid_domain->type == IOMMU_DOMAIN_IDENTITY)
2825+
s1dss = STRTAB_STE_1_S1DSS_BYPASS;
2826+
else
2827+
WARN_ON(sid_domain->type != IOMMU_DOMAIN_BLOCKED);
2828+
2829+
/*
2830+
* Change the STE into a cdtable one with SID IDENTITY/BLOCKED behavior
2831+
* using s1dss if necessary. If the cd_table is already installed then
2832+
* the S1DSS is correct and this will just update the EATS. Otherwise it
2833+
* installs the entire thing. This will be hitless.
2834+
*/
2835+
arm_smmu_make_cdtable_ste(&ste, master, ats_enabled, s1dss);
2836+
arm_smmu_install_ste_for_dev(master, &ste);
2837+
}
2838+
28112839
int arm_smmu_set_pasid(struct arm_smmu_master *master,
28122840
struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
28132841
const struct arm_smmu_cd *cd)
28142842
{
2843+
struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
28152844
struct arm_smmu_attach_state state = {
28162845
.master = master,
28172846
/*
@@ -2828,8 +2857,10 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
28282857
if (smmu_domain->smmu != master->smmu)
28292858
return -EINVAL;
28302859

2831-
if (!master->cd_table.in_ste)
2832-
return -ENODEV;
2860+
if (!master->cd_table.in_ste &&
2861+
sid_domain->type != IOMMU_DOMAIN_IDENTITY &&
2862+
sid_domain->type != IOMMU_DOMAIN_BLOCKED)
2863+
return -EINVAL;
28332864

28342865
cdptr = arm_smmu_alloc_cd_ptr(master, pasid);
28352866
if (!cdptr)
@@ -2841,6 +2872,7 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
28412872
goto out_unlock;
28422873

28432874
arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
2875+
arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
28442876

28452877
arm_smmu_attach_commit(&state);
28462878

@@ -2863,6 +2895,19 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
28632895
arm_smmu_atc_inv_master(master, pasid);
28642896
arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
28652897
mutex_unlock(&arm_smmu_asid_lock);
2898+
2899+
/*
2900+
* When the last user of the CD table goes away downgrade the STE back
2901+
* to a non-cd_table one.
2902+
*/
2903+
if (!arm_smmu_ssids_in_use(&master->cd_table)) {
2904+
struct iommu_domain *sid_domain =
2905+
iommu_get_domain_for_dev(master->dev);
2906+
2907+
if (sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
2908+
sid_domain->type == IOMMU_DOMAIN_BLOCKED)
2909+
sid_domain->ops->attach_dev(sid_domain, dev);
2910+
}
28662911
}
28672912

28682913
static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ struct arm_smmu_master {
705705
/* Locked by the iommu core using the group mutex */
706706
struct arm_smmu_ctx_desc_cfg cd_table;
707707
unsigned int num_streams;
708-
bool ats_enabled;
708+
bool ats_enabled : 1;
709+
bool ste_ats_enabled : 1;
709710
bool stall_enabled;
710711
bool sva_enabled;
711712
bool iopf_enabled;

0 commit comments

Comments
 (0)