On Wed, Dec 18, 2019 at 10:59:36AM +0100, Auger Eric wrote: > > struct arm_smmu_s1_cfg { > > - struct arm_smmu_cd_table table; > > + struct arm_smmu_cd_table *tables; > > + size_t num_tables; > > + __le64 *l1ptr; > you may add a comment saying that l1ptr and l1ptr_dma are only set/used > in non linear case and one comment saying that "tables" represent leaf > tables. I now have /* Leaf tables or linear table */ and /* First level tables, when two level are used */ but I'm not entirely convinced it adds value > > + dma_addr_t l1ptr_dma; > > struct arm_smmu_ctx_desc cd; > > u8 s1fmt; > > u8 s1cdmax; > > @@ -1521,9 +1538,53 @@ static void arm_smmu_free_cd_leaf_table(struct arm_smmu_device *smmu, > > { > > size_t size = num_entries * (CTXDESC_CD_DWORDS << 3); > > > > + if (!table->ptr) > > + return; > > dmam_free_coherent(smmu->dev, size, table->ptr, table->ptr_dma); > > } > > > > +static void arm_smmu_write_cd_l1_desc(__le64 *dst, > > + struct arm_smmu_cd_table *table) > > +{ > > + u64 val = (table->ptr_dma & CTXDESC_L1_DESC_L2PTR_MASK) | > > + CTXDESC_L1_DESC_VALID; > > + > > + WRITE_ONCE(*dst, cpu_to_le64(val)); > > +} > > + > > +static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain, > > + u32 ssid) > > +{ > > + __le64 *l1ptr; > > + unsigned int idx; > > + struct arm_smmu_cd_table *table; > > + struct arm_smmu_device *smmu = smmu_domain->smmu; > > + struct arm_smmu_s1_cfg *cfg = &smmu_domain->s1_cfg; > > + > > + if (cfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR) { > > + table = &cfg->tables[0]; > > + idx = ssid; > > + } else { > nit: you may avoid this extra indent by either returning above or go to > a label. > > + idx = ssid >> CTXDESC_SPLIT; > > + if (idx >= cfg->num_tables) > > + return NULL; > > + > > + table = &cfg->tables[idx]; > > + if (!table->ptr) { > > + if (arm_smmu_alloc_cd_leaf_table(smmu, table, > > + CTXDESC_L2_ENTRIES)) > > + return NULL; > > + > > + l1ptr = cfg->l1ptr + idx * CTXDESC_L1_DESC_DWORDS; > > + arm_smmu_write_cd_l1_desc(l1ptr, table); > > + /* An invalid L1CD can be cached */ > > + arm_smmu_sync_cd(smmu_domain, ssid, false); > > + } > > + idx = ssid & (CTXDESC_L2_ENTRIES - 1); > > + } > > + return table->ptr + idx * CTXDESC_CD_DWORDS;> +} > > + > > static u64 arm_smmu_cpu_tcr_to_cd(u64 tcr) > > { > > u64 val = 0; > > @@ -1556,8 +1617,10 @@ static int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, > > u64 val; > > bool cd_live; > > struct arm_smmu_device *smmu = smmu_domain->smmu; > > - __le64 *cdptr = smmu_domain->s1_cfg.table.ptr + ssid * > > - CTXDESC_CD_DWORDS; > > + __le64 *cdptr = arm_smmu_get_cd_ptr(smmu_domain, ssid); > > + > > + if (!cdptr) > > + return -ENOMEM; > -ENOMEM does not fit well with (idx >= cfg->num_tables) case > Besides the idx is checked against the max table capacity only in non > linear mode. Can't you check the ssid against cfg->s1cdmax earlier? Ok, I'll move that check here Thanks, Jean