arm, arm64: move free_unused_memmap() to generic mm
authorMike Rapoport <rppt@linux.ibm.com>
Tue, 15 Dec 2020 03:09:59 +0000 (19:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 15 Dec 2020 20:13:42 +0000 (12:13 -0800)
ARM and ARM64 free unused parts of the memory map just before the
initialization of the page allocator. To allow holes in the memory map both
architectures overload pfn_valid() and define HAVE_ARCH_PFN_VALID.

Allowing holes in the memory map for FLATMEM may be useful for small
machines, such as ARC and m68k and will enable those architectures to cease
using DISCONTIGMEM and still support more than one memory bank.

Move the functions that free unused memory map to generic mm and enable
them in case HAVE_ARCH_PFN_VALID=y.

Link: https://lkml.kernel.org/r/20201101170454.9567-10-rppt@kernel.org
Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com> [arm64]
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Greg Ungerer <gerg@linux-m68k.org>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Matt Turner <mattst88@gmail.com>
Cc: Meelis Roos <mroos@linux.ee>
Cc: Michael Schmitz <schmitzmic@gmail.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/Kconfig
arch/arm/Kconfig
arch/arm/mm/init.c
arch/arm64/Kconfig
arch/arm64/mm/init.c
mm/memblock.c

index 54a240b61f560103e42f14b2634fb8c02a1f2b73..8d5efff59cd861eb9da068158d4757e13849fcef 100644 (file)
@@ -1044,6 +1044,9 @@ config ARCH_WANT_LD_ORPHAN_WARN
          by the linker, since the locations of such sections can change between linker
          versions.
 
+config HAVE_ARCH_PFN_VALID
+       bool
+
 source "kernel/gcov/Kconfig"
 
 source "scripts/gcc-plugins/Kconfig"
index 353c3979a2d568a841ea56bb03d2b151b6bdbdff..03602e8fe16d9a6d055d9db2ff02976463515aed 100644 (file)
@@ -69,6 +69,7 @@ config ARM
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
        select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
        select HAVE_ARCH_MMAP_RND_BITS if MMU
+       select HAVE_ARCH_PFN_VALID
        select HAVE_ARCH_SECCOMP
        select HAVE_ARCH_SECCOMP_FILTER if AEABI && !OABI_COMPAT
        select HAVE_ARCH_THREAD_STRUCT_WHITELIST
@@ -1489,9 +1490,6 @@ config ARCH_SPARSEMEM_ENABLE
        bool
        select SPARSEMEM_STATIC if SPARSEMEM
 
-config HAVE_ARCH_PFN_VALID
-       def_bool y
-
 config HIGHMEM
        bool "High Memory Support"
        depends on MMU
index c23dbf8bebeeb7f4387b90e7827c6a570d940566..db623d7c30de3309241178d2318b7dcb55592db3 100644 (file)
@@ -267,83 +267,6 @@ static inline void poison_init_mem(void *s, size_t count)
                *p++ = 0xe7fddef0;
 }
 
