Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/vmalloc: enable mapping of huge pages at pte level in vmap

On some architectures like powerpc, there are huge pages that are mapped
at pte level.

Enable it in vmap.

For that, architectures can provide arch_vmap_pte_range_map_size() that
returns the size of pages to map at pte level.

Link: https://lkml.kernel.org/r/fb3ccc73377832ac6708181ec419128a2f98ce36.1620795204.git.christophe.leroy@csgroup.eu
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Uladzislau Rezki <uladzislau.rezki@sony.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Christophe Leroy and committed by
Linus Torvalds
f7ee1f13 c742199a

+26 -3
+8
include/linux/vmalloc.h
··· 104 104 } 105 105 #endif 106 106 107 + #ifndef arch_vmap_pte_range_map_size 108 + static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr, unsigned long end, 109 + u64 pfn, unsigned int max_page_shift) 110 + { 111 + return PAGE_SIZE; 112 + } 113 + #endif 114 + 107 115 /* 108 116 * Highlevel APIs for driver use 109 117 */
+18 -3
mm/vmalloc.c
··· 36 36 #include <linux/overflow.h> 37 37 #include <linux/pgtable.h> 38 38 #include <linux/uaccess.h> 39 + #include <linux/hugetlb.h> 39 40 #include <asm/tlbflush.h> 40 41 #include <asm/shmparam.h> 41 42 ··· 84 83 /*** Page table manipulation functions ***/ 85 84 static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, 86 85 phys_addr_t phys_addr, pgprot_t prot, 87 - pgtbl_mod_mask *mask) 86 + unsigned int max_page_shift, pgtbl_mod_mask *mask) 88 87 { 89 88 pte_t *pte; 90 89 u64 pfn; 90 + unsigned long size = PAGE_SIZE; 91 91 92 92 pfn = phys_addr >> PAGE_SHIFT; 93 93 pte = pte_alloc_kernel_track(pmd, addr, mask); ··· 96 94 return -ENOMEM; 97 95 do { 98 96 BUG_ON(!pte_none(*pte)); 97 + 98 + #ifdef CONFIG_HUGETLB_PAGE 99 + size = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift); 100 + if (size != PAGE_SIZE) { 101 + pte_t entry = pfn_pte(pfn, prot); 102 + 103 + entry = pte_mkhuge(entry); 104 + entry = arch_make_huge_pte(entry, ilog2(size), 0); 105 + set_huge_pte_at(&init_mm, addr, pte, entry); 106 + pfn += PFN_DOWN(size); 107 + continue; 108 + } 109 + #endif 99 110 set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot)); 100 111 pfn++; 101 - } while (pte++, addr += PAGE_SIZE, addr != end); 112 + } while (pte += PFN_DOWN(size), addr += size, addr != end); 102 113 *mask |= PGTBL_PTE_MODIFIED; 103 114 return 0; 104 115 } ··· 160 145 continue; 161 146 } 162 147 163 - if (vmap_pte_range(pmd, addr, next, phys_addr, prot, mask)) 148 + if (vmap_pte_range(pmd, addr, next, phys_addr, prot, max_page_shift, mask)) 164 149 return -ENOMEM; 165 150 } while (pmd++, phys_addr += (next - addr), addr = next, addr != end); 166 151 return 0;