Skip to content

Commit 8ee9175

Browse files
jgunthorpewilldeacon
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 <[email protected]> Tested-by: Shameer Kolothum <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Reviewed-by: Jerry Snitselaar <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 3b5302c commit 8ee9175

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
@@ -2435,6 +2435,9 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
24352435
master->cd_table.in_ste =
24362436
FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) ==
24372437
STRTAB_STE_0_CFG_S1_TRANS;
2438+
master->ste_ats_enabled =
2439+
FIELD_GET(STRTAB_STE_1_EATS, le64_to_cpu(target->data[1])) ==
2440+
STRTAB_STE_1_EATS_TRANS;
24382441

24392442
for (i = 0; i < master->num_streams; ++i) {
24402443
u32 sid = master->streams[i].id;
@@ -2795,10 +2798,36 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
27952798
return 0;
27962799
}
27972800

2801+
static void arm_smmu_update_ste(struct arm_smmu_master *master,
2802+
struct iommu_domain *sid_domain,
2803+
bool ats_enabled)
2804+
{
2805+
unsigned int s1dss = STRTAB_STE_1_S1DSS_TERMINATE;
2806+
struct arm_smmu_ste ste;
2807+
2808+
if (master->cd_table.in_ste && master->ste_ats_enabled == ats_enabled)
2809+
return;
2810+
2811+
if (sid_domain->type == IOMMU_DOMAIN_IDENTITY)
2812+
s1dss = STRTAB_STE_1_S1DSS_BYPASS;
2813+
else
2814+
WARN_ON(sid_domain->type != IOMMU_DOMAIN_BLOCKED);
2815+
2816+
/*
2817+
* Change the STE into a cdtable one with SID IDENTITY/BLOCKED behavior
2818+
* using s1dss if necessary. If the cd_table is already installed then
2819+
* the S1DSS is correct and this will just update the EATS. Otherwise it
2820+
* installs the entire thing. This will be hitless.
2821+
*/
2822+
arm_smmu_make_cdtable_ste(&ste, master, ats_enabled, s1dss);
2823+
arm_smmu_install_ste_for_dev(master, &ste);
2824+
}
2825+
27982826
int arm_smmu_set_pasid(struct arm_smmu_master *master,
27992827
struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
28002828
const struct arm_smmu_cd *cd)
28012829
{
2830+
struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
28022831
struct arm_smmu_attach_state state = {
28032832
.master = master,
28042833
/*
@@ -2815,8 +2844,10 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
28152844
if (smmu_domain->smmu != master->smmu)
28162845
return -EINVAL;
28172846

2818-
if (!master->cd_table.in_ste)
2819-
return -ENODEV;
2847+
if (!master->cd_table.in_ste &&
2848+
sid_domain->type != IOMMU_DOMAIN_IDENTITY &&
2849+
sid_domain->type != IOMMU_DOMAIN_BLOCKED)
2850+
return -EINVAL;
28202851

28212852
cdptr = arm_smmu_alloc_cd_ptr(master, pasid);
28222853
if (!cdptr)
@@ -2828,6 +2859,7 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
28282859
goto out_unlock;
28292860

28302861
arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
2862+
arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
28312863

28322864
arm_smmu_attach_commit(&state);
28332865

@@ -2850,6 +2882,19 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid,
28502882
arm_smmu_atc_inv_master(master, pasid);
28512883
arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
28522884
mutex_unlock(&arm_smmu_asid_lock);
2885+
2886+
/*
2887+
* When the last user of the CD table goes away downgrade the STE back
2888+
* to a non-cd_table one.
2889+
*/
2890+
if (!arm_smmu_ssids_in_use(&master->cd_table)) {
2891+
struct iommu_domain *sid_domain =
2892+
iommu_get_domain_for_dev(master->dev);
2893+
2894+
if (sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
2895+
sid_domain->type == IOMMU_DOMAIN_BLOCKED)
2896+
sid_domain->ops->attach_dev(sid_domain, dev);
2897+
}
28532898
}
28542899

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