diff mbox series

[V5,2/4] LoongArch: Add sparse memory vmemmap support

Message ID 20220721130419.1904711-3-chenhuacai@loongson.cn (mailing list archive)
State Superseded
Headers show
Series mm/sparse-vmemmap: Generalise helpers and enable for LoongArch | expand

Commit Message

Huacai Chen July 21, 2022, 1:04 p.m. UTC
From: Feiyang Chen <chenfeiyang@loongson.cn>

Add sparse memory vmemmap support for LoongArch. SPARSEMEM_VMEMMAP
uses a virtually mapped memmap to optimise pfn_to_page and page_to_pfn
operations. This is the most efficient option when sufficient kernel
resources are available.

Signed-off-by: Min Zhou <zhoumin@loongson.cn>
Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
---
 arch/loongarch/Kconfig                 |  1 +
 arch/loongarch/include/asm/pgtable.h   |  5 +-
 arch/loongarch/include/asm/sparsemem.h |  8 +++
 arch/loongarch/mm/init.c               | 71 +++++++++++++++++++++++++-
 include/linux/mm.h                     |  2 +
 mm/sparse-vmemmap.c                    | 10 ++++
 6 files changed, 95 insertions(+), 2 deletions(-)

Comments

kernel test robot July 24, 2022, 4:07 a.m. UTC | #1
Hi Huacai,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on soc/for-next]
[also build test ERROR on linus/master v5.19-rc7 next-20220722]
[cannot apply to akpm-mm/mm-everything tip/x86/mm]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Huacai-Chen/mm-sparse-vmemmap-Generalise-helpers-and-enable-for-LoongArch/20220721-211006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git for-next
config: loongarch-allnoconfig (https://download.01.org/0day-ci/archive/20220724/202207241100.dTmn1Js6-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/46a065b827f834b046cffafc7fa165b6fadd9c5c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Huacai-Chen/mm-sparse-vmemmap-Generalise-helpers-and-enable-for-LoongArch/20220721-211006
        git checkout 46a065b827f834b046cffafc7fa165b6fadd9c5c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=loongarch SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   fs/proc/meminfo.c:22:28: warning: no previous prototype for 'arch_report_meminfo' [-Wmissing-prototypes]
      22 | void __attribute__((weak)) arch_report_meminfo(struct seq_file *m)
         |                            ^~~~~~~~~~~~~~~~~~~
   In file included from arch/loongarch/include/asm/uaccess.h:17,
                    from include/linux/uaccess.h:11,
                    from include/linux/sched/task.h:11,
                    from include/linux/sched/signal.h:9,
                    from include/linux/rcuwait.h:6,
                    from include/linux/percpu-rwsem.h:7,
                    from include/linux/fs.h:33,
                    from fs/proc/meminfo.c:2:
   fs/proc/meminfo.c: In function 'meminfo_proc_show':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   include/linux/vmalloc.h:286:24: note: in expansion of macro 'VMALLOC_END'
     286 | #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
         |                        ^~~~~~~~~~~
   fs/proc/meminfo.c:127:35: note: in expansion of macro 'VMALLOC_TOTAL'
     127 |                    (unsigned long)VMALLOC_TOTAL >> 10);
         |                                   ^~~~~~~~~~~~~
   arch/loongarch/include/asm/pgtable.h:95:119: note: each undeclared identifier is reported only once for each function it appears in
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   include/linux/vmalloc.h:286:24: note: in expansion of macro 'VMALLOC_END'
     286 | #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
         |                        ^~~~~~~~~~~
   fs/proc/meminfo.c:127:35: note: in expansion of macro 'VMALLOC_TOTAL'
     127 |                    (unsigned long)VMALLOC_TOTAL >> 10);
         |                                   ^~~~~~~~~~~~~
--
   In file included from include/linux/pgtable.h:6,
                    from include/linux/mm.h:29,
                    from mm/util.c:2:
   mm/util.c: In function 'kvmalloc_node':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/util.c:634:61: note: in expansion of macro 'VMALLOC_END'
     634 |         return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
         |                                                             ^~~~~~~~~~~
   arch/loongarch/include/asm/pgtable.h:95:119: note: each undeclared identifier is reported only once for each function it appears in
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/util.c:634:61: note: in expansion of macro 'VMALLOC_END'
     634 |         return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
         |                                                             ^~~~~~~~~~~
   mm/util.c:637:1: error: control reaches end of non-void function [-Werror=return-type]
     637 | }
         | ^
   cc1: some warnings being treated as errors