-static inline void __init
-free_memmap(unsigned long start_pfn, unsigned long end_pfn)
-{
-       struct page *start_pg, *end_pg;
-       phys_addr_t pg, pgend;
-
-       /*
-        * Convert start_pfn/end_pfn to a struct page pointer.
-        */
-       start_pg = pfn_to_page(start_pfn - 1) + 1;
-       end_pg = pfn_to_page(end_pfn - 1) + 1;
-
-       /*
-        * Convert to physical addresses, and
-        * round start upwards and end downwards.
-        */
-       pg = PAGE_ALIGN(__pa(start_pg));
-       pgend = __pa(end_pg) & PAGE_MASK;
-
-       /*
-        * If there are free pages between these,
-        * free the section of the memmap array.
-        */
-       if (pg < pgend)
-               memblock_free_early(pg, pgend - pg);
-}
-
-/*
- * The mem_map array can get very big.  Free the unused area of the memory map.
- */
-static void __init free_unused_memmap(void)
-{
-       unsigned long start, end, prev_end = 0;
-       int i;
-
-       /*
-        * This relies on each bank being in address order.
-        * The banks are sorted previously in bootmem_init().
-        */
-       for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {
-#ifdef CONFIG_SPARSEMEM
-               /*
-                * Take care not to free memmap entries that don't exist
-                * due to SPARSEMEM sections which aren't present.
-                */
-               start = min(start,
-                                ALIGN(prev_end, PAGES_PER_SECTION));
-#else
-               /*
-                * Align down here since the VM subsystem insists that the
-                * memmap entries are valid from the bank start aligned to
-                * MAX_ORDER_NR_PAGES.
-                */
-               start = round_down(start, MAX_ORDER_NR_PAGES);
-#endif
-               /*
-                * If we had a previous bank, and there is a space
-                * between the current bank and the previous, free it.
-                */
-               if (prev_end && prev_end < start)
-                       free_memmap(prev_end, start);
-
-               /*
-                * Align up here since the VM subsystem insists that the
-                * memmap entries are valid from the bank end aligned to
-                * MAX_ORDER_NR_PAGES.
-                */
-               prev_end = ALIGN(end, MAX_ORDER_NR_PAGES);
-       }
-
-#ifdef CONFIG_SPARSEMEM
-       if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
-               free_memmap(prev_end,
-                           ALIGN(prev_end, PAGES_PER_SECTION));
-#endif
-}
-
 static void __init free_highpages(void)
 {
 #ifdef CONFIG_HIGHMEM
@@ -385,7 +308,6 @@ void __init mem_init(void)
        set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
 
        /* this will put all unused low memory onto the freelists */
-       free_unused_memmap();
        memblock_free_all();
 
 #ifdef CONFIG_SA1111
index 15bb857e42e186cf23e7a296c31bc4f63d5e75c0..6f0751631ef153711676ba12f7e416ba46f645c7 100644 (file)
@@ -140,6 +140,7 @@ config ARM64
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_MMAP_RND_BITS
        select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
+       select HAVE_ARCH_PFN_VALID
        select HAVE_ARCH_PREL32_RELOCATIONS
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_STACKLEAK
@@ -1043,9 +1044,6 @@ config ARCH_SELECT_MEMORY_MODEL
 config ARCH_FLATMEM_ENABLE
        def_bool !NUMA
 
-config HAVE_ARCH_PFN_VALID
-       def_bool y
-
 config HW_PERF_EVENTS
        def_bool y
        depends on ARM_PMU
index 095540667f0fdd7ed408202264ffd57d5c22d0da..3d8328277bec5b0a2bd1272cb2e41d9c79baeb01 100644 (file)
@@ -430,71 +430,6 @@ void __init bootmem_init(void)
        memblock_dump_all();
 }
 
-#ifndef CONFIG_SPARSEMEM_VMEMMAP
-static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn)
-{
-       struct page *start_pg, *end_pg;
-       unsigned long pg, pgend;
-
-       /*
-        * Convert start_pfn/end_pfn to a struct page pointer.
-        */
-       start_pg = pfn_to_page(start_pfn - 1) + 1;
-       end_pg = pfn_to_page(end_pfn - 1) + 1;
-
-       /*
-        * Convert to physical addresses, and round start upwards and end
-        * downwards.
-        */
-       pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
-       pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
-
-       /*
-        * If there are free pages between these, free the section of the
-        * memmap array.
-        */
-       if (pg < pgend)
-               memblock_free(pg, pgend - pg);
-}
-
-/*
- * The mem_map array can get very big. Free the unused area of the memory map.
- */
-static void __init free_unused_memmap(void)
-{
-       unsigned long start, end, prev_end = 0;
-       int i;
-
-       for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {
-#ifdef CONFIG_SPARSEMEM
-               /*
-                * Take care not to free memmap entries that don't exist due
-                * to SPARSEMEM sections which aren't present.
-                */
-               start = min(start, ALIGN(prev_end, PAGES_PER_SECTION));
-#endif
-               /*
-                * If we had a previous bank, and there is a space between the
-                * current bank and the previous, free it.
-                */
-               if (prev_end && prev_end < start)
-                       free_memmap(prev_end, start);
-
-               /*
-                * Align up here since the VM subsystem insists that the
-                * memmap entries are valid from the bank end aligned to
-                * MAX_ORDER_NR_PAGES.
-                */
-               prev_end = ALIGN(end, MAX_ORDER_NR_PAGES);
-       }
-
-#ifdef CONFIG_SPARSEMEM
-       if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
-               free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION));
-#endif
-}
-#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
-
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much memory
  * is free.  This is done after various parts of the system have claimed their
