diff options
Diffstat (limited to 'arch/arm64/mm/mmu.c')
| -rw-r--r-- | arch/arm64/mm/mmu.c | 47 | 
1 files changed, 33 insertions, 14 deletions
| diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index e97f018ff740..ef82312860ac 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -97,7 +97,7 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,  }  EXPORT_SYMBOL(phys_mem_access_prot); -static phys_addr_t __init early_pgtable_alloc(void) +static phys_addr_t __init early_pgtable_alloc(int shift)  {  	phys_addr_t phys;  	void *ptr; @@ -174,7 +174,7 @@ static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,  static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,  				unsigned long end, phys_addr_t phys,  				pgprot_t prot, -				phys_addr_t (*pgtable_alloc)(void), +				phys_addr_t (*pgtable_alloc)(int),  				int flags)  {  	unsigned long next; @@ -184,7 +184,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,  	if (pmd_none(pmd)) {  		phys_addr_t pte_phys;  		BUG_ON(!pgtable_alloc); -		pte_phys = pgtable_alloc(); +		pte_phys = pgtable_alloc(PAGE_SHIFT);  		__pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE);  		pmd = READ_ONCE(*pmdp);  	} @@ -208,7 +208,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,  static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,  		     phys_addr_t phys, pgprot_t prot, -		     phys_addr_t (*pgtable_alloc)(void), int flags) +		     phys_addr_t (*pgtable_alloc)(int), int flags)  {  	unsigned long next;  	pmd_t *pmdp; @@ -246,7 +246,7 @@ static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,  static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,  				unsigned long end, phys_addr_t phys,  				pgprot_t prot, -				phys_addr_t (*pgtable_alloc)(void), int flags) +				phys_addr_t (*pgtable_alloc)(int), int flags)  {  	unsigned long next;  	pud_t pud = READ_ONCE(*pudp); @@ -258,7 +258,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,  	if (pud_none(pud)) {  		phys_addr_t pmd_phys;  		BUG_ON(!pgtable_alloc); -		pmd_phys = pgtable_alloc(); +		pmd_phys = pgtable_alloc(PMD_SHIFT);  		__pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE);  		pud = READ_ONCE(*pudp);  	} @@ -294,7 +294,7 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next,  static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,  			   phys_addr_t phys, pgprot_t prot, -			   phys_addr_t (*pgtable_alloc)(void), +			   phys_addr_t (*pgtable_alloc)(int),  			   int flags)  {  	unsigned long next; @@ -304,7 +304,7 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,  	if (pgd_none(pgd)) {  		phys_addr_t pud_phys;  		BUG_ON(!pgtable_alloc); -		pud_phys = pgtable_alloc(); +		pud_phys = pgtable_alloc(PUD_SHIFT);  		__pgd_populate(pgdp, pud_phys, PUD_TYPE_TABLE);  		pgd = READ_ONCE(*pgdp);  	} @@ -345,7 +345,7 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,  static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,  				 unsigned long virt, phys_addr_t size,  				 pgprot_t prot, -				 phys_addr_t (*pgtable_alloc)(void), +				 phys_addr_t (*pgtable_alloc)(int),  				 int flags)  {  	unsigned long addr, length, end, next; @@ -371,17 +371,36 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,  	} while (pgdp++, addr = next, addr != end);  } -static phys_addr_t pgd_pgtable_alloc(void) +static phys_addr_t __pgd_pgtable_alloc(int shift)  {  	void *ptr = (void *)__get_free_page(PGALLOC_GFP); -	if (!ptr || !pgtable_page_ctor(virt_to_page(ptr))) -		BUG(); +	BUG_ON(!ptr);  	/* Ensure the zeroed page is visible to the page table walker */  	dsb(ishst);  	return __pa(ptr);  } +static phys_addr_t pgd_pgtable_alloc(int shift) +{ +	phys_addr_t pa = __pgd_pgtable_alloc(shift); + +	/* +	 * Call proper page table ctor in case later we need to +	 * call core mm functions like apply_to_page_range() on +	 * this pre-allocated page table. +	 * +	 * We don't select ARCH_ENABLE_SPLIT_PMD_PTLOCK if pmd is +	 * folded, and if so pgtable_pmd_page_ctor() becomes nop. +	 */ +	if (shift == PAGE_SHIFT) +		BUG_ON(!pgtable_page_ctor(phys_to_page(pa))); +	else if (shift == PMD_SHIFT) +		BUG_ON(!pgtable_pmd_page_ctor(phys_to_page(pa))); + +	return pa; +} +  /*   * This function can only be used to modify existing table entries,   * without allocating new levels of table. Note that this permits the @@ -583,7 +602,7 @@ static int __init map_entry_trampoline(void)  	/* Map only the text into the trampoline page table */  	memset(tramp_pg_dir, 0, PGD_SIZE);  	__create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE, -			     prot, pgd_pgtable_alloc, 0); +			     prot, __pgd_pgtable_alloc, 0);  	/* Map both the text and data into the kernel page table */  	__set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot); @@ -1055,7 +1074,7 @@ int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,  		flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;  	__create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), -			     size, PAGE_KERNEL, pgd_pgtable_alloc, flags); +			     size, PAGE_KERNEL, __pgd_pgtable_alloc, flags);  	return __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,  			   altmap, want_memblock); |