Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cb248ab authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds
Browse files

[PATCH] Have x86_64 use add_active_range() and free_area_init_nodes



Size zones and holes in an architecture independent manner for x86_64.

Signed-off-by: default avatarMel Gorman <mel@csn.ul.ie>
Cc: Dave Hansen <haveblue@us.ibm.com>
Cc: Andy Whitcroft <apw@shadowen.org>
Cc: Andi Kleen <ak@muc.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: "Keith Mannthey" <kmannth@gmail.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Yasunori Goto <y-goto@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4cfee88a
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -85,6 +85,9 @@ config ARCH_MAY_HAVE_PC_FDC
	bool
	default y

config ARCH_POPULATES_NODE_MAP
	def_bool y

config DMI
	bool
	default y
+45 −80
Original line number Diff line number Diff line
@@ -162,58 +162,13 @@ unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsi
	return -1UL;		
} 

/* 
 * Free bootmem based on the e820 table for a node.
 */
void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
{
	int i;
	for (i = 0; i < e820.nr_map; i++) {
		struct e820entry *ei = &e820.map[i]; 
		unsigned long last, addr;

		if (ei->type != E820_RAM || 
		    ei->addr+ei->size <= start || 
		    ei->addr >= end)
			continue;

		addr = round_up(ei->addr, PAGE_SIZE);
		if (addr < start) 
			addr = start;

		last = round_down(ei->addr + ei->size, PAGE_SIZE); 
		if (last >= end)
			last = end; 

		if (last > addr && last-addr >= PAGE_SIZE)
			free_bootmem_node(pgdat, addr, last-addr);
	}
}

/*
 * Find the highest page frame number we have available
 */
unsigned long __init e820_end_of_ram(void)
{
	int i;
	unsigned long end_pfn = 0;
	
	for (i = 0; i < e820.nr_map; i++) {
		struct e820entry *ei = &e820.map[i]; 
		unsigned long start, end;

		start = round_up(ei->addr, PAGE_SIZE); 
		end = round_down(ei->addr + ei->size, PAGE_SIZE); 
		if (start >= end)
			continue;
		if (ei->type == E820_RAM) { 
		if (end > end_pfn<<PAGE_SHIFT)
			end_pfn = end>>PAGE_SHIFT;
		} else { 
			if (end > end_pfn_map<<PAGE_SHIFT) 
				end_pfn_map = end>>PAGE_SHIFT;
		} 
	}
	end_pfn = find_max_pfn_with_active_regions();
	
	if (end_pfn > end_pfn_map) 
		end_pfn_map = end_pfn;
@@ -224,43 +179,10 @@ unsigned long __init e820_end_of_ram(void)
	if (end_pfn > end_pfn_map) 
		end_pfn = end_pfn_map; 

	printk("end_pfn_map = %lu\n", end_pfn_map);
	return end_pfn;	
}

/* 
 * Compute how much memory is missing in a range.
 * Unlike the other functions in this file the arguments are in page numbers.
 */
unsigned long __init
e820_hole_size(unsigned long start_pfn, unsigned long end_pfn)
{
	unsigned long ram = 0;
	unsigned long start = start_pfn << PAGE_SHIFT;
	unsigned long end = end_pfn << PAGE_SHIFT;
	int i;
	for (i = 0; i < e820.nr_map; i++) {
		struct e820entry *ei = &e820.map[i];
		unsigned long last, addr;

		if (ei->type != E820_RAM ||
		    ei->addr+ei->size <= start ||
		    ei->addr >= end)
			continue;

		addr = round_up(ei->addr, PAGE_SIZE);
		if (addr < start)
			addr = start;

		last = round_down(ei->addr + ei->size, PAGE_SIZE);
		if (last >= end)
			last = end;

		if (last > addr)
			ram += last - addr;
	}
	return ((end - start) - ram) >> PAGE_SHIFT;
}

/*
 * Mark e820 reserved areas as busy for the resource manager.
 */
@@ -342,6 +264,49 @@ void __init e820_mark_nosave_regions(void)
	}
}

/* Walk the e820 map and register active regions within a node */
void __init
e820_register_active_regions(int nid, unsigned long start_pfn,
							unsigned long end_pfn)
{
	int i;
	unsigned long ei_startpfn, ei_endpfn;
	for (i = 0; i < e820.nr_map; i++) {
		struct e820entry *ei = &e820.map[i];
		ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
		ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE)
								>> PAGE_SHIFT;

		/* Skip map entries smaller than a page */
		if (ei_startpfn > ei_endpfn)
			continue;

		/* Check if end_pfn_map should be updated */
		if (ei->type != E820_RAM && ei_endpfn > end_pfn_map)
			end_pfn_map = ei_endpfn;

		/* Skip if map is outside the node */
		if (ei->type != E820_RAM ||
				ei_endpfn <= start_pfn ||
				ei_startpfn >= end_pfn)
			continue;

		/* Check for overlaps */
		if (ei_startpfn < start_pfn)
			ei_startpfn = start_pfn;
		if (ei_endpfn > end_pfn)
			ei_endpfn = end_pfn;

		/* Obey end_user_pfn to save on memmap */
		if (ei_startpfn >= end_user_pfn)
			continue;
		if (ei_endpfn > end_user_pfn)
			ei_endpfn = end_user_pfn;

		add_active_range(nid, ei_startpfn, ei_endpfn);
	}
}

