X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Farm%2Fmm%2Finit.c;h=8277802ec85926abe0e3bd7ad6dd10fb83e987d4;hb=3835f6cb645bdb9a58aa6e062fe1d5777f1a9748;hp=b5814b4b6f35c6ffe392a358f884b04af3cb3a5f;hpb=5e7098275094ec405f2b19285ec0c38aead42d53;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index b5814b4..8277802 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -9,15 +9,16 @@ */ #include #include -#include #include #include #include #include #include #include +#include #include +#include #include #include #include @@ -27,19 +28,49 @@ #include "mm.h" -extern void _text, _etext, __data_start, _end, __init_begin, __init_end; -extern unsigned long phys_initrd_start; -extern unsigned long phys_initrd_size; +static unsigned long phys_initrd_start __initdata = 0; +static unsigned long phys_initrd_size __initdata = 0; + +static void __init early_initrd(char **p) +{ + unsigned long start, size; + + start = memparse(*p, p); + if (**p == ',') { + size = memparse((*p) + 1, p); + + phys_initrd_start = start; + phys_initrd_size = size; + } +} +__early_param("initrd=", early_initrd); + +static int __init parse_tag_initrd(const struct tag *tag) +{ + printk(KERN_WARNING "ATAG_INITRD is deprecated; " + "please update your bootloader.\n"); + phys_initrd_start = __virt_to_phys(tag->u.initrd.start); + phys_initrd_size = tag->u.initrd.size; + return 0; +} + +__tagtable(ATAG_INITRD, parse_tag_initrd); + +static int __init parse_tag_initrd2(const struct tag *tag) +{ + phys_initrd_start = tag->u.initrd.start; + phys_initrd_size = tag->u.initrd.size; + return 0; +} + +__tagtable(ATAG_INITRD2, parse_tag_initrd2); /* - * This is used to pass memory configuration data from paging_init - * to mem_init, and by show_mem() to skip holes in the memory map. + * This keeps memory configuration data used by a couple memory + * initialization functions, as well as show_mem() for the skipping + * of holes in the memory map. It is populated by arm_add_memory(). */ -static struct meminfo meminfo = { 0, }; - -#define for_each_nodebank(iter,mi,no) \ - for (iter = 0; iter < mi->nr_banks; iter++) \ - if (mi->bank[iter].node == no) +struct meminfo meminfo; void show_mem(void) { @@ -49,18 +80,20 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - for_each_online_node(node) { + pg_data_t *n = NODE_DATA(node); + struct page *map = pgdat_page_nr(n, 0) - n->node_start_pfn; + for_each_nodebank (i,mi,node) { + struct membank *bank = &mi->bank[i]; unsigned int pfn1, pfn2; struct page *page, *end; - pfn1 = mi->bank[i].start >> PAGE_SHIFT; - pfn2 = (mi->bank[i].size + mi->bank[i].start) >> PAGE_SHIFT; + pfn1 = bank_pfn_start(bank); + pfn2 = bank_pfn_end(bank); - page = NODE_MEM_MAP(node) + pfn1; - end = NODE_MEM_MAP(node) + pfn2; + page = map + pfn1; + end = map + pfn2; do { total++; @@ -96,17 +129,17 @@ void show_mem(void) static unsigned int __init find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) { - unsigned int start_pfn, bank, bootmap_pfn; + unsigned int start_pfn, i, bootmap_pfn; - start_pfn = PAGE_ALIGN(__pa(&_end)) >> PAGE_SHIFT; + start_pfn = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT; bootmap_pfn = 0; - for_each_nodebank(bank, mi, node) { + for_each_nodebank(i, mi, node) { + struct membank *bank = &mi->bank[i]; unsigned int start, end; - start = mi->bank[bank].start >> PAGE_SHIFT; - end = (mi->bank[bank].size + - mi->bank[bank].start) >> PAGE_SHIFT; + start = bank_pfn_start(bank); + end = bank_pfn_end(bank); if (end < start_pfn) continue; @@ -145,20 +178,17 @@ static int __init check_initrd(struct meminfo *mi) initrd_node = -1; for (i = 0; i < mi->nr_banks; i++) { - unsigned long bank_end; - - bank_end = mi->bank[i].start + mi->bank[i].size; - - if (mi->bank[i].start <= phys_initrd_start && - end <= bank_end) - initrd_node = mi->bank[i].node; + struct membank *bank = &mi->bank[i]; + if (bank_phys_start(bank) <= phys_initrd_start && + end <= bank_phys_end(bank)) + initrd_node = bank->node; } } if (initrd_node == -1) { - printk(KERN_ERR "initrd (0x%08lx - 0x%08lx) extends beyond " + printk(KERN_ERR "INITRD: 0x%08lx+0x%08lx extends beyond " "physical memory - disabling initrd\n", - phys_initrd_start, end); + phys_initrd_start, phys_initrd_size); phys_initrd_start = phys_initrd_size = 0; } #endif @@ -171,19 +201,17 @@ static inline void map_memory_bank(struct membank *bank) #ifdef CONFIG_MMU struct map_desc map; - map.pfn = __phys_to_pfn(bank->start); - map.virtual = __phys_to_virt(bank->start); - map.length = bank->size; + map.pfn = bank_pfn_start(bank); + map.virtual = __phys_to_virt(bank_phys_start(bank)); + map.length = bank_phys_size(bank); map.type = MT_MEMORY; create_mapping(&map); #endif } -static unsigned long __init -bootmem_init_node(int node, int initrd_node, struct meminfo *mi) +static unsigned long __init bootmem_init_node(int node, struct meminfo *mi) { - unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; unsigned long start_pfn, end_pfn, boot_pfn; unsigned int boot_pages; pg_data_t *pgdat; @@ -199,8 +227,8 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi) struct membank *bank = &mi->bank[i]; unsigned long start, end; - start = bank->start >> PAGE_SHIFT; - end = (bank->start + bank->size) >> PAGE_SHIFT; + start = bank_pfn_start(bank); + end = bank_pfn_end(bank); if (start_pfn > start) start_pfn = start; @@ -230,32 +258,51 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi) pgdat = NODE_DATA(node); init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn); - for_each_nodebank(i, mi, node) - free_bootmem_node(pgdat, mi->bank[i].start, mi->bank[i].size); + for_each_nodebank(i, mi, node) { + struct membank *bank = &mi->bank[i]; + free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank)); + memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank)); + } /* * Reserve the bootmem bitmap for this node. */ reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, - boot_pages << PAGE_SHIFT); + boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); + + return end_pfn; +} +static void __init bootmem_reserve_initrd(int node) +{ #ifdef CONFIG_BLK_DEV_INITRD - /* - * If the initrd is in this node, reserve its memory. - */ - if (node == initrd_node) { - reserve_bootmem_node(pgdat, phys_initrd_start, - phys_initrd_size); + pg_data_t *pgdat = NODE_DATA(node); + int res; + + res = reserve_bootmem_node(pgdat, phys_initrd_start, + phys_initrd_size, BOOTMEM_EXCLUSIVE); + + if (res == 0) { initrd_start = __phys_to_virt(phys_initrd_start); initrd_end = initrd_start + phys_initrd_size; + } else { + printk(KERN_ERR + "INITRD: 0x%08lx+0x%08lx overlaps in-use " + "memory region - disabling initrd\n", + phys_initrd_start, phys_initrd_size); } #endif +} - /* - * Finally, reserve any node zero regions. - */ - if (node == 0) - reserve_node_zero(pgdat); +static void __init bootmem_free_node(int node, struct meminfo *mi) +{ + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; + unsigned long start_pfn, end_pfn; + pg_data_t *pgdat = NODE_DATA(node); + int i; + + start_pfn = pgdat->bdata->node_min_pfn; + end_pfn = pgdat->bdata->node_low_pfn; /* * initialise the zones within this node. @@ -276,7 +323,7 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi) */ zhole_size[0] = zone_size[0]; for_each_nodebank(i, mi, node) - zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT; + zhole_size[0] -= bank_pfn_size(&mi->bank[i]); /* * Adjust the sizes according to any special requirements for @@ -284,24 +331,14 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi) */ arch_adjust_zones(node, zone_size, zhole_size); - free_area_init_node(node, pgdat, zone_size, start_pfn, zhole_size); - - return end_pfn; + free_area_init_node(node, zone_size, start_pfn, zhole_size); } -void __init bootmem_init(struct meminfo *mi) +void __init bootmem_init(void) { + struct meminfo *mi = &meminfo; unsigned long memend_pfn = 0; - int node, initrd_node, i; - - /* - * Invalidate the node number for empty or invalid memory banks - */ - for (i = 0; i < mi->nr_banks; i++) - if (mi->bank[i].size == 0 || mi->bank[i].node >= MAX_NUMNODES) - mi->bank[i].node = -1; - - memcpy(&meminfo, mi, sizeof(meminfo)); + int node, initrd_node; /* * Locate which node contains the ramdisk image, if any. @@ -312,9 +349,19 @@ void __init bootmem_init(struct meminfo *mi) * Run through each node initialising the bootmem allocator. */ for_each_node(node) { - unsigned long end_pfn; + unsigned long end_pfn = bootmem_init_node(node, mi); - end_pfn = bootmem_init_node(node, initrd_node, mi); + /* + * Reserve any special node zero regions. + */ + if (node == 0) + reserve_node_zero(NODE_DATA(node)); + + /* + * If the initrd is in this node, reserve its memory. + */ + if (node == initrd_node) + bootmem_reserve_initrd(node); /* * Remember the highest memory PFN. @@ -323,7 +370,20 @@ void __init bootmem_init(struct meminfo *mi) memend_pfn = end_pfn; } - high_memory = __va(memend_pfn << PAGE_SHIFT); + /* + * sparse_init() needs the bootmem allocator up and running. + */ + sparse_init(); + + /* + * Now free memory in each node - free_area_init_node needs + * the sparse mem_map arrays initialized by sparse_init() + * for memmap_init_zone(), otherwise all PFNs are invalid. + */ + for_each_node(node) + bootmem_free_node(node, mi); + + high_memory = __va((memend_pfn << PAGE_SHIFT) - 1) + 1; /* * This doesn't seem to be used by the Linux memory manager any @@ -336,20 +396,22 @@ void __init bootmem_init(struct meminfo *mi) max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET; } -static inline void free_area(unsigned long addr, unsigned long end, char *s) +static inline int free_area(unsigned long pfn, unsigned long end, char *s) { - unsigned int size = (end - addr) >> 10; + unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10); - for (; addr < end; addr += PAGE_SIZE) { - struct page *page = virt_to_page(addr); + for (; pfn < end; pfn++) { + struct page *page = pfn_to_page(pfn); ClearPageReserved(page); init_page_count(page); - free_page(addr); - totalram_pages++; + __free_page(page); + pages++; } if (size && s) printk(KERN_INFO "Freeing %s memory: %dK\n", s, size); + + return pages; } static inline void @@ -393,7 +455,9 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi) * information on the command line. */ for_each_nodebank(i, mi, node) { - bank_start = mi->bank[i].start >> PAGE_SHIFT; + struct membank *bank = &mi->bank[i]; + + bank_start = bank_pfn_start(bank); if (bank_start < prev_bank_end) { printk(KERN_ERR "MEM: unordered memory banks. " "Not freeing memmap.\n"); @@ -407,8 +471,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi) if (prev_bank_end && prev_bank_end != bank_start) free_memmap(node, prev_bank_end, bank_start); - prev_bank_end = (mi->bank[i].start + - mi->bank[i].size) >> PAGE_SHIFT; + prev_bank_end = bank_pfn_end(bank); } } @@ -419,15 +482,11 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi) */ void __init mem_init(void) { - unsigned int codepages, datapages, initpages; + unsigned int codesize, datasize, initsize; int i, node; - codepages = &_etext - &_text; - datapages = &_end - &__data_start; - initpages = &__init_end - &__init_begin; - #ifndef CONFIG_DISCONTIGMEM - max_mapnr = virt_to_page(high_memory) - mem_map; + max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; #endif /* this will put all unused low memory onto the freelists */ @@ -442,7 +501,21 @@ void __init mem_init(void) #ifdef CONFIG_SA1111 /* now that our DMA memory is actually so designated, we can free it */ - free_area(PAGE_OFFSET, (unsigned long)swapper_pg_dir, NULL); + totalram_pages += free_area(PHYS_PFN_OFFSET, + __phys_to_pfn(__pa(swapper_pg_dir)), NULL); +#endif + +#ifdef CONFIG_HIGHMEM + /* set highmem page free */ + for_each_online_node(node) { + for_each_nodebank (i, &meminfo, node) { + unsigned long start = bank_pfn_start(&meminfo.bank[i]); + unsigned long end = bank_pfn_end(&meminfo.bank[i]); + if (start >= max_low_pfn + PHYS_PFN_OFFSET) + totalhigh_pages += free_area(start, end, NULL); + } + } + totalram_pages += totalhigh_pages; #endif /* @@ -450,18 +523,22 @@ void __init mem_init(void) * real number of pages we have in this system */ printk(KERN_INFO "Memory:"); - num_physpages = 0; for (i = 0; i < meminfo.nr_banks; i++) { - num_physpages += meminfo.bank[i].size >> PAGE_SHIFT; - printk(" %ldMB", meminfo.bank[i].size >> 20); + num_physpages += bank_pfn_size(&meminfo.bank[i]); + printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20); } - printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); + + codesize = _etext - _text; + datasize = _end - _data; + initsize = __init_end - __init_begin; + printk(KERN_NOTICE "Memory: %luKB available (%dK code, " - "%dK data, %dK init)\n", + "%dK data, %dK init, %luK highmem)\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), - codepages >> 10, datapages >> 10, initpages >> 10); + codesize >> 10, datasize >> 10, initsize >> 10, + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); if (PAGE_SIZE >= 16384 && num_physpages <= 128) { extern int sysctl_overcommit_memory; @@ -476,11 +553,10 @@ void __init mem_init(void) void free_initmem(void) { - if (!machine_is_integrator() && !machine_is_cintegrator()) { - free_area((unsigned long)(&__init_begin), - (unsigned long)(&__init_end), - "init"); - } + if (!machine_is_integrator() && !machine_is_cintegrator()) + totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)), + __phys_to_pfn(__pa(__init_end)), + "init"); } #ifdef CONFIG_BLK_DEV_INITRD @@ -490,7 +566,9 @@ static int keep_initrd; void free_initrd_mem(unsigned long start, unsigned long end) { if (!keep_initrd) - free_area(start, end, "initrd"); + totalram_pages += free_area(__phys_to_pfn(__pa(start)), + __phys_to_pfn(__pa(end)), + "initrd"); } static int __init keepinitrd_setup(char *__unused)