* [PATCH v3 1/6] sparc32: use memblock when mapping the kernel
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
@ 2026-09-01 21:45 ` Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 2/6] sparc32: use memblock to find available system memory Magnus Lindholm
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-01 21:45 UTC (permalink / raw)
To: sparclinux; +Cc: davem, andreas, linux-kernel, sam, glaubitz, Magnus Lindholm
memblock already contains the available memory ranges when map_kernel()
runs. Iterate those ranges directly and remove the sp_banks-specific
mapping helper. memblock range ends are exclusive, so use end - start as
the range size.
Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
arch/sparc/mm/srmmu.c | 47 +++++++++++++++++++------------------------
1 file changed, 21 insertions(+), 26 deletions(-)
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 1b24c5e8d73d..23a6383feb15 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -846,39 +846,34 @@ static void __init do_large_mapping(unsigned long vaddr, unsigned long phys_base
*__nocache_fix(pgdp) = __pgd(big_pte);
}
-/* Map sp_bank entry SP_ENTRY, starting at virtual address VBASE. */
-static unsigned long __init map_spbank(unsigned long vbase, int sp_entry)
-{
- unsigned long pstart = (sp_banks[sp_entry].base_addr & PGDIR_MASK);
- unsigned long vstart = (vbase & PGDIR_MASK);
- unsigned long vend = PGDIR_ALIGN(vbase + sp_banks[sp_entry].num_bytes);
- /* Map "low" memory only */
- const unsigned long min_vaddr = PAGE_OFFSET;
- const unsigned long max_vaddr = PAGE_OFFSET + SRMMU_MAXMEM;
-
- if (vstart < min_vaddr || vstart >= max_vaddr)
- return vstart;
-
- if (vend > max_vaddr || vend < min_vaddr)
- vend = max_vaddr;
-
- while (vstart < vend) {
- do_large_mapping(vstart, pstart);
- vstart += PGDIR_SIZE; pstart += PGDIR_SIZE;
- }
- return vstart;
-}
-
static void __init map_kernel(void)
{
- int i;
+ phys_addr_t start, end;
+ u64 i;
if (phys_base > 0) {
do_large_mapping(PAGE_OFFSET, phys_base);
}
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- map_spbank((unsigned long)__va(sp_banks[i].base_addr), i);
+ for_each_mem_range(i, &start, &end) {
+ unsigned long vbase = (unsigned long)__va(start);
+ unsigned long pstart = start & PGDIR_MASK;
+ unsigned long vstart = vbase & PGDIR_MASK;
+ unsigned long vend = PGDIR_ALIGN(vbase + end - start);
+ const unsigned long min_vaddr = PAGE_OFFSET;
+ const unsigned long max_vaddr = PAGE_OFFSET + SRMMU_MAXMEM;
+
+ /* Map low memory only. */
+ if (vstart < min_vaddr || vstart >= max_vaddr)
+ continue;
+ if (vend > max_vaddr || vend < min_vaddr)
+ vend = max_vaddr;
+
+ while (vstart < vend) {
+ do_large_mapping(vstart, pstart);
+ vstart += PGDIR_SIZE;
+ pstart += PGDIR_SIZE;
+ }
}
}
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 2/6] sparc32: use memblock to find available system memory
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 1/6] sparc32: use memblock when mapping the kernel Magnus Lindholm
@ 2026-09-01 21:45 ` Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 3/6] sparc32: populate memblock from the PROM memory map Magnus Lindholm
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-01 21:45 UTC (permalink / raw)
To: sparclinux; +Cc: davem, andreas, linux-kernel, sam, glaubitz, Magnus Lindholm
The SRMMU nocache pool is sized after memblock has been populated. Use
memblock_phys_mem_size() instead of summing the private sp_banks array.
Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
arch/sparc/mm/srmmu.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 23a6383feb15..f094f6c105a2 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -226,25 +226,13 @@ void srmmu_free_nocache(void *addr, int size)
static void srmmu_early_allocate_ptable_skeleton(unsigned long start,
unsigned long end);
-/* Return how much physical memory we have. */
-static unsigned long __init probe_memory(void)
-{
- unsigned long total = 0;
- int i;
-
- for (i = 0; sp_banks[i].num_bytes; i++)
- total += sp_banks[i].num_bytes;
-
- return total;
-}
-
/*
* Reserve nocache dynamically proportionally to the amount of
* system RAM. -- Tomas Szepe <szepe@pinerecords.com>, June 2002
*/
static void __init srmmu_nocache_calcsize(void)
{
- unsigned long sysmemavail = probe_memory() / 1024;
+ unsigned long sysmemavail = memblock_phys_mem_size() / 1024;
int srmmu_nocache_npages;
srmmu_nocache_npages =
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 3/6] sparc32: populate memblock from the PROM memory map
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 1/6] sparc32: use memblock when mapping the kernel Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 2/6] sparc32: use memblock to find available system memory Magnus Lindholm
@ 2026-09-01 21:45 ` Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 4/6] sparc32: drop unused valid address bitmap Magnus Lindholm
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-01 21:45 UTC (permalink / raw)
To: sparclinux; +Cc: davem, andreas, linux-kernel, sam, glaubitz, Magnus Lindholm
Add each available PROM memory range to memblock as it is discovered.
Keep populating sp_banks temporarily so the remaining users continue to
work while they are converted in the following patches.
Since the complete PROM map is now present before bootmem_init(), enforce
the mem= limit after the legacy bank processing. Adding a smaller
overlapping range would otherwise leave memory beyond the requested limit
in memblock during this intermediate commit.
Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
arch/sparc/mm/init_32.c | 3 +++
arch/sparc/prom/memory.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index e0e66f91ceeb..75050dfbc2ea 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -165,6 +165,9 @@ unsigned long __init bootmem_init(unsigned long *pages_avail)
memblock_add(sp_banks[i].base_addr, sp_banks[i].num_bytes);
}
+ if (cmdline_memory_size)
+ memblock_enforce_memory_limit(cmdline_memory_size);
+
/* Start with page aligned address of last symbol in kernel
* image.
*/
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index 269d6ab5ef5e..59962bc0bc82 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -7,6 +7,7 @@
*/
#include <linux/kernel.h>
+#include <linux/memblock.h>
#include <linux/sort.h>
#include <linux/init.h>
@@ -23,6 +24,7 @@ static int __init prom_meminit_v0(void)
for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more) {
sp_banks[index].base_addr = (unsigned long) p->start_adr;
sp_banks[index].num_bytes = p->num_bytes;
+ memblock_add(p->start_adr, p->num_bytes & PAGE_MASK);
index++;
}
@@ -42,6 +44,7 @@ static int __init prom_meminit_v2(void)
for (i = 0; i < num_ents; i++) {
sp_banks[i].base_addr = reg[i].phys_addr;
sp_banks[i].num_bytes = reg[i].reg_size;
+ memblock_add(reg[i].phys_addr, reg[i].reg_size & PAGE_MASK);
}
return num_ents;
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 4/6] sparc32: drop unused valid address bitmap
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
` (2 preceding siblings ...)
2026-09-01 21:45 ` [PATCH v3 3/6] sparc32: populate memblock from the PROM memory map Magnus Lindholm
@ 2026-09-01 21:45 ` Magnus Lindholm
2026-09-01 21:45 ` [PATCH v3 5/6] sparc32: move early memory setup to setup_arch Magnus Lindholm
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-01 21:45 UTC (permalink / raw)
To: sparclinux; +Cc: davem, andreas, linux-kernel, sam, glaubitz, Magnus Lindholm
sparc_valid_addr_bitmap is populated during early memory setup but never
read. Remove the bitmap, its allocation and the population helper.
Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
arch/sparc/mm/init_32.c | 36 ------------------------------------
1 file changed, 36 deletions(-)
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index 75050dfbc2ea..6880d9cb30a5 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
@@ -24,7 +23,6 @@
#include <linux/highmem.h>
#include <linux/memblock.h>
#include <linux/pagemap.h>
-#include <linux/poison.h>
#include <linux/gfp.h>
#include <asm/sections.h>
@@ -37,8 +35,6 @@
#include "mm_32.h"
-static unsigned long *sparc_valid_addr_bitmap;
-
unsigned long phys_base;
EXPORT_SYMBOL(phys_base);
@@ -218,27 +214,8 @@ void __init paging_init(void)
device_scan();
}
-static void __init taint_real_pages(void)
-{
- int i;
-
- for (i = 0; sp_banks[i].num_bytes; i++) {
- unsigned long start, end;
-
- start = sp_banks[i].base_addr;
- end = start + sp_banks[i].num_bytes;
-
- while (start < end) {
- set_bit(start >> 20, sparc_valid_addr_bitmap);
- start += PAGE_SIZE;
- }
- }
-}
-
void __init arch_mm_preinit(void)
{
- int i;
-
if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
prom_printf("BUG: fixmap and pkmap areas overlap\n");
prom_printf("pkbase: 0x%lx pkend: 0x%lx fixstart 0x%lx\n",
@@ -248,19 +225,6 @@ void __init arch_mm_preinit(void)
prom_printf("Please mail sparclinux@vger.kernel.org.\n");
prom_halt();
}
-
- i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5);
- i += 1;
- sparc_valid_addr_bitmap = (unsigned long *)
- memblock_alloc(i << 2, SMP_CACHE_BYTES);
-
- if (sparc_valid_addr_bitmap == NULL) {
- prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
- prom_halt();
- }
- memset(sparc_valid_addr_bitmap, 0, i << 2);
-
- taint_real_pages();
}
void sparc_flush_page_to_ram(struct page *page)
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v3 5/6] sparc32: move early memory setup to setup_arch
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
` (3 preceding siblings ...)
2026-09-01 21:45 ` [PATCH v3 4/6] sparc32: drop unused valid address bitmap Magnus Lindholm
@ 2026-09-01 21:45 ` Magnus Lindholm
2026-09-02 5:31 ` Sam Ravnborg
2026-09-01 21:45 ` [PATCH v3 6/6] sparc32: drop sp_banks Magnus Lindholm
2026-09-02 5:35 ` [PATCH v3 0/6] sparc32: replace sp_banks with memblock Sam Ravnborg
6 siblings, 1 reply; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-01 21:45 UTC (permalink / raw)
To: sparclinux; +Cc: davem, andreas, linux-kernel, sam, glaubitz, Magnus Lindholm
Move the early memory configuration out of SRMMU paging setup and next to
the rest of setup_arch(). Derive the PFN limits from memblock, reserve the
kernel and initrd there, and retain mem= support with
memblock_enforce_memory_limit().
Use for_each_mem_pfn_range() to find the lowmem boundary and replace
last_valid_pfn with the standard max_low_pfn variable. Set the standard
max_pfn variable to the end of physical memory and use it as the highmem
zone limit. This tightens LEON's _pfn_valid() upper bound from all RAM to
the lowmem limit, with no functional change because LEON does not use
highmem.
The removed bootmem code also printed a private HIGHMEM summary. Generic
memory initialization already reports the highmem zone, so do not retain
the duplicate message.
When PAGE_OFFSET maps a relocated kernel, remove memory below phys_base
from memblock because it cannot be reached through the linear map. This
replaces the equivalent trimming of sp_banks.
Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
---
arch/sparc/include/asm/highmem.h | 3 -
arch/sparc/include/asm/leon.h | 2 +-
arch/sparc/include/asm/pgtable_32.h | 3 +-
arch/sparc/include/asm/pgtsrmmu.h | 1 -
arch/sparc/kernel/setup_32.c | 112 ++++++++++++-----------
arch/sparc/mm/init_32.c | 132 +---------------------------
arch/sparc/mm/leon_mm.c | 1 +
arch/sparc/mm/srmmu.c | 8 +-
8 files changed, 67 insertions(+), 195 deletions(-)
diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h
index c7b2e208328b..b1b915ac604d 100644
--- a/arch/sparc/include/asm/highmem.h
+++ b/arch/sparc/include/asm/highmem.h
@@ -26,9 +26,6 @@
#include <asm/vaddrs.h>
#include <asm/pgtsrmmu.h>
-/* declarations for highmem.c */
-extern unsigned long highstart_pfn, highend_pfn;
-
#define kmap_prot __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE)
extern pte_t *pkmap_page_table;
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index 053a24b67aed..815131c77ed7 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -251,7 +251,7 @@ extern int leon_ipi_irq;
/* macros used in leon_mm.c */
#define PFN(x) ((x) >> PAGE_SHIFT)
-#define _pfn_valid(pfn) ((pfn < last_valid_pfn) && (pfn >= PFN(phys_base)))
+#define _pfn_valid(pfn) ((pfn < max_low_pfn) && (pfn >= PFN(phys_base)))
#define _SRMMU_PTE_PMASK_LEON 0xffffffff
/*
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index f89b1250661d..91a6032cf6a2 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -37,8 +37,7 @@ struct vm_area_struct;
struct page;
void load_mmu(void);
-unsigned long calc_highpages(void);
-unsigned long __init bootmem_init(unsigned long *pages_avail);
+void __init find_ramdisk(unsigned long end_of_phys_memory);
#define pte_ERROR(e) __builtin_trap()
#define pmd_ERROR(e) __builtin_trap()
diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h
index a265822a475e..a2a6c8564c3e 100644
--- a/arch/sparc/include/asm/pgtsrmmu.h
+++ b/arch/sparc/include/asm/pgtsrmmu.h
@@ -98,7 +98,6 @@
restore %g0, %g0, %g0;
#ifndef __ASSEMBLER__
-extern unsigned long last_valid_pfn;
/* This makes sense. Honest it does - Anton */
/* XXX Yes but it's ugly as sin. FIXME. -KMW */
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
index 795714959da6..6ad85538964d 100644
--- a/arch/sparc/kernel/setup_32.c
+++ b/arch/sparc/kernel/setup_32.c
@@ -23,6 +23,7 @@
#include <linux/syscalls.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
+#include <linux/memblock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -254,28 +255,71 @@ static __init void leon_patch(void)
struct tt_entry *sparc_ttable;
-/* Drop RAM below the kernel; the linear map runs upward from phys_base
- * and cannot reach it.
- */
-static void __init trim_sp_banks_below(unsigned long base)
+unsigned long phys_base;
+EXPORT_SYMBOL(phys_base);
+
+unsigned long pfn_base;
+EXPORT_SYMBOL(pfn_base);
+
+static unsigned long __init calc_max_low_pfn(void)
{
- int i, j = 0;
+ unsigned long limit = pfn_base + PHYS_PFN(SRMMU_MAXMEM);
+ unsigned long start_pfn, end_pfn;
+ unsigned long last_pfn = 0;
+ int i;
+
+ for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) {
+ if (start_pfn >= limit) {
+ if (last_pfn < limit)
+ limit = last_pfn;
+ break;
+ }
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- unsigned long start = sp_banks[i].base_addr;
- unsigned long end = start + sp_banks[i].num_bytes;
+ last_pfn = end_pfn;
+ }
- if (end <= base)
- continue; /* wholly below - drop it */
- if (start < base)
- start = base; /* straddles - trim the front */
+ return limit;
+}
- sp_banks[j].base_addr = start;
- sp_banks[j].num_bytes = end - start;
- j++;
+static void __init setup_memory(void)
+{
+ unsigned long ram_base = memblock_start_of_DRAM();
+ unsigned long real_base = __get_phys(PAGE_OFFSET);
+ unsigned long size;
+
+ memblock_set_bottom_up(true);
+ memblock_allow_resize();
+
+ phys_base = ram_base;
+ if (real_base && real_base != phys_base) {
+ prom_printf("phys_base: RAM starts 0x%x but kernel is at 0x%x\n",
+ (unsigned int)phys_base, (unsigned int)real_base);
+ phys_base = real_base;
+ memblock_remove(0, phys_base);
+ prom_printf("phys_base: adopted 0x%x, RAM below it dropped\n",
+ (unsigned int)phys_base);
}
- sp_banks[j].base_addr = 0;
- sp_banks[j].num_bytes = 0;
+
+ if (cmdline_memory_size)
+ memblock_enforce_memory_limit(cmdline_memory_size);
+
+ min_low_pfn = PFN_DOWN(memblock_start_of_DRAM());
+ pfn_base = PHYS_PFN(phys_base);
+ max_pfn = PFN_DOWN(memblock_end_of_DRAM());
+ max_low_pfn = max_pfn;
+
+ if (max_low_pfn > pfn_base + PHYS_PFN(SRMMU_MAXMEM))
+ max_low_pfn = calc_max_low_pfn();
+
+ find_ramdisk(memblock_end_of_DRAM());
+
+ /* Reserve the kernel text/data/bss. */
+ size = __pa(PAGE_ALIGN((unsigned long)&_end)) - phys_base;
+ memblock_reserve(phys_base, size);
+ memblock_add(phys_base, size);
+
+ /* Only allow low memory to be allocated by memblock. */
+ memblock_set_current_limit(PFN_PHYS(max_low_pfn));
}
/* Called from head_32.S - before we have setup anything
@@ -306,9 +350,6 @@ void __init sparc32_start_kernel(struct linux_romvec *rp)
void __init setup_arch(char **cmdline_p)
{
- int i;
- unsigned long highest_paddr;
-
sparc_ttable = &trapbase[0];
/* Initialize PROM console and command line. */
@@ -343,36 +384,7 @@ void __init setup_arch(char **cmdline_p)
idprom_init();
load_mmu();
-
- phys_base = 0xffffffffUL;
- highest_paddr = 0UL;
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- unsigned long top;
-
- if (sp_banks[i].base_addr < phys_base)
- phys_base = sp_banks[i].base_addr;
- top = sp_banks[i].base_addr +
- sp_banks[i].num_bytes;
- if (highest_paddr < top)
- highest_paddr = top;
- }
-
- /* phys_base must describe what PAGE_OFFSET maps to, not where RAM starts. */
- {
- unsigned long real_base = __get_phys(PAGE_OFFSET);
-
- if (real_base && real_base != phys_base) {
- prom_printf("phys_base: RAM starts 0x%x but kernel is at 0x%x\n",
- (unsigned int)phys_base,
- (unsigned int)real_base);
- phys_base = real_base;
- trim_sp_banks_below(phys_base);
- prom_printf("phys_base: adopted 0x%x, RAM below it dropped\n",
- (unsigned int)phys_base);
- }
- }
-
- pfn_base = phys_base >> PAGE_SHIFT;
+ setup_memory();
if (!root_flags)
root_mountflags &= ~MS_RDONLY;
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index 6880d9cb30a5..ac4462f1cf76 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -35,66 +35,13 @@
#include "mm_32.h"
-unsigned long phys_base;
-EXPORT_SYMBOL(phys_base);
-
-unsigned long pfn_base;
-EXPORT_SYMBOL(pfn_base);
-
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
/* Initial ramdisk setup */
extern unsigned int sparc_ramdisk_image;
extern unsigned int sparc_ramdisk_size;
-unsigned long highstart_pfn, highend_pfn;
-
-unsigned long last_valid_pfn;
-
-unsigned long calc_highpages(void)
-{
- int i;
- int nr = 0;
-
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
- unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
-
- if (end_pfn <= max_low_pfn)
- continue;
-
- if (start_pfn < max_low_pfn)
- start_pfn = max_low_pfn;
-
- nr += end_pfn - start_pfn;
- }
-
- return nr;
-}
-
-static unsigned long calc_max_low_pfn(void)
-{
- int i;
- unsigned long tmp = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
- unsigned long curr_pfn, last_pfn;
-
- last_pfn = (sp_banks[0].base_addr + sp_banks[0].num_bytes) >> PAGE_SHIFT;
- for (i = 1; sp_banks[i].num_bytes != 0; i++) {
- curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
-
- if (curr_pfn >= tmp) {
- if (last_pfn < tmp)
- tmp = last_pfn;
- break;
- }
-
- last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
- }
-
- return tmp;
-}
-
-static void __init find_ramdisk(unsigned long end_of_phys_memory)
+void __init find_ramdisk(unsigned long end_of_phys_memory)
{
#ifdef CONFIG_BLK_DEV_INITRD
unsigned long size;
@@ -124,83 +71,6 @@ static void __init find_ramdisk(unsigned long end_of_phys_memory)
#endif
}
-unsigned long __init bootmem_init(unsigned long *pages_avail)
-{
- unsigned long start_pfn, bytes_avail, size;
- unsigned long end_of_phys_memory = 0;
- unsigned long high_pages = 0;
- int i;
-
- memblock_set_bottom_up(true);
- memblock_allow_resize();
-
- bytes_avail = 0UL;
- for (i = 0; sp_banks[i].num_bytes != 0; i++) {
- end_of_phys_memory = sp_banks[i].base_addr +
- sp_banks[i].num_bytes;
- bytes_avail += sp_banks[i].num_bytes;
- if (cmdline_memory_size) {
- if (bytes_avail > cmdline_memory_size) {
- unsigned long slack = bytes_avail - cmdline_memory_size;
-
- bytes_avail -= slack;
- end_of_phys_memory -= slack;
-
- sp_banks[i].num_bytes -= slack;
- if (sp_banks[i].num_bytes == 0) {
- sp_banks[i].base_addr = 0xdeadbeef;
- } else {
- memblock_add(sp_banks[i].base_addr,
- sp_banks[i].num_bytes);
- sp_banks[i+1].num_bytes = 0;
- sp_banks[i+1].base_addr = 0xdeadbeef;
- }
- break;
- }
- }
- memblock_add(sp_banks[i].base_addr, sp_banks[i].num_bytes);
- }
-
- if (cmdline_memory_size)
- memblock_enforce_memory_limit(cmdline_memory_size);
-
- /* Start with page aligned address of last symbol in kernel
- * image.
- */
- start_pfn = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end));
-
- /* Now shift down to get the real physical page frame number. */
- start_pfn >>= PAGE_SHIFT;
-
- max_pfn = end_of_phys_memory >> PAGE_SHIFT;
-
- max_low_pfn = max_pfn;
- highstart_pfn = highend_pfn = max_pfn;
-
- if (max_low_pfn > pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT)) {
- highstart_pfn = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
- max_low_pfn = calc_max_low_pfn();
- high_pages = calc_highpages();
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
- high_pages >> (20 - PAGE_SHIFT));
- }
-
- find_ramdisk(end_of_phys_memory);
-
- /* Reserve the kernel text/data/bss. */
- size = (start_pfn << PAGE_SHIFT) - phys_base;
- memblock_reserve(phys_base, size);
- memblock_add(phys_base, size);
-
- size = memblock_phys_mem_size() - memblock_reserved_size();
- *pages_avail = (size >> PAGE_SHIFT) - high_pages;
-
- /* Only allow low memory to be allocated via memblock allocation */
- memblock_set_current_limit(max_low_pfn << PAGE_SHIFT);
-
- return max_pfn;
-}
-
/*
* paging_init() sets up the page tables: We call the MMU specific
* init routine based upon the Sun model type on the Sparc.
diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c
index 1dc9b3d70eda..a43c5ffbbbe5 100644
--- a/arch/sparc/mm/leon_mm.c
+++ b/arch/sparc/mm/leon_mm.c
@@ -11,6 +11,7 @@
*/
#include <linux/kernel.h>
+#include <linux/memblock.h>
#include <linux/mm.h>
#include <asm/asi.h>
#include <asm/leon.h>
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index f094f6c105a2..e333d3eac451 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -59,8 +59,6 @@ int vac_line_size;
extern struct resource sparc_iomap;
-extern unsigned long last_valid_pfn;
-
static pgd_t *srmmu_swapper_pg_dir;
const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
@@ -871,7 +869,7 @@ void __init arch_zone_limits_init(unsigned long *max_zone_pfns)
{
max_zone_pfns[ZONE_DMA] = max_low_pfn;
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
- max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
+ max_zone_pfns[ZONE_HIGHMEM] = max_pfn;
}
void __init srmmu_paging_init(void)
@@ -884,7 +882,6 @@ void __init srmmu_paging_init(void)
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
- unsigned long pages_avail;
init_mm.context = (unsigned long) NO_CONTEXT;
sparc_iomap.start = SUN4M_IOBASE_VADDR; /* 16MB of IOSPACE on all sun4m's. */
@@ -910,9 +907,6 @@ void __init srmmu_paging_init(void)
prom_halt();
}
- pages_avail = 0;
- last_valid_pfn = bootmem_init(&pages_avail);
-
srmmu_nocache_calcsize();
srmmu_nocache_init();
srmmu_inherit_prom_mappings(0xfe400000, (LINUX_OPPROM_ENDVM - PAGE_SIZE));
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v3 5/6] sparc32: move early memory setup to setup_arch
2026-09-01 21:45 ` [PATCH v3 5/6] sparc32: move early memory setup to setup_arch Magnus Lindholm
@ 2026-09-02 5:31 ` Sam Ravnborg
0 siblings, 0 replies; 10+ messages in thread
From: Sam Ravnborg @ 2026-09-02 5:31 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: sparclinux, davem, andreas, linux-kernel, glaubitz
On Tue, Sep 01, 2026 at 11:45:49PM +0200, Magnus Lindholm wrote:
> Move the early memory configuration out of SRMMU paging setup and next to
> the rest of setup_arch(). Derive the PFN limits from memblock, reserve the
> kernel and initrd there, and retain mem= support with
> memblock_enforce_memory_limit().
>
> Use for_each_mem_pfn_range() to find the lowmem boundary and replace
> last_valid_pfn with the standard max_low_pfn variable. Set the standard
> max_pfn variable to the end of physical memory and use it as the highmem
> zone limit. This tightens LEON's _pfn_valid() upper bound from all RAM to
> the lowmem limit, with no functional change because LEON does not use
> highmem.
>
> The removed bootmem code also printed a private HIGHMEM summary. Generic
> memory initialization already reports the highmem zone, so do not retain
> the duplicate message.
>
> When PAGE_OFFSET maps a relocated kernel, remove memory below phys_base
> from memblock because it cannot be reached through the linear map. This
> replaces the equivalent trimming of sp_banks.
>
> Suggested-by: Sam Ravnborg <sam@ravnborg.org>
> Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Looks good!
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 6/6] sparc32: drop sp_banks
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
` (4 preceding siblings ...)
2026-09-01 21:45 ` [PATCH v3 5/6] sparc32: move early memory setup to setup_arch Magnus Lindholm
@ 2026-09-01 21:45 ` Magnus Lindholm
2026-09-02 5:35 ` [PATCH v3 0/6] sparc32: replace sp_banks with memblock Sam Ravnborg
6 siblings, 0 replies; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-01 21:45 UTC (permalink / raw)
To: sparclinux; +Cc: davem, andreas, linux-kernel, sam, glaubitz, Magnus Lindholm
All memory-map consumers now use memblock. Stop duplicating the PROM map
in sp_banks and remove the array, its type, and its fixed bank limit.
Suggested-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Magnus Lindholm <linmag7@gmail.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
---
arch/sparc/include/asm/page_32.h | 16 -----------
arch/sparc/mm/init_32.c | 2 --
arch/sparc/prom/memory.c | 48 ++++----------------------------
3 files changed, 6 insertions(+), 60 deletions(-)
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h
index c1bccbedf567..5daa5fd8eaa5 100644
--- a/arch/sparc/include/asm/page_32.h
+++ b/arch/sparc/include/asm/page_32.h
@@ -26,22 +26,6 @@
sparc_flush_page_to_ram(page); \
} while (0)
-/* The following structure is used to hold the physical
- * memory configuration of the machine. This is filled in
- * prom_meminit() and is later used by mem_init() to set up
- * mem_map[]. We statically allocate SPARC_PHYS_BANKS+1 of
- * these structs, this is arbitrary. The entry after the
- * last valid one has num_bytes==0.
- */
-struct sparc_phys_banks {
- unsigned long base_addr;
- unsigned long num_bytes;
-};
-
-#define SPARC_PHYS_BANKS 32
-
-extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
-
/* passing structs on the Sparc slow us down tremendously... */
/* #define STRICT_MM_TYPECHECKS */
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index ac4462f1cf76..2f693b70dbd8 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -35,8 +35,6 @@
#include "mm_32.h"
-struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
-
/* Initial ramdisk setup */
extern unsigned int sparc_ramdisk_image;
extern unsigned int sparc_ramdisk_size;
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c
index 59962bc0bc82..3f65bde2bb89 100644
--- a/arch/sparc/prom/memory.c
+++ b/arch/sparc/prom/memory.c
@@ -8,30 +8,21 @@
#include <linux/kernel.h>
#include <linux/memblock.h>
-#include <linux/sort.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/page.h>
-static int __init prom_meminit_v0(void)
+static void __init prom_meminit_v0(void)
{
struct linux_mlist_v0 *p;
- int index;
- index = 0;
- for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more) {
- sp_banks[index].base_addr = (unsigned long) p->start_adr;
- sp_banks[index].num_bytes = p->num_bytes;
+ for (p = *(romvec->pv_v0mem.v0_available); p; p = p->theres_more)
memblock_add(p->start_adr, p->num_bytes & PAGE_MASK);
- index++;
- }
-
- return index;
}
-static int __init prom_meminit_v2(void)
+static void __init prom_meminit_v2(void)
{
struct linux_prom_registers reg[64];
phandle node;
@@ -41,51 +32,24 @@ static int __init prom_meminit_v2(void)
size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
num_ents = size / sizeof(struct linux_prom_registers);
- for (i = 0; i < num_ents; i++) {
- sp_banks[i].base_addr = reg[i].phys_addr;
- sp_banks[i].num_bytes = reg[i].reg_size;
+ for (i = 0; i < num_ents; i++)
memblock_add(reg[i].phys_addr, reg[i].reg_size & PAGE_MASK);
- }
-
- return num_ents;
-}
-
-static int sp_banks_cmp(const void *a, const void *b)
-{
- const struct sparc_phys_banks *x = a, *y = b;
-
- if (x->base_addr > y->base_addr)
- return 1;
- if (x->base_addr < y->base_addr)
- return -1;
- return 0;
}
/* Initialize the memory lists based upon the prom version. */
void __init prom_meminit(void)
{
- int i, num_ents = 0;
-
switch (prom_vers) {
case PROM_V0:
- num_ents = prom_meminit_v0();
+ prom_meminit_v0();
break;
case PROM_V2:
case PROM_V3:
- num_ents = prom_meminit_v2();
+ prom_meminit_v2();
break;
default:
break;
}
- sort(sp_banks, num_ents, sizeof(struct sparc_phys_banks),
- sp_banks_cmp, NULL);
-
- /* Sentinel. */
- sp_banks[num_ents].base_addr = 0xdeadbeef;
- sp_banks[num_ents].num_bytes = 0;
-
- for (i = 0; i < num_ents; i++)
- sp_banks[i].num_bytes &= PAGE_MASK;
}
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v3 0/6] sparc32: replace sp_banks with memblock
2026-09-01 21:45 [PATCH v3 0/6] sparc32: replace sp_banks with memblock Magnus Lindholm
` (5 preceding siblings ...)
2026-09-01 21:45 ` [PATCH v3 6/6] sparc32: drop sp_banks Magnus Lindholm
@ 2026-09-02 5:35 ` Sam Ravnborg
2026-09-02 5:38 ` Magnus Lindholm
6 siblings, 1 reply; 10+ messages in thread
From: Sam Ravnborg @ 2026-09-02 5:35 UTC (permalink / raw)
To: Magnus Lindholm; +Cc: sparclinux, davem, andreas, linux-kernel, glaubitz
Hi Magnus.
On Tue, Sep 01, 2026 at 11:45:44PM +0200, Magnus Lindholm wrote:
> Replace the sparc32-private sp_banks memory description with memblock.
>
> The first two patches convert the SRMMU consumers that already run after
> bootmem_init() has populated memblock. The third patch moves memblock
> population to prom_meminit() and applies the mem= limit there. Patch 4
> removes an unused address bitmap before patch 5 moves the early memory
> setup into setup_32.c. Patch 6 removes the now-unused sp_banks array.
>
> This work is based on an earlier eight-patch series by Sam Ravnborg.
> Patch 2 directly carries over Sam's memblock sizing conversion. The series
> has otherwise been substantially reorganized and reworked for the current
> kernel. It retains the sparc32 mem= command-line option by using
> memblock_enforce_memory_limit() and uses memblock's exclusive range-end
> semantics throughout.
>
> The series applies on top of the sparc32 phys_base and Viking fixes.
> setup_memory() preserves relocated-kernel handling by removing RAM below
> the physical address to which PAGE_OFFSET maps.
>
> Link: https://lore.kernel.org/sparclinux/20260816075141.3489194-1-linmag7@gmail.com/T/#t
>
> The v1 series was boot tested on a Sun SPARCstation 20 with dual
> SuperSPARC-II CPUs (SM71).
> The v2 series was boot tested on a Sun SPARCstation 20 with dual
> ROSS HyperSPARC (RT626) CPUs.
> The v3 series was cross-compiled with the SPARCstation 20 and LEON
> configurations as well as boot tested on a Sun SPARCstation 20
> with dual ROSS HyperSPARC (RT626) CPUs.
>
> Changes in v3:
> - Add Sam's Reviewed-by tag to patch 4.
> - Initialize max_pfn in patch 5 and use it as the highmem zone limit.
> - Use PHYS_PFN() instead of open-coded PAGE_SHIFT conversions in patch 5.
> - Remove the obsolete highstart_pfn and highend_pfn declarations.
> - Use the generic max_low_pfn declaration from linux/memblock.h.
> - Document removal of the duplicate private HIGHMEM summary.
>
> Changes in v2:
> - Add Sam's Reviewed-by tags to patches 1-3 and 6. Patch 6 is the
> unchanged source change from patch 5 in v1, renumbered by the new patch.
> - Drop the unused sparc_valid_addr_bitmap in a preparation patch.
> - Use for_each_mem_pfn_range() and the standard max_low_pfn variable in
> the early memory setup. This tightens LEON's _pfn_valid() upper bound
> from all memory to the lowmem limit, with no functional change because
> LEON does not use highmem.
The full series looks good now, thanks for picking this up and adressing
my review feedback.
For anyone looking at sparc32 code this is now much more standard
and you managed to remove ~250 lines of old code.
It is now ready for Andreas to take a look.
Sam
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v3 0/6] sparc32: replace sp_banks with memblock
2026-09-02 5:35 ` [PATCH v3 0/6] sparc32: replace sp_banks with memblock Sam Ravnborg
@ 2026-09-02 5:38 ` Magnus Lindholm
0 siblings, 0 replies; 10+ messages in thread
From: Magnus Lindholm @ 2026-09-02 5:38 UTC (permalink / raw)
To: Sam Ravnborg; +Cc: sparclinux, davem, andreas, linux-kernel, glaubitz
Hi Sam,
On Wed, Sep 2, 2026 at 7:35 AM Sam Ravnborg <sam@ravnborg.org> wrote:
> The full series looks good now, thanks for picking this up and adressing
> my review feedback.
> For anyone looking at sparc32 code this is now much more standard
> and you managed to remove ~250 lines of old code.
>
> It is now ready for Andreas to take a look.
>
Thanks alot for spending time on reviewing this, and for all the
feedback pointing me in the right direction.
Magnus
^ permalink raw reply [flat|nested] 10+ messages in thread