* [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; 29+ 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] 29+ 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
` (2 more replies)
2026-11-12 11:25 ` [PATCH v2 2/6] mm: remove ARCH_NEEDS_KMAP_HIGH_GET Arnd Bergmann
` (4 subsequent siblings)
5 siblings, 3 replies; 29+ 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] 29+ 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-13 18:39 ` Lorenzo Stoakes (ARM)
2026-11-12 11:25 ` [PATCH v2 3/6] ARM: drop CONFIG_HIGHPTE support Arnd Bergmann
` (3 subsequent siblings)
5 siblings, 2 replies; 29+ 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] 29+ 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-13 18:41 ` Lorenzo Stoakes (ARM)
2026-11-12 11:25 ` [PATCH v2 4/6] mm: drop HIGHPTE support altogether Arnd Bergmann
` (2 subsequent siblings)
5 siblings, 2 replies; 29+ 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] 29+ 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-13 18:53 ` Lorenzo Stoakes (ARM)
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, 2 replies; 29+ 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] 29+ 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
` (3 more replies)
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
5 siblings, 4 replies; 29+ 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] 29+ 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
2026-11-13 11:26 ` sashiko-bot
2026-11-13 19:20 ` Lorenzo Stoakes (ARM)
5 siblings, 2 replies; 29+ 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] 29+ 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
2026-11-13 18:41 ` Lorenzo Stoakes (ARM)
1 sibling, 1 reply; 29+ 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] 29+ 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
2026-11-13 18:39 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 29+ 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] 29+ 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
2026-11-13 18:53 ` Lorenzo Stoakes (ARM)
1 sibling, 2 replies; 29+ 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] 29+ 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
2026-11-13 11:26 ` sashiko-bot
` (2 subsequent siblings)
3 siblings, 0 replies; 29+ 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] 29+ 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; 29+ 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] 29+ 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; 29+ 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] 29+ 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
2026-11-13 10:50 ` David Hildenbrand (Arm)
1 sibling, 1 reply; 29+ 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] 29+ 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
2026-11-13 11:26 ` sashiko-bot
2026-11-13 18:28 ` Lorenzo Stoakes (ARM)
2 siblings, 0 replies; 29+ 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] 29+ messages in thread
* Re: [PATCH v2 4/6] mm: drop HIGHPTE support altogether
2026-11-12 13:26 ` Arnd Bergmann
@ 2026-11-13 10:50 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 29+ messages in thread
From: David Hildenbrand (Arm) @ 2026-11-13 10:50 UTC (permalink / raw)
To: Arnd Bergmann, Mike Rapoport, Arnd Bergmann
Cc: linux-mm, Andrew Morton, Andreas Larsson, Christophe Leroy,
Dave Hansen, Jason Gunthorpe, Linus Walleij, Lorenzo Stoakes,
Matthew Wilcox, Malin Jonsson, Richard Weinberger, Russell King,
linux-arm-kernel, linux-fsdevel, linuxppc-dev, x86
On 11/12/26 14:26, Arnd Bergmann wrote:
> 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);
> }
>
> /*
Yeah, that LGTM. I assume you'll send out a v3.
--
Cheers,
David
^ permalink raw reply [flat|nested] 29+ 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
@ 2026-11-13 11:26 ` sashiko-bot
2026-11-13 11:36 ` Arnd Bergmann
2026-11-13 18:28 ` Lorenzo Stoakes (ARM)
2 siblings, 1 reply; 29+ messages in thread
From: sashiko-bot @ 2026-11-13 11:26 UTC (permalink / raw)
To: Arnd Bergmann, 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,
x86
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] ARM: configs: mv78xx0_defconfig retains unreachable
CONFIG_HIGHMEM=y
--
commit a6e3d614ee0118d4a0f2639acca9b5620bed4dd2
Author: Arnd Bergmann <arnd@arndb.de>
ARM: remove support for highmem on VIVT
This commit makes CONFIG_HIGHMEM depend on !CPU_CACHE_VIVT, drops the
now-unreachable CONFIG_HIGHMEM=y entries from VIVT defconfigs, and
removes VIVT highmem handling from ARM cache and DMA code.
Link: https://lore.kernel.org/all/20251219171412.GG254720@nvidia.com/
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index ffbc7f3861315..77614080f317c 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1210,6 +1210,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 5860b2fe7d1fb..95debf46581be 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 a0d2fb2fcf9a8..bc34b6026e377 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 dbc6c511e70bc..5adf6c75304eb 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
[Severity: Low]
Should arch/arm/configs/mv78xx0_defconfig also drop CONFIG_HIGHMEM=y?
ARCH_MV78XX0 selects CPU_FEROCEON, which selects CPU_CACHE_VIVT, leaving
CONFIG_HIGHMEM=y unreachable there as well.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261112112528.1116405-1-arnd@kernel.org?part=1
^ permalink raw reply [flat|nested] 29+ 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
@ 2026-11-13 11:26 ` sashiko-bot
2026-11-13 17:54 ` Arnd Bergmann
2026-11-13 18:35 ` H. Peter Anvin
2026-11-13 18:58 ` Lorenzo Stoakes (ARM)
3 siblings, 1 reply; 29+ messages in thread
From: sashiko-bot @ 2026-11-13 11:26 UTC (permalink / raw)
To: Arnd Bergmann, 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,
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
Thank you for your contribution! Sashiko AI review found 9 potential
issues to consider:
- [High] powerpc: 85xx LOWMEM_CAM_NUM and PAGE_OFFSET cap lowmem at 768
MiB
- [High] ARM: omap2: dropping HIGHMEM select limits multi_v7 and
omap2plus to 1 GiB
- [High] KVM: PPC: e500: get_host_mas0() hits kernel TLB with
PAGE_OFFSET 0x70000000
- [High] powerpc/47x: 2 GiB LOWMEM_SIZE triggers BUG_ON in
ppc47x_pin_tlb()
- [High] KVM: PPC: BookE: hardcoded 0xc0000000 host IVPR breaks new
KERNEL_START
- [High] KVM: PPC: Book3S: LOAD_HOST_SEGMENTS leaves kernel SRs 7..11
unrestored
- [Medium] powerpc/kasan: 32-bit HIGHMEM lowmem overlaps KASAN shadow
and fixmap
- [Medium] ARM: config: aspeed_g5: dropping HIGHMEM truncates 2 GiB
AST2600 RAM
- [Medium] ARM: pxa: hardcoded 0xc0000000 dereference in
pxa3xx_cpu_pm_suspend()
--
commit bedc943a8dd41812a1db37560a98b5754effd200
Author: Arnd Bergmann <arnd@arndb.de>
arch/*: increase lowmem size to avoid highmem use
This commit changes the default 32-bit virtual memory split on ARM, x86,
PowerPC, and MicroBlaze to provide 1 GiB of lowmem without HIGHMEM and up
to 1.75 GiB or 2 GiB of lowmem with HIGHMEM, and drops CONFIG_HIGHMEM from
several platform configs and defconfigs.
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 93350d2e51b99..fee6b7435b7ca 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1027,7 +1027,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
[Severity: Medium]
Does switching the non-HIGHMEM default to VMSPLIT_3G_OPT (PAGE_OFFSET =
0xb0000000) break suspend-to-RAM on PXA3xx?
In pxa_pm_enter() -> pxa3xx_cpu_pm_enter() -> pxa3xx_cpu_pm_suspend(), the
code saves the first word of SDRAM and writes the physical resume address
for the boot ROM using a hardcoded 0xc0000000 virtual address instead of
PAGE_OFFSET:
arch/arm/mach-pxa/pxa3xx.c:pxa3xx_cpu_pm_suspend() {
volatile unsigned long *p = (volatile void *)0xc0000000;
unsigned long saved_data = *p;
...
*p = __pa_symbol(cpu_resume);
}
On PXA3xx boards with 64 MiB or 128 MiB of RAM (such as pxa3xx_defconfig),
0xc0000000 is now in the vmalloc area rather than the start of SDRAM, so
entering PM_SUSPEND_MEM faults or corrupts vmalloc memory.
[ ... ]
> diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
> index 45b937419dbda..5c5d831df36ab 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
[Severity: Medium]
Does dropping CONFIG_HIGHMEM=y from aspeed_g5_defconfig truncate RAM on
2 GiB AST2600 boards?
Despite its name, aspeed_g5_defconfig also enables CONFIG_MACH_ASPEED_G6=y
and explicitly selects CONFIG_VMSPLIT_2G=y. Commit 4cdabee7d6d2 ("ARM:
configs: aspeed_g5: Enable AST2600") enabled CONFIG_HIGHMEM=y here because
AST2600 boards (such as aspeed-ast2600-evb.dts) have 2 GiB of RAM, while
CONFIG_VMSPLIT_2G=y without HIGHMEM only maps at most 1.75 GiB of lowmem
after reserving space for vmalloc, ioremap, and fixmap.
[ ... ]
> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> index f0f1d7a8640ca..d145e448a6b80 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
[Severity: High]
Does removing this select silently disable CONFIG_HIGHMEM in both
multi_v7_defconfig and omap2plus_defconfig?
Neither defconfig contains an explicit CONFIG_HIGHMEM=y line because both
enable ARCH_OMAP2PLUS_TYPICAL, which previously selected HIGHMEM. With
this line removed, both defconfigs build with CONFIG_HIGHMEM=n and fall
back to CONFIG_VMSPLIT_3G_OPT=y, limiting all 1.5 GiB to 4 GiB ARMv7
boards booted with multi_v7_defconfig or omap2plus_defconfig to 1 GiB of
RAM.
[ ... ]
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 2580e27e43287..dfc4f518c6fb4 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
[ ... ]
> @@ -1193,7 +1194,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"
[Severity: High]
On PPC_85xx, doesn't CONFIG_LOWMEM_CAM_NUM still cap lowmem at 768 MiB?
Right below LOWMEM_SIZE, LOWMEM_CAM_NUM still defaults to 3 (or 9/12/15
with STRICT_KERNEL_RWX, where the first 256 MiB uses 7/10/13 smaller CAMs).
Furthermore, because the new PAGE_OFFSET defaults (0xb0000000 and
0x70000000) are only 256 MiB-aligned, calc_cam_sz() bounds each CAM to
1UL << __ffs(virt | phys), which is at most 256 MiB at every 256 MiB
boundary. As a result, MMU_init() -> adjust_total_lowmem() ->
map_mem_in_cams() still caps __max_low_memory at 3 * 256 MiB = 768 MiB:
non-HIGHMEM 85xx builds (including ksi8560_defconfig and stx_gp3_defconfig)
discard RAM above 768 MiB via memblock_enforce_memory_limit(), while
HIGHMEM 85xx builds shrink TASK_SIZE to 1.75 GiB without gaining any
lowmem.
[Severity: High]
Can a 2 GiB LOWMEM_SIZE trigger a boot BUG_ON in ppc47x_pin_tlb() on
PPC_47x systems with more than 1.5 GiB of RAM?
Unlike 85xx, 44x/47x does not call adjust_total_lowmem(), so mmu_mapin_ram()
pins 256 MiB TLB entries in a loop up to lowmem_end_addr (now up to 2 GiB
when HIGHMEM=y, such as in currituck_defconfig). However, PPC47x hardware
only has 6 bolted TLB slots in ppc47x_find_free_bolted() (5 if
CONFIG_PPC_EARLY_DEBUG_44x=y uses slot 5), covering at most 1.5 GiB (or
1.25 GiB) before ppc47x_pin_tlb() hits BUG_ON(bolted < 0). In addition,
dropping CONFIG_HIGHMEM=y from arch/powerpc/configs/44x/akebono_defconfig
limits the IBM Akebono PPC476GTR board, which supports multi-gigabyte DDR3
configurations via SWIOTLB, to 1 GiB of RAM.
> @@ -1245,7 +1247,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"
[Severity: Medium]
When both CONFIG_HIGHMEM=y and CONFIG_KASAN=y are enabled on 32-bit
PowerPC, does lowmem overlap the KASAN shadow and fixmap regions?
With PAGE_OFFSET at 0x70000000 and LOWMEM_SIZE at 0x80000000, lowmem can
extend up to 0xf0000000. However, KASAN_SHADOW_OFFSET is fixed at
0xe0000000 in arch/powerpc/Kconfig.debug, which places KASAN_SHADOW_START
at 0xec000000 (with CONFIG_EXECMEM=y) or 0xee000000 (with CONFIG_EXECMEM=n)
and places FIXADDR_TOP, PKMAP_BASE, and VMALLOC_END below
KASAN_SHADOW_START, colliding with lowmem on systems with ~1.9 GiB or more
of RAM and triggering a boot BUG_ON in map_kernel_page().
[Severity: High]
With PAGE_OFFSET=0x70000000, can get_host_mas0() in the e500 KVM host MMU
match and overwrite a host kernel TLB entry instead of forcing a miss?
arch/powerpc/kvm/e500_mmu_host.c:get_host_mas0() {
local_irq_save(flags);
mtspr(SPRN_MAS6, 0);
mas4 = mfspr(SPRN_MAS4);
mtspr(SPRN_MAS4, mas4 & ~MAS4_TLBSEL_MASK);
asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
mas0 = mfspr(SPRN_MAS0);
}
get_host_mas0() masks eaddr with ~CONFIG_PAGE_OFFSET to produce a userspace
address (< PAGE_OFFSET) that is guaranteed to miss in PID 0. When
CONFIG_PAGE_OFFSET is 0x70000000, ~CONFIG_PAGE_OFFSET is 0x8fffffff, so any
guest eaddr >= 0x80000000 masks to 0x80000000..0x8fffffff, which lies
inside the host kernel linear mapping (>= 0x70000000) and can hit and
overwrite an active host kernel TLB entry in write_host_tlbe().
> config KERNEL_START_BOOL
> bool "Set custom kernel base address"
> @@ -1261,8 +1264,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
[Severity: High]
Does changing the default KERNEL_START away from 0xc0000000 break KVM guest
exit on 32-bit Book-E hosts?
On 85xx and 44x, interrupt_base is linked at KERNEL_START (now 0xb0000000
or 0x70000000 by default), but kvmppc_resume_host in
arch/powerpc/kvm/booke_interrupts.S restores the host SPRN_IVPR to a
hardcoded 0xc0000000:
/* Restore host IVPR before re-enabling interrupts. We cheat and know
* that Linux IVPR is always 0xc0000000. */
lis r3, 0xc000
mtspr SPRN_IVPR, r3
The first host interrupt or exception after guest exit will jump to
0xc0000000 + IVOR offset instead of interrupt_base and crash the host.
> @@ -1298,7 +1302,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
[Severity: High]
On 32-bit Book3S KVM hosts, does lowering TASK_SIZE and PAGE_OFFSET leave
host kernel segment registers 7..11 (or 11) unrestored on guest exit?
LOAD_GUEST_SEGMENTS in arch/powerpc/kvm/book3s_32_sr.S overwrites all 16
segment registers with guest values, but LOAD_HOST_SEGMENTS only restores
the 4 segment registers 0xc..0xf (0xc0000000..0xffffffff):
arch/powerpc/kvm/book3s_32_sr.S:LOAD_HOST_SEGMENTS {
li r0, 4
mtctr r0
LOAD_REG_IMMEDIATE(r3, 0x20000000 | (0x111 * 0xc))
lis r4, 0xc000
3: mtsrin r3, r4
addi r3, r3, 0x111 /* increment VSID */
addis r4, r4, 0x1000 /* address of next segment */
bdnz 3b
}
Because switch_mmu_context() -> update_user_segments() only reloads
0 .. NUM_USER_SEGMENTS - 1 (segments 0..10 when TASK_SIZE is 0xb0000000, or
0..6 when TASK_SIZE is 0x70000000), the host kernel segments covering
0xb0000000..0xbfffffff (or 0x70000000..0xbfffffff, plus any module/execmem
segment below PAGE_OFFSET) retain guest segment register values after
exiting the guest.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261112112528.1116405-1-arnd@kernel.org?part=5
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
@ 2026-11-13 11:26 ` sashiko-bot
2026-11-13 14:18 ` Arnd Bergmann
2026-11-13 19:20 ` Lorenzo Stoakes (ARM)
1 sibling, 1 reply; 29+ messages in thread
From: sashiko-bot @ 2026-11-13 11:26 UTC (permalink / raw)
To: Arnd Bergmann, 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,
x86
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] ARM: Kconfig: missing PAGE_OFFSET=0x70000000 in
ARCH_MMAP_RND_BITS_MAX
--
commit 174ed2566532b79fdcb5633054674e730fcadf44
Author: Arnd Bergmann <arnd@arndb.de>
ARM: add CONFIG_VMSPLIT_2G_OPT option
This commit adds CONFIG_VMSPLIT_2G_OPT with PAGE_OFFSET=0x70000000 to
provide a full 2 GiB lowmem region on non-LPAE builds, and makes it the
default when CONFIG_HIGHMEM is enabled.
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index fee6b7435b7ca..17b4da137a8ea 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
[ ... ]
> @@ -1052,6 +1056,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
[Severity: Low]
Should ARCH_MMAP_RND_BITS_MAX also handle PAGE_OFFSET=0x70000000?
arch/arm/Kconfig:
config ARCH_MMAP_RND_BITS_MAX
default 14 if PAGE_OFFSET=0x40000000
default 15 if PAGE_OFFSET=0x80000000
default 16
With VMSPLIT_2G_OPT, PAGE_OFFSET=0x70000000 falls through to 16 bits
(up to 256 MiB of mmap randomization), which is twice the maximum
allowed for the larger user address space under PAGE_OFFSET=0x80000000.
When KASAN is enabled (shrinking TASK_SIZE to 0x5ce00000) and the stack
gap reaches MAX_GAP, a 16-bit random offset can exceed STACK_TOP -
MAX_GAP in mmap_base() and cause top-down mmap allocations to fall back
to bottom-up.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261112112528.1116405-1-arnd@kernel.org?part=6
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 1/6] ARM: remove support for highmem on VIVT
2026-11-13 11:26 ` sashiko-bot
@ 2026-11-13 11:36 ` Arnd Bergmann
0 siblings, 0 replies; 29+ messages in thread
From: Arnd Bergmann @ 2026-11-13 11:36 UTC (permalink / raw)
To: sashiko-reviews, 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, x86
On Fri, Nov 13, 2026, at 12:26, sashiko-bot@kernel.org wrote:
> [Severity: Low]
> Should arch/arm/configs/mv78xx0_defconfig also drop CONFIG_HIGHMEM=y?
> ARCH_MV78XX0 selects CPU_FEROCEON, which selects CPU_CACHE_VIVT, leaving
> CONFIG_HIGHMEM=y unreachable there as well.
I have already sent an unrelated patch to remove that file, so
changing it here would only cause a merge conflict.
Arnd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option
2026-11-13 11:26 ` sashiko-bot
@ 2026-11-13 14:18 ` Arnd Bergmann
0 siblings, 0 replies; 29+ messages in thread
From: Arnd Bergmann @ 2026-11-13 14:18 UTC (permalink / raw)
To: sashiko-reviews, 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, x86
On Fri, Nov 13, 2026, at 12:26, sashiko-bot@kernel.org wrote:
>> @@ -1052,6 +1056,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
>
> [Severity: Low]
> Should ARCH_MMAP_RND_BITS_MAX also handle PAGE_OFFSET=0x70000000?
>
> arch/arm/Kconfig:
> config ARCH_MMAP_RND_BITS_MAX
> default 14 if PAGE_OFFSET=0x40000000
> default 15 if PAGE_OFFSET=0x80000000
> default 16
>
> With VMSPLIT_2G_OPT, PAGE_OFFSET=0x70000000 falls through to 16 bits
> (up to 256 MiB of mmap randomization), which is twice the maximum
> allowed for the larger user address space under PAGE_OFFSET=0x80000000.
> When KASAN is enabled (shrinking TASK_SIZE to 0x5ce00000) and the stack
> gap reaches MAX_GAP, a 16-bit random offset can exceed STACK_TOP -
> MAX_GAP in mmap_base() and cause top-down mmap allocations to fall back
> to bottom-up.
I've changed it now to use '<=' instead of '=' and hopefully handle
do something sensible for any PAGE_OFFSET value. I'm not sure I understand
if these are intended as heuristics or if there is a hard limit we
can use instead. Should this be 'default 14 if PAGE_OFFSET < 0x80000000'?
Arnd
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -329,8 +329,8 @@ config ARCH_MMAP_RND_BITS_MIN
default 8
config ARCH_MMAP_RND_BITS_MAX
- default 14 if PAGE_OFFSET=0x40000000
- default 15 if PAGE_OFFSET=0x80000000
+ default 14 if PAGE_OFFSET<=0x40000000
+ default 15 if PAGE_OFFSET<=0x80000000
default 16
config ARCH_MULTIPLATFORM
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 5/6] arch/*: increase lowmem size to avoid highmem use
2026-11-13 11:26 ` sashiko-bot
@ 2026-11-13 17:54 ` Arnd Bergmann
0 siblings, 0 replies; 29+ messages in thread
From: Arnd Bergmann @ 2026-11-13 17:54 UTC (permalink / raw)
To: sashiko-reviews, 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, 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
On Fri, Nov 13, 2026, at 12:26, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 9 potential
> issues to consider:
> - [High] powerpc: 85xx LOWMEM_CAM_NUM and PAGE_OFFSET cap lowmem at 768
> MiB
> - [High] ARM: omap2: dropping HIGHMEM select limits multi_v7 and
> omap2plus to 1 GiB
> - [High] KVM: PPC: e500: get_host_mas0() hits kernel TLB with
> PAGE_OFFSET 0x70000000
> - [High] powerpc/47x: 2 GiB LOWMEM_SIZE triggers BUG_ON in
> ppc47x_pin_tlb()
> - [High] KVM: PPC: BookE: hardcoded 0xc0000000 host IVPR breaks new
> KERNEL_START
> - [High] KVM: PPC: Book3S: LOAD_HOST_SEGMENTS leaves kernel SRs 7..11
> unrestored
> - [Medium] powerpc/kasan: 32-bit HIGHMEM lowmem overlaps KASAN shadow
> and fixmap
> - [Medium] ARM: config: aspeed_g5: dropping HIGHMEM truncates 2 GiB
> AST2600 RAM
> - [Medium] ARM: pxa: hardcoded 0xc0000000 dereference in
> pxa3xx_cpu_pm_suspend()
> --
>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 93350d2e51b99..fee6b7435b7ca 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -1027,7 +1027,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
>
> [Severity: Medium]
> Does switching the non-HIGHMEM default to VMSPLIT_3G_OPT (PAGE_OFFSET =
> 0xb0000000) break suspend-to-RAM on PXA3xx?
>
> In pxa_pm_enter() -> pxa3xx_cpu_pm_enter() -> pxa3xx_cpu_pm_suspend(), the
> code saves the first word of SDRAM and writes the physical resume address
> for the boot ROM using a hardcoded 0xc0000000 virtual address instead of
> PAGE_OFFSET:
>
> arch/arm/mach-pxa/pxa3xx.c:pxa3xx_cpu_pm_suspend() {
> volatile unsigned long *p = (volatile void *)0xc0000000;
> unsigned long saved_data = *p;
> ...
> *p = __pa_symbol(cpu_resume);
> }
>
> On PXA3xx boards with 64 MiB or 128 MiB of RAM (such as pxa3xx_defconfig),
> 0xc0000000 is now in the vmalloc area rather than the start of SDRAM, so
> entering PM_SUSPEND_MEM faults or corrupts vmalloc memory.
Right, I added a fix for this bug now:
commit c795c18cfdda3220280ccdbbb0aeb17b9e3ae9df
Author: Arnd Bergmann <arnd@arndb.de>
Date: Fri Nov 13 15:22:55 2026 +0100
ARM: pxa: support arbitrary PAGE_OFFSET
The pxa3xx_cpu_pm_suspend() implementation hardcodes the default
PAGE_OFFSET value for CONFIG_VMSPLIT_3G. This has always been broken
for other configurations but becomes much worse now that the default
is changing.
Fix this to use the correct compile-time constant instead.
Reported-by: sashiko-bot@kernel.org
Fixes: c4d1fb627ff3 ("[ARM] pxa: add preliminary suspend/resume code for pxa3xx")
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/sashiko-outbox-212719@kernel.org/
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 06c578ea658e..253770075a8b 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -103,7 +103,7 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode)
*/
static void pxa3xx_cpu_pm_suspend(void)
{
- volatile unsigned long *p = (volatile void *)0xc0000000;
+ volatile unsigned long *p = (volatile void *)PAGE_OFFSET;
unsigned long saved_data = *p;
#ifndef CONFIG_IWMMXT
u64 acc0;
>> diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
>> index 45b937419dbda..5c5d831df36ab 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
>
> [Severity: Medium]
> Does dropping CONFIG_HIGHMEM=y from aspeed_g5_defconfig truncate RAM on
> 2 GiB AST2600 boards?
>
> Despite its name, aspeed_g5_defconfig also enables CONFIG_MACH_ASPEED_G6=y
> and explicitly selects CONFIG_VMSPLIT_2G=y. Commit 4cdabee7d6d2 ("ARM:
> configs: aspeed_g5: Enable AST2600") enabled CONFIG_HIGHMEM=y here because
> AST2600 boards (such as aspeed-ast2600-evb.dts) have 2 GiB of RAM, while
> CONFIG_VMSPLIT_2G=y without HIGHMEM only maps at most 1.75 GiB of lowmem
> after reserving space for vmalloc, ioremap, and fixmap.
Right, I've removed that change here now, and change it to
CONFIG_VMSPLIT_2G_OPT in the patch that introduces it.
>> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
>> index f0f1d7a8640ca..d145e448a6b80 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
>
> [Severity: High]
> Does removing this select silently disable CONFIG_HIGHMEM in both
> multi_v7_defconfig and omap2plus_defconfig?
>
> Neither defconfig contains an explicit CONFIG_HIGHMEM=y line because both
> enable ARCH_OMAP2PLUS_TYPICAL, which previously selected HIGHMEM. With
> this line removed, both defconfigs build with CONFIG_HIGHMEM=n and fall
> back to CONFIG_VMSPLIT_3G_OPT=y, limiting all 1.5 GiB to 4 GiB ARMv7
> boards booted with multi_v7_defconfig or omap2plus_defconfig to 1 GiB of
> RAM.
Indeed, I had missed how ARCH_OMAP2PLUS_TYPICAL sets the default for
multi_v7_defconfig as well, and definitely did not mean to sneak that
in quietly, though it is at least tempting to have it explicitly turned
off anyway, if only to see who would notice.
I've removed this change here, and would replace it with a separate
patch later. As far as I can tell, we support multiple OMAP5 boards
with 2GB on mainline dts. Larger configurations are possible as well,
but would be extremely rare and require LPAE, which is also not
enabled in the defconfig.
Something like this version, though I suspect any change I propose
here will be controversial because it pessimises some other
hardware.
diff --git a/arch/arm/configs/lpae.config b/arch/arm/configs/lpae.config
index 1ab94da8345d..535696d6de96 100644
--- a/arch/arm/configs/lpae.config
+++ b/arch/arm/configs/lpae.config
@@ -1,3 +1,4 @@
# Help: Enable Large Physical Address Extension mode
CONFIG_ARM_LPAE=y
CONFIG_VMSPLIT_2G=y
+CONFIG_HIGHMEM=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 069d5a49f01c..c3e427ce8d88 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -103,6 +103,7 @@ CONFIG_ARCH_VEXPRESS_TC2_PM=y
CONFIG_ARCH_WM8850=y
CONFIG_ARCH_ZYNQ=y
CONFIG_SMP=y
+CONFIG_VMSPLIT_2G_OPT=y
CONFIG_NR_CPUS=16
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 5791953b75ff..b00789279f25 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -36,6 +36,7 @@ CONFIG_POWER_AVS_OMAP_CLASS3=y
CONFIG_ARM_THUMBEE=y
CONFIG_ARM_ERRATA_411920=y
CONFIG_SMP=y
+CONFIG_VMSPLIT_2G_OPT=y
CONFIG_NR_CPUS=2
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 79f8afe3a6bf..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
select I2C
select I2C_OMAP
select MENELAUS if ARCH_OMAP2
>> @@ -1193,7 +1194,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"
>
> [Severity: High]
> On PPC_85xx, doesn't CONFIG_LOWMEM_CAM_NUM still cap lowmem at 768 MiB?
>
> Right below LOWMEM_SIZE, LOWMEM_CAM_NUM still defaults to 3 (or 9/12/15
> with STRICT_KERNEL_RWX, where the first 256 MiB uses 7/10/13 smaller CAMs).
> Furthermore, because the new PAGE_OFFSET defaults (0xb0000000 and
> 0x70000000) are only 256 MiB-aligned, calc_cam_sz() bounds each CAM to
> 1UL << __ffs(virt | phys), which is at most 256 MiB at every 256 MiB
> boundary. As a result, MMU_init() -> adjust_total_lowmem() ->
> map_mem_in_cams() still caps __max_low_memory at 3 * 256 MiB = 768 MiB:
> non-HIGHMEM 85xx builds (including ksi8560_defconfig and stx_gp3_defconfig)
> discard RAM above 768 MiB via memblock_enforce_memory_limit(), while
> HIGHMEM 85xx builds shrink TASK_SIZE to 1.75 GiB without gaining any
> lowmem.
Based on the explanation in commit 49e3d8ea6248 ("powerpc/fsl_booke:
Enable STRICT_KERNEL_RWX"), I've now increased LOWMEM_CAM_NUM to
config LOWMEM_CAM_NUM
depends on PPC_85xx
int "Number of CAMs to use to map low memory" if LOWMEM_CAM_NUM_BOOL
default 8 if !STRICT_KERNEL_RWX
default 14 if DATA_SHIFT >= 24
default 17 if DATA_SHIFT >= 22
default 20
I think Richard Weinberger mentioned that his 2GiB machine was still
limited to 1.75GiB, but I'm not sure why.
> [Severity: High]
> Can a 2 GiB LOWMEM_SIZE trigger a boot BUG_ON in ppc47x_pin_tlb() on
> PPC_47x systems with more than 1.5 GiB of RAM?
>
> Unlike 85xx, 44x/47x does not call adjust_total_lowmem(), so mmu_mapin_ram()
> pins 256 MiB TLB entries in a loop up to lowmem_end_addr (now up to 2 GiB
> when HIGHMEM=y, such as in currituck_defconfig). However, PPC47x hardware
> only has 6 bolted TLB slots in ppc47x_find_free_bolted() (5 if
> CONFIG_PPC_EARLY_DEBUG_44x=y uses slot 5), covering at most 1.5 GiB (or
> 1.25 GiB) before ppc47x_pin_tlb() hits BUG_ON(bolted < 0). In addition,
> dropping CONFIG_HIGHMEM=y from arch/powerpc/configs/44x/akebono_defconfig
> limits the IBM Akebono PPC476GTR board, which supports multi-gigabyte DDR3
> configurations via SWIOTLB, to 1 GiB of RAM.
Right, I don't see a good solution here. It sounds like we can
easily support 1GiB of lowmem on all 44x machines, but supporting more
than those would require non-bolted TLBs for the linear map, which I
imagine will cause more problems.
I've added a special case for 44x now, at least most of these would
be old enough to not require more than 1GiB, and the ones that do
are less likely to run updated mainline kernels than the better supported
freescale parts.
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1191,6 +1191,6 @@ config LOWMEM_SIZE_BOOL
config LOWMEM_SIZE
hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
- default "0x80000000" if HIGHMEM
+ default "0x80000000" if HIGHMEM && !44x
default "0x40000000"
@@ -1244,7 +1245,7 @@ config PAGE_OFFSET_BOOL
config PAGE_OFFSET
hex "Virtual address of memory base" if PAGE_OFFSET_BOOL
- default "0x70000000" if HIGHMEM
+ default "0x70000000" if HIGHMEM && !44x
default "0xb0000000"
config KERNEL_START_BOOL
@@ -1261,7 +1262,7 @@ 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 "0x72000000" if HIGHMEM && CRASH_DUMP && !NONSTATIC_KERNEL
+ default "0x72000000" if HIGHMEM && !44x && CRASH_DUMP && !NONSTATIC_KERNEL
default "0xb2000000" if CRASH_DUMP && !NONSTATIC_KERNEL
default PAGE_OFFSET
>> @@ -1245,7 +1247,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"
>
> [Severity: Medium]
> When both CONFIG_HIGHMEM=y and CONFIG_KASAN=y are enabled on 32-bit
> PowerPC, does lowmem overlap the KASAN shadow and fixmap regions?
>
> With PAGE_OFFSET at 0x70000000 and LOWMEM_SIZE at 0x80000000, lowmem can
> extend up to 0xf0000000. However, KASAN_SHADOW_OFFSET is fixed at
> 0xe0000000 in arch/powerpc/Kconfig.debug, which places KASAN_SHADOW_START
> at 0xec000000 (with CONFIG_EXECMEM=y) or 0xee000000 (with CONFIG_EXECMEM=n)
> and places FIXADDR_TOP, PKMAP_BASE, and VMALLOC_END below
> KASAN_SHADOW_START, colliding with lowmem on systems with ~1.9 GiB or more
> of RAM and triggering a boot BUG_ON in map_kernel_page().
This took me a while to process. As far as I understand now, the upper
end of lowmem is unchanged, but the maximum KASAN shadow is now ~300MB
instead of ~134MB and this no longer fits into the 240MiB vmalloc area
above the linear map. Before my patch, using 134MB of the vmalloc area
for the shadow wasn't ideal either but did not immediately break the
system.
The question is whether the extra address space for KASAN should come
out of lowmem or user. Taking it out of lowmem would be easier, in this
case limiting a KASAN kernel again to 1.75GiB:
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index fe33032dbc13..1eef831faf3a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1192,6 +1192,7 @@ config LOWMEM_SIZE_BOOL
config LOWMEM_SIZE
hex "Maximum low memory size (in bytes)" if LOWMEM_SIZE_BOOL
default "0x40000000" if 44x
+ default "0x70000000" if HIGHMEM && KASAN
default "0x80000000" if HIGHMEM
default "0x40000000"
> [Severity: High]
> With PAGE_OFFSET=0x70000000, can get_host_mas0() in the e500 KVM host MMU
> match and overwrite a host kernel TLB entry instead of forcing a miss?
>
> arch/powerpc/kvm/e500_mmu_host.c:get_host_mas0() {
> local_irq_save(flags);
> mtspr(SPRN_MAS6, 0);
> mas4 = mfspr(SPRN_MAS4);
> mtspr(SPRN_MAS4, mas4 & ~MAS4_TLBSEL_MASK);
> asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
> mas0 = mfspr(SPRN_MAS0);
> }
>
> get_host_mas0() masks eaddr with ~CONFIG_PAGE_OFFSET to produce a userspace
> address (< PAGE_OFFSET) that is guaranteed to miss in PID 0. When
> CONFIG_PAGE_OFFSET is 0x70000000, ~CONFIG_PAGE_OFFSET is 0x8fffffff, so any
> guest eaddr >= 0x80000000 masks to 0x80000000..0x8fffffff, which lies
> inside the host kernel linear mapping (>= 0x70000000) and can hit and
> overwrite an active host kernel TLB entry in write_host_tlbe().
I should probably revisit my patches to remove 32-bit KVM, as I don't
understand this code at all ;-)
Would this work correctly by masking the address to the next lower
power of two below PAGE_OFFSET?
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -115,7 +115,8 @@ static u32 get_host_mas0(unsigned long eaddr)
mtspr(SPRN_MAS6, 0);
mas4 = mfspr(SPRN_MAS4);
mtspr(SPRN_MAS4, mas4 & ~MAS4_TLBSEL_MASK);
- asm volatile("tlbsx 0, %0" : : "b" (eaddr & ~CONFIG_PAGE_OFFSET));
+ asm volatile("tlbsx 0, %0" :
+ : "b" (eaddr & (rounddown_pow_of_two(CONFIG_PAGE_OFFSET)-1)));
mas0 = mfspr(SPRN_MAS0);
mtspr(SPRN_MAS4, mas4);
local_irq_restore(flags);
>> config KERNEL_START_BOOL
>> bool "Set custom kernel base address"
>> @@ -1261,8 +1264,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
>
> [Severity: High]
> Does changing the default KERNEL_START away from 0xc0000000 break KVM guest
> exit on 32-bit Book-E hosts?
>
> On 85xx and 44x, interrupt_base is linked at KERNEL_START (now 0xb0000000
> or 0x70000000 by default), but kvmppc_resume_host in
> arch/powerpc/kvm/booke_interrupts.S restores the host SPRN_IVPR to a
> hardcoded 0xc0000000:
>
> /* Restore host IVPR before re-enabling interrupts. We cheat and know
> * that Linux IVPR is always 0xc0000000. */
> lis r3, 0xc000
> mtspr SPRN_IVPR, r3
>
> The first host interrupt or exception after guest exit will jump to
> 0xc0000000 + IVOR offset instead of interrupt_base and crash the host.
I see, so this was already broken if manually configured to
something else, or if someone had tried to run a KVM guest
from a crash dump kernel.
I would add this as a preparation patch:
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -230,8 +230,8 @@ _GLOBAL(kvmppc_resume_host)
#endif
/* Restore host IVPR before re-enabling interrupts. We cheat and know
- * that Linux IVPR is always 0xc0000000. */
- lis r3, 0xc000
+ * that Linux IVPR is always KERNEL_START. */
+ lis r3, CONFIG_KERNEL_START >> 16
mtspr SPRN_IVPR, r3
/* Switch to kernel stack and jump to handler. */
>> @@ -1298,7 +1302,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
> [Severity: High]
> On 32-bit Book3S KVM hosts, does lowering TASK_SIZE and PAGE_OFFSET leave
> host kernel segment registers 7..11 (or 11) unrestored on guest exit?
>
> LOAD_GUEST_SEGMENTS in arch/powerpc/kvm/book3s_32_sr.S overwrites all 16
> segment registers with guest values, but LOAD_HOST_SEGMENTS only restores
> the 4 segment registers 0xc..0xf (0xc0000000..0xffffffff):
>
> arch/powerpc/kvm/book3s_32_sr.S:LOAD_HOST_SEGMENTS {
> li r0, 4
> mtctr r0
> LOAD_REG_IMMEDIATE(r3, 0x20000000 | (0x111 * 0xc))
> lis r4, 0xc000
> 3: mtsrin r3, r4
> addi r3, r3, 0x111 /* increment VSID */
> addis r4, r4, 0x1000 /* address of next segment */
> bdnz 3b
> }
>
> Because switch_mmu_context() -> update_user_segments() only reloads
> 0 .. NUM_USER_SEGMENTS - 1 (segments 0..10 when TASK_SIZE is 0xb0000000, or
> 0..6 when TASK_SIZE is 0x70000000), the host kernel segments covering
> 0xb0000000..0xbfffffff (or 0x70000000..0xbfffffff, plus any module/execmem
> segment below PAGE_OFFSET) retain guest segment register values after
> exiting the guest.
I guess this is enough?
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -230,8 +230,8 @@ _GLOBAL(kvmppc_resume_host)
#endif
/* Restore host IVPR before re-enabling interrupts. We cheat and know
- * that Linux IVPR is always 0xc0000000. */
- lis r3, 0xc000
+ * that Linux IVPR is always KERNEL_START. */
+ lis r3, CONFIG_KERNEL_START >> 16
mtspr SPRN_IVPR, r3
/* Switch to kernel stack and jump to handler. */
However, I have the feeling that there are other code instances that
make an assumption about the 0xc0000000 start. This may take a while
to find. On the plus side, both Christophe and Richard have been
able to run ppc32 kernels with the previous version of my patch.
Arnd
^ permalink raw reply related [flat|nested] 29+ 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
2026-11-13 11:26 ` sashiko-bot
@ 2026-11-13 18:28 ` Lorenzo Stoakes (ARM)
2 siblings, 0 replies; 29+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-13 18:28 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, Matthew Wilcox, Malin Jonsson,
Richard Weinberger, Russell King, linux-arm-kernel, linux-fsdevel,
linuxppc-dev, x86
On Thu, Nov 12, 2026 at 12:25:23PM +0100, Arnd Bergmann wrote:
> 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>
Really lovely! All looks reasonable AFAICT so:
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> 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
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 29+ 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
2026-11-13 11:26 ` sashiko-bot
@ 2026-11-13 18:35 ` H. Peter Anvin
2026-11-13 18:58 ` Lorenzo Stoakes (ARM)
3 siblings, 0 replies; 29+ messages in thread
From: H. Peter Anvin @ 2026-11-13 18:35 UTC (permalink / raw)
To: Arnd Bergmann, 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,
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
On November 12, 2026 3:25:27 AM PST, Arnd Bergmann <arnd@kernel.org> 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.
>
>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.
The usage of 32-but kernels has certainly drifted, but I do remember us having tried this at one point and having to revert it.
Then again, it is kind of valid to squeeze the users here: these days if you have that kind of constraints the answer really is "use a 64-bit CPU, silly." As the price of memory is expected to remain high for much of the remaining decade, the cost-benefit tradeoff for not using your gigabytes of memory well versus the incremental cost of a 64-bit CPU should make the choice trivial.
That leaves *very* memory-constrained systems (< 1 GiB) and legacy systems as the main target. Legacy systems presumably will want to change as little as possible, which means at least leaving the current split as an option (and will then be picked up by their previous kernel config, even); for the severely memory-constrained systems it doesn't matter all that much.
One advantage of reducing the split line is that for architectures with gigabyte split lines you actually get to fit *all* of a 1 GiB RAM in the virtual space, helping systems with exactly 1 GiB as pushing a few hundred MiB into highmem probably is more expensive than that memory is worth!
^ permalink raw reply [flat|nested] 29+ 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
@ 2026-11-13 18:39 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 29+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-13 18:39 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, 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>
Lovely :)
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> 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
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 29+ 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-13 18:41 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 29+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-13 18:41 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, 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>
With Mike's change applied, LGTM and:
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> 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
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 29+ 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-13 18:53 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 29+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-13 18:53 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, 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>
LGTM assuming Mike's changes :)
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> 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
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 29+ 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
` (2 preceding siblings ...)
2026-11-13 18:35 ` H. Peter Anvin
@ 2026-11-13 18:58 ` Lorenzo Stoakes (ARM)
3 siblings, 0 replies; 29+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-13 18:58 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, 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
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.
>
> 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>
Very nice, thanks! :)
Acked-by: Lorenzo Stoakes (ARM) <ljs@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(-)
>
> 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
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
2026-11-13 11:26 ` sashiko-bot
@ 2026-11-13 19:20 ` Lorenzo Stoakes (ARM)
1 sibling, 0 replies; 29+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-13 19:20 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, Matthew Wilcox, Malin Jonsson,
Richard Weinberger, Russell King, linux-arm-kernel, linux-fsdevel,
linuxppc-dev, x86
On Thu, Nov 12, 2026 at 12:25:28PM +0100, Arnd Bergmann wrote:
> 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>
With sashiko fix, LGTM and:
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> ---
> 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
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-11-13 19:20 UTC | newest]
Thread overview: 29+ 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-13 11:26 ` sashiko-bot
2026-11-13 11:36 ` Arnd Bergmann
2026-11-13 18:28 ` Lorenzo Stoakes (ARM)
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-13 18:39 ` Lorenzo Stoakes (ARM)
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-13 18:41 ` Lorenzo Stoakes (ARM)
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-13 10:50 ` David Hildenbrand (Arm)
2026-11-13 18:53 ` Lorenzo Stoakes (ARM)
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-13 11:26 ` sashiko-bot
2026-11-13 17:54 ` Arnd Bergmann
2026-11-13 18:35 ` H. Peter Anvin
2026-11-13 18:58 ` Lorenzo Stoakes (ARM)
2026-11-12 11:25 ` [PATCH v2 6/6] ARM: add CONFIG_VMSPLIT_2G_OPT option Arnd Bergmann
2026-11-13 11:26 ` sashiko-bot
2026-11-13 14:18 ` Arnd Bergmann
2026-11-13 19:20 ` Lorenzo Stoakes (ARM)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox