Skip to content

Commit 85cfaac

Browse files
jgunthorpewilldeacon
authored andcommitted
iommu/vt-d: Split paging_domain_compatible()
Make First/Second stage specific functions that follow the same pattern in intel_iommu_domain_alloc_first/second_stage() for computing EOPNOTSUPP. This makes the code easier to understand as if we couldn't create a domain with the parameters for this IOMMU instance then we certainly are not compatible with it. Check superpage support directly against the per-stage cap bits and the pgsize_bitmap. Add a note that the force_snooping is read without locking. The locking needs to cover the compatible check and the add of the device to the list. Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Lu Baolu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 0fa6f08 commit 85cfaac

File tree

1 file changed

+54
-12
lines changed

1 file changed

+54
-12
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3431,33 +3431,75 @@ static void intel_iommu_domain_free(struct iommu_domain *domain)
34313431
kfree(dmar_domain);
34323432
}
34333433

3434+
static int paging_domain_compatible_first_stage(struct dmar_domain *dmar_domain,
3435+
struct intel_iommu *iommu)
3436+
{
3437+
if (WARN_ON(dmar_domain->domain.dirty_ops ||
3438+
dmar_domain->nested_parent))
3439+
return -EINVAL;
3440+
3441+
/* Only SL is available in legacy mode */
3442+
if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
3443+
return -EINVAL;
3444+
3445+
/* Same page size support */
3446+
if (!cap_fl1gp_support(iommu->cap) &&
3447+
(dmar_domain->domain.pgsize_bitmap & SZ_1G))
3448+
return -EINVAL;
3449+
return 0;
3450+
}
3451+
3452+
static int
3453+
paging_domain_compatible_second_stage(struct dmar_domain *dmar_domain,
3454+
struct intel_iommu *iommu)
3455+
{
3456+
unsigned int sslps = cap_super_page_val(iommu->cap);
3457+
3458+
if (dmar_domain->domain.dirty_ops && !ssads_supported(iommu))
3459+
return -EINVAL;
3460+
if (dmar_domain->nested_parent && !nested_supported(iommu))
3461+
return -EINVAL;
3462+
3463+
/* Legacy mode always supports second stage */
3464+
if (sm_supported(iommu) && !ecap_slts(iommu->ecap))
3465+
return -EINVAL;
3466+
3467+
/* Same page size support */
3468+
if (!(sslps & BIT(0)) && (dmar_domain->domain.pgsize_bitmap & SZ_2M))
3469+
return -EINVAL;
3470+
if (!(sslps & BIT(1)) && (dmar_domain->domain.pgsize_bitmap & SZ_1G))
3471+
return -EINVAL;
3472+
return 0;
3473+
}
3474+
34343475
int paging_domain_compatible(struct iommu_domain *domain, struct device *dev)
34353476
{
34363477
struct device_domain_info *info = dev_iommu_priv_get(dev);
34373478
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
34383479
struct intel_iommu *iommu = info->iommu;
3480+
int ret = -EINVAL;
34393481
int addr_width;
34403482

3441-
if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING)))
3442-
return -EPERM;
3483+
if (intel_domain_is_fs_paging(dmar_domain))
3484+
ret = paging_domain_compatible_first_stage(dmar_domain, iommu);
3485+
else if (intel_domain_is_ss_paging(dmar_domain))
3486+
ret = paging_domain_compatible_second_stage(dmar_domain, iommu);
3487+
else if (WARN_ON(true))
3488+
ret = -EINVAL;
3489+
if (ret)
3490+
return ret;
34433491

3492+
/*
3493+
* FIXME this is locked wrong, it needs to be under the
3494+
* dmar_domain->lock
3495+
*/
34443496
if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap))
34453497
return -EINVAL;
34463498

3447-
if (domain->dirty_ops && !ssads_supported(iommu))
3448-
return -EINVAL;
3449-
34503499
if (dmar_domain->iommu_coherency !=
34513500
iommu_paging_structure_coherency(iommu))
34523501
return -EINVAL;
34533502

3454-
if (dmar_domain->iommu_superpage !=
3455-
iommu_superpage_capability(iommu, dmar_domain->use_first_level))
3456-
return -EINVAL;
3457-
3458-
if (dmar_domain->use_first_level &&
3459-
(!sm_supported(iommu) || !ecap_flts(iommu->ecap)))
3460-
return -EINVAL;
34613503

34623504
/* check if this iommu agaw is sufficient for max mapped address */
34633505
addr_width = agaw_to_width(iommu->agaw);

0 commit comments

Comments
 (0)