Hi Will, I found current smmu driver may generate wrong page tables, after apply this patch, the result is correct. I have verified this patch on our platform.
BR, Yifan On Fri, Jan 3, 2014 at 8:01 PM, Yifan Zhang <[email protected]> wrote: > From: Yifan Zhang <[email protected]> > > Pgd/pud entry should be filled only once when their next level pud/pmd > created, the value should be pud/pmd start address, while in current > code, pgd/pud entry is filled every time when pud/pmd walk occurs, > the value is pud/pmd start address + iova pud/pmd index , this is > incorrect; Besides, when pud/pmd are created, we need to add pud/pmd > index, then pass to next level, while in currect code, if a new pud/pmd > created, their iova pud/pmd index is not taken into account, only > existing pud/pmd do. This patch change pud/pmd entry fill sequence, > fixes the 2 bugs. > > Signed-off-by: Yifan Zhang <[email protected]> > --- > drivers/iommu/arm-smmu.c | 14 ++++++++++---- > 1 file changed, 10 insertions(+), 4 deletions(-) > > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c > index e46a887..e3168a2 100644 > --- a/drivers/iommu/arm-smmu.c > +++ b/drivers/iommu/arm-smmu.c > @@ -1317,6 +1317,11 @@ static int arm_smmu_alloc_init_pmd(struct > arm_smmu_device *smmu, pud_t *pud, > pmd = pmd_alloc_one(NULL, addr); > if (!pmd) > return -ENOMEM; > + > + pud_populate(NULL, pud, pmd); > + arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); > + > + pmd += pmd_index(addr); > } else > #endif > pmd = pmd_offset(pud, addr); > @@ -1325,8 +1330,6 @@ static int arm_smmu_alloc_init_pmd(struct > arm_smmu_device *smmu, pud_t *pud, > next = pmd_addr_end(addr, end); > ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn, > flags, stage); > - pud_populate(NULL, pud, pmd); > - arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); > phys += next - addr; > } while (pmd++, addr = next, addr < end); > > @@ -1346,6 +1349,11 @@ static int arm_smmu_alloc_init_pud(struct > arm_smmu_device *smmu, pgd_t *pgd, > pud = pud_alloc_one(NULL, addr); > if (!pud) > return -ENOMEM; > + > + pgd_populate(NULL, pgd, pud); > + arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); > + > + pud += pud_index(addr); > } else > #endif > pud = pud_offset(pgd, addr); > @@ -1354,8 +1362,6 @@ static int arm_smmu_alloc_init_pud(struct > arm_smmu_device *smmu, pgd_t *pgd, > next = pud_addr_end(addr, end); > ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys, > flags, stage); > - pgd_populate(NULL, pud, pgd); > - arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); > phys += next - addr; > } while (pud++, addr = next, addr < end); > > -- > 1.7.9.5 > > > _______________________________________________ > linux-arm-kernel mailing list > [email protected] > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >
_______________________________________________ iommu mailing list [email protected] https://lists.linuxfoundation.org/mailman/listinfo/iommu
