aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Picco <bob.picco@hp.com>2005-09-03 18:54:28 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:38 -0400
commit3e347261a80b57df792ab9464b5f0ed59add53a8 (patch)
tree047b35e0f9ec82b3beeff882a9af6292a500097c
parent802f192e4a600f7ef84ca25c8b818c8830acef5a (diff)
[PATCH] sparsemem extreme implementation
With cleanups from Dave Hansen <haveblue@us.ibm.com> SPARSEMEM_EXTREME makes mem_section a one dimensional array of pointers to mem_sections. This two level layout scheme is able to achieve smaller memory requirements for SPARSEMEM with the tradeoff of an additional shift and load when fetching the memory section. The current SPARSEMEM implementation is a one dimensional array of mem_sections which is the default SPARSEMEM configuration. The patch attempts isolates the implementation details of the physical layout of the sparsemem section array. SPARSEMEM_EXTREME requires bootmem to be functioning at the time of memory_present() calls. This is not always feasible, so architectures which do not need it may allocate everything statically by using SPARSEMEM_STATIC. Signed-off-by: Andy Whitcroft <apw@shadowen.org> Signed-off-by: Bob Picco <bob.picco@hp.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>
-rw-r--r--arch/i386/Kconfig1
-rw-r--r--include/linux/mmzone.h40
-rw-r--r--mm/Kconfig19
-rw-r--r--mm/sparse.c26
4 files changed, 49 insertions, 37 deletions
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 619d843ba231..dcb0ad098c60 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -754,6 +754,7 @@ config NUMA
754 depends on SMP && HIGHMEM64G && (X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI)) 754 depends on SMP && HIGHMEM64G && (X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI))
755 default n if X86_PC 755 default n if X86_PC
756 default y if (X86_NUMAQ || X86_SUMMIT) 756 default y if (X86_NUMAQ || X86_SUMMIT)
757 select SPARSEMEM_STATIC
757 758
758# Need comments to help the hapless user trying to turn on NUMA support 759# Need comments to help the hapless user trying to turn on NUMA support
759comment "NUMA (NUMA-Q) requires SMP, 64GB highmem support" 760comment "NUMA (NUMA-Q) requires SMP, 64GB highmem support"
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index b97054bbc394..79cf578e21b9 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -487,39 +487,29 @@ struct mem_section {
487 unsigned long section_mem_map; 487 unsigned long section_mem_map;
488}; 488};
489 489
490#ifdef CONFIG_ARCH_SPARSEMEM_EXTREME 490#ifdef CONFIG_SPARSEMEM_EXTREME
491/* 491#define SECTIONS_PER_ROOT (PAGE_SIZE / sizeof (struct mem_section))
492 * Should we ever require GCC 4 or later then the flat array scheme 492#else
493 * can be eliminated and a uniform solution for EXTREME and !EXTREME can 493#define SECTIONS_PER_ROOT 1
494 * be arrived at. 494#endif
495 */
496#define SECTION_ROOT_SHIFT (PAGE_SHIFT-3)
497#define SECTION_ROOT_MASK ((1UL<<SECTION_ROOT_SHIFT) - 1)
498#define SECTION_TO_ROOT(_sec) ((_sec) >> SECTION_ROOT_SHIFT)
499#define NR_SECTION_ROOTS (NR_MEM_SECTIONS >> SECTION_ROOT_SHIFT)
500 495
501extern struct mem_section *mem_section[NR_SECTION_ROOTS]; 496#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT)
502 497#define NR_SECTION_ROOTS (NR_MEM_SECTIONS / SECTIONS_PER_ROOT)
503static inline struct mem_section *__nr_to_section(unsigned long nr) 498#define SECTION_ROOT_MASK (SECTIONS_PER_ROOT - 1)
504{
505 if (!mem_section[SECTION_TO_ROOT(nr)])
506 return NULL;
507 return &mem_section[SECTION_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
508}
509 499
500#ifdef CONFIG_SPARSEMEM_EXTREME
501extern struct mem_section *mem_section[NR_SECTION_ROOTS];
510#else 502#else
511 503extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT];
512extern struct mem_section mem_section[NR_MEM_SECTIONS]; 504#endif
513 505
514static inline struct mem_section *__nr_to_section(unsigned long nr) 506static inline struct mem_section *__nr_to_section(unsigned long nr)
515{ 507{
516 return &mem_section[nr]; 508 if (!mem_section[SECTION_NR_TO_ROOT(nr)])
509 return NULL;
510 return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK];
517} 511}
518 512
519#define sparse_index_init(_sec, _nid) do {} while (0)
520
521#endif
522
523/* 513/*
524 * We use the lower bits of the mem_map pointer to store 514 * We use the lower bits of the mem_map pointer to store
525 * a little bit of information. There should be at least 515 * a little bit of information. There should be at least
diff --git a/mm/Kconfig b/mm/Kconfig
index fc644c5c065d..4e9937ac3529 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -91,10 +91,23 @@ config HAVE_MEMORY_PRESENT
91 depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM 91 depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM
92 92
93# 93#
94# SPARSEMEM_EXTREME (which is the default) does some bootmem
95# allocations when memory_present() is called. If this can not
96# be done on your architecture, select this option. However,
97# statically allocating the mem_section[] array can potentially
98# consume vast quantities of .bss, so be careful.
99#
100# This option will also potentially produce smaller runtime code
101# with gcc 3.4 and later.
102#
103config SPARSEMEM_STATIC
104 def_bool n
105
106#
94# Architectecture platforms which require a two level mem_section in SPARSEMEM 107# Architectecture platforms which require a two level mem_section in SPARSEMEM
95# must select this option. This is usually for architecture platforms with 108# must select this option. This is usually for architecture platforms with
96# an extremely sparse physical address space. 109# an extremely sparse physical address space.
97# 110#
98config ARCH_SPARSEMEM_EXTREME 111config SPARSEMEM_EXTREME
99 def_bool n 112 def_bool y
100 depends on SPARSEMEM && 64BIT 113 depends on SPARSEMEM && !SPARSEMEM_STATIC
diff --git a/mm/sparse.c b/mm/sparse.c
index b2b456bf0a5d..fa01292157a9 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -13,28 +13,36 @@
13 * 13 *
14 * 1) mem_section - memory sections, mem_map's for valid memory 14 * 1) mem_section - memory sections, mem_map's for valid memory
15 */ 15 */
16#ifdef CONFIG_ARCH_SPARSEMEM_EXTREME 16#ifdef CONFIG_SPARSEMEM_EXTREME
17struct mem_section *mem_section[NR_SECTION_ROOTS] 17struct mem_section *mem_section[NR_SECTION_ROOTS]
18 ____cacheline_maxaligned_in_smp; 18 ____cacheline_maxaligned_in_smp;
19#else
20struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]
21 ____cacheline_maxaligned_in_smp;
22#endif
23EXPORT_SYMBOL(mem_section);
24
25static void sparse_alloc_root(unsigned long root, int nid)
26{
27#ifdef CONFIG_SPARSEMEM_EXTREME
28 mem_section[root] = alloc_bootmem_node(NODE_DATA(nid), PAGE_SIZE);
29#endif
30}
19 31
20static void sparse_index_init(unsigned long section, int nid) 32static void sparse_index_init(unsigned long section, int nid)
21{ 33{
22 unsigned long root = SECTION_TO_ROOT(section); 34 unsigned long root = SECTION_NR_TO_ROOT(section);
23 35
24 if (mem_section[root]) 36 if (mem_section[root])
25 return; 37 return;
26 mem_section[root] = alloc_bootmem_node(NODE_DATA(nid), PAGE_SIZE); 38
39 sparse_alloc_root(root, nid);
40
27 if (mem_section[root]) 41 if (mem_section[root])
28 memset(mem_section[root], 0, PAGE_SIZE); 42 memset(mem_section[root], 0, PAGE_SIZE);
29 else 43 else
30 panic("memory_present: NO MEMORY\n"); 44 panic("memory_present: NO MEMORY\n");
31} 45}
32#else
33struct mem_section mem_section[NR_MEM_SECTIONS]
34 ____cacheline_maxaligned_in_smp;
35#endif
36EXPORT_SYMBOL(mem_section);
37
38/* Record a memory area against a node. */ 46/* Record a memory area against a node. */
39void memory_present(int nid, unsigned long start, unsigned long end) 47void memory_present(int nid, unsigned long start, unsigned long end)
40{ 48{