aboutsummaryrefslogtreecommitdiffstats
path: root/mm/bootmem.c
diff options
context:
space:
mode:
authorAndy Whitcroft <apw@shadowen.org>2005-06-23 03:07:54 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:04 -0400
commitd41dee369bff3b9dcb6328d4d822926c28cc2594 (patch)
treea0405f3b7af3ebca21838a7d427bd75a067bf850 /mm/bootmem.c
parentaf705362ab6018071310c5fcd436a6b457517d5f (diff)
[PATCH] sparsemem memory model
Sparsemem abstracts the use of discontiguous mem_maps[]. This kind of mem_map[] is needed by discontiguous memory machines (like in the old CONFIG_DISCONTIGMEM case) as well as memory hotplug systems. Sparsemem replaces DISCONTIGMEM when enabled, and it is hoped that it can eventually become a complete replacement. A significant advantage over DISCONTIGMEM is that it's completely separated from CONFIG_NUMA. When producing this patch, it became apparent in that NUMA and DISCONTIG are often confused. Another advantage is that sparse doesn't require each NUMA node's ranges to be contiguous. It can handle overlapping ranges between nodes with no problems, where DISCONTIGMEM currently throws away that memory. Sparsemem uses an array to provide different pfn_to_page() translations for each SECTION_SIZE area of physical memory. This is what allows the mem_map[] to be chopped up. In order to do quick pfn_to_page() operations, the section number of the page is encoded in page->flags. Part of the sparsemem infrastructure enables sharing of these bits more dynamically (at compile-time) between the page_zone() and sparsemem operations. However, on 32-bit architectures, the number of bits is quite limited, and may require growing the size of the page->flags type in certain conditions. Several things might force this to occur: a decrease in the SECTION_SIZE (if you want to hotplug smaller areas of memory), an increase in the physical address space, or an increase in the number of used page->flags. One thing to note is that, once sparsemem is present, the NUMA node information no longer needs to be stored in the page->flags. It might provide speed increases on certain platforms and will be stored there if there is room. But, if out of room, an alternate (theoretically slower) mechanism is used. This patch introduces CONFIG_FLATMEM. It is used in almost all cases where there used to be an #ifndef DISCONTIG, because SPARSEMEM and DISCONTIGMEM often have to compile out the same areas of code. Signed-off-by: Andy Whitcroft <apw@shadowen.org> Signed-off-by: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Martin Bligh <mbligh@aracnet.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com> Signed-off-by: Bob Picco <bob.picco@hp.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm/bootmem.c')
-rw-r--r--mm/bootmem.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 260e703850d8..f82f7aebbee3 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -256,6 +256,7 @@ found:
256static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) 256static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
257{ 257{
258 struct page *page; 258 struct page *page;
259 unsigned long pfn;
259 bootmem_data_t *bdata = pgdat->bdata; 260 bootmem_data_t *bdata = pgdat->bdata;
260 unsigned long i, count, total = 0; 261 unsigned long i, count, total = 0;
261 unsigned long idx; 262 unsigned long idx;
@@ -266,7 +267,7 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
266 267
267 count = 0; 268 count = 0;
268 /* first extant page of the node */ 269 /* first extant page of the node */
269 page = virt_to_page(phys_to_virt(bdata->node_boot_start)); 270 pfn = bdata->node_boot_start >> PAGE_SHIFT;
270 idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); 271 idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
271 map = bdata->node_bootmem_map; 272 map = bdata->node_bootmem_map;
272 /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ 273 /* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */
@@ -275,9 +276,11 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
275 gofast = 1; 276 gofast = 1;
276 for (i = 0; i < idx; ) { 277 for (i = 0; i < idx; ) {
277 unsigned long v = ~map[i / BITS_PER_LONG]; 278 unsigned long v = ~map[i / BITS_PER_LONG];
279
278 if (gofast && v == ~0UL) { 280 if (gofast && v == ~0UL) {
279 int j, order; 281 int j, order;
280 282
283 page = pfn_to_page(pfn);
281 count += BITS_PER_LONG; 284 count += BITS_PER_LONG;
282 __ClearPageReserved(page); 285 __ClearPageReserved(page);
283 order = ffs(BITS_PER_LONG) - 1; 286 order = ffs(BITS_PER_LONG) - 1;
@@ -292,6 +295,8 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
292 page += BITS_PER_LONG; 295 page += BITS_PER_LONG;
293 } else if (v) { 296 } else if (v) {
294 unsigned long m; 297 unsigned long m;
298
299 page = pfn_to_page(pfn);
295 for (m = 1; m && i < idx; m<<=1, page++, i++) { 300 for (m = 1; m && i < idx; m<<=1, page++, i++) {
296 if (v & m) { 301 if (v & m) {
297 count++; 302 count++;
@@ -302,8 +307,8 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat)
302 } 307 }
303 } else { 308 } else {
304 i+=BITS_PER_LONG; 309 i+=BITS_PER_LONG;
305 page += BITS_PER_LONG;
306 } 310 }
311 pfn += BITS_PER_LONG;
307 } 312 }
308 total += count; 313 total += count;
309 314