--
   In file included from include/linux/pgtable.h:6,
                    from include/linux/mm.h:29,
                    from mm/vmalloc.c:12:
   mm/vmalloc.c: In function 'is_vmalloc_addr':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:79:48: note: in expansion of macro 'VMALLOC_END'
      79 |         return addr >= VMALLOC_START && addr < VMALLOC_END;
         |                                                ^~~~~~~~~~~
   arch/loongarch/include/asm/pgtable.h:95:119: note: each undeclared identifier is reported only once for each function it appears in
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:79:48: note: in expansion of macro 'VMALLOC_END'
      79 |         return addr >= VMALLOC_START && addr < VMALLOC_END;
         |                                                ^~~~~~~~~~~
   mm/vmalloc.c: In function 'new_vmap_block':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:1915:56: note: in expansion of macro 'VMALLOC_END'
    1915 |                                         VMALLOC_START, VMALLOC_END,
         |                                                        ^~~~~~~~~~~
   In file included from include/linux/build_bug.h:5,
                    from include/linux/container_of.h:5,
                    from include/linux/list.h:5,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:55,
                    from include/linux/vmalloc.h:5,
                    from mm/vmalloc.c:11:
   mm/vmalloc.c: In function 'vm_unmap_ram':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   include/linux/compiler.h:78:45: note: in definition of macro 'unlikely'
      78 | # define unlikely(x)    __builtin_expect(!!(x), 0)
         |                                             ^
   mm/vmalloc.c:2166:9: note: in expansion of macro 'BUG_ON'
    2166 |         BUG_ON(addr > VMALLOC_END);
         |         ^~~~~~
   mm/vmalloc.c:2166:23: note: in expansion of macro 'VMALLOC_END'
    2166 |         BUG_ON(addr > VMALLOC_END);
         |                       ^~~~~~~~~~~
   mm/vmalloc.c: In function 'vm_map_ram':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:2213:48: note: in expansion of macro 'VMALLOC_END'
    2213 |                                 VMALLOC_START, VMALLOC_END, node, GFP_KERNEL);
         |                                                ^~~~~~~~~~~
   mm/vmalloc.c: In function 'vm_area_register_early':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   include/linux/compiler.h:78:45: note: in definition of macro 'unlikely'
      78 | # define unlikely(x)    __builtin_expect(!!(x), 0)
         |                                             ^
   mm/vmalloc.c:2309:9: note: in expansion of macro 'BUG_ON'
    2309 |         BUG_ON(addr > VMALLOC_END - vm->size);
         |         ^~~~~~
   mm/vmalloc.c:2309:23: note: in expansion of macro 'VMALLOC_END'
    2309 |         BUG_ON(addr > VMALLOC_END - vm->size);
         |                       ^~~~~~~~~~~
   mm/vmalloc.c: In function 'get_vm_area':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:2498:50: note: in expansion of macro 'VMALLOC_END'
    2498 |                                   VMALLOC_START, VMALLOC_END,
         |                                                  ^~~~~~~~~~~
   mm/vmalloc.c: In function 'get_vm_area_caller':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:2507:50: note: in expansion of macro 'VMALLOC_END'
    2507 |                                   VMALLOC_START, VMALLOC_END,
         |                                                  ^~~~~~~~~~~
   mm/vmalloc.c: In function '__vmalloc_node':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:3230:65: note: in expansion of macro 'VMALLOC_END'
    3230 |         return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
         |                                                                 ^~~~~~~~~~~
   mm/vmalloc.c: In function 'vmalloc_huge':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:3282:61: note: in expansion of macro 'VMALLOC_END'
    3282 |         return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
         |                                                             ^~~~~~~~~~~
   mm/vmalloc.c: In function 'vmalloc_user':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:3319:67: note: in expansion of macro 'VMALLOC_END'
    3319 |         return __vmalloc_node_range(size, SHMLBA,  VMALLOC_START, VMALLOC_END,
         |                                                                   ^~~~~~~~~~~
   mm/vmalloc.c: In function 'vmalloc_32_user':
>> arch/loongarch/include/asm/pgtable.h:95:119: error: 'VMEMMAP_SIZE' undeclared (first use in this function); did you mean 'VMEMMAP_END'?
      95 |          min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
         |                                                                                                                       ^~~~~~~~~~~~
   mm/vmalloc.c:3403:67: note: in expansion of macro 'VMALLOC_END'
    3403 |         return __vmalloc_node_range(size, SHMLBA,  VMALLOC_START, VMALLOC_END,
         |                                                                   ^~~~~~~~~~~
   mm/vmalloc.c: In function 'is_vmalloc_addr':
   mm/vmalloc.c:80:1: error: control reaches end of non-void function [-Werror=return-type]
      80 | }
         | ^
   mm/vmalloc.c: In function 'get_vm_area':
   mm/vmalloc.c:2501:1: error: control reaches end of non-void function [-Werror=return-type]
    2501 | }
         | ^
   mm/vmalloc.c: In function 'get_vm_area_caller':
   mm/vmalloc.c:2509:1: error: control reaches end of non-void function [-Werror=return-type]
    2509 | }
         | ^
   mm/vmalloc.c: In function '__vmalloc_node':
   mm/vmalloc.c:3232:1: error: control reaches end of non-void function [-Werror=return-type]
    3232 | }
         | ^
   mm/vmalloc.c: In function 'vmalloc_huge':
   mm/vmalloc.c:3285:1: error: control reaches end of non-void function [-Werror=return-type]
    3285 | }
         | ^
   mm/vmalloc.c: In function 'vmalloc_user':
   mm/vmalloc.c:3323:1: error: control reaches end of non-void function [-Werror=return-type]
    3323 | }
         | ^
   mm/vmalloc.c: In function 'vmalloc_32_user':
   mm/vmalloc.c:3407:1: error: control reaches end of non-void function [-Werror=return-type]
    3407 | }
         | ^
   cc1: some warnings being treated as errors


