* [PATCH v2 0/6] mm: highmem cleanups
@ 2026-11-12 11:25 Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 1/6] ARM: remove support for highmem on VIVT Arnd Bergmann
` (5 more replies)
0 siblings, 6 replies; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
From: Arnd Bergmann <arnd@arndb.de>
This is an updated series from what I posted last year [1], sorry for
taking way longer with this than I had planned. Linus brought it up today,
which triggered me to rebase the earlier patches and post it again.
At LPC 2025 [3], we got rough consensus on the plan to keep the
funcationality present for the time being but instead reduce the scope
of highmem in the kernel as much as we can without hurting users.
The short summary is a three stage process:
1. Nudge users towards using a larger lowmem zone with the
CONFIG_VMSPLIT_* options if at all possible.
2. Drop most __GFP_HIGHMEM allocations and corresponding kmap()
calls from the kernel, leaving only the subset that is likely
to contain the majority of the actual allocations.
Specifically we will keep anonymous and regular file backed
user mappings, zsmalloc, and huge pages.
3. In a few years, also drop the page cache allocations and leave
perhaps only zsmalloc using a much simpler interface. I suggested
five years as the time until we do this, but the timing depends a
lot on how the first two stages work out in practice, and how long
the remaining highmem users plan to keep updating their kernels.
This series implements stage 1, mostly using Kconfig changes to the
default settings but leaving the traditional behavior as a CONFIG_EXPERT
choice in Kconfig. With the new defaults, most installations that use
highmem today with 1 GiB or 2 GiB of system RAM will see all of their
RAM in the lowmem zone after upgrading their kernels. My estimate is
that instead of 80% to 90% of maintained embedded 32-bit systems, this
should cover over 98%.
As I don't actually have hardware in the category that still needs
highmem, I tested this using a qemu-system for Armv7 and PPC6xx running a
Debian userland with all combinations of VMSPLIT and HIGHMEM options. I
ran some kernel builds on the Arm guest to ensure that the new options
don't cause functional or performance regressions for regular workloads
that don't exceed the virtual address space. I also ran some tests
with Firefox and was positively surprised to see that this still works
on the VMSPLIT_2G_OPT configuration without highmem, though it gets
close to both the address space and lowmem size limits.
As I had to change the powerpc version a bit for the rebase, this
current version is entirely untested, but I hope that Richard and
Christophe are able to help out there, as they both understand this
code better than I do.
The change to use VMSPLIT_3G_OPT by default on Armv5 means that I could
include a patch to no longer support highmem at all on VIVT caches,
as suggested by Jason Gunthorpe. I also included the patch to drop
HIGHPTE support now, as suggested by David Hildenbrand.
The patches from this series are available in [4] for testing.
Arnd
[1] https://lore.kernel.org/all/20251219161559.556737-1-arnd@kernel.org/
[2] https://lore.kernel.org/all/CAHk-=wjPY=kfgnmtx4COEQjD5UzKx9m2-=KLGAZP4d=RKEH+pg@mail.gmail.com/
[3] https://lwn.net/Articles/1051010/
[4] https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/log/?h=highmem-7.4
Arnd Bergmann (5):
ARM: remove support for highmem on VIVT
mm: remove ARCH_NEEDS_KMAP_HIGH_GET
ARM: drop CONFIG_HIGHPTE support
mm: drop HIGHPTE support altogether
arch/*: increase lowmem size to avoid highmem use
arch/arm/Kconfig | 17 ++--
arch/arm/configs/aspeed_g5_defconfig | 1 -
arch/arm/configs/gemini_defconfig | 1 -
arch/arm/configs/multi_v5_defconfig | 1 -
arch/arm/configs/mvebu_v5_defconfig | 1 -
arch/arm/configs/u8500_defconfig | 1 -
arch/arm/configs/vt8500_v6_v7_defconfig | 2 -
arch/arm/include/asm/highmem.h | 56 +-------------
arch/arm/include/asm/pgalloc.h | 8 +-
arch/arm/mach-omap2/Kconfig | 1 -
arch/arm/mm/cache-feroceon-l2.c | 31 +-------
arch/arm/mm/cache-xsc3l2.c | 47 ++---------
arch/arm/mm/dma-mapping.c | 12 +--
arch/arm/mm/flush.c | 19 +----
arch/microblaze/Kconfig | 9 ++-
arch/microblaze/configs/mmu_defconfig | 1 -
arch/powerpc/Kconfig | 14 ++--
arch/powerpc/configs/44x/akebono_defconfig | 1 -
arch/powerpc/configs/85xx/ksi8560_defconfig | 1 -
arch/powerpc/configs/85xx/stx_gp3_defconfig | 1 -
arch/x86/Kconfig | 4 +-
include/linux/hugetlb.h | 5 +-
include/linux/mm.h | 1 -
include/linux/pgtable.h | 9 ---
mm/highmem.c | 86 +++------------------
25 files changed, 50 insertions(+), 280 deletions(-)
--
2.53.0
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Hildenbrand (Arm) <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Malin Jonsson <malin.jonsson@est.tech>
Cc: Richard Weinberger <richard@nod.at>
Cc: Russell King <linux@armlinux.org.uk>
Cc: linux-mm@kvack.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-fsdevel@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: x86@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 1/6] ARM: remove support for highmem on VIVT
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
@ 2026-11-12 11:25 ` Arnd Bergmann
2026-11-12 13:47 ` Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET Arnd Bergmann
` (4 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
From: Arnd Bergmann <arnd@arndb.de>
As Jason Gunthorpe noticed, supporting VIVT caches adds some complications
to highmem that can be avoided these days:
While all ARMv4 and ARMv5 CPUs use virtually indexed caches, they no
longer really need highmem because we have practically discontinued
support for large-memory configurations already. The only machines I
could find anywhere for memory on ARMv5 are:
- The Intel IOP platform was used on relatively large memory
configurations but we dropped kernel support in 2019 and 2022,
respectively.
- The Marvell mv78xx0 platform was the initial user of Arm highmem,
with the DB-78x00-BP supporting 2GB of memory. The only remaining
board file is for Buffalo WLX (Terastation Duo), which has only
512MB and is going to be removed soon.
- The Kirkwood platform supports 2GB, and there are actually boards
with that configuration that can still work. However, there are
no known users of the OpenBlocks A7, and the Freebox V6 is already
using CONFIG_VMSPLIT_2G to avoid enabling highmem.
Remove the Arm specific portions here, making CONFIG_HIGHMEM conditional
on modern caches. Since the cache type is enforced by Kconfig, no
boot time check is needed here.
Link: https://lore.kernel.org/all/20251219171412.GG254720@nvidia.com/
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/Kconfig | 1 +
arch/arm/configs/gemini_defconfig | 1 -
arch/arm/configs/multi_v5_defconfig | 1 -
arch/arm/configs/mvebu_v5_defconfig | 1 -
arch/arm/include/asm/highmem.h | 56 ++---------------------------
arch/arm/mach-omap2/Kconfig | 2 +-
arch/arm/mm/cache-feroceon-l2.c | 31 ++--------------
arch/arm/mm/cache-xsc3l2.c | 47 +++---------------------
arch/arm/mm/dma-mapping.c | 12 ++-----
arch/arm/mm/flush.c | 19 +++-------
10 files changed, 17 insertions(+), 154 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0cc289a7184a..fd01ccab9c12 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1208,6 +1208,7 @@ config ARCH_SPARSEMEM_ENABLE
config HIGHMEM
bool "High Memory Support"
depends on MMU
+ depends on !CPU_CACHE_VIVT
select KMAP_LOCAL
select KMAP_LOCAL_NON_LINEAR_PTE_ARRAY
help
diff --git a/arch/arm/configs/gemini_defconfig b/arch/arm/configs/gemini_defconfig
index 5860b2fe7d1f..95debf46581b 100644
--- a/arch/arm/configs/gemini_defconfig
+++ b/arch/arm/configs/gemini_defconfig
@@ -11,7 +11,6 @@ CONFIG_KEXEC=y
CONFIG_ARCH_MULTI_V4=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_GEMINI=y
-CONFIG_HIGHMEM=y
CONFIG_CMDLINE="console=ttyS0,115200n8"
CONFIG_PM=y
CONFIG_PARTITION_ADVANCED=y
diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig
index a0d2fb2fcf9a..bc34b6026e37 100644
--- a/arch/arm/configs/multi_v5_defconfig
+++ b/arch/arm/configs/multi_v5_defconfig
@@ -27,7 +27,6 @@ CONFIG_MACH_D2NET_DT=y
CONFIG_MACH_MSS2_DT=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_VERSATILE=y
-CONFIG_HIGHMEM=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CPU_FREQ=y
diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig
index dbc6c511e70b..5adf6c75304e 100644
--- a/arch/arm/configs/mvebu_v5_defconfig
+++ b/arch/arm/configs/mvebu_v5_defconfig
@@ -13,7 +13,6 @@ CONFIG_MACH_RD88F5182_DT=y
CONFIG_MACH_LINKSTATION_MINI=y
CONFIG_MACH_D2NET_DT=y
CONFIG_MACH_MSS2_DT=y
-CONFIG_HIGHMEM=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CPU_FREQ=y
diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
index bdb209e002a4..67ed46d1922b 100644
--- a/arch/arm/include/asm/highmem.h
+++ b/arch/arm/include/asm/highmem.h
@@ -11,66 +11,14 @@
#define PKMAP_NR(virt) (((virt) - PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-#define flush_cache_kmaps() \
- do { \
- if (cache_is_vivt()) \
- flush_cache_all(); \
- } while (0)
+#define flush_cache_kmaps() do { } while (0)
extern pte_t *pkmap_page_table;
-/*
- * The reason for kmap_high_get() is to ensure that the currently kmap'd
- * page usage count does not decrease to zero while we're using its
- * existing virtual mapping in an atomic context. With a VIVT cache this
- * is essential to do, but with a VIPT cache this is only an optimization
- * so not to pay the price of establishing a second mapping if an existing
- * one can be used. However, on platforms without hardware TLB maintenance
- * broadcast, we simply cannot use ARCH_NEEDS_KMAP_HIGH_GET at all since
- * the locking involved must also disable IRQs which is incompatible with
- * the IPI mechanism used by global TLB operations.
- */
-#define ARCH_NEEDS_KMAP_HIGH_GET
-#if defined(CONFIG_SMP) && defined(CONFIG_CPU_TLB_V6)
-#undef ARCH_NEEDS_KMAP_HIGH_GET
-#if defined(CONFIG_HIGHMEM) && defined(CONFIG_CPU_CACHE_VIVT)
-#error "The sum of features in your kernel config cannot be supported together"
-#endif
-#endif
-
-/*
- * Needed to be able to broadcast the TLB invalidation for kmap.
- */
-#ifdef CONFIG_ARM_ERRATA_798181
-#undef ARCH_NEEDS_KMAP_HIGH_GET
-#endif
-
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-extern void *kmap_high_get(const struct page *page);
-
-static inline void *arch_kmap_local_high_get(const struct page *page)
-{
- if (IS_ENABLED(CONFIG_DEBUG_HIGHMEM) && !cache_is_vivt())
- return NULL;
- return kmap_high_get(page);
-}
-#define arch_kmap_local_high_get arch_kmap_local_high_get
-
-#else /* ARCH_NEEDS_KMAP_HIGH_GET */
-static inline void *kmap_high_get(const struct page *page)
-{
- return NULL;
-}
-#endif /* !ARCH_NEEDS_KMAP_HIGH_GET */
-
#define arch_kmap_local_post_map(vaddr, pteval) \
local_flush_tlb_kernel_page(vaddr)
-#define arch_kmap_local_pre_unmap(vaddr) \
-do { \
- if (cache_is_vivt()) \
- __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE); \
-} while (0)
+#define arch_kmap_local_pre_unmap(vaddr) do { } while (0)
#define arch_kmap_local_post_unmap(vaddr) \
local_flush_tlb_kernel_page(vaddr)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 79f8afe3a6bf..f0f1d7a8640c 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -135,7 +135,7 @@ config ARCH_OMAP2PLUS_TYPICAL
bool "Typical OMAP configuration"
default y
select AEABI
- select HIGHMEM
+ select HIGHMEM if !CPU_CACHE_VIVT
select I2C
select I2C_OMAP
select MENELAUS if ARCH_OMAP2
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index 2bfefb252ffd..1316b6ab295a 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/highmem.h>
#include <linux/io.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
@@ -38,30 +37,6 @@
* between which we don't want to be preempted.
*/
-static inline unsigned long l2_get_va(unsigned long paddr)
-{
-#ifdef CONFIG_HIGHMEM
- /*
- * Because range ops can't be done on physical addresses,
- * we simply install a virtual mapping for it only for the
- * TLB lookup to occur, hence no need to flush the untouched
- * memory mapping afterwards (note: a cache flush may happen
- * in some circumstances depending on the path taken in kunmap_atomic).
- */
- void *vaddr = kmap_atomic_pfn(paddr >> PAGE_SHIFT);
- return (unsigned long)vaddr + (paddr & ~PAGE_MASK);
-#else
- return __phys_to_virt(paddr);
-#endif
-}
-
-static inline void l2_put_va(unsigned long vaddr)
-{
-#ifdef CONFIG_HIGHMEM
- kunmap_atomic((void *)vaddr);
-#endif
-}
-
static inline void l2_clean_pa(unsigned long addr)
{
__asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
@@ -78,14 +53,13 @@ static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
*/
BUG_ON((start ^ end) >> PAGE_SHIFT);
- va_start = l2_get_va(start);
+ va_start = __phys_to_virt(start);
va_end = va_start + (end - start);
raw_local_irq_save(flags);
__asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
"mcr p15, 1, %1, c15, c9, 5"
: : "r" (va_start), "r" (va_end));
raw_local_irq_restore(flags);
- l2_put_va(va_start);
}
static inline void l2_clean_inv_pa(unsigned long addr)
@@ -109,14 +83,13 @@ static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
*/
BUG_ON((start ^ end) >> PAGE_SHIFT);
- va_start = l2_get_va(start);
+ va_start = __phys_to_virt(start);
va_end = va_start + (end - start);
raw_local_irq_save(flags);
__asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
"mcr p15, 1, %1, c15, c11, 5"
: : "r" (va_start), "r" (va_end));
raw_local_irq_restore(flags);
- l2_put_va(va_start);
}
static inline void l2_inv_all(void)
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
index d20d7af02d10..477077387039 100644
--- a/arch/arm/mm/cache-xsc3l2.c
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -5,7 +5,6 @@
* Copyright (C) 2007 ARM Limited
*/
#include <linux/init.h>
-#include <linux/highmem.h>
#include <asm/cp15.h>
#include <asm/cputype.h>
#include <asm/cacheflush.h>
@@ -55,34 +54,6 @@ static inline void xsc3_l2_inv_all(void)
dsb();
}
-static inline void l2_unmap_va(unsigned long va)
-{
-#ifdef CONFIG_HIGHMEM
- if (va != -1)
- kunmap_atomic((void *)va);
-#endif
-}
-
-static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
-{
-#ifdef CONFIG_HIGHMEM
- unsigned long va = prev_va & PAGE_MASK;
- unsigned long pa_offset = pa << (32 - PAGE_SHIFT);
- if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) {
- /*
- * Switching to a new page. Because cache ops are
- * using virtual addresses only, we must put a mapping
- * in place for it.
- */
- l2_unmap_va(prev_va);
- va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
- }
- return va + (pa_offset >> (32 - PAGE_SHIFT));
-#else
- return __phys_to_virt(pa);
-#endif
-}
-
static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
{
unsigned long vaddr;
@@ -92,13 +63,11 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
return;
}
- vaddr = -1; /* to force the first mapping */
-
/*
* Clean and invalidate partial first cache line.
*/
if (start & (CACHE_LINE_SIZE - 1)) {
- vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
+ vaddr = __phys_to_virt(start & ~(CACHE_LINE_SIZE - 1));
xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr);
start = (start | (CACHE_LINE_SIZE - 1)) + 1;
@@ -108,7 +77,7 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
* Invalidate all full cache lines between 'start' and 'end'.
*/
while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
- vaddr = l2_map_va(start, vaddr);
+ vaddr = __phys_to_virt(start);
xsc3_l2_inv_mva(vaddr);
start += CACHE_LINE_SIZE;
}
@@ -117,13 +86,11 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
* Clean and invalidate partial last cache line.
*/
if (start < end) {
- vaddr = l2_map_va(start, vaddr);
+ vaddr = __phys_to_virt(start);
xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr);
}
- l2_unmap_va(vaddr);
-
dsb();
}
@@ -135,13 +102,11 @@ static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
- vaddr = l2_map_va(start, vaddr);
+ vaddr = __phys_to_virt(start);
xsc3_l2_clean_mva(vaddr);
start += CACHE_LINE_SIZE;
}
- l2_unmap_va(vaddr);
-
dsb();
}
@@ -178,14 +143,12 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) {
- vaddr = l2_map_va(start, vaddr);
+ vaddr = __phys_to_virt(start);
xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr);
start += CACHE_LINE_SIZE;
}
- l2_unmap_va(vaddr);
-
dsb();
}
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index fb2eb0ed7bb8..917a546af0b9 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -647,18 +647,10 @@ static void dma_cache_maint_page(phys_addr_t phys, size_t size,
if (len + offset > PAGE_SIZE)
len = PAGE_SIZE - offset;
- if (cache_is_vipt_nonaliasing()) {
- vaddr = kmap_atomic_pfn(pfn);
+ vaddr = kmap_atomic(phys_to_page(phys));
+ if (vaddr) {
op(vaddr + offset, len, dir);
kunmap_atomic(vaddr);
- } else {
- struct page *page = phys_to_page(phys);
-
- vaddr = kmap_high_get(page);
- if (vaddr) {
- op(vaddr + offset, len, dir);
- kunmap_high(page);
- }
}
} else {
phys += offset;
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 66270904f874..e21c5af6f34c 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -208,21 +208,10 @@ void __flush_dcache_folio(struct address_space *mapping, struct folio *folio)
folio_size(folio));
} else {
unsigned long i;
- if (cache_is_vipt_nonaliasing()) {
- for (i = 0; i < folio_nr_pages(folio); i++) {
- void *addr = kmap_local_folio(folio,
- i * PAGE_SIZE);
- __cpuc_flush_dcache_area(addr, PAGE_SIZE);
- kunmap_local(addr);
- }
- } else {
- for (i = 0; i < folio_nr_pages(folio); i++) {
- void *addr = kmap_high_get(folio_page(folio, i));
- if (addr) {
- __cpuc_flush_dcache_area(addr, PAGE_SIZE);
- kunmap_high(folio_page(folio, i));
- }
- }
+ for (i = 0; i < folio_nr_pages(folio); i++) {
+ void *addr = kmap_local_folio(folio, i * PAGE_SIZE);
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ kunmap_local(addr);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 1/6] ARM: remove support for highmem on VIVT Arnd Bergmann
@ 2026-11-12 11:25 ` Arnd Bergmann
2026-11-12 11:48 ` Mike Rapoport
2026-11-12 11:25 ` [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support Arnd Bergmann
` (3 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
From: Arnd Bergmann <arnd@arndb.de>
Arm has stopped setting ARCH_NEEDS_KMAP_HIGH_GET, so this
is handled using the same wrappers across all architectures
now, which leaves room for simplification.
Replace lock_kmap()/unlock_kmap() with open-coded spinlocks
and drop the now empty arch_kmap_local_high_get() and
kmap_high_unmap_local() helpers.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
mm/highmem.c | 100 ++++++---------------------------------------------
1 file changed, 10 insertions(+), 90 deletions(-)
diff --git a/mm/highmem.c b/mm/highmem.c
index a33e41183951..214164f9172b 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -143,25 +143,6 @@ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock);
pte_t *pkmap_page_table;
-/*
- * Most architectures have no use for kmap_high_get(), so let's abstract
- * the disabling of IRQ out of the locking in that case to save on a
- * potential useless overhead.
- */
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-#define lock_kmap() spin_lock_irq(&kmap_lock)
-#define unlock_kmap() spin_unlock_irq(&kmap_lock)
-#define lock_kmap_any(flags) spin_lock_irqsave(&kmap_lock, flags)
-#define unlock_kmap_any(flags) spin_unlock_irqrestore(&kmap_lock, flags)
-#else
-#define lock_kmap() spin_lock(&kmap_lock)
-#define unlock_kmap() spin_unlock(&kmap_lock)
-#define lock_kmap_any(flags) \
- do { spin_lock(&kmap_lock); (void)(flags); } while (0)
-#define unlock_kmap_any(flags) \
- do { spin_unlock(&kmap_lock); (void)(flags); } while (0)
-#endif
-
struct page *__kmap_to_page(void *vaddr)
{
unsigned long base = (unsigned long) vaddr & PAGE_MASK;
@@ -238,9 +219,9 @@ static void flush_all_zero_pkmaps(void)
void __kmap_flush_unused(void)
{
- lock_kmap();
+ spin_lock(&kmap_lock);
flush_all_zero_pkmaps();
- unlock_kmap();
+ spin_unlock(&kmap_lock);
}
static inline unsigned long map_new_virtual(struct page *page)
@@ -274,10 +255,10 @@ static inline unsigned long map_new_virtual(struct page *page)
__set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(pkmap_map_wait, &wait);
- unlock_kmap();
+ spin_unlock(&kmap_lock);
schedule();
remove_wait_queue(pkmap_map_wait, &wait);
- lock_kmap();
+ spin_lock(&kmap_lock);
/* Somebody else might have mapped it while we slept */
if (page_address(page))
@@ -313,60 +294,32 @@ void *kmap_high(struct page *page)
* For highmem pages, we can't trust "virtual" until
* after we have the lock.
*/
- lock_kmap();
+ spin_lock(&kmap_lock);
vaddr = (unsigned long)page_address(page);
if (!vaddr)
vaddr = map_new_virtual(page);
pkmap_count[PKMAP_NR(vaddr)]++;
BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
- unlock_kmap();
+ spin_unlock(&kmap_lock);
return (void *) vaddr;
}
EXPORT_SYMBOL(kmap_high);
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
-/**
- * kmap_high_get - pin a highmem page into memory
- * @page: &struct page to pin
- *
- * Returns the page's current virtual memory address, or NULL if no mapping
- * exists. If and only if a non null address is returned then a
- * matching call to kunmap_high() is necessary.
- *
- * This can be called from any context.
- */
-void *kmap_high_get(const struct page *page)
-{
- unsigned long vaddr, flags;
-
- lock_kmap_any(flags);
- vaddr = (unsigned long)page_address(page);
- if (vaddr) {
- BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1);
- pkmap_count[PKMAP_NR(vaddr)]++;
- }
- unlock_kmap_any(flags);
- return (void *) vaddr;
-}
-#endif
-
/**
* kunmap_high - unmap a highmem page into memory
* @page: &struct page to unmap
*
- * If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called
- * only from user context.
+ * This may be called only from user context.
*/
void kunmap_high(const struct page *page)
{
unsigned long vaddr;
unsigned long nr;
- unsigned long flags;
int need_wakeup;
unsigned int color = get_pkmap_color(page);
wait_queue_head_t *pkmap_map_wait;
- lock_kmap_any(flags);
+ spin_lock(&kmap_lock);
vaddr = (unsigned long)page_address(page);
BUG_ON(!vaddr);
nr = PKMAP_NR(vaddr);
@@ -393,7 +346,7 @@ void kunmap_high(const struct page *page)
pkmap_map_wait = get_pkmap_wait_queue_head(color);
need_wakeup = waitqueue_active(pkmap_map_wait);
}
- unlock_kmap_any(flags);
+ spin_unlock(&kmap_lock);
/* do wake-up, if needed, race-free outside of the spin lock */
if (need_wakeup)
@@ -508,30 +461,11 @@ static inline void kmap_local_idx_pop(void)
#define arch_kmap_local_unmap_idx(idx, vaddr) kmap_local_calc_idx(idx)
#endif
-#ifndef arch_kmap_local_high_get
-static inline void *arch_kmap_local_high_get(const struct page *page)
-{
- return NULL;
-}
-#endif
-
#ifndef arch_kmap_local_set_pte
#define arch_kmap_local_set_pte(mm, vaddr, ptep, ptev) \
set_pte_at(mm, vaddr, ptep, ptev)
#endif
-/* Unmap a local mapping which was obtained by kmap_high_get() */
-static inline bool kmap_high_unmap_local(unsigned long vaddr)
-{
-#ifdef ARCH_NEEDS_KMAP_HIGH_GET
- if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) {
- kunmap_high(pte_page(ptep_get(&pkmap_page_table[PKMAP_NR(vaddr)])));
- return true;
- }
-#endif
- return false;
-}
-
static pte_t *__kmap_pte;
static pte_t *kmap_get_pte(unsigned long vaddr, int idx)
@@ -575,8 +509,6 @@ EXPORT_SYMBOL_GPL(__kmap_local_pfn_prot);
void *__kmap_local_page_prot(const struct page *page, pgprot_t prot)
{
- void *kmap;
-
/*
* To broaden the usage of the actual kmap_local() machinery always map
* pages when debugging is enabled and the architecture has no problems
@@ -585,11 +517,6 @@ void *__kmap_local_page_prot(const struct page *page, pgprot_t prot)
if (!IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) && !PageHighMem(page))
return page_address(page);
- /* Try kmap_high_get() if architecture has it enabled */
- kmap = arch_kmap_local_high_get(page);
- if (kmap)
- return kmap;
-
return __kmap_local_pfn_prot(page_to_pfn(page), prot);
}
EXPORT_SYMBOL(__kmap_local_page_prot);
@@ -607,14 +534,7 @@ void kunmap_local_indexed(const void *vaddr)
WARN_ON_ONCE(1);
return;
}
- /*
- * Handle mappings which were obtained by kmap_high_get()
- * first as the virtual address of such mappings is below
- * PAGE_OFFSET. Warn for all other addresses which are in
- * the user space part of the virtual address space.
- */
- if (!kmap_high_unmap_local(addr))
- WARN_ON_ONCE(addr < PAGE_OFFSET);
+ WARN_ON_ONCE(addr < PAGE_OFFSET);
return;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 1/6] ARM: remove support for highmem on VIVT Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET Arnd Bergmann
@ 2026-11-12 11:25 ` Arnd Bergmann
2026-11-12 11:47 ` Mike Rapoport
2026-11-12 11:25 ` [PATCH v2 4/6] mm: drop HIGHPTE support altogether Arnd Bergmann
` (2 subsequent siblings)
5 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
From: Arnd Bergmann <arnd@arndb.de>
CONFIG_HIGHPTE was added in linux-2.6.32, a few years before 64-bit
support. At the time it made sense, as the CONFIG_ARM_LPAE option allowed
systems with 16GB of memory that made lowmem a particularly scarce
resource, and the HIGHPTE implementation gave feature parity with 32-bit
x86 and frv machines.
Since Arm is the last architecture remaining that uses this, and almost
no 32-bit machines support more than 4GB of RAM, the cost of continuing
to maintain HIGHPTE seems unjustified, so remove it here to allow
simplifying the generic page table handling.
Link: https://lore.kernel.org/lkml/20241204103042.1904639-8-arnd@kernel.org/T/#u
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
I sent a patch to drop HIGHPTE support on x86 today, see
https://lore.kernel.org/lkml/20241210144945.2325330-9-arnd@kernel.org/T/#u
If that one gets merged, we can merge this one instead of the one
that makes HIGHPTE depend on !PREEMPT_RT, but if we decide against
the x86 change, then we probably don't want this one either.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/Kconfig | 11 -----------
arch/arm/include/asm/pgalloc.h | 8 +-------
2 files changed, 1 insertion(+), 18 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fd01ccab9c12..fc66d52d847e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1225,17 +1225,6 @@ config HIGHMEM
If unsure, say n.
-config HIGHPTE
- bool "Allocate 2nd-level pagetables from highmem" if EXPERT
- depends on HIGHMEM && !PREEMPT_RT
- default y
- help
- The VM uses one page of physical memory for each page table.
- For systems with a lot of processes, this can use a lot of
- precious low memory, eventually leading to low memory being
- consumed by page tables. Setting this option will allow
- user-space 2nd level page tables to reside in high memory.
-
config ARM_PAN
bool "Enable privileged no-access"
depends on MMU
diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
index a17f01235c29..ef6cb3e6d179 100644
--- a/arch/arm/include/asm/pgalloc.h
+++ b/arch/arm/include/asm/pgalloc.h
@@ -85,18 +85,12 @@ pte_alloc_one_kernel(struct mm_struct *mm)
return pte;
}
-#ifdef CONFIG_HIGHPTE
-#define PGTABLE_HIGHMEM __GFP_HIGHMEM
-#else
-#define PGTABLE_HIGHMEM 0
-#endif
-
static inline pgtable_t
pte_alloc_one(struct mm_struct *mm)
{
struct page *pte;
- pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
+ pte = __pte_alloc_one(mm, GFP_PGTABLE_USER);
if (!pte)
return NULL;
if (!PageHighMem(pte))
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 4/6] mm: drop HIGHPTE support altogether
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
` (2 preceding siblings ...)
2026-11-12 11:25 ` [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support Arnd Bergmann
@ 2026-11-12 11:25 ` Arnd Bergmann
2026-11-12 11:54 ` Mike Rapoport
2026-11-12 11:25 ` [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
5 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
From: Arnd Bergmann <arnd@arndb.de>
With both x86 and arm having dropped CONFIG_HIGHPTE support, no
architecture is left using it, so remove the remnants in common code.
It is likely that further cleanups are possible in the page table
code but those are not obvious from the config options.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
include/linux/hugetlb.h | 5 +----
include/linux/mm.h | 1 -
include/linux/pgtable.h | 9 ---------
3 files changed, 1 insertion(+), 14 deletions(-)
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 58f755e70e96..7c6d191fdf50 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -178,7 +178,6 @@ void hugetlb_bootmem_set_nodes(void);
/* arch callbacks */
-#ifndef CONFIG_HIGHPTE
/*
* pte_offset_huge() and pte_alloc_huge() are helpers for those architectures
* which may go down to the lowest PTE level in their huge_pte_offset() and
@@ -193,7 +192,6 @@ static inline pte_t *pte_alloc_huge(struct mm_struct *mm, pmd_t *pmd,
{
return pte_alloc(mm, pmd) ? NULL : pte_offset_huge(pmd, address);
}
-#endif
pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, unsigned long sz);
@@ -1047,9 +1045,8 @@ static inline spinlock_t *huge_pte_lockptr(struct hstate *h,
*/
if (size >= PUD_SIZE)
return pud_lockptr(mm, (pud_t *) pte);
- else if (size >= PMD_SIZE || IS_ENABLED(CONFIG_HIGHPTE))
+ else if (size >= PMD_SIZE)
return pmd_lockptr(mm, (pmd_t *) pte);
- /* pte_alloc_huge() only applies with !CONFIG_HIGHPTE */
return ptep_lockptr(mm, pte);
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6af3b7008f1a..019de55bd796 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -4025,7 +4025,6 @@ static inline spinlock_t *pte_lockptr(struct mm_struct *mm, pmd_t *pmd)
static inline spinlock_t *ptep_lockptr(struct mm_struct *mm, pte_t *pte)
{
- BUILD_BUG_ON(IS_ENABLED(CONFIG_HIGHPTE));
BUILD_BUG_ON(MAX_PTRS_PER_PTE * sizeof(pte_t) > PAGE_SIZE);
return ptlock_ptr(virt_to_ptdesc(pte));
}
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 780fe849ff8b..1352b4cee7ae 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -100,14 +100,6 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address)
#define pte_offset_kernel pte_offset_kernel
#endif
-#ifdef CONFIG_HIGHPTE
-#define __pte_map(pmd, address) \
- ((pte_t *)kmap_local_page(pmd_page(*(pmd))) + pte_index((address)))
-#define pte_unmap(pte) do { \
- kunmap_local((pte)); \
- rcu_read_unlock(); \
-} while (0)
-#else
static inline pte_t *__pte_map(pmd_t *pmd, unsigned long address)
{
return pte_offset_kernel(pmd, address);
@@ -116,7 +108,6 @@ static inline void pte_unmap(pte_t *pte)
{
rcu_read_unlock();
}
-#endif
void pte_free_defer(struct mm_struct *mm, pgtable_t pgtable);
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
` (3 preceding siblings ...)
2026-11-12 11:25 ` [PATCH v2 4/6] mm: drop HIGHPTE support altogether Arnd Bergmann
@ 2026-11-12 11:25 ` Arnd Bergmann
2026-11-12 12:00 ` Mike Rapoport
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
5 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Michal Simek, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Nishanth Menon,
Lucas Stach
From: Arnd Bergmann <arnd@arndb.de>
Most of the common 32-bit architectures (x86, arm, powerpc) all use the
default virtual memory layout that was already in place for i386 systems
in the 1990s, using exactly 3GiB of user TASK_SIZE, with the upper 1GiB
of addresses split between (at most 896MiB) lowmem and vmalloc.
Linux-2.3 introduced CONFIG_HIGHMEM for large x86 server machines that
had 4GiB of RAM or more, with the VMSPLIT_3G/2G/1G options added in
v2.6.16 for machines that had one or two gigabytes of memory but wanted
to avoid the overhead from managing highmem. Over time, similar options
appeared on other 32-bit architectures.
Twenty years later, it makes sense to reconsider the default settings,
as the tradeoffs have changed a bit:
- Configurations with more than 2GiB have become extremely rare,
as any users with large memory have moved on to 64-bit systems.
There were only ever a few Laptop models in this category: Apple
Powerbook G4 (2005), Macbook (2006), IBM Thinkpad X60 (2006), Arm
Chromebooks based on Exynos 5800 (2014), Tegra K1 (2014) and RK3288
(2015), and manufacturer support for all of these has ended in 2020
or (much) earlier.
Embedded systems with more than 2GiB use additional SoCs of a
similar vintage: Intel Atom Z5xx (2008), Freescale QorIQ (2008),
Marvell Armada XP (2010), Freescale i.MX6Q (2011), LSI Axxia (2013),
TI Keystone2 (2014), Renesas RZ/G1M (2015). Most boards based on
these have stopped receiving kernel upgrades and later 32-bit chips
only support smaller memory configurations, though in particular the
i.MX6Q and Keystone2 families have expected support cycles past 2035.
While 32-bit server installations used to support even larger memory,
none of those seem to still be used in production on any architecture.
- While general-purpose distributes for 32-bit targets were common,
it was rather risky to change the CONFIG_VMSPLIT setting because
there is always a possibility of running into device driver bugs or
applications that need a large virtual memory size. Presumably
a lot of these issues have been resolved now, so most setups should
be fine using a custom vmsplit instead of highmem now.
- As fewer users test highmem, the expectation is that it will
increasingly break in the future, so getting users to change the
vmsplit means that even if there is a bug to fix initially,
it improves the situation in the long run.
- Highmem will ultimately need to be removed, at least for the page
cache and most other code using it today. In a previous discussion, I
had suggested doing this as early as 2029, but based on the discussions
since ELC, the plan is now to leave highmem-enabled page cache as an
option until at least 2029, at which point remaining users will have
the choice between no longer updating kernels or using a combination of
a custom vmsplit and zram/zswap. Changing the defaults now should both
speed up the highmem deprecation and make it less painful for users.
- The most VM space intensive applications tend to be web browsers,
specifcally Chrome/ChromeOS and Firefox. Both have now stopped
providing binary updates.
Testing various combinations on Debian/armhf, I found that Firefox 140
can still show complex websites with VMSPLIT_2G_OPT with and without
HIGHMEM, though it failed for me both with the small address space
of VMSPLIT_1G and the small lowmem of VMSPLIT_3G_OPT when HIGHMEM
is disabled.
This is likely to get worse with future versions, so embedded users
may still be forced to migrate to specialized browsers like WPE Webkit
when HIGHMEM pagecache is finally removed.
Based on the above observations and the discussion at the kernel summit,
change the defaults to the most appropriate values: use 1GiB of lowmem on
non-highmem configurations, and either 2GiB or 1.75GiB of lowmem on highmem
builds, depending on what is available on the architecture. As ARM_LPAE
and X86_PAE builds both require a gigabyte-aligned vmsplit, those get
to use VMSPLIT_2G. The result is that the majority of previous highmem
users now only need lowmem. For platform specific defconfig files that
are known to only support up to 1GiB of RAM, drop the CONFIG_HIGHMEM line
as well as a simplification.
On PowerPC and Microblaze, the options have somewhat different names but
should have the same effect. MIPS and Xtensa cannot support a larger
than 512MB of lowmem but are limited to small DDR2 memory in most
implementations, with MT7621 being a notable exception. ARC and C-Sky
could support a configurable vmsplit in theory, but it's not clear
if anyone still cares.
SPARC is currently limited to 192MB of lowmem and should get patched
to behave either like arm/x86 or powerpc/microblaze to support 2GiB
of lowmem.
There are likely going to be regressions from the changed defaults,
in particular when hitting previously hidden device driver bugs
that fail to set the correct DMA mask, or from applications that
need a large virtual address space.
Ideally the in-kernel problems should all be fixable, but as a fallback,
the previous behavior is still selectable based on CONFIG_EXPERT=y.
Cc: Russell King <linux@armlinux.org.uk>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Cc: Michal Simek <monstr@monstr.eu>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: linux-mm@kvack.org
Cc: Richard Weinberger <richard@nod.at>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Nishanth Menon <nm@ti.com>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/Kconfig | 5 ++++-
arch/arm/configs/aspeed_g5_defconfig | 1 -
arch/arm/configs/u8500_defconfig | 1 -
arch/arm/configs/vt8500_v6_v7_defconfig | 2 --
arch/arm/mach-omap2/Kconfig | 1 -
arch/microblaze/Kconfig | 9 ++++++---
arch/microblaze/configs/mmu_defconfig | 1 -
arch/powerpc/Kconfig | 14 +++++++++-----
arch/powerpc/configs/44x/akebono_defconfig | 1 -
arch/powerpc/configs/85xx/ksi8560_defconfig | 1 -
arch/powerpc/configs/85xx/stx_gp3_defconfig | 1 -
arch/x86/Kconfig | 4 +++-
12 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fc66d52d847e..797705a94b28 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1025,7 +1025,8 @@ config BL_SWITCHER_DUMMY_IF
choice
prompt "Memory split"
depends on MMU
- default VMSPLIT_3G
+ default VMSPLIT_2G if HIGHMEM || ARM_LPAE
+ default VMSPLIT_3G_OPT
help
Select the desired split between kernel and user memory.
@@ -1034,8 +1035,10 @@ choice
config VMSPLIT_3G
bool "3G/1G user/kernel split"
+ depends on !HIGHMEM || EXPERT
config VMSPLIT_3G_OPT
depends on !ARM_LPAE
+ depends on !HIGHMEM || EXPERT
bool "3G/1G user/kernel split (for full 1G low memory)"
config VMSPLIT_2G
bool "2G/2G user/kernel split"
diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
index 1327a09e163a..7f077c667478 100644
--- a/arch/arm/configs/aspeed_g5_defconfig
+++ b/arch/arm/configs/aspeed_g5_defconfig
@@ -27,7 +27,6 @@ CONFIG_SMP=y
# CONFIG_ARM_CPU_TOPOLOGY is not set
CONFIG_VMSPLIT_2G=y
CONFIG_NR_CPUS=2
-CONFIG_HIGHMEM=y
CONFIG_UACCESS_WITH_MEMCPY=y
CONFIG_VFP=y
CONFIG_NEON=y
diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig
index 2fe25f5eb9a5..b284c2c31758 100644
--- a/arch/arm/configs/u8500_defconfig
+++ b/arch/arm/configs/u8500_defconfig
@@ -6,7 +6,6 @@ CONFIG_KALLSYMS_ALL=y
CONFIG_ARCH_U8500=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
-CONFIG_HIGHMEM=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CMDLINE="root=/dev/ram0 console=ttyAMA2,115200n8"
diff --git a/arch/arm/configs/vt8500_v6_v7_defconfig b/arch/arm/configs/vt8500_v6_v7_defconfig
index 2925a1f1dbb6..1f6dca21d569 100644
--- a/arch/arm/configs/vt8500_v6_v7_defconfig
+++ b/arch/arm/configs/vt8500_v6_v7_defconfig
@@ -8,8 +8,6 @@ CONFIG_ARM_ERRATA_720789=y
CONFIG_ARM_ERRATA_754322=y
CONFIG_ARM_ERRATA_775420=y
CONFIG_HAVE_ARM_ARCH_TIMER=y
-CONFIG_HIGHMEM=y
-CONFIG_HIGHPTE=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_VFP=y
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index f0f1d7a8640c..d145e448a6b8 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -135,7 +135,6 @@ config ARCH_OMAP2PLUS_TYPICAL
bool "Typical OMAP configuration"
default y
select AEABI
- select HIGHMEM if !CPU_CACHE_VIVT
select I2C
select I2C_OMAP
select MENELAUS if ARCH_OMAP2
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 9063a91cfb41..8ce8d108bfd7 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -164,7 +164,8 @@ config LOWMEM_SIZE_BOOL
config LOWMEM_SIZE
hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
- default "0x30000000"
+ default "0x80000000" if HIGHMEM
+ default "0x40000000"
config MANUAL_RESET_VECTOR
hex "Microblaze reset vector address setup"
@@ -190,7 +191,8 @@ config KERNEL_START_BOOL
config KERNEL_START
hex "Virtual address of kernel base" if KERNEL_START_BOOL
- default "0xc0000000"
+ default "0x70000000" if HIGHMEM
+ default "0xb0000000"
config TASK_SIZE_BOOL
bool "Set custom user task size"
@@ -204,7 +206,8 @@ config TASK_SIZE_BOOL
config TASK_SIZE
hex "Size of user task space" if TASK_SIZE_BOOL
- default "0x80000000"
+ default "0x70000000" if HIGHMEM
+ default "0xb0000000"
config MB_MANAGER
bool "Support for Microblaze Manager"
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index 7f9b19d0d9db..19a13d3ece5c 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -15,7 +15,6 @@ CONFIG_XILINX_MICROBLAZE0_USE_FPU=2
CONFIG_HZ_100=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE_FORCE=y
-CONFIG_HIGHMEM=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index c3b6cd655606..31e68cd32a10 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -489,6 +489,7 @@ menu "Kernel options"
config HIGHMEM
bool "High memory support"
depends on PPC32
+ depends on PPC_BOOK3S_32 || PPC_85xx || 44x
select KMAP_LOCAL
source "kernel/Kconfig.hz"
@@ -1190,7 +1191,8 @@ config LOWMEM_SIZE_BOOL
config LOWMEM_SIZE
hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
- default "0x30000000"
+ default "0x80000000" if HIGHMEM
+ default "0x40000000"
config LOWMEM_CAM_NUM_BOOL
bool "Set number of CAMs to use to map low memory"
@@ -1242,7 +1244,8 @@ config PAGE_OFFSET_BOOL
config PAGE_OFFSET
hex "Virtual address of memory base" if PAGE_OFFSET_BOOL
- default "0xc0000000"
+ default "0x70000000" if HIGHMEM
+ default "0xb0000000"
config KERNEL_START_BOOL
bool "Set custom kernel base address"
@@ -1258,8 +1261,9 @@ config KERNEL_START_BOOL
config KERNEL_START
hex "Virtual address of kernel base" if KERNEL_START_BOOL
default PAGE_OFFSET if PAGE_OFFSET_BOOL
- default "0xc2000000" if CRASH_DUMP && !NONSTATIC_KERNEL
- default "0xc0000000"
+ default "0x72000000" if HIGHMEM && CRASH_DUMP && !NONSTATIC_KERNEL
+ default "0xb2000000" if CRASH_DUMP && !NONSTATIC_KERNEL
+ default PAGE_OFFSET
config PHYSICAL_START_BOOL
bool "Set physical address where the kernel is loaded"
@@ -1295,7 +1299,7 @@ config TASK_SIZE_BOOL
config TASK_SIZE
hex "Size of maximum user task space" if TASK_SIZE_BOOL
default "0x80000000" if PPC_8xx
- default "0xc0000000"
+ default PAGE_OFFSET
config MODULES_SIZE_BOOL
bool "Set custom size for modules/execmem area"
diff --git a/arch/powerpc/configs/44x/akebono_defconfig b/arch/powerpc/configs/44x/akebono_defconfig
index bdb0e6ece6ec..cc1e3da5f8f5 100644
--- a/arch/powerpc/configs/44x/akebono_defconfig
+++ b/arch/powerpc/configs/44x/akebono_defconfig
@@ -14,7 +14,6 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_PPC_47x=y
# CONFIG_EBONY is not set
CONFIG_AKEBONO=y
-CONFIG_HIGHMEM=y
CONFIG_HZ_100=y
CONFIG_IRQ_ALL_CPUS=y
# CONFIG_COMPACTION is not set
diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig
index 9cb211fb6d1e..f2ac1fc41303 100644
--- a/arch/powerpc/configs/85xx/ksi8560_defconfig
+++ b/arch/powerpc/configs/85xx/ksi8560_defconfig
@@ -9,7 +9,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_KSI8560=y
CONFIG_CPM2=y
CONFIG_GEN_RTC=y
-CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=y
CONFIG_MATH_EMULATION=y
# CONFIG_SECCOMP is not set
diff --git a/arch/powerpc/configs/85xx/stx_gp3_defconfig b/arch/powerpc/configs/85xx/stx_gp3_defconfig
index 0a42072fa23c..1033977711d6 100644
--- a/arch/powerpc/configs/85xx/stx_gp3_defconfig
+++ b/arch/powerpc/configs/85xx/stx_gp3_defconfig
@@ -7,7 +7,6 @@ CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_STX_GP3=y
-CONFIG_HIGHMEM=y
CONFIG_BINFMT_MISC=m
CONFIG_MATH_EMULATION=y
CONFIG_PCI=y
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 58dce0b66179..18b3eeebb7ce 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1410,7 +1410,9 @@ config HIGHMEM4G
choice
prompt "Memory split" if EXPERT
- default VMSPLIT_3G
+ default VMSPLIT_2G_OPT if HIGHMEM && !X86_PAE
+ default VMSPLIT_2G if X86_PAE
+ default VMSPLIT_3G_OPT
depends on X86_32
help
Select the desired split between kernel and user memory.
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
` (4 preceding siblings ...)
2026-11-12 11:25 ` [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use Arnd Bergmann
@ 2026-11-12 11:25 ` Arnd Bergmann
5 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 11:25 UTC (permalink / raw)
To: linux-mm
Cc: Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
From: Arnd Bergmann <arnd@arndb.de>
Unlike x86 and powerpc, there is currently no option to use exactly 2GiB
of lowmem on Arm. Since 2GiB is still a relatively common configuration
on embedded systems, it makes sense to allow this to be used in
non-highmem builds.
Add the Kconfig option and make this the default for non-LPAE builds
with highmem enabled instead of CONFIG_VMSPLIT_2G. LPAE still requires
the vmsplit to be on a gigabyte boundary, so this is only available for
classic pagetables at the moment, same as CONFIG_VMSPLIT_3G_OPT.
Tested in qemu -M virt, both with and without HIGHMEM enabled.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/Kconfig | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 797705a94b28..8992fedfdf37 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1025,7 +1025,8 @@ config BL_SWITCHER_DUMMY_IF
choice
prompt "Memory split"
depends on MMU
- default VMSPLIT_2G if HIGHMEM || ARM_LPAE
+ default VMSPLIT_2G if ARM_LPAE
+ default VMSPLIT_2G_OPT if HIGHMEM
default VMSPLIT_3G_OPT
help
Select the desired split between kernel and user memory.
@@ -1042,6 +1043,9 @@ choice
bool "3G/1G user/kernel split (for full 1G low memory)"
config VMSPLIT_2G
bool "2G/2G user/kernel split"
+ config VMSPLIT_2G_OPT
+ depends on !ARM_LPAE
+ bool "2G/2G user/kernel split (for full 2G low memory)"
config VMSPLIT_1G
bool "1G/3G user/kernel split"
endchoice
@@ -1050,6 +1054,7 @@ config PAGE_OFFSET
hex
default PHYS_OFFSET if !MMU
default 0x40000000 if VMSPLIT_1G
+ default 0x70000000 if VMSPLIT_2G_OPT
default 0x80000000 if VMSPLIT_2G
default 0xB0000000 if VMSPLIT_3G_OPT
default 0xC0000000
@@ -1058,6 +1063,7 @@ config KASAN_SHADOW_OFFSET
hex
depends on KASAN
default 0x1f000000 if PAGE_OFFSET=0x40000000
+ default 0x4f000000 if PAGE_OFFSET=0x70000000
default 0x5f000000 if PAGE_OFFSET=0x80000000
default 0x9f000000 if PAGE_OFFSET=0xC0000000
default 0x8f000000 if PAGE_OFFSET=0xB0000000
--
2.53.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support
2026-11-12 11:25 ` [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support Arnd Bergmann
@ 2026-11-12 11:47 ` Mike Rapoport
2026-11-12 12:22 ` Arnd Bergmann
0 siblings, 1 reply; 15+ messages in thread
From: Mike Rapoport @ 2026-11-12 11:47 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-mm, Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
On Thu, Nov 12, 2026 at 12:25:25PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> CONFIG_HIGHPTE was added in linux-2.6.32, a few years before 64-bit
> support. At the time it made sense, as the CONFIG_ARM_LPAE option allowed
> systems with 16GB of memory that made lowmem a particularly scarce
> resource, and the HIGHPTE implementation gave feature parity with 32-bit
> x86 and frv machines.
>
> Since Arm is the last architecture remaining that uses this, and almost
> no 32-bit machines support more than 4GB of RAM, the cost of continuing
> to maintain HIGHPTE seems unjustified, so remove it here to allow
> simplifying the generic page table handling.
>
> Link: https://lore.kernel.org/lkml/20241204103042.1904639-8-arnd@kernel.org/T/#u
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> I sent a patch to drop HIGHPTE support on x86 today, see
> https://lore.kernel.org/lkml/20241210144945.2325330-9-arnd@kernel.org/T/#u
>
> If that one gets merged, we can merge this one instead of the one
> that makes HIGHPTE depend on !PREEMPT_RT, but if we decide against
> the x86 change, then we probably don't want this one either.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> arch/arm/Kconfig | 11 -----------
> arch/arm/include/asm/pgalloc.h | 8 +-------
> 2 files changed, 1 insertion(+), 18 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index fd01ccab9c12..fc66d52d847e 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1225,17 +1225,6 @@ config HIGHMEM
>
> If unsure, say n.
>
> -config HIGHPTE
> - bool "Allocate 2nd-level pagetables from highmem" if EXPERT
> - depends on HIGHMEM && !PREEMPT_RT
> - default y
> - help
> - The VM uses one page of physical memory for each page table.
> - For systems with a lot of processes, this can use a lot of
> - precious low memory, eventually leading to low memory being
> - consumed by page tables. Setting this option will allow
> - user-space 2nd level page tables to reside in high memory.
> -
> config ARM_PAN
> bool "Enable privileged no-access"
> depends on MMU
> diff --git a/arch/arm/include/asm/pgalloc.h b/arch/arm/include/asm/pgalloc.h
> index a17f01235c29..ef6cb3e6d179 100644
> --- a/arch/arm/include/asm/pgalloc.h
> +++ b/arch/arm/include/asm/pgalloc.h
> @@ -85,18 +85,12 @@ pte_alloc_one_kernel(struct mm_struct *mm)
> return pte;
> }
>
> -#ifdef CONFIG_HIGHPTE
> -#define PGTABLE_HIGHMEM __GFP_HIGHMEM
> -#else
> -#define PGTABLE_HIGHMEM 0
> -#endif
> -
> static inline pgtable_t
> pte_alloc_one(struct mm_struct *mm)
> {
> struct page *pte;
>
> - pte = __pte_alloc_one(mm, GFP_PGTABLE_USER | PGTABLE_HIGHMEM);
> + pte = __pte_alloc_one(mm, GFP_PGTABLE_USER);
> if (!pte)
> return NULL;
> if (!PageHighMem(pte))
With HIGHPTE out this can be
if (pte)
clean_pte_table(pte);
return pte;
Otherwise
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> --
> 2.53.0
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET
2026-11-12 11:25 ` [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET Arnd Bergmann
@ 2026-11-12 11:48 ` Mike Rapoport
0 siblings, 0 replies; 15+ messages in thread
From: Mike Rapoport @ 2026-11-12 11:48 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-mm, Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
On Thu, Nov 12, 2026 at 12:25:24PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Arm has stopped setting ARCH_NEEDS_KMAP_HIGH_GET, so this
> is handled using the same wrappers across all architectures
> now, which leaves room for simplification.
>
> Replace lock_kmap()/unlock_kmap() with open-coded spinlocks
> and drop the now empty arch_kmap_local_high_get() and
> kmap_high_unmap_local() helpers.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> mm/highmem.c | 100 ++++++---------------------------------------------
> 1 file changed, 10 insertions(+), 90 deletions(-)
Nice :)
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/6] mm: drop HIGHPTE support altogether
2026-11-12 11:25 ` [PATCH v2 4/6] mm: drop HIGHPTE support altogether Arnd Bergmann
@ 2026-11-12 11:54 ` Mike Rapoport
2026-11-12 12:33 ` David Hildenbrand (Arm)
2026-11-12 13:26 ` Arnd Bergmann
0 siblings, 2 replies; 15+ messages in thread
From: Mike Rapoport @ 2026-11-12 11:54 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-mm, Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
On Thu, Nov 12, 2026 at 12:25:26PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> With both x86 and arm having dropped CONFIG_HIGHPTE support, no
> architecture is left using it, so remove the remnants in common code.
>
> It is likely that further cleanups are possible in the page table
> code but those are not obvious from the config options.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> include/linux/hugetlb.h | 5 +----
> include/linux/mm.h | 1 -
> include/linux/pgtable.h | 9 ---------
> 3 files changed, 1 insertion(+), 14 deletions(-)
With this and arm HIGHPTE patches applied there are still a few leftovers:
$ git grep HIGHPTE
arch/arm/configs/vt8500_v6_v7_defconfig:CONFIG_HIGHPTE=y
mm/memory.c: * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
mm/pgtable-generic.c: * kmapped if necessary (when CONFIG_HIGHPTE), and locked against concurrent
mm/userfaultfd.c: * index ordering when CONFIG_HIGHPTE is enabled. We mapped dst_pte
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use
2026-11-12 11:25 ` [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use Arnd Bergmann
@ 2026-11-12 12:00 ` Mike Rapoport
0 siblings, 0 replies; 15+ messages in thread
From: Mike Rapoport @ 2026-11-12 12:00 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-mm, Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, David Hildenbrand (Arm),
Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes (ARM),
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Michal Simek, Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka,
Suren Baghdasaryan, Michal Hocko, Nishanth Menon, Lucas Stach
On Thu, Nov 12, 2026 at 12:25:27PM +0100, Arnd Bergmann wrote:
> From: Arnd Bergmann <arnd@arndb.de>
>
> Most of the common 32-bit architectures (x86, arm, powerpc) all use the
> default virtual memory layout that was already in place for i386 systems
> in the 1990s, using exactly 3GiB of user TASK_SIZE, with the upper 1GiB
> of addresses split between (at most 896MiB) lowmem and vmalloc.
...
> Based on the above observations and the discussion at the kernel summit,
> change the defaults to the most appropriate values: use 1GiB of lowmem on
> non-highmem configurations, and either 2GiB or 1.75GiB of lowmem on highmem
> builds, depending on what is available on the architecture.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
> arch/arm/Kconfig | 5 ++++-
> arch/arm/configs/aspeed_g5_defconfig | 1 -
> arch/arm/configs/u8500_defconfig | 1 -
> arch/arm/configs/vt8500_v6_v7_defconfig | 2 --
> arch/arm/mach-omap2/Kconfig | 1 -
> arch/microblaze/Kconfig | 9 ++++++---
> arch/microblaze/configs/mmu_defconfig | 1 -
> arch/powerpc/Kconfig | 14 +++++++++-----
> arch/powerpc/configs/44x/akebono_defconfig | 1 -
> arch/powerpc/configs/85xx/ksi8560_defconfig | 1 -
> arch/powerpc/configs/85xx/stx_gp3_defconfig | 1 -
> arch/x86/Kconfig | 4 +++-
> 12 files changed, 22 insertions(+), 19 deletions(-)
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support
2026-11-12 11:47 ` Mike Rapoport
@ 2026-11-12 12:22 ` Arnd Bergmann
0 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 12:22 UTC (permalink / raw)
To: Mike Rapoport, Arnd Bergmann
Cc: linux-mm, Andrew Morton, Andreas Larsson, Christophe Leroy,
Dave Hansen, David Hildenbrand (Red Hat), Jason Gunthorpe,
Linus Walleij, Lorenzo Stoakes, Matthew Wilcox, Malin Jonsson,
Richard Weinberger, Russell King, linux-arm-kernel, linux-fsdevel,
linuxppc-dev, x86
On Thu, Nov 12, 2026, at 12:47, Mike Rapoport wrote:
> On Thu, Nov 12, 2026 at 12:25:25PM +0100, Arnd Bergmann wrote:
>> if (!pte)
>> return NULL;
>> if (!PageHighMem(pte))
>
> With HIGHPTE out this can be
>
> if (pte)
> clean_pte_table(pte);
>
> return pte;
>
Makes sense, changed now.
Arnd
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/6] mm: drop HIGHPTE support altogether
2026-11-12 11:54 ` Mike Rapoport
@ 2026-11-12 12:33 ` David Hildenbrand (Arm)
2026-11-12 13:26 ` Arnd Bergmann
1 sibling, 0 replies; 15+ messages in thread
From: David Hildenbrand (Arm) @ 2026-11-12 12:33 UTC (permalink / raw)
To: Mike Rapoport, Arnd Bergmann
Cc: linux-mm, Arnd Bergmann, Andrew Morton, Andreas Larsson,
Christophe Leroy (CS GROUP), Dave Hansen, Jason Gunthorpe,
Linus Walleij, Lorenzo Stoakes (ARM), Matthew Wilcox,
Malin Jonsson, Richard Weinberger, Russell King, linux-arm-kernel,
linux-fsdevel, linuxppc-dev, x86
On 11/12/26 12:54, Mike Rapoport wrote:
> On Thu, Nov 12, 2026 at 12:25:26PM +0100, Arnd Bergmann wrote:
>> From: Arnd Bergmann <arnd@arndb.de>
>>
>> With both x86 and arm having dropped CONFIG_HIGHPTE support, no
>> architecture is left using it, so remove the remnants in common code.
>>
>> It is likely that further cleanups are possible in the page table
>> code but those are not obvious from the config options.
>>
>> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>> ---
>> include/linux/hugetlb.h | 5 +----
>> include/linux/mm.h | 1 -
>> include/linux/pgtable.h | 9 ---------
>> 3 files changed, 1 insertion(+), 14 deletions(-)
>
> With this and arm HIGHPTE patches applied there are still a few leftovers:
>
> $ git grep HIGHPTE
> arch/arm/configs/vt8500_v6_v7_defconfig:CONFIG_HIGHPTE=y
> mm/memory.c: * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
> mm/pgtable-generic.c: * kmapped if necessary (when CONFIG_HIGHPTE), and locked against concurrent
> mm/userfaultfd.c: * index ordering when CONFIG_HIGHPTE is enabled. We mapped dst_pte
>
> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
>
With these gone
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/6] mm: drop HIGHPTE support altogether
2026-11-12 11:54 ` Mike Rapoport
2026-11-12 12:33 ` David Hildenbrand (Arm)
@ 2026-11-12 13:26 ` Arnd Bergmann
1 sibling, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 13:26 UTC (permalink / raw)
To: Mike Rapoport, Arnd Bergmann
Cc: linux-mm, Andrew Morton, Andreas Larsson, Christophe Leroy,
Dave Hansen, David Hildenbrand (Red Hat), Jason Gunthorpe,
Linus Walleij, Lorenzo Stoakes, Matthew Wilcox, Malin Jonsson,
Richard Weinberger, Russell King, linux-arm-kernel, linux-fsdevel,
linuxppc-dev, x86
On Thu, Nov 12, 2026, at 12:54, Mike Rapoport wrote:
> On Thu, Nov 12, 2026 at 12:25:26PM +0100, Arnd Bergmann wrote:
>> From: Arnd Bergmann <arnd@arndb.de>
>>
>> With both x86 and arm having dropped CONFIG_HIGHPTE support, no
>> architecture is left using it, so remove the remnants in common code.
>>
>> It is likely that further cleanups are possible in the page table
>> code but those are not obvious from the config options.
>>
>> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>> ---
>> include/linux/hugetlb.h | 5 +----
>> include/linux/mm.h | 1 -
>> include/linux/pgtable.h | 9 ---------
>> 3 files changed, 1 insertion(+), 14 deletions(-)
>
> With this and arm HIGHPTE patches applied there are still a few leftovers:
>
> $ git grep HIGHPTE
> arch/arm/configs/vt8500_v6_v7_defconfig:CONFIG_HIGHPTE=y
This got dropped in patch 5/6 in v2, but I've moved that here now.
> mm/memory.c: * Dumping the PTE would be nice, but it's tricky with
> CONFIG_HIGHPTE,
Added the patch below for this. Untested so far.
> mm/pgtable-generic.c: * kmapped if necessary (when CONFIG_HIGHPTE), and
> locked against concurrent
Updated the comment and also dropped __pte_map() after I noticed that
open-coding the only caller in pte_offset_map_rw_nolock() is consistent
with that comment change:
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -314,7 +314,7 @@ pte_t *__pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp)
pmd_clear_bad(pmd);
goto nomap;
}
- return __pte_map(&pmdval, addr);
+ return pte_offset_kernel(&pmdval, addr);
nomap:
rcu_read_unlock();
return NULL;
> mm/userfaultfd.c: * index ordering when CONFIG_HIGHPTE is
> enabled. We mapped dst_pte
Dropped that comment block as it no longer applies.
> Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Thanks,
Arnd
---
Subject: [PATCH] mm: print pte in __print_bad_page_map_pgtable()
HIGHPTE support is gone now, so it's easy enough to print the
PTE here along with the upper level entries.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
diff --git a/mm/memory.c b/mm/memory.c
index ec3d9d99ccee..dabeb5568c94 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -528,9 +528,11 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
char p4d_str[PTVAL_STR_MAX];
char pud_str[PTVAL_STR_MAX];
char pmd_str[PTVAL_STR_MAX];
+ char pte_str[PTVAL_STR_MAX];
p4d_t p4d, *p4dp;
pud_t pud, *pudp;
pmd_t pmd, *pmdp;
+ pte_t pte, *ptep;
pgd_t *pgdp;
/*
@@ -567,13 +569,18 @@ static void __print_bad_page_map_pgtable(struct mm_struct *mm, unsigned long add
pmd = pmdp_get(pmdp);
ptval_to_str(pmd_str, pmd_val(pmd));
- /*
- * Dumping the PTE would be nice, but it's tricky with CONFIG_HIGHPTE,
- * because the table should already be mapped by the caller and
- * doing another map would be bad. print_bad_page_map() should
- * already take care of printing the PTE.
- */
- pr_alert("pgd:%s p4d:%s pud:%s pmd:%s\n", pgd_str, p4d_str, pud_str, pmd_str);
+ if (!pmd_present(pmd) || pmd_leaf(pmd)) {
+ pr_alert("pgd:%s p4d:%s pud:%s pmd: %s\n",
+ pgd_str, p4d_str, pud_str, pmd_str);
+ return;
+ }
+
+ ptep = pte_offset_kernel(pmdp, addr);
+ pte = ptep_get(ptep);
+ ptval_to_str(pte_str, pte_val(pte));
+
+ pr_alert("pgd:%s p4d:%s pud:%s pmd:%s pte:%s\n",
+ pgd_str, p4d_str, pud_str, pmd_str, pte_str);
}
/*
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 1/6] ARM: remove support for highmem on VIVT
2026-11-12 11:25 ` [PATCH v2 1/6] ARM: remove support for highmem on VIVT Arnd Bergmann
@ 2026-11-12 13:47 ` Arnd Bergmann
0 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2026-11-12 13:47 UTC (permalink / raw)
To: Arnd Bergmann, linux-mm
Cc: Andrew Morton, Andreas Larsson, Christophe Leroy, Dave Hansen,
David Hildenbrand (Red Hat), Jason Gunthorpe, Linus Walleij,
Lorenzo Stoakes, Matthew Wilcox, Malin Jonsson,
Richard Weinberger, Russell King, linux-arm-kernel, linux-fsdevel,
linuxppc-dev, x86
On Thu, Nov 12, 2026, at 12:25, Arnd Bergmann wrote:
> --- a/arch/arm/mach-omap2/Kconfig
> +++ b/arch/arm/mach-omap2/Kconfig
> @@ -135,7 +135,7 @@ config ARCH_OMAP2PLUS_TYPICAL
> bool "Typical OMAP configuration"
> default y
> select AEABI
> - select HIGHMEM
> + select HIGHMEM if !CPU_CACHE_VIVT
> select I2C
> select I2C_OMAP
> select MENELAUS if ARCH_OMAP2
I'm not sure where this comes from, it was probably a mistake during
rebasing. None of the V6/V7 CPUs can be built with CPU_CACHE_VIVT, so
I've dropped this part.
Arnd
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-11-12 13:48 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 11:25 [PATCH v2 0/6] mm: highmem cleanups Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 1/6] ARM: remove support for highmem on VIVT Arnd Bergmann
2026-11-12 13:47 ` Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET Arnd Bergmann
2026-11-12 11:48 ` Mike Rapoport
2026-11-12 11:25 ` [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support Arnd Bergmann
2026-11-12 11:47 ` Mike Rapoport
2026-11-12 12:22 ` Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 4/6] mm: drop HIGHPTE support altogether Arnd Bergmann
2026-11-12 11:54 ` Mike Rapoport
2026-11-12 12:33 ` David Hildenbrand (Arm)
2026-11-12 13:26 ` Arnd Bergmann
2026-11-12 11:25 ` [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use Arnd Bergmann
2026-11-12 12:00 ` Mike Rapoport
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox