Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] add x86-64 specific support for sparsemem

This patch adds in the necessary support for sparsemem such that x86-64
kernels may use sparsemem as an alternative to discontigmem for NUMA
kernels. Note that this does no preclude one from continuing to build NUMA
kernels using discontigmem, but merely allows the option to build NUMA
kernels with sparsemem.

Interestingly, the use of sparsemem in lieu of discontigmem in NUMA kernels
results in reduced text size for otherwise equivalent kernels as shown in
the example builds below:

text data bss dec hex filename
2371036 765884 1237108 4374028 42be0c vmlinux.discontig
2366549 776484 1302772 4445805 43d66d vmlinux.sparse

Signed-off-by: Matt Tolentino <matthew.e.tolentino@intel.com>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Matt Tolentino and committed by
Linus Torvalds
bbfceef4 2b97690f

+51 -12
+17 -10
arch/x86_64/kernel/setup.c
··· 40 40 #include <linux/acpi.h> 41 41 #include <linux/kallsyms.h> 42 42 #include <linux/edd.h> 43 + #include <linux/mmzone.h> 44 + 43 45 #include <asm/mtrr.h> 44 46 #include <asm/uaccess.h> 45 47 #include <asm/system.h> ··· 380 378 } 381 379 382 380 #ifndef CONFIG_NUMA 383 - static void __init contig_initmem_init(void) 381 + static void __init 382 + contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn) 384 383 { 385 - unsigned long bootmap_size, bootmap; 386 - bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT; 387 - bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size); 388 - if (bootmap == -1L) 389 - panic("Cannot find bootmem map of size %ld\n",bootmap_size); 390 - bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn); 391 - e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT); 392 - reserve_bootmem(bootmap, bootmap_size); 384 + unsigned long bootmap_size, bootmap; 385 + 386 + memory_present(0, start_pfn, end_pfn); 387 + bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT; 388 + bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size); 389 + if (bootmap == -1L) 390 + panic("Cannot find bootmem map of size %ld\n",bootmap_size); 391 + bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn); 392 + e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT); 393 + reserve_bootmem(bootmap, bootmap_size); 393 394 } 394 395 #endif 395 396 ··· 562 557 #ifdef CONFIG_NUMA 563 558 numa_initmem_init(0, end_pfn); 564 559 #else 565 - contig_initmem_init(); 560 + contig_initmem_init(0, end_pfn); 566 561 #endif 567 562 568 563 /* Reserve direct mapping */ ··· 623 618 } 624 619 } 625 620 #endif 621 + 622 + sparse_init(); 626 623 paging_init(); 627 624 628 625 check_ioapic();
+8
arch/x86_64/mm/numa.c
··· 66 66 return -1; 67 67 } 68 68 69 + #ifdef CONFIG_SPARSEMEM 70 + int early_pfn_to_nid(unsigned long pfn) 71 + { 72 + return phys_to_nid(pfn << PAGE_SHIFT); 73 + } 74 + #endif 75 + 69 76 /* Initialize bootmem allocator for a node */ 70 77 void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) 71 78 { ··· 87 80 start_pfn = start >> PAGE_SHIFT; 88 81 end_pfn = end >> PAGE_SHIFT; 89 82 83 + memory_present(nodeid, start_pfn, end_pfn); 90 84 nodedata_phys = find_e820_area(start, end, pgdat_size); 91 85 if (nodedata_phys == -1L) 92 86 panic("Cannot find memory pgdat in node %d\n", nodeid);
-2
include/asm-x86_64/bitops.h
··· 411 411 /* find last set bit */ 412 412 #define fls(x) generic_fls(x) 413 413 414 - #define ARCH_HAS_ATOMIC_UNSIGNED 1 415 - 416 414 #endif /* __KERNEL__ */ 417 415 418 416 #endif /* _X86_64_BITOPS_H */
+26
include/asm-x86_64/sparsemem.h
··· 1 + #ifndef _ASM_X86_64_SPARSEMEM_H 2 + #define _ASM_X86_64_SPARSEMEM_H 1 3 + 4 + #ifdef CONFIG_SPARSEMEM 5 + 6 + /* 7 + * generic non-linear memory support: 8 + * 9 + * 1) we will not split memory into more chunks than will fit into the flags 10 + * field of the struct page 11 + * 12 + * SECTION_SIZE_BITS 2^n: size of each section 13 + * MAX_PHYSADDR_BITS 2^n: max size of physical address space 14 + * MAX_PHYSMEM_BITS 2^n: how much memory we can have in that space 15 + * 16 + */ 17 + 18 + #define SECTION_SIZE_BITS 27 /* matt - 128 is convenient right now */ 19 + #define MAX_PHYSADDR_BITS 40 20 + #define MAX_PHYSMEM_BITS 40 21 + 22 + extern int early_pfn_to_nid(unsigned long pfn); 23 + 24 + #endif /* CONFIG_SPARSEMEM */ 25 + 26 + #endif /* _ASM_X86_64_SPARSEMEM_H */