MIPS: Allow auto-dection of ARCH_PFN_OFFSET & PHYS_OFFSET

This change “MIPS: Allow auto-dection of ARCH_PFN_OFFSET & PHYS_OFFSET” in Linux kernel is authored by Paul Burton <paul.burton [at] mips.com> on Fri Jul 27 18:23:20 2018 -0700.

MIPS: Allow auto-dection of ARCH_PFN_OFFSET & PHYS_OFFSET

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

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

Signed-off-by: Paul Burton <paul.burton@mips.com>
Suggested-by: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
Patchwork: https://patchwork.linux-mips.org/patch/20048/
Cc: James Hogan <jhogan@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org

This Linux change may have been applied to various maintained Linux releases and you can find Linux releases including commit 6c359eb.

There are 34 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 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 1025605..fbf7f67 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
+	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 952b0fd..ee5ebe9 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)
+#ifndef __ASSEMBLY__
+#  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
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index a051b82..e8cc328 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -80,7 +80,12 @@ static inline unsigned int page_size_ftlb(unsigned int mmuextdef)
  * used in our early mem init code for all memory models.
  * So always define it.
+extern unsigned long ARCH_PFN_OFFSET;
 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 3d45243..c71d1eb 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -85,6 +85,11 @@
 static void *detect_magic __initdata = detect_memory_region;
+unsigned long ARCH_PFN_OFFSET;
 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 !!!");
+	ARCH_PFN_OFFSET = PFN_UP(ramstart);
 	 * 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,
-	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 pagesn",
 			(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;
 	 * Determine low and high memory ranges

The commit for this change in Linux stable tree is 6c359eb (patch).

Leave a Reply

Your email address will not be published. Required fields are marked *