Regions remapped as MAP_CODE are still cacheable, even if they aren't MAP_CACHED. To handle that and to support a future use of flags in the maptype_t, let's limit the existing memory type enumeration to the lower 16 bits and use a MAP_CODE/MAP_CACHED aware comparison helper.
Signed-off-by: Ahmad Fatoum <a.fat...@pengutronix.de> --- arch/arm/cpu/mmu-common.h | 6 +++--- arch/arm/cpu/mmu_32.c | 10 +++++----- arch/arm/cpu/mmu_64.c | 4 ++-- arch/powerpc/cpu-85xx/mmu.c | 2 +- include/mmu.h | 19 ++++++++++++++++++- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/arch/arm/cpu/mmu-common.h b/arch/arm/cpu/mmu-common.h index a545958b5cc2..e9005dfae766 100644 --- a/arch/arm/cpu/mmu-common.h +++ b/arch/arm/cpu/mmu-common.h @@ -10,8 +10,8 @@ #include <linux/kernel.h> #include <linux/sizes.h> -#define ARCH_MAP_CACHED_RWX ((unsigned)-2) -#define ARCH_MAP_CACHED_RO ((unsigned)-3) +#define ARCH_MAP_CACHED_RWX MAP_ARCH(2) +#define ARCH_MAP_CACHED_RO MAP_ARCH(3) struct device; @@ -26,7 +26,7 @@ static inline maptype_t arm_mmu_maybe_skip_permissions(maptype_t map_type) if (IS_ENABLED(CONFIG_ARM_MMU_PERMISSIONS)) return map_type; - switch (map_type) { + switch (map_type & MAP_TYPE_MASK) { case MAP_CODE: case MAP_CACHED: case ARCH_MAP_CACHED_RO: diff --git a/arch/arm/cpu/mmu_32.c b/arch/arm/cpu/mmu_32.c index 8d1343b5d7d7..ae86c27e7e27 100644 --- a/arch/arm/cpu/mmu_32.c +++ b/arch/arm/cpu/mmu_32.c @@ -226,7 +226,7 @@ static u32 pte_flags_to_pmd(u32 pte) static uint32_t get_pte_flags(maptype_t map_type) { if (cpu_architecture() >= CPU_ARCH_ARMv7) { - switch (map_type) { + switch (map_type & MAP_TYPE_MASK) { case ARCH_MAP_CACHED_RWX: return PTE_FLAGS_CACHED_V7_RWX; case ARCH_MAP_CACHED_RO: @@ -244,7 +244,7 @@ static uint32_t get_pte_flags(maptype_t map_type) return 0x0; } } else { - switch (map_type) { + switch (map_type & MAP_TYPE_MASK) { case ARCH_MAP_CACHED_RO: case MAP_CODE: return PTE_FLAGS_CACHED_RO_V4; @@ -300,7 +300,7 @@ static void __arch_remap_range(void *_virt_addr, phys_addr_t phys_addr, size_t s */ chunk = PGDIR_SIZE; val = phys_addr | pmd_flags; - if (map_type != MAP_FAULT) + if (!maptype_is_compatible(map_type, MAP_FAULT)) val |= PMD_TYPE_SECT; // TODO break-before-make missing set_pte(pgd, val); @@ -346,7 +346,7 @@ static void __arch_remap_range(void *_virt_addr, phys_addr_t phys_addr, size_t s val = phys_addr + i * PAGE_SIZE; val |= pte_flags; - if (map_type != MAP_FAULT) + if (!maptype_is_compatible(map_type, MAP_FAULT)) val |= PTE_TYPE_SMALL; // TODO break-before-make missing @@ -375,7 +375,7 @@ int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, maptyp __arch_remap_range(virt_addr, phys_addr, size, map_type, false); - if (map_type == MAP_UNCACHED) + if (maptype_is_compatible(map_type, MAP_UNCACHED)) dma_inv_range(virt_addr, size); return 0; diff --git a/arch/arm/cpu/mmu_64.c b/arch/arm/cpu/mmu_64.c index ad96bda702b8..9e8d36d94944 100644 --- a/arch/arm/cpu/mmu_64.c +++ b/arch/arm/cpu/mmu_64.c @@ -289,7 +289,7 @@ static void flush_cacheable_pages(void *start, size_t size) static unsigned long get_pte_attrs(maptype_t map_type) { - switch (map_type) { + switch (map_type & MAP_TYPE_MASK) { case MAP_CACHED: return attrs_xn() | CACHED_MEM; case MAP_UNCACHED: @@ -330,7 +330,7 @@ int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, maptyp if (attrs == ~0UL) return -EINVAL; - if (map_type != MAP_CACHED) + if (!maptype_is_compatible(map_type, MAP_CACHED)) flush_cacheable_pages(virt_addr, size); create_sections((uint64_t)virt_addr, phys_addr, (uint64_t)size, attrs, false); diff --git a/arch/powerpc/cpu-85xx/mmu.c b/arch/powerpc/cpu-85xx/mmu.c index 5fe9ba9db6d8..eec4d3e05b56 100644 --- a/arch/powerpc/cpu-85xx/mmu.c +++ b/arch/powerpc/cpu-85xx/mmu.c @@ -27,7 +27,7 @@ int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, maptyp if (phys_addr != virt_to_phys(virt_addr)) return -ENOSYS; - switch (flags) { + switch (flags & MAP_TYPE_MASK) { case MAP_UNCACHED: pte_flags = MAS2_I; break; diff --git a/include/mmu.h b/include/mmu.h index db8453f58521..29992ae1d6c6 100644 --- a/include/mmu.h +++ b/include/mmu.h @@ -16,6 +16,9 @@ #define MAP_WRITECOMBINE MAP_UNCACHED #endif +#define MAP_TYPE_MASK 0xFFFF +#define MAP_ARCH(x) ((u16)~(x)) + /* * Depending on the architecture the default mapping can be * cached or uncached. Without ARCH_HAS_REMAP being set this @@ -25,11 +28,25 @@ #include <asm/mmu.h> +static inline bool maptype_is_compatible(maptype_t active, maptype_t check) +{ + active &= MAP_TYPE_MASK; + check &= MAP_TYPE_MASK; + + if (active == check) + return true; + if (active == MAP_CODE && check == MAP_CACHED) + return true; + + return false; +} + #ifndef ARCH_HAS_REMAP static inline int arch_remap_range(void *virt_addr, phys_addr_t phys_addr, size_t size, maptype_t map_type) { - if (map_type == MAP_ARCH_DEFAULT && phys_addr == virt_to_phys(virt_addr)) + if (maptype_is_compatible(map_type, MAP_ARCH_DEFAULT) && + phys_addr == virt_to_phys(virt_addr)) return 0; return -EINVAL; -- 2.39.5