diff options
Diffstat (limited to 'arch/x86/mm/init_64.c')
| -rw-r--r-- | arch/x86/mm/init_64.c | 73 | 
1 files changed, 34 insertions, 39 deletions
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 474e28f1081..71ff55a1b28 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1011,11 +1011,8 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct)  	flush_tlb_all();  } -void __ref vmemmap_free(struct page *memmap, unsigned long nr_pages) +void __ref vmemmap_free(unsigned long start, unsigned long end)  { -	unsigned long start = (unsigned long)memmap; -	unsigned long end = (unsigned long)(memmap + nr_pages); -  	remove_pagetable(start, end, false);  } @@ -1067,10 +1064,9 @@ void __init mem_init(void)  	/* clear_bss() already clear the empty_zero_page */ -	reservedpages = 0; - -	/* this will put all low memory onto the freelists */  	register_page_bootmem_info(); + +	/* this will put all memory onto the freelists */  	totalram_pages = free_all_bootmem();  	absent_pages = absent_pages_in_range(0, max_pfn); @@ -1285,18 +1281,17 @@ static long __meminitdata addr_start, addr_end;  static void __meminitdata *p_start, *p_end;  static int __meminitdata node_start; -int __meminit -vmemmap_populate(struct page *start_page, unsigned long size, int node) +static int __meminit vmemmap_populate_hugepages(unsigned long start, +						unsigned long end, int node)  { -	unsigned long addr = (unsigned long)start_page; -	unsigned long end = (unsigned long)(start_page + size); +	unsigned long addr;  	unsigned long next;  	pgd_t *pgd;  	pud_t *pud;  	pmd_t *pmd; -	for (; addr < end; addr = next) { -		void *p = NULL; +	for (addr = start; addr < end; addr = next) { +		next = pmd_addr_end(addr, end);  		pgd = vmemmap_pgd_populate(addr, node);  		if (!pgd) @@ -1306,31 +1301,14 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)  		if (!pud)  			return -ENOMEM; -		if (!cpu_has_pse) { -			next = (addr + PAGE_SIZE) & PAGE_MASK; -			pmd = vmemmap_pmd_populate(pud, addr, node); - -			if (!pmd) -				return -ENOMEM; - -			p = vmemmap_pte_populate(pmd, addr, node); +		pmd = pmd_offset(pud, addr); +		if (pmd_none(*pmd)) { +			void *p; -			if (!p) -				return -ENOMEM; - -			addr_end = addr + PAGE_SIZE; -			p_end = p + PAGE_SIZE; -		} else { -			next = pmd_addr_end(addr, end); - -			pmd = pmd_offset(pud, addr); -			if (pmd_none(*pmd)) { +			p = vmemmap_alloc_block_buf(PMD_SIZE, node); +			if (p) {  				pte_t entry; -				p = vmemmap_alloc_block_buf(PMD_SIZE, node); -				if (!p) -					return -ENOMEM; -  				entry = pfn_pte(__pa(p) >> PAGE_SHIFT,  						PAGE_KERNEL_LARGE);  				set_pmd(pmd, __pmd(pte_val(entry))); @@ -1347,15 +1325,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)  				addr_end = addr + PMD_SIZE;  				p_end = p + PMD_SIZE; -			} else -				vmemmap_verify((pte_t *)pmd, node, addr, next); +				continue; +			} +		} else if (pmd_large(*pmd)) { +			vmemmap_verify((pte_t *)pmd, node, addr, next); +			continue;  		} - +		pr_warn_once("vmemmap: falling back to regular page backing\n"); +		if (vmemmap_populate_basepages(addr, next, node)) +			return -ENOMEM;  	} -	sync_global_pgds((unsigned long)start_page, end - 1);  	return 0;  } +int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) +{ +	int err; + +	if (cpu_has_pse) +		err = vmemmap_populate_hugepages(start, end, node); +	else +		err = vmemmap_populate_basepages(start, end, node); +	if (!err) +		sync_global_pgds(start, end - 1); +	return err; +} +  #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HAVE_BOOTMEM_INFO_NODE)  void register_page_bootmem_memmap(unsigned long section_nr,  				  struct page *start_page, unsigned long size)  |