Skip to content

Commit f3b273b

Browse files
jgunthorpewilldeacon
authored andcommitted
iommu/arm-smmu-v3: Allow setting a S1 domain to a PASID
The SVA cleanup made the SSID logic entirely general so all we need to do is call it with the correct cd table entry for a S1 domain. This is slightly tricky because of the ASID and how the locking works, the simple fix is to just update the ASID once we get the right locks. 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 8ee9175 commit f3b273b

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

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

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2798,6 +2798,36 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
27982798
return 0;
27992799
}
28002800

2801+
static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
2802+
struct device *dev, ioasid_t id)
2803+
{
2804+
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
2805+
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
2806+
struct arm_smmu_device *smmu = master->smmu;
2807+
struct arm_smmu_cd target_cd;
2808+
int ret = 0;
2809+
2810+
mutex_lock(&smmu_domain->init_mutex);
2811+
if (!smmu_domain->smmu)
2812+
ret = arm_smmu_domain_finalise(smmu_domain, smmu);
2813+
else if (smmu_domain->smmu != smmu)
2814+
ret = -EINVAL;
2815+
mutex_unlock(&smmu_domain->init_mutex);
2816+
if (ret)
2817+
return ret;
2818+
2819+
if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
2820+
return -EINVAL;
2821+
2822+
/*
2823+
* We can read cd.asid outside the lock because arm_smmu_set_pasid()
2824+
* will fix it
2825+
*/
2826+
arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
2827+
return arm_smmu_set_pasid(master, to_smmu_domain(domain), id,
2828+
&target_cd);
2829+
}
2830+
28012831
static void arm_smmu_update_ste(struct arm_smmu_master *master,
28022832
struct iommu_domain *sid_domain,
28032833
bool ats_enabled)
@@ -2825,7 +2855,7 @@ static void arm_smmu_update_ste(struct arm_smmu_master *master,
28252855

28262856
int arm_smmu_set_pasid(struct arm_smmu_master *master,
28272857
struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
2828-
const struct arm_smmu_cd *cd)
2858+
struct arm_smmu_cd *cd)
28292859
{
28302860
struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
28312861
struct arm_smmu_attach_state state = {
@@ -2858,6 +2888,14 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
28582888
if (ret)
28592889
goto out_unlock;
28602890

2891+
/*
2892+
* We don't want to obtain to the asid_lock too early, so fix up the
2893+
* caller set ASID under the lock in case it changed.
2894+
*/
2895+
cd->data[0] &= ~cpu_to_le64(CTXDESC_CD_0_ASID);
2896+
cd->data[0] |= cpu_to_le64(
2897+
FIELD_PREP(CTXDESC_CD_0_ASID, smmu_domain->cd.asid));
2898+
28612899
arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
28622900
arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
28632901

@@ -3376,6 +3414,7 @@ static struct iommu_ops arm_smmu_ops = {
33763414
.owner = THIS_MODULE,
33773415
.default_domain_ops = &(const struct iommu_domain_ops) {
33783416
.attach_dev = arm_smmu_attach_dev,
3417+
.set_dev_pasid = arm_smmu_s1_set_dev_pasid,
33793418
.map_pages = arm_smmu_map_pages,
33803419
.unmap_pages = arm_smmu_unmap_pages,
33813420
.flush_iotlb_all = arm_smmu_flush_iotlb_all,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
801801

802802
int arm_smmu_set_pasid(struct arm_smmu_master *master,
803803
struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
804-
const struct arm_smmu_cd *cd);
804+
struct arm_smmu_cd *cd);
805805

806806
void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
807807
void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,

0 commit comments

Comments
 (0)