Hi Will,
We would still need a mechanism to distinguish stage1 mapping from stage2 
mapping i.e. for nested translation we should be able to specify whether the 
mapping corresponds to stage1 or stage 2 translation. Also, correspondingly we 
would require different context banks for stage 1 and stage 2 translation. 

Regards
Varun

> -----Original Message-----
> From: iommu-boun...@lists.linux-foundation.org [mailto:iommu-
> boun...@lists.linux-foundation.org] On Behalf Of Will Deacon
> Sent: Tuesday, September 02, 2014 3:24 PM
> To: iommu@lists.linux-foundation.org
> Cc: Will Deacon
> Subject: [PATCH v3 3/3] iommu/arm-smmu: add support for
> DOMAIN_ATTR_NESTING attribute
> 
> When domains are set with the DOMAIN_ATTR_NESTING flag, we must ensure
> that we allocate them to stage-2 context banks if the hardware permits it.
> 
> This patch adds support for the attribute to the ARM SMMU driver, with the
> actual stage being determined depending on the features supported by the
> hardware.
> 
> Signed-off-by: Will Deacon <will.dea...@arm.com>
> ---
>  drivers/iommu/arm-smmu.c | 110
> ++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 90 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index
> d2d8cdaf4f0b..c745296b170f 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -404,9 +404,16 @@ struct arm_smmu_cfg {
>  #define ARM_SMMU_CB_ASID(cfg)                ((cfg)->cbndx)
>  #define ARM_SMMU_CB_VMID(cfg)                ((cfg)->cbndx + 1)
> 
> +enum arm_smmu_domain_stage {
> +     ARM_SMMU_DOMAIN_S1 = 0,
> +     ARM_SMMU_DOMAIN_S2,
> +     ARM_SMMU_DOMAIN_NESTED,
> +};
> +
>  struct arm_smmu_domain {
>       struct arm_smmu_device          *smmu;
>       struct arm_smmu_cfg             cfg;
> +     enum arm_smmu_domain_stage      stage;
>       spinlock_t                      lock;
>  };
> 
> @@ -899,19 +906,46 @@ static int arm_smmu_init_domain_context(struct
> iommu_domain *domain,
>       if (smmu_domain->smmu)
>               goto out_unlock;
> 
> -     if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
> +     /*
> +      * Mapping the requested stage onto what we support is surprisingly
> +      * complicated, mainly because the spec allows S1+S2 SMMUs without
> +      * support for nested translation. That means we end up with the
> +      * following table:
> +      *
> +      * Requested        Supported        Actual
> +      *     S1               N              S1
> +      *     S1             S1+S2            S1
> +      *     S1               S2             S2
> +      *     S1               S1             S1
> +      *     N                N              N
> +      *     N              S1+S2            S2
> +      *     N                S2             S2
> +      *     N                S1             S1
> +      *
> +      * Note that you can't actually request stage-2 mappings.
> +      */
> +     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;
> +
> +     switch (smmu_domain->stage) {
> +     case ARM_SMMU_DOMAIN_S1:
> +             cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
> +             start = smmu->num_s2_context_banks;
> +             break;
> +     case ARM_SMMU_DOMAIN_NESTED:
>               /*
>                * We will likely want to change this if/when KVM gets
>                * involved.
>                */
> -             cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
> -             start = smmu->num_s2_context_banks;
> -     } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S1) {
> -             cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
> -             start = smmu->num_s2_context_banks;
> -     } else {
> +     case ARM_SMMU_DOMAIN_S2:
>               cfg->cbar = CBAR_TYPE_S2_TRANS;
>               start = 0;
> +             break;
> +     default:
> +             ret = -EINVAL;
> +             goto out_unlock;
>       }
> 
>       ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, @@ -
> 1637,20 +1671,56 @@ static void arm_smmu_remove_device(struct device
> *dev)
>       iommu_group_remove_device(dev);
>  }
> 
> +static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
> +                                 enum iommu_attr attr, void *data) {
> +     struct arm_smmu_domain *smmu_domain = domain->priv;
> +
> +     switch (attr) {
> +     case DOMAIN_ATTR_NESTING:
> +             *(int *)data = (smmu_domain->stage ==
> ARM_SMMU_DOMAIN_NESTED);
> +             return 0;
> +     default:
> +             return -ENODEV;
> +     }
> +}
> +
> +static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
> +                                 enum iommu_attr attr, void *data) {
> +     struct arm_smmu_domain *smmu_domain = domain->priv;
> +
> +     switch (attr) {
> +     case DOMAIN_ATTR_NESTING:
> +             if (smmu_domain->smmu)
> +                     return -EPERM;
> +             if (*(int *)data)
> +                     smmu_domain->stage =
> ARM_SMMU_DOMAIN_NESTED;
> +             else
> +                     smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
> +
> +             return 0;
> +     default:
> +             return -ENODEV;
> +     }
> +}
> +
>  static const struct iommu_ops arm_smmu_ops = {
> -     .domain_init    = arm_smmu_domain_init,
> -     .domain_destroy = arm_smmu_domain_destroy,
> -     .attach_dev     = arm_smmu_attach_dev,
> -     .detach_dev     = arm_smmu_detach_dev,
> -     .map            = arm_smmu_map,
> -     .unmap          = arm_smmu_unmap,
> -     .iova_to_phys   = arm_smmu_iova_to_phys,
> -     .domain_has_cap = arm_smmu_domain_has_cap,
> -     .add_device     = arm_smmu_add_device,
> -     .remove_device  = arm_smmu_remove_device,
> -     .pgsize_bitmap  = (SECTION_SIZE |
> -                        ARM_SMMU_PTE_CONT_SIZE |
> -                        PAGE_SIZE),
> +     .domain_init            = arm_smmu_domain_init,
> +     .domain_destroy         = arm_smmu_domain_destroy,
> +     .attach_dev             = arm_smmu_attach_dev,
> +     .detach_dev             = arm_smmu_detach_dev,
> +     .map                    = arm_smmu_map,
> +     .unmap                  = arm_smmu_unmap,
> +     .iova_to_phys           = arm_smmu_iova_to_phys,
> +     .domain_has_cap         = arm_smmu_domain_has_cap,
> +     .add_device             = arm_smmu_add_device,
> +     .remove_device          = arm_smmu_remove_device,
> +     .domain_get_attr        = arm_smmu_domain_get_attr,
> +     .domain_set_attr        = arm_smmu_domain_set_attr,
> +     .pgsize_bitmap          = (SECTION_SIZE |
> +                                ARM_SMMU_PTE_CONT_SIZE |
> +                                PAGE_SIZE),
>  };
> 
>  static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
> --
> 2.1.0
> 
> _______________________________________________
> iommu mailing list
> iommu@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to