vim +95 arch/loongarch/include/asm/pgtable.h

    91	
    92	#define VMALLOC_START	MODULES_END
    93	#define VMALLOC_END	\
    94		(vm_map_base +	\
  > 95		 min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
    96
kernel test robot July 24, 2022, 4:38 a.m. UTC | #2
Hi Huacai,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on soc/for-next]
[also build test ERROR on kvm/queue arm64/for-next/core linus/master v5.19-rc7 next-20220722]
[cannot apply to akpm-mm/mm-everything tip/x86/mm]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Huacai-Chen/mm-sparse-vmemmap-Generalise-helpers-and-enable-for-LoongArch/20220721-211006
base:   https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git for-next
config: nios2-allnoconfig (https://download.01.org/0day-ci/archive/20220724/202207241246.ZV8cRK1g-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/46a065b827f834b046cffafc7fa165b6fadd9c5c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Huacai-Chen/mm-sparse-vmemmap-Generalise-helpers-and-enable-for-LoongArch/20220721-211006
        git checkout 46a065b827f834b046cffafc7fa165b6fadd9c5c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=nios2 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from kernel/fork.c:102:
>> arch/nios2/include/asm/pgalloc.h:32:13: error: conflicting types for 'pmd_init'; have 'void(long unsigned int,  long unsigned int)'
      32 | extern void pmd_init(unsigned long page, unsigned long pagetable);
         |             ^~~~~~~~
   In file included from include/linux/pid_namespace.h:7,
                    from include/linux/ptrace.h:10,
                    from arch/nios2/include/uapi/asm/elf.h:24,
                    from arch/nios2/include/asm/elf.h:9,
                    from include/linux/elf.h:6,
                    from include/linux/module.h:19,
                    from kernel/fork.c:30:
   include/linux/mm.h:3206:6: note: previous declaration of 'pmd_init' with type 'void(void *)'
    3206 | void pmd_init(void *addr);
         |      ^~~~~~~~
   kernel/fork.c:163:13: warning: no previous prototype for 'arch_release_task_struct' [-Wmissing-prototypes]
     163 | void __weak arch_release_task_struct(struct task_struct *tsk)
         |             ^~~~~~~~~~~~~~~~~~~~~~~~
   kernel/fork.c:852:20: warning: no previous prototype for 'arch_task_cache_init' [-Wmissing-prototypes]
     852 | void __init __weak arch_task_cache_init(void) { }
         |                    ^~~~~~~~~~~~~~~~~~~~
   kernel/fork.c:947:12: warning: no previous prototype for 'arch_dup_task_struct' [-Wmissing-prototypes]
     947 | int __weak arch_dup_task_struct(struct task_struct *dst,
         |            ^~~~~~~~~~~~~~~~~~~~
--
   In file included from mm/filemap.c:45:
>> arch/nios2/include/asm/pgalloc.h:32:13: error: conflicting types for 'pmd_init'; have 'void(long unsigned int,  long unsigned int)'
      32 | extern void pmd_init(unsigned long page, unsigned long pagetable);
         |             ^~~~~~~~
   In file included from include/linux/dax.h:6,
                    from mm/filemap.c:15:
   include/linux/mm.h:3206:6: note: previous declaration of 'pmd_init' with type 'void(void *)'
    3206 | void pmd_init(void *addr);
         |      ^~~~~~~~


vim +32 arch/nios2/include/asm/pgalloc.h

cbd15b3fadc27e Ley Foon Tan 2014-11-06  28  
cbd15b3fadc27e Ley Foon Tan 2014-11-06  29  /*
cbd15b3fadc27e Ley Foon Tan 2014-11-06  30   * Initialize a new pmd table with invalid pointers.
cbd15b3fadc27e Ley Foon Tan 2014-11-06  31   */
cbd15b3fadc27e Ley Foon Tan 2014-11-06 @32  extern void pmd_init(unsigned long page, unsigned long pagetable);
cbd15b3fadc27e Ley Foon Tan 2014-11-06  33
diff mbox series

Patch

diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 516a4ebbd97e..f3ff806317ac 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -418,6 +418,7 @@  config ARCH_FLATMEM_ENABLE
 
 config ARCH_SPARSEMEM_ENABLE
 	def_bool y
+	select SPARSEMEM_VMEMMAP_ENABLE
 	help
 	  Say Y to support efficient handling of sparse physical memory,
 	  for architectures which are either NUMA (Non-Uniform Memory Access)
diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
index 9c811c3f7572..b701ec7a0309 100644
--- a/arch/loongarch/include/asm/pgtable.h
+++ b/arch/loongarch/include/asm/pgtable.h
@@ -92,7 +92,10 @@  extern unsigned long zero_page_mask;
 #define VMALLOC_START	MODULES_END
 #define VMALLOC_END	\
 	(vm_map_base +	\
-	 min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE)
+	 min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, (1UL << cpu_vabits)) - PMD_SIZE - VMEMMAP_SIZE)
+
+#define vmemmap		((struct page *)((VMALLOC_END + PMD_SIZE) & PMD_MASK))
+#define VMEMMAP_END	((unsigned long)vmemmap + VMEMMAP_SIZE - 1)
 
 #define pte_ERROR(e) \
 	pr_err("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
diff --git a/arch/loongarch/include/asm/sparsemem.h b/arch/loongarch/include/asm/sparsemem.h
index 3d18cdf1b069..a1e440f6bec7 100644
--- a/arch/loongarch/include/asm/sparsemem.h
+++ b/arch/loongarch/include/asm/sparsemem.h
@@ -11,6 +11,14 @@ 
 #define SECTION_SIZE_BITS	29 /* 2^29 = Largest Huge Page Size */
 #define MAX_PHYSMEM_BITS	48
 
+#ifndef CONFIG_SPARSEMEM_VMEMMAP
+#define VMEMMAP_SIZE	0
+#else
+#define VMEMMAP_SIZE	(sizeof(struct page) * (1UL << (cpu_pabits + 1 - PAGE_SHIFT)))
+#endif
+
+#include <linux/mm_types.h>
+
 #endif /* CONFIG_SPARSEMEM */
 
 #ifdef CONFIG_MEMORY_HOTPLUG
diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c
index 7094a68c9b83..35128229fe46 100644
--- a/arch/loongarch/mm/init.c
+++ b/arch/loongarch/mm/init.c
@@ -22,7 +22,7 @@ 
 #include <linux/pfn.h>
 #include <linux/hardirq.h>
 #include <linux/gfp.h>
-#include <linux/initrd.h>
+#include <linux/hugetlb.h>
 #include <linux/mmzone.h>
 
 #include <asm/asm-offsets.h>
@@ -157,6 +157,75 @@  void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap)
 #endif
 #endif
 
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+int __meminit vmemmap_populate_hugepages(unsigned long start, unsigned long end,
+					 int node, struct vmem_altmap *altmap)
+{
+	unsigned long addr = start;
+	unsigned long next;
+	pgd_t *pgd;
+	p4d_t *p4d;
+	pud_t *pud;
+	pmd_t *pmd;
+
+	for (addr = start; addr < end; addr = next) {
+		next = pmd_addr_end(addr, end);
+
+		pgd = vmemmap_pgd_populate(addr, node);
+		if (!pgd)
+			return -ENOMEM;
+		p4d = vmemmap_p4d_populate(pgd, addr, node);
+		if (!p4d)
+			return -ENOMEM;
+		pud = vmemmap_pud_populate(p4d, addr, node);
+		if (!pud)
+			return -ENOMEM;
+
+		pmd = pmd_offset(pud, addr);
+		if (pmd_none(*pmd)) {
+			void *p = NULL;
+
+			p = vmemmap_alloc_block_buf(PMD_SIZE, node, NULL);
+			if (p) {
+				pmd_t entry;
+
+				entry = pfn_pmd(virt_to_pfn(p), PAGE_KERNEL);
+				pmd_val(entry) |= _PAGE_HUGE | _PAGE_HGLOBAL;
+				set_pmd_at(&init_mm, addr, pmd, entry);
+
+				continue;
+			}
+		} else if (pmd_val(*pmd) & _PAGE_HUGE) {
+			vmemmap_verify((pte_t *)pmd, node, addr, next);
+			continue;
+		}
+		if (vmemmap_populate_basepages(addr, next, node, NULL))
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+#if CONFIG_PGTABLE_LEVELS == 2
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
+		struct vmem_altmap *altmap)
+{
+	return vmemmap_populate_basepages(start, end, node, NULL);
+}
+#else
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
+		struct vmem_altmap *altmap)
+{
+	return vmemmap_populate_hugepages(start, end, node, NULL);
+}
+#endif
+
+void vmemmap_free(unsigned long start, unsigned long end,
+		struct vmem_altmap *altmap)
+{
+}
+#endif
+
 /*
  * Align swapper_pg_dir in to 64K, allows its address to be loaded
  * with a single LUI instruction in the TLB handlers.  If we used
diff --git a/include/linux/mm.h b/include/linux/mm.h
index cf3d0d673f6b..f6ed6bc0a65f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3203,6 +3203,8 @@  void *sparse_buffer_alloc(unsigned long size);
 struct page * __populate_section_memmap(unsigned long pfn,
 		unsigned long nr_pages, int nid, struct vmem_altmap *altmap,
 		struct dev_pagemap *pgmap);
+void pmd_init(void *addr);
+void pud_init(void *addr);
 pgd_t *vmemmap_pgd_populate(unsigned long addr, int node);
 p4d_t *vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node);
 pud_t *vmemmap_pud_populate(p4d_t *p4d, unsigned long addr, int node);
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index dbbd1a7e65f3..0abcb0a5f1b5 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -595,6 +595,10 @@  pmd_t * __meminit vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node)
 	return pmd;
 }
 
+void __weak __meminit pmd_init(void *addr)
+{
+}
+
 pud_t * __meminit vmemmap_pud_populate(p4d_t *p4d, unsigned long addr, int node)
 {
 	pud_t *pud = pud_offset(p4d, addr);
@@ -602,11 +606,16 @@  pud_t * __meminit vmemmap_pud_populate(p4d_t *p4d, unsigned long addr, int node)
 		void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node);
 		if (!p)
 			return NULL;
+		pmd_init(p);
 		pud_populate(&init_mm, pud, p);
 	}
 	return pud;
 }
 
+void __weak __meminit pud_init(void *addr)
+{
+}
+
 p4d_t * __meminit vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node)
 {
 	p4d_t *p4d = p4d_offset(pgd, addr);
@@ -614,6 +623,7 @@  p4d_t * __meminit vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node)
 		void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node);
 		if (!p)
 			return NULL;
+		pud_init(p);
 		p4d_populate(&init_mm, p4d, p);
 	}
 	return p4d;