]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
arm: armv8: mmu: fix DCACHE_OFF incorrectly unmapping region main
authorAkshay Belsare <akshay.belsare@amd.com>
Wed, 8 Jul 2026 11:17:10 +0000 (16:47 +0530)
committerTom Rini <trini@konsulko.com>
Thu, 23 Jul 2026 21:16:29 +0000 (15:16 -0600)
DCACHE_OFF is defined as (0 << 2) = 0, and PTE_TYPE_FAULT is defined
as (0 << 0) = 0. In mmu_set_region_dcache_behaviour(), the cache
attribute passed to set_regions() is computed as:
  attrs = PMD_ATTRINDX(option >> 2)
For DCACHE_OFF=0 this evaluates to PMD_ATTRINDX(0) = 0, which equals
PTE_TYPE_FAULT.

Commit 6468ca13ffd6f ("armv8: mmu: fix and optimise explicitly unmapping
regions") added an unmap path to set_one_region() that
triggers when attrs == PTE_TYPE_FAULT. Because DCACHE_OFF and
PTE_TYPE_FAULT share the same numerical value (0), any call to
mmu_set_region_dcache_behaviour() with DCACHE_OFF silently unmaps the
target region instead of changing its cache attributes to non-cached.

The subsequent flush_dcache_range() call at the end of
mmu_set_region_dcache_behaviour() then crashes with a Level 3
translation fault because the region it tries to flush has just been
unmapped.

The existing flag parameter already distinguishes the two callers:
 - mmu_set_region_dcache_behaviour() always passes flag=false
 - mmu_change_region_attr_nobreak() always passes flag=true, and is the
   only legitimate caller that passes PTE_TYPE_FAULT to unmap a region

Guard the unmap path with flag so that DCACHE_OFF attribute changes
take the correct else branch, which ORs in the ATTRINDX bits only,
leaving the PTE valid.

This was observed as a boot crash on Versal, Versal Net, and ZynqMP
platforms during network initialisation. The zynq_gem driver calls
mmu_set_region_dcache_behaviour() with DCACHE_OFF to make its BD
descriptor ring non-cached. With the bug the BD memory is unmapped,
and the subsequent dcache flush inside
mmu_set_region_dcache_behaviour() faults.

Fixes: 6468ca13ffd6f ("armv8: mmu: fix and optimise explicitly unmapping regions")
Signed-off-by: Akshay Belsare <akshay.belsare@amd.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
arch/arm/cpu/armv8/cache_v8.c

index e59528e576ee7257803c44a03a11bc55e6b5888f..ad232435eb28ad12d22cfdbbbb9ea754b9d7c9e6 100644 (file)
@@ -1006,7 +1006,7 @@ static u64 set_one_region(u64 start, u64 size, u64 attrs, bool flag, int level)
 
        /* Can we can just modify the current level block/page? */
        if (is_aligned(start, size, levelsize)) {
-               if (attrs == PTE_TYPE_FAULT) {
+               if (attrs == PTE_TYPE_FAULT && flag) {
                        if (pte_type(pte) == PTE_TYPE_TABLE && level < 3)
                                *pte = 0;
                        else