diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /mm/bootmem.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'mm/bootmem.c')
-rw-r--r-- | mm/bootmem.c | 182 |
1 files changed, 128 insertions, 54 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index edc69e6b3..463073251 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -2,13 +2,13 @@ * linux/mm/initmem.c * * Copyright (C) 1999 Ingo Molnar + * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 * * simple boot-time physical memory area allocator and * free memory collector. It's used to deal with reserved * system memory and memory holes as well. */ -#include <linux/config.h> #include <linux/mm.h> #include <linux/kernel_stat.h> #include <linux/swap.h> @@ -16,62 +16,75 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/mmzone.h> #include <asm/dma.h> /* - * Pointer to a bitmap - the bits represent all physical memory pages - * from physical address 0 to physical address end_mem. - * * Access to this subsystem has to be serialized externally. (this is * true for the boot process anyway) */ unsigned long max_low_pfn; -static void * bootmem_map = NULL; +/* return the number of _pages_ that will be allocated for the boot bitmap */ +unsigned long __init bootmem_bootmap_pages (unsigned long pages) +{ + unsigned long mapsize; + + mapsize = (pages+7)/8; + mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK; + mapsize >>= PAGE_SHIFT; + + return mapsize; +} /* * Called once to set up the allocator itself. */ -unsigned long __init init_bootmem (unsigned long start, unsigned long pages) +static unsigned long __init init_bootmem_core (bootmem_data_t *bdata, + unsigned long mapstart, unsigned long start, unsigned long end) { - unsigned long mapsize = (pages+7)/8; + unsigned long mapsize = ((end - start)+7)/8; - bootmem_map = phys_to_virt(start << PAGE_SHIFT); - max_low_pfn = pages; + bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); + bdata->node_boot_start = (start << PAGE_SHIFT); + bdata->node_low_pfn = end; /* * Initially all pages are reserved - setup_arch() has to * register free RAM areas explicitly. */ - memset(bootmem_map, 0xff, mapsize); + memset(bdata->node_bootmem_map, 0xff, mapsize); return mapsize; } /* - * Marks a particular physical memory range as usable. Usable RAM + * Marks a particular physical memory range as unallocatable. Usable RAM * might be used for boot-time allocations - or it might get added * to the free page pool later on. */ -void __init reserve_bootmem (unsigned long addr, unsigned long size) +static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) { unsigned long i; /* * round up, partially reserved pages are considered * fully reserved. */ + unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE; + unsigned long eidx = (addr + size - bdata->node_boot_start + + PAGE_SIZE-1)/PAGE_SIZE; unsigned long end = (addr + size + PAGE_SIZE-1)/PAGE_SIZE; if (!size) BUG(); - if (end > max_low_pfn) + if (end > bdata->node_low_pfn) BUG(); - for (i = addr/PAGE_SIZE; i < end; i++) - if (test_and_set_bit(i, bootmem_map)) + for (i = sidx; i < eidx; i++) + if (test_and_set_bit(i, bdata->node_bootmem_map)) BUG(); } -void __init free_bootmem (unsigned long addr, unsigned long size) +static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size) { unsigned long i; unsigned long start; @@ -79,19 +92,22 @@ void __init free_bootmem (unsigned long addr, unsigned long size) * round down end of usable mem, partially free pages are * considered reserved. */ + unsigned long sidx; + unsigned long eidx = (addr + size - bdata->node_boot_start)/PAGE_SIZE; unsigned long end = (addr + size)/PAGE_SIZE; if (!size) BUG(); - if (end > max_low_pfn) + if (end > bdata->node_low_pfn) BUG(); /* * Round up the beginning of the address. */ start = (addr + PAGE_SIZE-1) / PAGE_SIZE; + sidx = start - (bdata->node_boot_start/PAGE_SIZE); - for (i = start; i < end; i++) { - if (!test_and_clear_bit(i, bootmem_map)) + for (i = sidx; i < eidx; i++) { + if (!test_and_clear_bit(i, bdata->node_bootmem_map)) BUG(); } } @@ -105,19 +121,20 @@ void __init free_bootmem (unsigned long addr, unsigned long size) * * On low memory boxes we get it right in 100% of the cases. */ -static unsigned long last_pos = 0; -static unsigned long last_offset = 0; /* * alignment has to be a power of 2 value. */ -void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) +static void * __init __alloc_bootmem_core (bootmem_data_t *bdata, + unsigned long size, unsigned long align, unsigned long goal) { int area = 0; unsigned long i, start = 0, reserved; void *ret; unsigned long offset, remaining_size; unsigned long areasize, preferred; + unsigned long eidx = bdata->node_low_pfn - (bdata->node_boot_start >> + PAGE_SHIFT); if (!size) BUG(); @@ -125,18 +142,17 @@ void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned * We try to allocate bootmem pages above 'goal' * first, then we try to allocate lower pages. */ - if (goal) { - preferred = goal >> PAGE_SHIFT; - if (preferred >= max_low_pfn) - preferred = 0; + if (goal && (goal >= bdata->node_boot_start) && + ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { + preferred = (goal - bdata->node_boot_start) >> PAGE_SHIFT; } else preferred = 0; areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; restart_scan: - for (i = preferred; i < max_low_pfn; i++) { - reserved = test_bit(i, bootmem_map); + for (i = preferred; i < eidx; i++) { + reserved = test_bit(i, bdata->node_bootmem_map); if (!reserved) { if (!area) { area = 1; @@ -158,7 +174,7 @@ restart_scan: */ BUG(); found: - if (start >= max_low_pfn) + if (start >= eidx) BUG(); /* @@ -166,8 +182,8 @@ found: * of this allocation's buffer? If yes then we can 'merge' * the previous partial page with this allocation. */ - if (last_offset && (last_pos+1 == start)) { - offset = (last_offset+align-1) & ~(align-1); + if (bdata->last_offset && (bdata->last_pos+1 == start)) { + offset = (bdata->last_offset+align-1) & ~(align-1); if (offset > PAGE_SIZE) BUG(); remaining_size = PAGE_SIZE-offset; @@ -176,47 +192,49 @@ found: if (size < remaining_size) { areasize = 0; // last_pos unchanged - last_offset = offset+size; - ret = phys_to_virt(last_pos*PAGE_SIZE + offset); + bdata->last_offset = offset+size; + ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + + bdata->node_boot_start); } else { - size -= remaining_size; - areasize = (size+PAGE_SIZE-1)/PAGE_SIZE; - ret = phys_to_virt(last_pos*PAGE_SIZE + offset); - last_pos = start+areasize-1; - last_offset = size; + remaining_size = size - remaining_size; + areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE; + ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset + + bdata->node_boot_start); + bdata->last_pos = start+areasize-1; + bdata->last_offset = remaining_size; } - last_offset &= ~PAGE_MASK; + bdata->last_offset &= ~PAGE_MASK; } else { - last_pos = start + areasize - 1; - last_offset = size & ~PAGE_MASK; - ret = phys_to_virt(start * PAGE_SIZE); + bdata->last_pos = start + areasize - 1; + bdata->last_offset = size & ~PAGE_MASK; + ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start); } /* * Reserve the area now: */ for (i = start; i < start+areasize; i++) - if (test_and_set_bit(i, bootmem_map)) + if (test_and_set_bit(i, bdata->node_bootmem_map)) BUG(); - + memset(ret, 0, size); return ret; } -unsigned long __init free_all_bootmem (void) +static unsigned long __init free_all_bootmem_core(int nid, bootmem_data_t *bdata) { struct page * page; unsigned long i, count, total = 0; + unsigned long idx; - if (!bootmem_map) BUG(); + if (!bdata->node_bootmem_map) BUG(); - page = mem_map; + page = NODE_MEM_MAP(nid); count = 0; - for (i = 0; i < max_low_pfn; i++, page++) { - if (!test_bit(i, bootmem_map)) { + idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); + for (i = 0; i < idx; i++, page++) { + if (!test_bit(i, bdata->node_bootmem_map)) { count++; ClearPageReserved(page); set_page_count(page, 1); - if (i >= (virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT)) - clear_bit(PG_DMA, &page->flags); __free_page(page); } } @@ -226,16 +244,72 @@ unsigned long __init free_all_bootmem (void) * Now free the allocator bitmap itself, it's not * needed anymore: */ - page = mem_map + MAP_NR(bootmem_map); + page = mem_map + MAP_NR(bdata->node_bootmem_map); count = 0; - for (i = 0; i < (max_low_pfn/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { + for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) { count++; ClearPageReserved(page); set_page_count(page, 1); __free_page(page); } total += count; - bootmem_map = NULL; + bdata->node_bootmem_map = NULL; return total; } + +unsigned long __init init_bootmem_node (int nid, unsigned long freepfn, unsigned long startpfn, unsigned long endpfn) +{ + return(init_bootmem_core(NODE_DATA(nid)->bdata, freepfn, startpfn, endpfn)); +} + +void __init reserve_bootmem_node (int nid, unsigned long physaddr, unsigned long size) +{ + reserve_bootmem_core(NODE_DATA(nid)->bdata, physaddr, size); +} + +void __init free_bootmem_node (int nid, unsigned long physaddr, unsigned long size) +{ + return(free_bootmem_core(NODE_DATA(nid)->bdata, physaddr, size)); +} + +unsigned long __init free_all_bootmem_node (int nid) +{ + return(free_all_bootmem_core(nid, NODE_DATA(nid)->bdata)); +} + +unsigned long __init init_bootmem (unsigned long start, unsigned long pages) +{ + max_low_pfn = pages; + return(init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages)); +} + +void __init reserve_bootmem (unsigned long addr, unsigned long size) +{ + reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size); +} + +void __init free_bootmem (unsigned long addr, unsigned long size) +{ + return(free_bootmem_core(NODE_DATA(0)->bdata, addr, size)); +} + +unsigned long __init free_all_bootmem (void) +{ + return(free_all_bootmem_core(0, NODE_DATA(0)->bdata)); +} + +void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal) +{ + /* + * In the discontigmem case, all non-node specific allocations come + * from the first node, node 0. + */ + return(__alloc_bootmem_core(NODE_DATA(0)->bdata, size, align, goal)); +} + +void * __init __alloc_bootmem_node (int nid, unsigned long size, unsigned long align, unsigned long goal) +{ + return(__alloc_bootmem_core(NODE_DATA(nid)->bdata, size, align, goal)); +} + |