mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-14 12:21:15 -04:00
iommu/arm-smmu-v3: Make domain_alloc_paging_flags() directly determine the S1/S2
The selection of S1/S2 is a bit indirect today, make domain_alloc_paging_flags() directly decode the flags and select the correct S1/S2 type. Directly reject flag combinations the HW doesn't support when processing the flags. Fix missing rejection of some flag combinations that are not supported today (ie NEST_PARENT | DIRTY_TRACKING) by using a switch statement to list out exactly the combinations that are currently supported. Move the determination of the stage out of arm_smmu_domain_finalise() and into both callers. As today the default stage is S1 if supported in HW. This makes arm_smmu_domain_alloc_paging_flags() self contained and no longer calling arm_smmu_domain_alloc_paging(). Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/2-v1-0bb8d5313a27+27b-smmuv3_paging_flags_jgg@nvidia.com Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
48e7b8e284
commit
bb857c5c01
@@ -2481,6 +2481,11 @@ static struct iommu_domain *arm_smmu_domain_alloc_paging(struct device *dev)
|
||||
if (IS_ERR(smmu_domain))
|
||||
return ERR_CAST(smmu_domain);
|
||||
|
||||
if (master->smmu->features & ARM_SMMU_FEAT_TRANS_S1)
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
|
||||
else
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
|
||||
|
||||
ret = arm_smmu_domain_finalise(smmu_domain, master->smmu, 0);
|
||||
if (ret) {
|
||||
kfree(smmu_domain);
|
||||
@@ -2554,12 +2559,6 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
|
||||
struct arm_smmu_domain *smmu_domain);
|
||||
bool enable_dirty = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
|
||||
|
||||
/* Restrict the stage to what we can actually support */
|
||||
if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1))
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
|
||||
if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2))
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
|
||||
|
||||
pgtbl_cfg = (struct io_pgtable_cfg) {
|
||||
.pgsize_bitmap = smmu->pgsize_bitmap,
|
||||
.coherent_walk = smmu->features & ARM_SMMU_FEAT_COHERENCY,
|
||||
@@ -3231,6 +3230,7 @@ arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags,
|
||||
const struct iommu_user_data *user_data)
|
||||
{
|
||||
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
|
||||
struct arm_smmu_device *smmu = master->smmu;
|
||||
const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING |
|
||||
IOMMU_HWPT_ALLOC_PASID |
|
||||
IOMMU_HWPT_ALLOC_NEST_PARENT;
|
||||
@@ -3242,25 +3242,43 @@ arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags,
|
||||
if (user_data)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
if (flags & IOMMU_HWPT_ALLOC_PASID)
|
||||
return arm_smmu_domain_alloc_paging(dev);
|
||||
|
||||
smmu_domain = arm_smmu_domain_alloc();
|
||||
if (IS_ERR(smmu_domain))
|
||||
return ERR_CAST(smmu_domain);
|
||||
|
||||
if (flags & IOMMU_HWPT_ALLOC_NEST_PARENT) {
|
||||
if (!(master->smmu->features & ARM_SMMU_FEAT_NESTING)) {
|
||||
switch (flags) {
|
||||
case 0:
|
||||
/* Prefer S1 if available */
|
||||
if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
|
||||
else
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
|
||||
break;
|
||||
case IOMMU_HWPT_ALLOC_NEST_PARENT:
|
||||
if (!(smmu->features & ARM_SMMU_FEAT_NESTING)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_free;
|
||||
}
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
|
||||
smmu_domain->nest_parent = true;
|
||||
break;
|
||||
case IOMMU_HWPT_ALLOC_DIRTY_TRACKING:
|
||||
case IOMMU_HWPT_ALLOC_DIRTY_TRACKING | IOMMU_HWPT_ALLOC_PASID:
|
||||
case IOMMU_HWPT_ALLOC_PASID:
|
||||
if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_free;
|
||||
}
|
||||
smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
smmu_domain->domain.type = IOMMU_DOMAIN_UNMANAGED;
|
||||
smmu_domain->domain.ops = arm_smmu_ops.default_domain_ops;
|
||||
ret = arm_smmu_domain_finalise(smmu_domain, master->smmu, flags);
|
||||
ret = arm_smmu_domain_finalise(smmu_domain, smmu, flags);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
return &smmu_domain->domain;
|
||||
|
||||
Reference in New Issue
Block a user