/* 
 * Add a memory region to the kernel e820 map.
 */ 
+6 −1
Original line number Diff line number Diff line
@@ -292,7 +292,8 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
	if (bootmap == -1L)
		panic("Cannot find bootmem map of size %ld\n",bootmap_size);
	bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
	e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT);
	e820_register_active_regions(0, start_pfn, end_pfn);
	free_bootmem_with_active_regions(0, end_pfn);
	reserve_bootmem(bootmap, bootmap_size);
} 
#endif
@@ -384,6 +385,7 @@ void __init setup_arch(char **cmdline_p)

	finish_e820_parsing();

	e820_register_active_regions(0, 0, -1UL);
	/*
	 * partially used pages are not usable - thus
	 * we are rounding upwards:
@@ -414,6 +416,9 @@ void __init setup_arch(char **cmdline_p)
	max_pfn = end_pfn;
	high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;

	/* Remove active ranges so rediscovery with NUMA-awareness happens */
	remove_all_active_ranges();

#ifdef CONFIG_ACPI_NUMA
	/*
	 * Parse SRAT to discover nodes.
+6 −59
Original line number Diff line number Diff line
@@ -403,69 +403,15 @@ void __cpuinit zap_low_mappings(int cpu)
	__flush_tlb_all();
}

/* Compute zone sizes for the DMA and DMA32 zones in a node. */
__init void
size_zones(unsigned long *z, unsigned long *h,
	   unsigned long start_pfn, unsigned long end_pfn)
{
 	int i;
 	unsigned long w;

 	for (i = 0; i < MAX_NR_ZONES; i++)
 		z[i] = 0;

 	if (start_pfn < MAX_DMA_PFN)
 		z[ZONE_DMA] = MAX_DMA_PFN - start_pfn;
 	if (start_pfn < MAX_DMA32_PFN) {
 		unsigned long dma32_pfn = MAX_DMA32_PFN;
 		if (dma32_pfn > end_pfn)
 			dma32_pfn = end_pfn;
 		z[ZONE_DMA32] = dma32_pfn - start_pfn;
 	}
 	z[ZONE_NORMAL] = end_pfn - start_pfn;

 	/* Remove lower zones from higher ones. */
 	w = 0;
 	for (i = 0; i < MAX_NR_ZONES; i++) {
 		if (z[i])
 			z[i] -= w;
 	        w += z[i];
	}

	/* Compute holes */
	w = start_pfn;
	for (i = 0; i < MAX_NR_ZONES; i++) {
		unsigned long s = w;
		w += z[i];
		h[i] = e820_hole_size(s, w);
	}

	/* Add the space pace needed for mem_map to the holes too. */
	for (i = 0; i < MAX_NR_ZONES; i++)
		h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE;

	/* The 16MB DMA zone has the kernel and other misc mappings.
 	   Account them too */
	if (h[ZONE_DMA]) {
		h[ZONE_DMA] += dma_reserve;
		if (h[ZONE_DMA] >= z[ZONE_DMA]) {
			printk(KERN_WARNING
				"Kernel too large and filling up ZONE_DMA?\n");
			h[ZONE_DMA] = z[ZONE_DMA];
		}
	}
}

#ifndef CONFIG_NUMA
void __init paging_init(void)
{
	unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES];

	unsigned long max_zone_pfns[MAX_NR_ZONES] = {MAX_DMA_PFN,
							MAX_DMA32_PFN,
							end_pfn};
	memory_present(0, 0, end_pfn);
	sparse_init();
	size_zones(zones, holes, 0, end_pfn);
	free_area_init_node(0, NODE_DATA(0), zones,
			    __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
	free_area_init_nodes(max_zone_pfns);
}
#endif

@@ -608,7 +554,8 @@ void __init mem_init(void)
#else
	totalram_pages = free_all_bootmem();
#endif
	reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
	reservedpages = end_pfn - totalram_pages -
					absent_pages_in_range(0, end_pfn);

	after_bootmem = 1;

+3 −0
Original line number Diff line number Diff line
@@ -149,6 +149,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
		
		nodes[nodeid].start = base; 
		nodes[nodeid].end = limit;
		e820_register_active_regions(nodeid,
				nodes[nodeid].start >> PAGE_SHIFT,
				nodes[nodeid].end >> PAGE_SHIFT);

		prevbase = base;

Loading