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 <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/14-v9-5cd718286059+79186-smmuv3_newapi_p2b_jgg@nvidia.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
8ee9175c25
commit
f3b273b7c7
@ -2798,6 +2798,36 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
|
||||
struct device *dev, ioasid_t id)
|
||||
{
|
||||
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
|
||||
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
|
||||
struct arm_smmu_device *smmu = master->smmu;
|
||||
struct arm_smmu_cd target_cd;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&smmu_domain->init_mutex);
|
||||
if (!smmu_domain->smmu)
|
||||
ret = arm_smmu_domain_finalise(smmu_domain, smmu);
|
||||
else if (smmu_domain->smmu != smmu)
|
||||
ret = -EINVAL;
|
||||
mutex_unlock(&smmu_domain->init_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* We can read cd.asid outside the lock because arm_smmu_set_pasid()
|
||||
* will fix it
|
||||
*/
|
||||
arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
|
||||
return arm_smmu_set_pasid(master, to_smmu_domain(domain), id,
|
||||
&target_cd);
|
||||
}
|
||||
|
||||
static void arm_smmu_update_ste(struct arm_smmu_master *master,
|
||||
struct iommu_domain *sid_domain,
|
||||
bool ats_enabled)
|
||||
@ -2825,7 +2855,7 @@ static void arm_smmu_update_ste(struct arm_smmu_master *master,
|
||||
|
||||
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 arm_smmu_cd *cd)
|
||||
{
|
||||
struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
|
||||
struct arm_smmu_attach_state state = {
|
||||
@ -2858,6 +2888,14 @@ int arm_smmu_set_pasid(struct arm_smmu_master *master,
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* We don't want to obtain to the asid_lock too early, so fix up the
|
||||
* caller set ASID under the lock in case it changed.
|
||||
*/
|
||||
cd->data[0] &= ~cpu_to_le64(CTXDESC_CD_0_ASID);
|
||||
cd->data[0] |= cpu_to_le64(
|
||||
FIELD_PREP(CTXDESC_CD_0_ASID, smmu_domain->cd.asid));
|
||||
|
||||
arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
|
||||
arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
|
||||
|
||||
@ -3376,6 +3414,7 @@ static struct iommu_ops arm_smmu_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.default_domain_ops = &(const struct iommu_domain_ops) {
|
||||
.attach_dev = arm_smmu_attach_dev,
|
||||
.set_dev_pasid = arm_smmu_s1_set_dev_pasid,
|
||||
.map_pages = arm_smmu_map_pages,
|
||||
.unmap_pages = arm_smmu_unmap_pages,
|
||||
.flush_iotlb_all = arm_smmu_flush_iotlb_all,
|
||||
|
@ -801,7 +801,7 @@ void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
|
||||
|
||||
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 arm_smmu_cd *cd);
|
||||
|
||||
void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
|
||||
void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
|
||||
|
Loading…
x
Reference in New Issue
Block a user