[PATCH] iommu/arm-smmu-v2: Workaround for ThunderX errata#27704

Tirumalesh Chalamarla tchalamarla at caviumnetworks.com
Wed Mar 2 10:12:50 PST 2016



On 03/02/2016 05:10 AM, Robin Murphy wrote:
> On 24/02/16 21:13, Tirumalesh Chalamarla wrote:
>> Due to Errata#27704 CN88xx SMMUv2,supports  only shared ASID and VMID
>> namespaces; specifically within a given node SMMU0 and SMMU1 share,
>> as does SMMU2 and SMMU3.
>>
>> This patch address these issuee by supplying asid and vmid
>> while calculating ASID and VMID for Thunder SMMUv2.
>>
>> NOTE: resending with commit message fix.
>>
>> changes from V2:
>>     - removed *_base from DT, and replaced with compatible string
>>
>> changes from V1:
>>     - rebased on top of 16 bit VMID patch
>>     - removed redundent options from DT
>>     - insted of transform, DT now supplies starting ASID/VMID
>>
>> Signed-off-by: Tirumalesh Chalamarla <tchalamarla at caviumnetworks.com>
>> Signed-off-by: Akula Geethasowjanya
>> <Geethasowjanya.Akula at caviumnetworks.com>
>> ---
>>   .../devicetree/bindings/iommu/arm,smmu.txt         |  1 +
>>   drivers/iommu/arm-smmu.c                           | 48
>> +++++++++++++++++-----
>
> I guess Documentation/arm64/silicon-errata.txt wants updating too?
>
YES, will update it.
>>   2 files changed, 38 insertions(+), 11 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> index 7180745..19fe6f2 100644
>> --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> @@ -16,6 +16,7 @@ conditions.
>>                           "arm,mmu-400"
>>                           "arm,mmu-401"
>>                           "arm,mmu-500"
>> +                        "cavium,smmu-v2"
>
> That seems a rather broad name for a compatible - will there definitely
> never be another Cavium implementation of SMMUv2? Even then, if there is
> future respin of CN88xx silicon where the SMMU needs some other
> workaround for some other issue, will that be discoverable from
> SMMU_IDR7 or similar? Even an absurdly over-specific compatible such as
> "cavium,thunderx-cn88xx-pass2-smmu" would be preferable to something
> which later turns out to be insufficient to uniquely identify a specific
> implementation.
>

i don't think there is a SMMUv2 from Cavium again, there will be SMMUv3 
of course.

there will be other flavors like 86xx etc, which has same implementation 
as 88xx so will have same errata. i think this name is more appropriate.

