diff options
-rw-r--r-- | include/linux/memblock.h | 26 | ||||
-rw-r--r-- | include/linux/mm.h | 2 | ||||
-rw-r--r-- | mm/Kconfig | 3 | ||||
-rw-r--r-- | mm/memblock.c | 142 | ||||
-rw-r--r-- | mm/page_alloc.c | 47 |
5 files changed, 183 insertions, 37 deletions
diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 434b958a4f5f..c36a55d3c1c2 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h | |||
@@ -24,6 +24,9 @@ | |||
24 | struct memblock_region { | 24 | struct memblock_region { |
25 | phys_addr_t base; | 25 | phys_addr_t base; |
26 | phys_addr_t size; | 26 | phys_addr_t size; |
27 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP | ||
28 | int nid; | ||
29 | #endif | ||
27 | }; | 30 | }; |
28 | 31 | ||
29 | struct memblock_type { | 32 | struct memblock_type { |
@@ -58,6 +61,29 @@ extern long memblock_remove(phys_addr_t base, phys_addr_t size); | |||
58 | extern long memblock_free(phys_addr_t base, phys_addr_t size); | 61 | extern long memblock_free(phys_addr_t base, phys_addr_t size); |
59 | extern long memblock_reserve(phys_addr_t base, phys_addr_t size); | 62 | extern long memblock_reserve(phys_addr_t base, phys_addr_t size); |
60 | 63 | ||
64 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP | ||
65 | extern int memblock_set_node(phys_addr_t base, phys_addr_t size, int nid); | ||
66 | |||
67 | static inline void memblock_set_region_node(struct memblock_region *r, int nid) | ||
68 | { | ||
69 | r->nid = nid; | ||
70 | } | ||
71 | |||
72 | static inline int memblock_get_region_node(const struct memblock_region *r) | ||
73 | { | ||
74 | return r->nid; | ||
75 | } | ||
76 | #else | ||
77 | static inline void memblock_set_region_node(struct memblock_region *r, int nid) | ||
78 | { | ||
79 | } | ||
80 | |||
81 | static inline int memblock_get_region_node(const struct memblock_region *r) | ||
82 | { | ||
83 | return 0; | ||
84 | } | ||
85 | #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ | ||
86 | |||
61 | /* The numa aware allocator is only available if | 87 | /* The numa aware allocator is only available if |
62 | * CONFIG_ARCH_POPULATES_NODE_MAP is set | 88 | * CONFIG_ARCH_POPULATES_NODE_MAP is set |
63 | */ | 89 | */ |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 9ebc65ae6863..ceb1e4a1a736 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -1307,12 +1307,14 @@ extern void free_area_init_node(int nid, unsigned long * zones_size, | |||
1307 | * CONFIG_ARCH_POPULATES_NODE_MAP | 1307 | * CONFIG_ARCH_POPULATES_NODE_MAP |
1308 | */ | 1308 | */ |
1309 | extern void free_area_init_nodes(unsigned long *max_zone_pfn); | 1309 | extern void free_area_init_nodes(unsigned long *max_zone_pfn); |
1310 | #ifndef CONFIG_HAVE_MEMBLOCK_NODE_MAP | ||
1310 | extern void add_active_range(unsigned int nid, unsigned long start_pfn, | 1311 | extern void add_active_range(unsigned int nid, unsigned long start_pfn, |
1311 | unsigned long end_pfn); | 1312 | unsigned long end_pfn); |
1312 | extern void remove_active_range(unsigned int nid, unsigned long start_pfn, | 1313 | extern void remove_active_range(unsigned int nid, unsigned long start_pfn, |
1313 | unsigned long end_pfn); | 1314 | unsigned long end_pfn); |
1314 | extern void remove_all_active_ranges(void); | 1315 | extern void remove_all_active_ranges(void); |
1315 | void sort_node_map(void); | 1316 | void sort_node_map(void); |
1317 | #endif | ||
1316 | unsigned long node_map_pfn_alignment(void); | 1318 | unsigned long node_map_pfn_alignment(void); |
1317 | unsigned long __absent_pages_in_range(int nid, unsigned long start_pfn, | 1319 | unsigned long __absent_pages_in_range(int nid, unsigned long start_pfn, |
1318 | unsigned long end_pfn); | 1320 | unsigned long end_pfn); |
diff --git a/mm/Kconfig b/mm/Kconfig index 8ca47a5ee9c8..30a5d4792b83 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
@@ -131,6 +131,9 @@ config SPARSEMEM_VMEMMAP | |||
131 | config HAVE_MEMBLOCK | 131 | config HAVE_MEMBLOCK |
132 | boolean | 132 | boolean |
133 | 133 | ||
134 | config HAVE_MEMBLOCK_NODE_MAP | ||
135 | boolean | ||
136 | |||
134 | # eventually, we can have this option just 'select SPARSEMEM' | 137 | # eventually, we can have this option just 'select SPARSEMEM' |
135 | config MEMORY_HOTPLUG | 138 | config MEMORY_HOTPLUG |
136 | bool "Allow for memory hot-add" | 139 | bool "Allow for memory hot-add" |
diff --git a/mm/memblock.c b/mm/memblock.c index 992aa1807473..e815f4b75809 100644 --- a/mm/memblock.c +++ b/mm/memblock.c | |||
@@ -161,12 +161,8 @@ int __init_memblock memblock_reserve_reserved_regions(void) | |||
161 | 161 | ||
162 | static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) | 162 | static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r) |
163 | { | 163 | { |
164 | unsigned long i; | 164 | memmove(&type->regions[r], &type->regions[r + 1], |
165 | 165 | (type->cnt - (r + 1)) * sizeof(type->regions[r])); | |
166 | for (i = r; i < type->cnt - 1; i++) { | ||
167 | type->regions[i].base = type->regions[i + 1].base; | ||
168 | type->regions[i].size = type->regions[i + 1].size; | ||
169 | } | ||
170 | type->cnt--; | 166 | type->cnt--; |
171 | 167 | ||
172 | /* Special case for empty arrays */ | 168 | /* Special case for empty arrays */ |
@@ -174,6 +170,7 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u | |||
174 | type->cnt = 1; | 170 | type->cnt = 1; |
175 | type->regions[0].base = 0; | 171 | type->regions[0].base = 0; |
176 | type->regions[0].size = 0; | 172 | type->regions[0].size = 0; |
173 | memblock_set_region_node(&type->regions[0], MAX_NUMNODES); | ||
177 | } | 174 | } |
178 | } | 175 | } |
179 | 176 | ||
@@ -266,7 +263,9 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type) | |||
266 | struct memblock_region *this = &type->regions[i]; | 263 | struct memblock_region *this = &type->regions[i]; |
267 | struct memblock_region *next = &type->regions[i + 1]; | 264 | struct memblock_region *next = &type->regions[i + 1]; |
268 | 265 | ||
269 | if (this->base + this->size != next->base) { | 266 | if (this->base + this->size != next->base || |
267 | memblock_get_region_node(this) != | ||
268 | memblock_get_region_node(next)) { | ||
270 | BUG_ON(this->base + this->size > next->base); | 269 | BUG_ON(this->base + this->size > next->base); |
271 | i++; | 270 | i++; |
272 | continue; | 271 | continue; |
@@ -290,7 +289,7 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type) | |||
290 | */ | 289 | */ |
291 | static void __init_memblock memblock_insert_region(struct memblock_type *type, | 290 | static void __init_memblock memblock_insert_region(struct memblock_type *type, |
292 | int idx, phys_addr_t base, | 291 | int idx, phys_addr_t base, |
293 | phys_addr_t size) | 292 | phys_addr_t size, int nid) |
294 | { | 293 | { |
295 | struct memblock_region *rgn = &type->regions[idx]; | 294 | struct memblock_region *rgn = &type->regions[idx]; |
296 | 295 | ||
@@ -298,6 +297,7 @@ static void __init_memblock memblock_insert_region(struct memblock_type *type, | |||
298 | memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn)); | 297 | memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn)); |
299 | rgn->base = base; | 298 | rgn->base = base; |
300 | rgn->size = size; | 299 | rgn->size = size; |
300 | memblock_set_region_node(rgn, nid); | ||
301 | type->cnt++; | 301 | type->cnt++; |
302 | } | 302 | } |
303 | 303 | ||
@@ -327,6 +327,7 @@ static long __init_memblock memblock_add_region(struct memblock_type *type, | |||
327 | WARN_ON(type->cnt != 1); | 327 | WARN_ON(type->cnt != 1); |
328 | type->regions[0].base = base; | 328 | type->regions[0].base = base; |
329 | type->regions[0].size = size; | 329 | type->regions[0].size = size; |
330 | memblock_set_region_node(&type->regions[0], MAX_NUMNODES); | ||
330 | return 0; | 331 | return 0; |
331 | } | 332 | } |
332 | repeat: | 333 | repeat: |
@@ -355,7 +356,7 @@ repeat: | |||
355 | nr_new++; | 356 | nr_new++; |
356 | if (insert) | 357 | if (insert) |
357 | memblock_insert_region(type, i++, base, | 358 | memblock_insert_region(type, i++, base, |
358 | rbase - base); | 359 | rbase - base, MAX_NUMNODES); |
359 | } | 360 | } |
360 | /* area below @rend is dealt with, forget about it */ | 361 | /* area below @rend is dealt with, forget about it */ |
361 | base = min(rend, end); | 362 | base = min(rend, end); |
@@ -365,7 +366,8 @@ repeat: | |||
365 | if (base < end) { | 366 | if (base < end) { |
366 | nr_new++; | 367 | nr_new++; |
367 | if (insert) | 368 | if (insert) |
368 | memblock_insert_region(type, i, base, end - base); | 369 | memblock_insert_region(type, i, base, end - base, |
370 | MAX_NUMNODES); | ||
369 | } | 371 | } |
370 | 372 | ||
371 | /* | 373 | /* |
@@ -459,6 +461,101 @@ long __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) | |||
459 | return memblock_add_region(_rgn, base, size); | 461 | return memblock_add_region(_rgn, base, size); |
460 | } | 462 | } |
461 | 463 | ||
464 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP | ||
465 | /* | ||
466 | * Common iterator interface used to define for_each_mem_range(). | ||
467 | */ | ||
468 | void __init_memblock __next_mem_pfn_range(int *idx, int nid, | ||
469 | unsigned long *out_start_pfn, | ||
470 | unsigned long *out_end_pfn, int *out_nid) | ||
471 | { | ||
472 | struct memblock_type *type = &memblock.memory; | ||
473 | struct memblock_region *r; | ||
474 | |||
475 | while (++*idx < type->cnt) { | ||
476 | r = &type->regions[*idx]; | ||
477 | |||
478 | if (PFN_UP(r->base) >= PFN_DOWN(r->base + r->size)) | ||
479 | continue; | ||
480 | if (nid == MAX_NUMNODES || nid == r->nid) | ||
481 | break; | ||
482 | } | ||
483 | if (*idx >= type->cnt) { | ||
484 | *idx = -1; | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | if (out_start_pfn) | ||
489 | *out_start_pfn = PFN_UP(r->base); | ||
490 | if (out_end_pfn) | ||
491 | *out_end_pfn = PFN_DOWN(r->base + r->size); | ||
492 | if (out_nid) | ||
493 | *out_nid = r->nid; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * memblock_set_node - set node ID on memblock regions | ||
498 | * @base: base of area to set node ID for | ||
499 | * @size: size of area to set node ID for | ||
500 | * @nid: node ID to set | ||
501 | * | ||
502 | * Set the nid of memblock memory regions in [@base,@base+@size) to @nid. | ||
503 | * Regions which cross the area boundaries are split as necessary. | ||
504 | * | ||
505 | * RETURNS: | ||
506 | * 0 on success, -errno on failure. | ||
507 | */ | ||
508 | int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, | ||
509 | int nid) | ||
510 | { | ||
511 | struct memblock_type *type = &memblock.memory; | ||
512 | phys_addr_t end = base + size; | ||
513 | int i; | ||
514 | |||
515 | /* we'll create at most two more regions */ | ||
516 | while (type->cnt + 2 > type->max) | ||
517 | if (memblock_double_array(type) < 0) | ||
518 | return -ENOMEM; | ||
519 | |||
520 | for (i = 0; i < type->cnt; i++) { | ||
521 | struct memblock_region *rgn = &type->regions[i]; | ||
522 | phys_addr_t rbase = rgn->base; | ||
523 | phys_addr_t rend = rbase + rgn->size; | ||
524 | |||
525 | if (rbase >= end) | ||
526 | break; | ||
527 | if (rend <= base) | ||
528 | continue; | ||
529 | |||
530 | if (rbase < base) { | ||
531 | /* | ||
532 | * @rgn intersects from below. Split and continue | ||
533 | * to process the next region - the new top half. | ||
534 | */ | ||
535 | rgn->base = base; | ||
536 | rgn->size = rend - rgn->base; | ||
537 | memblock_insert_region(type, i, rbase, base - rbase, | ||
538 | rgn->nid); | ||
539 | } else if (rend > end) { | ||
540 | /* | ||
541 | * @rgn intersects from above. Split and redo the | ||
542 | * current region - the new bottom half. | ||
543 | */ | ||
544 | rgn->base = end; | ||
545 | rgn->size = rend - rgn->base; | ||
546 | memblock_insert_region(type, i--, rbase, end - rbase, | ||
547 | rgn->nid); | ||
548 | } else { | ||
549 | /* @rgn is fully contained, set ->nid */ | ||
550 | rgn->nid = nid; | ||
551 | } | ||
552 | } | ||
553 | |||
554 | memblock_merge_regions(type); | ||
555 | return 0; | ||
556 | } | ||
557 | #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ | ||
558 | |||
462 | phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr) | 559 | phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr) |
463 | { | 560 | { |
464 | phys_addr_t found; | 561 | phys_addr_t found; |
@@ -689,19 +786,26 @@ void __init_memblock memblock_set_current_limit(phys_addr_t limit) | |||
689 | memblock.current_limit = limit; | 786 | memblock.current_limit = limit; |
690 | } | 787 | } |
691 | 788 | ||
692 | static void __init_memblock memblock_dump(struct memblock_type *region, char *name) | 789 | static void __init_memblock memblock_dump(struct memblock_type *type, char *name) |
693 | { | 790 | { |
694 | unsigned long long base, size; | 791 | unsigned long long base, size; |
695 | int i; | 792 | int i; |
696 | 793 | ||
697 | pr_info(" %s.cnt = 0x%lx\n", name, region->cnt); | 794 | pr_info(" %s.cnt = 0x%lx\n", name, type->cnt); |
698 | |||
699 | for (i = 0; i < region->cnt; i++) { | ||
700 | base = region->regions[i].base; | ||
701 | size = region->regions[i].size; | ||
702 | 795 | ||
703 | pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes\n", | 796 | for (i = 0; i < type->cnt; i++) { |
704 | name, i, base, base + size - 1, size); | 797 | struct memblock_region *rgn = &type->regions[i]; |
798 | char nid_buf[32] = ""; | ||
799 | |||
800 | base = rgn->base; | ||
801 | size = rgn->size; | ||
802 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP | ||
803 | if (memblock_get_region_node(rgn) != MAX_NUMNODES) | ||
804 | snprintf(nid_buf, sizeof(nid_buf), " on node %d", | ||
805 | memblock_get_region_node(rgn)); | ||
806 | #endif | ||
807 | pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes%s\n", | ||
808 | name, i, base, base + size - 1, size, nid_buf); | ||
705 | } | 809 | } |
706 | } | 810 | } |
707 | 811 | ||
@@ -759,11 +863,13 @@ void __init memblock_init(void) | |||
759 | */ | 863 | */ |
760 | memblock.memory.regions[0].base = 0; | 864 | memblock.memory.regions[0].base = 0; |
761 | memblock.memory.regions[0].size = 0; | 865 | memblock.memory.regions[0].size = 0; |
866 | memblock_set_region_node(&memblock.memory.regions[0], MAX_NUMNODES); | ||
762 | memblock.memory.cnt = 1; | 867 | memblock.memory.cnt = 1; |
763 | 868 | ||
764 | /* Ditto. */ | 869 | /* Ditto. */ |
765 | memblock.reserved.regions[0].base = 0; | 870 | memblock.reserved.regions[0].base = 0; |
766 | memblock.reserved.regions[0].size = 0; | 871 | memblock.reserved.regions[0].size = 0; |
872 | memblock_set_region_node(&memblock.reserved.regions[0], MAX_NUMNODES); | ||
767 | memblock.reserved.cnt = 1; | 873 | memblock.reserved.cnt = 1; |
768 | 874 | ||
769 | memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE; | 875 | memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8ab5e5e7fdad..3c7ea45ffba9 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -182,28 +182,31 @@ static unsigned long __meminitdata nr_all_pages; | |||
182 | static unsigned long __meminitdata dma_reserve; | 182 | static unsigned long __meminitdata dma_reserve; |
183 | 183 | ||
184 | #ifdef CONFIG_ARCH_POPULATES_NODE_MAP | 184 | #ifdef CONFIG_ARCH_POPULATES_NODE_MAP |
185 | /* | 185 | #ifndef CONFIG_HAVE_MEMBLOCK_NODE_MAP |
186 | * MAX_ACTIVE_REGIONS determines the maximum number of distinct | 186 | /* |
187 | * ranges of memory (RAM) that may be registered with add_active_range(). | 187 | * MAX_ACTIVE_REGIONS determines the maximum number of distinct ranges |
188 | * Ranges passed to add_active_range() will be merged if possible | 188 | * of memory (RAM) that may be registered with add_active_range(). |
189 | * so the number of times add_active_range() can be called is | 189 | * Ranges passed to add_active_range() will be merged if possible so |
190 | * related to the number of nodes and the number of holes | 190 | * the number of times add_active_range() can be called is related to |
191 | */ | 191 | * the number of nodes and the number of holes |
192 | #ifdef CONFIG_MAX_ACTIVE_REGIONS | 192 | */ |
193 | /* Allow an architecture to set MAX_ACTIVE_REGIONS to save memory */ | 193 | #ifdef CONFIG_MAX_ACTIVE_REGIONS |
194 | #define MAX_ACTIVE_REGIONS CONFIG_MAX_ACTIVE_REGIONS | 194 | /* Allow an architecture to set MAX_ACTIVE_REGIONS to save memory */ |
195 | #else | 195 | #define MAX_ACTIVE_REGIONS CONFIG_MAX_ACTIVE_REGIONS |
196 | #if MAX_NUMNODES >= 32 | ||
197 | /* If there can be many nodes, allow up to 50 holes per node */ | ||
198 | #define MAX_ACTIVE_REGIONS (MAX_NUMNODES*50) | ||
199 | #else | 196 | #else |
200 | /* By default, allow up to 256 distinct regions */ | 197 | #if MAX_NUMNODES >= 32 |
201 | #define MAX_ACTIVE_REGIONS 256 | 198 | /* If there can be many nodes, allow up to 50 holes per node */ |
199 | #define MAX_ACTIVE_REGIONS (MAX_NUMNODES*50) | ||
200 | #else | ||
201 | /* By default, allow up to 256 distinct regions */ | ||
202 | #define MAX_ACTIVE_REGIONS 256 | ||
203 | #endif | ||
202 | #endif | 204 | #endif |
203 | #endif | ||
204 | 205 | ||
205 | static struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS]; | 206 | static struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS]; |
206 | static int __meminitdata nr_nodemap_entries; | 207 | static int __meminitdata nr_nodemap_entries; |
208 | #endif /* !CONFIG_HAVE_MEMBLOCK_NODE_MAP */ | ||
209 | |||
207 | static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; | 210 | static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; |
208 | static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; | 211 | static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; |
209 | static unsigned long __initdata required_kernelcore; | 212 | static unsigned long __initdata required_kernelcore; |
@@ -4268,6 +4271,7 @@ static inline void setup_nr_node_ids(void) | |||
4268 | } | 4271 | } |
4269 | #endif | 4272 | #endif |
4270 | 4273 | ||
4274 | #ifndef CONFIG_HAVE_MEMBLOCK_NODE_MAP | ||
4271 | /* | 4275 | /* |
4272 | * Common iterator interface used to define for_each_mem_pfn_range(). | 4276 | * Common iterator interface used to define for_each_mem_pfn_range(). |
4273 | */ | 4277 | */ |
@@ -4456,6 +4460,11 @@ void __init sort_node_map(void) | |||
4456 | sizeof(struct node_active_region), | 4460 | sizeof(struct node_active_region), |
4457 | cmp_node_active_region, NULL); | 4461 | cmp_node_active_region, NULL); |
4458 | } | 4462 | } |
4463 | #else /* !CONFIG_HAVE_MEMBLOCK_NODE_MAP */ | ||
4464 | static inline void sort_node_map(void) | ||
4465 | { | ||
4466 | } | ||
4467 | #endif | ||
4459 | 4468 | ||
4460 | /** | 4469 | /** |
4461 | * node_map_pfn_alignment - determine the maximum internode alignment | 4470 | * node_map_pfn_alignment - determine the maximum internode alignment |