diff options
Diffstat (limited to 'arch/x86/mm/init.c')
| -rw-r--r-- | arch/x86/mm/init.c | 58 | 
1 files changed, 31 insertions, 27 deletions
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index ab1f6a93b527..d7aea41563b3 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -35,40 +35,44 @@ struct map_range {  	unsigned page_size_mask;  }; -static void __init find_early_table_space(struct map_range *mr, unsigned long end, -					  int use_pse, int use_gbpages) +/* + * First calculate space needed for kernel direct mapping page tables to cover + * mr[0].start to mr[nr_range - 1].end, while accounting for possible 2M and 1GB + * pages. Then find enough contiguous space for those page tables. + */ +static void __init find_early_table_space(struct map_range *mr, int nr_range)  { -	unsigned long puds, pmds, ptes, tables, start = 0, good_end = end; +	int i; +	unsigned long puds = 0, pmds = 0, ptes = 0, tables; +	unsigned long start = 0, good_end;  	phys_addr_t base; -	puds = (end + PUD_SIZE - 1) >> PUD_SHIFT; -	tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); - -	if (use_gbpages) { -		unsigned long extra; - -		extra = end - ((end>>PUD_SHIFT) << PUD_SHIFT); -		pmds = (extra + PMD_SIZE - 1) >> PMD_SHIFT; -	} else -		pmds = (end + PMD_SIZE - 1) >> PMD_SHIFT; +	for (i = 0; i < nr_range; i++) { +		unsigned long range, extra; -	tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE); +		range = mr[i].end - mr[i].start; +		puds += (range + PUD_SIZE - 1) >> PUD_SHIFT; -	if (use_pse) { -		unsigned long extra; +		if (mr[i].page_size_mask & (1 << PG_LEVEL_1G)) { +			extra = range - ((range >> PUD_SHIFT) << PUD_SHIFT); +			pmds += (extra + PMD_SIZE - 1) >> PMD_SHIFT; +		} else { +			pmds += (range + PMD_SIZE - 1) >> PMD_SHIFT; +		} -		extra = end - ((end>>PMD_SHIFT) << PMD_SHIFT); +		if (mr[i].page_size_mask & (1 << PG_LEVEL_2M)) { +			extra = range - ((range >> PMD_SHIFT) << PMD_SHIFT);  #ifdef CONFIG_X86_32 -		extra += PMD_SIZE; +			extra += PMD_SIZE;  #endif -		/* The first 2/4M doesn't use large pages. */ -		if (mr->start < PMD_SIZE) -			extra += mr->end - mr->start; - -		ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; -	} else -		ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; +			ptes += (extra + PAGE_SIZE - 1) >> PAGE_SHIFT; +		} else { +			ptes += (range + PAGE_SIZE - 1) >> PAGE_SHIFT; +		} +	} +	tables = roundup(puds * sizeof(pud_t), PAGE_SIZE); +	tables += roundup(pmds * sizeof(pmd_t), PAGE_SIZE);  	tables += roundup(ptes * sizeof(pte_t), PAGE_SIZE);  #ifdef CONFIG_X86_32 @@ -86,7 +90,7 @@ static void __init find_early_table_space(struct map_range *mr, unsigned long en  	pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT);  	printk(KERN_DEBUG "kernel direct mapping tables up to %#lx @ [mem %#010lx-%#010lx]\n", -		end - 1, pgt_buf_start << PAGE_SHIFT, +		mr[nr_range - 1].end - 1, pgt_buf_start << PAGE_SHIFT,  		(pgt_buf_top << PAGE_SHIFT) - 1);  } @@ -267,7 +271,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,  	 * nodes are discovered.  	 */  	if (!after_bootmem) -		find_early_table_space(&mr[0], end, use_pse, use_gbpages); +		find_early_table_space(mr, nr_range);  	for (i = 0; i < nr_range; i++)  		ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,  | 
