Skip to content

Commit

Permalink
iommu/arm-smmu-v3: Allow a PASID to be set when RID is IDENTITY/BLOCKED
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jason Gunthorpe authored and Will Deacon committed Jul 2, 2024
1 parent 3b5302c commit 8ee9175
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
49 changes: 47 additions & 2 deletions drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2795,10 +2798,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 ats_enabled)
{
unsigned int s1dss = STRTAB_STE_1_S1DSS_TERMINATE;
struct arm_smmu_ste ste;

if (master->cd_table.in_ste && master->ste_ats_enabled == ats_enabled)
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. If 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, ats_enabled, 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 arm_smmu_attach_state state = {
.master = master,
/*
Expand All @@ -2815,8 +2844,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)
Expand All @@ -2828,6 +2859,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.ats_enabled);

arm_smmu_attach_commit(&state);

Expand All @@ -2850,6 +2882,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 (sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
sid_domain->type == IOMMU_DOMAIN_BLOCKED)
sid_domain->ops->attach_dev(sid_domain, dev);
}
}

static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
Expand Down
3 changes: 2 additions & 1 deletion drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 8ee9175

Please sign in to comment.