> Otherwise, modulo Will's comments, this looks a lot more reasonable than
> before, thanks.
>
> Robin.
>
>>                     depending on the particular implementation and/or the
>>                     version of the architecture implemented.
>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>> index 247a469..c704f88 100644
>> --- a/drivers/iommu/arm-smmu.c
>> +++ b/drivers/iommu/arm-smmu.c
>> @@ -326,6 +326,12 @@ struct arm_smmu_device {
>>
>>       struct list_head        list;
>>       struct rb_root            masters;
>> +    /*
>> +     *The following fields are specific to Cavium, Thunder
>> +     */
>> +    u32                cavium_smmu_id;
>> +    u32                cavium_id_base;
>> +
>>   };
>>
>>   struct arm_smmu_cfg {
>> @@ -335,8 +341,8 @@ struct arm_smmu_cfg {
>>   };
>>   #define INVALID_IRPTNDX            0xff
>>
>> -#define ARM_SMMU_CB_ASID(cfg)        ((cfg)->cbndx)
>> -#define ARM_SMMU_CB_VMID(cfg)        ((cfg)->cbndx + 1)
>> +#define ARM_SMMU_CB_ASID(smmu, cfg) ((u16)(smmu)->cavium_id_base +
>> (cfg)->cbndx)
>> +#define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base +
>> (cfg)->cbndx + 1)
>>
>>   enum arm_smmu_domain_stage {
>>       ARM_SMMU_DOMAIN_S1 = 0,
>> @@ -364,6 +370,8 @@ struct arm_smmu_option_prop {
>>       const char *prop;
>>   };
>>
>> +static int cavium_smmu_count;
>> +
>>   static struct arm_smmu_option_prop arm_smmu_options[] = {
>>       { ARM_SMMU_OPT_SECURE_CFG_ACCESS,
>> "calxeda,smmu-secure-config-access" },
>>       { 0, NULL},
>> @@ -575,11 +583,11 @@ static void arm_smmu_tlb_inv_context(void *cookie)
>>
>>       if (stage1) {
>>           base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
>> -        writel_relaxed(ARM_SMMU_CB_ASID(cfg),
>> +        writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg),
>>                      base + ARM_SMMU_CB_S1_TLBIASID);
>>       } else {
>>           base = ARM_SMMU_GR0(smmu);
>> -        writel_relaxed(ARM_SMMU_CB_VMID(cfg),
>> +        writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg),
>>                      base + ARM_SMMU_GR0_TLBIVMID);
>>       }
>>
>> @@ -601,7 +609,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned
>> long iova, size_t size,
>>
>>           if (!IS_ENABLED(CONFIG_64BIT) || smmu->version ==
>> ARM_SMMU_V1) {
>>               iova &= ~12UL;
>> -            iova |= ARM_SMMU_CB_ASID(cfg);
>> +            iova |= ARM_SMMU_CB_ASID(smmu, cfg);
>>               do {
>>                   writel_relaxed(iova, reg);
>>                   iova += granule;
>> @@ -609,7 +617,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned
>> long iova, size_t size,
>>   #ifdef CONFIG_64BIT
>>           } else {
>>               iova >>= 12;
>> -            iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48;
>> +            iova |= (u64)ARM_SMMU_CB_ASID(smmu, cfg) << 48;
>>               do {
>>                   writeq_relaxed(iova, reg);
>>                   iova += granule >> 12;
>> @@ -629,7 +637,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned
>> long iova, size_t size,
>>   #endif
>>       } else {
>>           reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID;
>> -        writel_relaxed(ARM_SMMU_CB_VMID(cfg), reg);
>> +        writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), reg);
>>       }
>>   }
>>
>> @@ -738,7 +746,7 @@ static void arm_smmu_init_context_bank(struct
>> arm_smmu_domain *smmu_domain,
>>   #endif
>>           /* if 16bit VMID supported set VMID in CBA2R */
>>           if (smmu->features & ARM_SMMU_FEAT_VMID16)
>> -            reg |= ARM_SMMU_CB_VMID(cfg) << CBA2R_VMID_SHIFT;
>> +            reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBA2R_VMID_SHIFT;
>>
>>           writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
>>       }
>> @@ -757,7 +765,7 @@ static void arm_smmu_init_context_bank(struct
>> arm_smmu_domain *smmu_domain,
>>               (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
>>       } else if (!(smmu->features & ARM_SMMU_FEAT_VMID16)) {
>>           /*16 bit VMID is not supported set 8 bit VMID here */
>> -        reg |= ARM_SMMU_CB_VMID(cfg) << CBAR_VMID_SHIFT;
>> +        reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBAR_VMID_SHIFT;
>>       }
>>       writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx));
>>
>> @@ -765,11 +773,11 @@ static void arm_smmu_init_context_bank(struct
>> arm_smmu_domain *smmu_domain,
>>       if (stage1) {
>>           reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
>>
>> -        reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) << TTBRn_ASID_SHIFT;
>> +        reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT;
>>           smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0);
>>
>>           reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
>> -        reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) << TTBRn_ASID_SHIFT;
>> +        reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT;
>>           smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR1);
>>       } else {
>>           reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
>> @@ -1717,6 +1725,7 @@ static const struct of_device_id
>> arm_smmu_of_match[] = {
>>       { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 },
>>       { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 },
>>       { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 },
>> +    { .compatible = "cavium,smmu-v2", .data = (void *)ARM_SMMU_V2 },
>>       { },
>>   };
>>   MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
>> @@ -1827,6 +1836,23 @@ static int arm_smmu_device_dt_probe(struct
>> platform_device *pdev)
>>           }
>>       }
>>
>> +    /*
>> +     * Due to Errata#27704 CN88xx SMMUv2,supports  only shared ASID
>> and VMID
>> +     * namespaces; specifically within a given node SMMU0 and SMMU1
>> share,
>> +     * as does SMMU2 and SMMU3. see if this is a Cavium SMMU, if so
>> +     * set asid and vmid base such that each SMMU gets unique
>> +     * asid/vmid space.
>> +     */
>> +    if (!strcasecmp(of_id->compatible, "cavium,smmu-v2")) {
>> +        /* VMID16 must be present on Cavium SMMUv2*/
>> +        if (!(smmu->features & ARM_SMMU_FEAT_VMID16))
>> +            goto out_free_irqs;
>> +        smmu->cavium_smmu_id = cavium_smmu_count;
>> +        cavium_smmu_count++;
>> +        smmu->cavium_id_base =
>> +            (smmu->cavium_smmu_id * ARM_SMMU_MAX_CBS);
>> +    }
>> +
>>       INIT_LIST_HEAD(&smmu->list);
>>       spin_lock(&arm_smmu_devices_lock);
>>       list_add(&smmu->list, &arm_smmu_devices);
>>
>



More information about the linux-arm-kernel mailing list