On systems where physical memory begins at a non-zero address, defining PHYS_OFFSET (which influences ARCH_PFN_OFFSET) can save us time & memory by avoiding book-keeping for pages from address zero to the start of memory. Some MIPS platforms already make use of this, but with the definition of PHYS_OFFSET being compile-time constant it hasn't been possible to enable this optimization for a kernel which may run on systems with varying physical memory base addresses. Introduce a new Kconfig option CONFIG_MIPS_AUTO_PFN_OFFSET which, when enabled, makes ARCH_PFN_OFFSET a variable & detects it from the boot memory map (which for example may have been populated from DT). The relationship with PHYS_OFFSET is reversed, with PHYS_OFFSET now being based on ARCH_PFN_OFFSET. This is because ARCH_PFN_OFFSET is used far more often, so avoiding the need for runtime calculation gives us a smaller impact on kernel text size (0.1% rather than 0.15% for 64r6el_defconfig). Signed-off-by: Paul Burton <paul.burton@xxxxxxxx> Suggested-by: Vladimir Kondratiev <vladimir.kondratiev@xxxxxxxxx> Cc: James Hogan <jhogan@xxxxxxxxxx> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx> Cc: linux-mips@xxxxxxxxxxxxxx --- arch/mips/Kconfig | 3 +++ arch/mips/include/asm/mach-generic/spaces.h | 10 +++++++--- arch/mips/include/asm/page.h | 7 ++++++- arch/mips/kernel/setup.c | 14 ++++++++++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 10256056647c..fbf7f678e856 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2985,6 +2985,9 @@ config PGTABLE_LEVELS default 3 if 64BIT && !PAGE_SIZE_64KB default 2 +config MIPS_AUTO_PFN_OFFSET + bool + source "init/Kconfig" source "kernel/Kconfig.freezer" diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h index 952b0fdfda0e..ee5ebe98f6cf 100644 --- a/arch/mips/include/asm/mach-generic/spaces.h +++ b/arch/mips/include/asm/mach-generic/spaces.h @@ -17,9 +17,13 @@ /* * This gives the physical RAM offset. */ -#ifndef PHYS_OFFSET -#define PHYS_OFFSET _AC(0, UL) -#endif +#ifndef __ASSEMBLY__ +# if defined(CONFIG_MIPS_AUTO_PFN_OFFSET) +# define PHYS_OFFSET ((unsigned long)PFN_PHYS(ARCH_PFN_OFFSET)) +# elif !defined(PHYS_OFFSET) +# define PHYS_OFFSET _AC(0, UL) +# endif +#endif /* __ASSEMBLY__ */ #ifdef CONFIG_32BIT #ifdef CONFIG_KVM_GUEST diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index a051b82f8009..e8cc328fce2d 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -80,7 +80,12 @@ extern void build_copy_page(void); * used in our early mem init code for all memory models. * So always define it. */ -#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET) +#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET +extern unsigned long ARCH_PFN_OFFSET; +# define ARCH_PFN_OFFSET ARCH_PFN_OFFSET +#else +# define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET) +#endif extern void clear_page(void * page); extern void copy_page(void * to, void * from); diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 3d4524309b5c..c71d1eb7da59 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -85,6 +85,11 @@ static struct resource bss_resource = { .name = "Kernel bss", }; static void *detect_magic __initdata = detect_memory_region; +#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET +unsigned long ARCH_PFN_OFFSET; +EXPORT_SYMBOL(ARCH_PFN_OFFSET); +#endif + void __init add_memory_region(phys_addr_t start, phys_addr_t size, long type) { int x = boot_mem_map.nr_map; @@ -442,6 +447,12 @@ static void __init bootmem_init(void) mapstart = max(reserved_end, start); } + if (min_low_pfn >= max_low_pfn) + panic("Incorrect memory mapping !!!"); + +#ifdef CONFIG_MIPS_AUTO_PFN_OFFSET + ARCH_PFN_OFFSET = PFN_UP(ramstart); +#else /* * Reserve any memory between the start of RAM and PHYS_OFFSET */ @@ -449,8 +460,6 @@ static void __init bootmem_init(void) add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET, BOOT_MEM_RESERVED); - if (min_low_pfn >= max_low_pfn) - panic("Incorrect memory mapping !!!"); if (min_low_pfn > ARCH_PFN_OFFSET) { pr_info("Wasting %lu bytes for tracking %lu unused pages\n", (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page), @@ -460,6 +469,7 @@ static void __init bootmem_init(void) ARCH_PFN_OFFSET - min_low_pfn); } min_low_pfn = ARCH_PFN_OFFSET; +#endif /* * Determine low and high memory ranges -- 2.18.0