diff options
Diffstat (limited to 'arch/arm/mm/init.c')
| -rw-r--r-- | arch/arm/mm/init.c | 380 | 
1 files changed, 136 insertions, 244 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index e00404e6f45..240b68d511d 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -17,6 +17,7 @@  #include <linux/initrd.h>  #include <linux/highmem.h>  #include <linux/gfp.h> +#include <linux/memblock.h>  #include <asm/mach-types.h>  #include <asm/sections.h> @@ -79,38 +80,37 @@ struct meminfo meminfo;  void show_mem(void)  {  	int free = 0, total = 0, reserved = 0; -	int shared = 0, cached = 0, slab = 0, node, i; +	int shared = 0, cached = 0, slab = 0, i;  	struct meminfo * mi = &meminfo;  	printk("Mem-info:\n");  	show_free_areas(); -	for_each_online_node(node) { -		for_each_nodebank (i,mi,node) { -			struct membank *bank = &mi->bank[i]; -			unsigned int pfn1, pfn2; -			struct page *page, *end; -			pfn1 = bank_pfn_start(bank); -			pfn2 = bank_pfn_end(bank); +	for_each_bank (i, mi) { +		struct membank *bank = &mi->bank[i]; +		unsigned int pfn1, pfn2; +		struct page *page, *end; -			page = pfn_to_page(pfn1); -			end  = pfn_to_page(pfn2 - 1) + 1; +		pfn1 = bank_pfn_start(bank); +		pfn2 = bank_pfn_end(bank); -			do { -				total++; -				if (PageReserved(page)) -					reserved++; -				else if (PageSwapCache(page)) -					cached++; -				else if (PageSlab(page)) -					slab++; -				else if (!page_count(page)) -					free++; -				else -					shared += page_count(page) - 1; -				page++; -			} while (page < end); -		} +		page = pfn_to_page(pfn1); +		end  = pfn_to_page(pfn2 - 1) + 1; + +		do { +			total++; +			if (PageReserved(page)) +				reserved++; +			else if (PageSwapCache(page)) +				cached++; +			else if (PageSlab(page)) +				slab++; +			else if (!page_count(page)) +				free++; +			else +				shared += page_count(page) - 1; +			page++; +		} while (page < end);  	}  	printk("%d pages of RAM\n", total); @@ -121,7 +121,7 @@ void show_mem(void)  	printk("%d pages swap cached\n", cached);  } -static void __init find_node_limits(int node, struct meminfo *mi, +static void __init find_limits(struct meminfo *mi,  	unsigned long *min, unsigned long *max_low, unsigned long *max_high)  {  	int i; @@ -129,7 +129,7 @@ static void __init find_node_limits(int node, struct meminfo *mi,  	*min = -1UL;  	*max_low = *max_high = 0; -	for_each_nodebank(i, mi, node) { +	for_each_bank (i, mi) {  		struct membank *bank = &mi->bank[i];  		unsigned long start, end; @@ -147,155 +147,64 @@ static void __init find_node_limits(int node, struct meminfo *mi,  	}  } -/* - * FIXME: We really want to avoid allocating the bootmap bitmap - * over the top of the initrd.  Hopefully, this is located towards - * the start of a bank, so if we allocate the bootmap bitmap at - * the end, we won't clash. - */ -static unsigned int __init -find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages) -{ -	unsigned int start_pfn, i, bootmap_pfn; - -	start_pfn   = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT; -	bootmap_pfn = 0; - -	for_each_nodebank(i, mi, node) { -		struct membank *bank = &mi->bank[i]; -		unsigned int start, end; - -		start = bank_pfn_start(bank); -		end   = bank_pfn_end(bank); - -		if (end < start_pfn) -			continue; - -		if (start < start_pfn) -			start = start_pfn; - -		if (end <= start) -			continue; - -		if (end - start >= bootmap_pages) { -			bootmap_pfn = start; -			break; -		} -	} - -	if (bootmap_pfn == 0) -		BUG(); - -	return bootmap_pfn; -} - -static int __init check_initrd(struct meminfo *mi) -{ -	int initrd_node = -2; -#ifdef CONFIG_BLK_DEV_INITRD -	unsigned long end = phys_initrd_start + phys_initrd_size; - -	/* -	 * Make sure that the initrd is within a valid area of -	 * memory. -	 */ -	if (phys_initrd_size) { -		unsigned int i; - -		initrd_node = -1; - -		for (i = 0; i < mi->nr_banks; i++) { -			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 " -		       "physical memory - disabling initrd\n", -		       phys_initrd_start, phys_initrd_size); -		phys_initrd_start = phys_initrd_size = 0; -	} -#endif - -	return initrd_node; -} - -static void __init bootmem_init_node(int node, struct meminfo *mi, +static void __init arm_bootmem_init(struct meminfo *mi,  	unsigned long start_pfn, unsigned long end_pfn)  { -	unsigned long boot_pfn;  	unsigned int boot_pages; +	phys_addr_t bitmap;  	pg_data_t *pgdat;  	int i;  	/* -	 * Allocate the bootmem bitmap page. +	 * Allocate the bootmem bitmap page.  This must be in a region +	 * of memory which has already been mapped.  	 */  	boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn); -	boot_pfn = find_bootmap_pfn(node, mi, boot_pages); +	bitmap = memblock_alloc_base(boot_pages << PAGE_SHIFT, L1_CACHE_BYTES, +				__pfn_to_phys(end_pfn));  	/* -	 * Initialise the bootmem allocator for this node, handing the +	 * Initialise the bootmem allocator, handing the  	 * memory banks over to bootmem.  	 */ -	node_set_online(node); -	pgdat = NODE_DATA(node); -	init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn); +	node_set_online(0); +	pgdat = NODE_DATA(0); +	init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn); -	for_each_nodebank(i, mi, node) { +	for_each_bank(i, mi) {  		struct membank *bank = &mi->bank[i];  		if (!bank->highmem) -			free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank)); +			free_bootmem(bank_phys_start(bank), bank_phys_size(bank));  	}  	/* -	 * Reserve the bootmem bitmap for this node. +	 * Reserve the memblock reserved regions in bootmem.  	 */ -	reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, -			     boot_pages << PAGE_SHIFT, BOOTMEM_DEFAULT); -} - -static void __init bootmem_reserve_initrd(int node) -{ -#ifdef CONFIG_BLK_DEV_INITRD -	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); +	for (i = 0; i < memblock.reserved.cnt; i++) { +		phys_addr_t start = memblock_start_pfn(&memblock.reserved, i); +		if (start >= start_pfn && +		    memblock_end_pfn(&memblock.reserved, i) <= end_pfn) +			reserve_bootmem_node(pgdat, __pfn_to_phys(start), +				memblock_size_bytes(&memblock.reserved, i), +				BOOTMEM_DEFAULT);  	} -#endif  } -static void __init bootmem_free_node(int node, struct meminfo *mi) +static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min, +	unsigned long max_low, unsigned long max_high)  {  	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; -	unsigned long min, max_low, max_high;  	int i; -	find_node_limits(node, mi, &min, &max_low, &max_high); -  	/* -	 * initialise the zones within this node. +	 * initialise the zones.  	 */  	memset(zone_size, 0, sizeof(zone_size));  	/* -	 * The size of this node has already been determined.  If we need -	 * to do anything fancy with the allocation of this memory to the -	 * zones, now is the time to do it. +	 * The memory size has already been determined.  If we need +	 * to do anything fancy with the allocation of this memory +	 * to the zones, now is the time to do it.  	 */  	zone_size[0] = max_low - min;  #ifdef CONFIG_HIGHMEM @@ -303,11 +212,11 @@ static void __init bootmem_free_node(int node, struct meminfo *mi)  #endif  	/* -	 * For each bank in this node, calculate the size of the holes. -	 *  holes = node_size - sum(bank_sizes_in_node) +	 * Calculate the size of the holes. +	 *  holes = node_size - sum(bank_sizes)  	 */  	memcpy(zhole_size, zone_size, sizeof(zhole_size)); -	for_each_nodebank(i, mi, node) { +	for_each_bank(i, mi) {  		int idx = 0;  #ifdef CONFIG_HIGHMEM  		if (mi->bank[i].highmem) @@ -320,24 +229,23 @@ static void __init bootmem_free_node(int node, struct meminfo *mi)  	 * Adjust the sizes according to any special requirements for  	 * this machine type.  	 */ -	arch_adjust_zones(node, zone_size, zhole_size); +	arch_adjust_zones(zone_size, zhole_size); -	free_area_init_node(node, zone_size, min, zhole_size); +	free_area_init_node(0, zone_size, min, zhole_size);  }  #ifndef CONFIG_SPARSEMEM  int pfn_valid(unsigned long pfn)  { -	struct meminfo *mi = &meminfo; -	unsigned int left = 0, right = mi->nr_banks; +	struct memblock_region *mem = &memblock.memory; +	unsigned int left = 0, right = mem->cnt;  	do {  		unsigned int mid = (right + left) / 2; -		struct membank *bank = &mi->bank[mid]; -		if (pfn < bank_pfn_start(bank)) +		if (pfn < memblock_start_pfn(mem, mid))  			right = mid; -		else if (pfn >= bank_pfn_end(bank)) +		else if (pfn >= memblock_end_pfn(mem, mid))  			left = mid + 1;  		else  			return 1; @@ -346,73 +254,69 @@ int pfn_valid(unsigned long pfn)  }  EXPORT_SYMBOL(pfn_valid); -static void arm_memory_present(struct meminfo *mi, int node) +static void arm_memory_present(void)  {  }  #else -static void arm_memory_present(struct meminfo *mi, int node) +static void arm_memory_present(void)  {  	int i; -	for_each_nodebank(i, mi, node) { -		struct membank *bank = &mi->bank[i]; -		memory_present(node, bank_pfn_start(bank), bank_pfn_end(bank)); -	} +	for (i = 0; i < memblock.memory.cnt; i++) +		memory_present(0, memblock_start_pfn(&memblock.memory, i), +				  memblock_end_pfn(&memblock.memory, i));  }  #endif -void __init bootmem_init(void) +void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)  { -	struct meminfo *mi = &meminfo; -	unsigned long min, max_low, max_high; -	int node, initrd_node; +	int i; -	/* -	 * Locate which node contains the ramdisk image, if any. -	 */ -	initrd_node = check_initrd(mi); +	memblock_init(); +	for (i = 0; i < mi->nr_banks; i++) +		memblock_add(mi->bank[i].start, mi->bank[i].size); -	max_low = max_high = 0; +	/* Register the kernel text, kernel data and initrd with memblock. */ +#ifdef CONFIG_XIP_KERNEL +	memblock_reserve(__pa(_data), _end - _data); +#else +	memblock_reserve(__pa(_stext), _end - _stext); +#endif +#ifdef CONFIG_BLK_DEV_INITRD +	if (phys_initrd_size) { +		memblock_reserve(phys_initrd_start, phys_initrd_size); -	/* -	 * Run through each node initialising the bootmem allocator. -	 */ -	for_each_node(node) { -		unsigned long node_low, node_high; +		/* Now convert initrd to virtual addresses */ +		initrd_start = __phys_to_virt(phys_initrd_start); +		initrd_end = initrd_start + phys_initrd_size; +	} +#endif -		find_node_limits(node, mi, &min, &node_low, &node_high); +	arm_mm_memblock_reserve(); -		if (node_low > max_low) -			max_low = node_low; -		if (node_high > max_high) -			max_high = node_high; +	/* reserve any platform specific memblock areas */ +	if (mdesc->reserve) +		mdesc->reserve(); -		/* -		 * If there is no memory in this node, ignore it. -		 * (We can't have nodes which have no lowmem) -		 */ -		if (node_low == 0) -			continue; +	memblock_analyze(); +	memblock_dump_all(); +} -		bootmem_init_node(node, mi, min, node_low); +void __init bootmem_init(void) +{ +	struct meminfo *mi = &meminfo; +	unsigned long min, max_low, max_high; -		/* -		 * Reserve any special node zero regions. -		 */ -		if (node == 0) -			reserve_node_zero(NODE_DATA(node)); +	max_low = max_high = 0; -		/* -		 * If the initrd is in this node, reserve its memory. -		 */ -		if (node == initrd_node) -			bootmem_reserve_initrd(node); +	find_limits(mi, &min, &max_low, &max_high); -		/* -		 * Sparsemem tries to allocate bootmem in memory_present(), -		 * so must be done after the fixed reservations -		 */ -		arm_memory_present(mi, node); -	} +	arm_bootmem_init(mi, min, max_low); + +	/* +	 * Sparsemem tries to allocate bootmem in memory_present(), +	 * so must be done after the fixed reservations +	 */ +	arm_memory_present();  	/*  	 * sparse_init() needs the bootmem allocator up and running. @@ -420,12 +324,11 @@ void __init bootmem_init(void)  	sparse_init();  	/* -	 * Now free memory in each node - free_area_init_node needs +	 * Now free the memory - 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); +	arm_bootmem_free(mi, min, max_low, max_high);  	high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1; @@ -460,7 +363,7 @@ static inline int free_area(unsigned long pfn, unsigned long end, char *s)  }  static inline void -free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn) +free_memmap(unsigned long start_pfn, unsigned long end_pfn)  {  	struct page *start_pg, *end_pg;  	unsigned long pg, pgend; @@ -483,13 +386,13 @@ free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)  	 * free the section of the memmap array.  	 */  	if (pg < pgend) -		free_bootmem_node(NODE_DATA(node), pg, pgend - pg); +		free_bootmem(pg, pgend - pg);  }  /*   * The mem_map array can get very big.  Free the unused area of the memory map.   */ -static void __init free_unused_memmap_node(int node, struct meminfo *mi) +static void __init free_unused_memmap(struct meminfo *mi)  {  	unsigned long bank_start, prev_bank_end = 0;  	unsigned int i; @@ -499,7 +402,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)  	 * may not be the case, especially if the user has provided the  	 * information on the command line.  	 */ -	for_each_nodebank(i, mi, node) { +	for_each_bank(i, mi) {  		struct membank *bank = &mi->bank[i];  		bank_start = bank_pfn_start(bank); @@ -514,7 +417,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)  		 * between the current bank and the previous, free it.  		 */  		if (prev_bank_end && prev_bank_end != bank_start) -			free_memmap(node, prev_bank_end, bank_start); +			free_memmap(prev_bank_end, bank_start);  		prev_bank_end = bank_pfn_end(bank);  	} @@ -528,26 +431,19 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)  void __init mem_init(void)  {  	unsigned long reserved_pages, free_pages; -	int i, node; +	int i;  #ifdef CONFIG_HAVE_TCM  	/* These pointers are filled in on TCM detection */  	extern u32 dtcm_end;  	extern u32 itcm_end;  #endif -#ifndef CONFIG_DISCONTIGMEM  	max_mapnr   = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; -#endif  	/* this will put all unused low memory onto the freelists */ -	for_each_online_node(node) { -		pg_data_t *pgdat = NODE_DATA(node); - -		free_unused_memmap_node(node, &meminfo); +	free_unused_memmap(&meminfo); -		if (pgdat->node_spanned_pages != 0) -			totalram_pages += free_all_bootmem_node(pgdat); -	} +	totalram_pages += free_all_bootmem();  #ifdef CONFIG_SA1111  	/* now that our DMA memory is actually so designated, we can free it */ @@ -557,39 +453,35 @@ void __init mem_init(void)  #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); -		} +	for_each_bank (i, &meminfo) { +		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  	reserved_pages = free_pages = 0; -	for_each_online_node(node) { -		for_each_nodebank(i, &meminfo, node) { -			struct membank *bank = &meminfo.bank[i]; -			unsigned int pfn1, pfn2; -			struct page *page, *end; +	for_each_bank(i, &meminfo) { +		struct membank *bank = &meminfo.bank[i]; +		unsigned int pfn1, pfn2; +		struct page *page, *end; -			pfn1 = bank_pfn_start(bank); -			pfn2 = bank_pfn_end(bank); +		pfn1 = bank_pfn_start(bank); +		pfn2 = bank_pfn_end(bank); -			page = pfn_to_page(pfn1); -			end  = pfn_to_page(pfn2 - 1) + 1; +		page = pfn_to_page(pfn1); +		end  = pfn_to_page(pfn2 - 1) + 1; -			do { -				if (PageReserved(page)) -					reserved_pages++; -				else if (!page_count(page)) -					free_pages++; -				page++; -			} while (page < end); -		} +		do { +			if (PageReserved(page)) +				reserved_pages++; +			else if (!page_count(page)) +				free_pages++; +			page++; +		} while (page < end);  	}  	/*  |