@@ -510,9 +445,6 @@ void __init mem_init(void)
 
        set_max_mapnr(max_pfn - PHYS_PFN_OFFSET);
 
-#ifndef CONFIG_SPARSEMEM_VMEMMAP
-       free_unused_memmap();
-#endif
        /* this will put all unused low memory onto the freelists */
        memblock_free_all();
 
index b68ee86788af91f2ed3646543eec78404a72d52e..049df4163a976c84460b6a269725f9454b58dd92 100644 (file)
@@ -1926,6 +1926,85 @@ static int __init early_memblock(char *p)
 }
 early_param("memblock", early_memblock);
 
+static void __init free_memmap(unsigned long start_pfn, unsigned long end_pfn)
+{
+       struct page *start_pg, *end_pg;
+       phys_addr_t pg, pgend;
+
+       /*
+        * Convert start_pfn/end_pfn to a struct page pointer.
+        */
+       start_pg = pfn_to_page(start_pfn - 1) + 1;
+       end_pg = pfn_to_page(end_pfn - 1) + 1;
+
+       /*
+        * Convert to physical addresses, and round start upwards and end
+        * downwards.
+        */
+       pg = PAGE_ALIGN(__pa(start_pg));
+       pgend = __pa(end_pg) & PAGE_MASK;
+
+       /*
+        * If there are free pages between these, free the section of the
+        * memmap array.
+        */
+       if (pg < pgend)
+               memblock_free(pg, pgend - pg);
+}
+
+/*
+ * The mem_map array can get very big.  Free the unused area of the memory map.
+ */
+static void __init free_unused_memmap(void)
+{
+       unsigned long start, end, prev_end = 0;
+       int i;
+
+       if (!IS_ENABLED(CONFIG_HAVE_ARCH_PFN_VALID) ||
+           IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP))
+               return;
+
+       /*
+        * This relies on each bank being in address order.
+        * The banks are sorted previously in bootmem_init().
+        */
+       for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {
+#ifdef CONFIG_SPARSEMEM
+               /*
+                * Take care not to free memmap entries that don't exist
+                * due to SPARSEMEM sections which aren't present.
+                */
+               start = min(start, ALIGN(prev_end, PAGES_PER_SECTION));
+#else
+               /*
+                * Align down here since the VM subsystem insists that the
+                * memmap entries are valid from the bank start aligned to
+                * MAX_ORDER_NR_PAGES.
+                */
+               start = round_down(start, MAX_ORDER_NR_PAGES);
+#endif
+
+               /*
+                * If we had a previous bank, and there is a space
+                * between the current bank and the previous, free it.
+                */
+               if (prev_end && prev_end < start)
+                       free_memmap(prev_end, start);
+
+               /*
+                * Align up here since the VM subsystem insists that the
+                * memmap entries are valid from the bank end aligned to
+                * MAX_ORDER_NR_PAGES.
+                */
+               prev_end = ALIGN(end, MAX_ORDER_NR_PAGES);
+       }
+
+#ifdef CONFIG_SPARSEMEM
+       if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION))
+               free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION));
+#endif
+}
+
 static void __init __free_pages_memory(unsigned long start, unsigned long end)
 {
        int order;
@@ -2012,6 +2091,7 @@ unsigned long __init memblock_free_all(void)
 {
        unsigned long pages;
 
+       free_unused_memmap();
        reset_all_zones_managed_pages();
 
        pages = free_low_memory_core_early();