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

MIPS: Add 48-bit VA space (and 4-level page tables) for 4K pages.

Some users must have 4K pages while needing a 48-bit VA space size.
The cleanest way do do this is to go to a 4-level page table for this
case. Each page table level using order-0 pages adds 9 bits to the
VA size (at 4K pages, so for four levels we get 9 * 4 + 12 == 48-bits.

For the 4K page size case only we add support functions for the PUD
level of the page table tree, also the TLB exception handlers get an
extra level of tree walk.

[david.daney@cavium.com: Forward port to v4.10.]
[david.daney@cavium.com: Forward port to v4.11.]

Signed-off-by: Alex Belits <alex.belits@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Alex Belits <alex.belits@cavium.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/15312/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Alex Belits and committed by
Ralf Baechle
3377e227 dfa32261

+173 -14
+8 -5
arch/mips/Kconfig
··· 2121 2121 bool "48 bits virtual memory" 2122 2122 depends on 64BIT 2123 2123 help 2124 - Support a maximum at least 48 bits of application virtual memory. 2125 - Default is 40 bits or less, depending on the CPU. 2126 - This option result in a small memory overhead for page tables. 2127 - This option is only supported with 16k and 64k page sizes. 2124 + Support a maximum at least 48 bits of application virtual 2125 + memory. Default is 40 bits or less, depending on the CPU. 2126 + For page sizes 16k and above, this option results in a small 2127 + memory overhead for page tables. For 4k page size, a fourth 2128 + level of page tables is added which imposes both a memory 2129 + overhead as well as slower TLB fault handling. 2130 + 2128 2131 If unsure, say N. 2129 2132 2130 2133 choice ··· 2137 2134 config PAGE_SIZE_4KB 2138 2135 bool "4kB" 2139 2136 depends on !CPU_LOONGSON2 && !CPU_LOONGSON3 2140 - depends on !MIPS_VA_BITS_48 2141 2137 help 2142 2138 This option select the standard 4kB Linux page size. On some 2143 2139 R3000-family processors this is the only available page size. Using ··· 2985 2983 2986 2984 config PGTABLE_LEVELS 2987 2985 int 2986 + default 4 if PAGE_SIZE_4KB && MIPS_VA_BITS_48 2988 2987 default 3 if 64BIT && !PAGE_SIZE_64KB 2989 2988 default 2 2990 2989
+26
arch/mips/include/asm/pgalloc.h
··· 110 110 111 111 #endif 112 112 113 + #ifndef __PAGETABLE_PUD_FOLDED 114 + 115 + static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) 116 + { 117 + pud_t *pud; 118 + 119 + pud = (pud_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, PUD_ORDER); 120 + if (pud) 121 + pud_init((unsigned long)pud, (unsigned long)invalid_pmd_table); 122 + return pud; 123 + } 124 + 125 + static inline void pud_free(struct mm_struct *mm, pud_t *pud) 126 + { 127 + free_pages((unsigned long)pud, PUD_ORDER); 128 + } 129 + 130 + static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) 131 + { 132 + set_pgd(pgd, __pgd((unsigned long)pud)); 133 + } 134 + 135 + #define __pud_free_tlb(tlb, x, addr) pud_free((tlb)->mm, x) 136 + 137 + #endif /* __PAGETABLE_PUD_FOLDED */ 138 + 113 139 #define check_pgt_cache() do { } while (0) 114 140 115 141 extern void pagetable_init(void);
+84 -6
arch/mips/include/asm/pgtable-64.h
··· 20 20 #define __ARCH_USE_5LEVEL_HACK 21 21 #if defined(CONFIG_PAGE_SIZE_64KB) && !defined(CONFIG_MIPS_VA_BITS_48) 22 22 #include <asm-generic/pgtable-nopmd.h> 23 - #else 23 + #elif !(defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_MIPS_VA_BITS_48)) 24 24 #include <asm-generic/pgtable-nopud.h> 25 25 #endif 26 26 ··· 54 54 #define PMD_SIZE (1UL << PMD_SHIFT) 55 55 #define PMD_MASK (~(PMD_SIZE-1)) 56 56 57 - 58 - #define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) 57 + # ifdef __PAGETABLE_PUD_FOLDED 58 + # define PGDIR_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) 59 + # endif 59 60 #endif 61 + 62 + #ifndef __PAGETABLE_PUD_FOLDED 63 + #define PUD_SHIFT (PMD_SHIFT + (PAGE_SHIFT + PMD_ORDER - 3)) 64 + #define PUD_SIZE (1UL << PUD_SHIFT) 65 + #define PUD_MASK (~(PUD_SIZE-1)) 66 + #define PGDIR_SHIFT (PUD_SHIFT + (PAGE_SHIFT + PUD_ORDER - 3)) 67 + #endif 68 + 60 69 #define PGDIR_SIZE (1UL << PGDIR_SHIFT) 61 70 #define PGDIR_MASK (~(PGDIR_SIZE-1)) 62 71 ··· 88 79 * of virtual address space. 89 80 */ 90 81 #ifdef CONFIG_PAGE_SIZE_4KB 91 - #define PGD_ORDER 1 92 - #define PUD_ORDER aieeee_attempt_to_allocate_pud 82 + # ifdef CONFIG_MIPS_VA_BITS_48 83 + # define PGD_ORDER 0 84 + # define PUD_ORDER 0 85 + # else 86 + # define PGD_ORDER 1 87 + # define PUD_ORDER aieeee_attempt_to_allocate_pud 88 + # endif 93 89 #define PMD_ORDER 0 94 90 #define PTE_ORDER 0 95 91 #endif ··· 132 118 #endif 133 119 134 120 #define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t)) 121 + #ifndef __PAGETABLE_PUD_FOLDED 122 + #define PTRS_PER_PUD ((PAGE_SIZE << PUD_ORDER) / sizeof(pud_t)) 123 + #endif 135 124 #ifndef __PAGETABLE_PMD_FOLDED 136 125 #define PTRS_PER_PMD ((PAGE_SIZE << PMD_ORDER) / sizeof(pmd_t)) 137 126 #endif ··· 151 134 #define VMALLOC_START (MAP_BASE + (2 * PAGE_SIZE)) 152 135 #define VMALLOC_END \ 153 136 (MAP_BASE + \ 154 - min(PTRS_PER_PGD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, \ 137 + min(PTRS_PER_PGD * PTRS_PER_PUD * PTRS_PER_PMD * PTRS_PER_PTE * PAGE_SIZE, \ 155 138 (1UL << cpu_vmbits)) - (1UL << 32)) 156 139 157 140 #if defined(CONFIG_MODULES) && defined(KBUILD_64BIT_SYM32) && \ ··· 167 150 #define pmd_ERROR(e) \ 168 151 printk("%s:%d: bad pmd %016lx.\n", __FILE__, __LINE__, pmd_val(e)) 169 152 #endif 153 + #ifndef __PAGETABLE_PUD_FOLDED 154 + #define pud_ERROR(e) \ 155 + printk("%s:%d: bad pud %016lx.\n", __FILE__, __LINE__, pud_val(e)) 156 + #endif 170 157 #define pgd_ERROR(e) \ 171 158 printk("%s:%d: bad pgd %016lx.\n", __FILE__, __LINE__, pgd_val(e)) 172 159 173 160 extern pte_t invalid_pte_table[PTRS_PER_PTE]; 174 161 extern pte_t empty_bad_page_table[PTRS_PER_PTE]; 175 162 163 + #ifndef __PAGETABLE_PUD_FOLDED 164 + /* 165 + * For 4-level pagetables we defines these ourselves, for 3-level the 166 + * definitions are below, for 2-level the 167 + * definitions are supplied by <asm-generic/pgtable-nopmd.h>. 168 + */ 169 + typedef struct { unsigned long pud; } pud_t; 170 + #define pud_val(x) ((x).pud) 171 + #define __pud(x) ((pud_t) { (x) }) 172 + 173 + extern pud_t invalid_pud_table[PTRS_PER_PUD]; 174 + 175 + /* 176 + * Empty pgd entries point to the invalid_pud_table. 177 + */ 178 + static inline int pgd_none(pgd_t pgd) 179 + { 180 + return pgd_val(pgd) == (unsigned long)invalid_pud_table; 181 + } 182 + 183 + static inline int pgd_bad(pgd_t pgd) 184 + { 185 + if (unlikely(pgd_val(pgd) & ~PAGE_MASK)) 186 + return 1; 187 + 188 + return 0; 189 + } 190 + 191 + static inline int pgd_present(pgd_t pgd) 192 + { 193 + return pgd_val(pgd) != (unsigned long)invalid_pud_table; 194 + } 195 + 196 + static inline void pgd_clear(pgd_t *pgdp) 197 + { 198 + pgd_val(*pgdp) = (unsigned long)invalid_pud_table; 199 + } 200 + 201 + #define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) 202 + 203 + static inline unsigned long pgd_page_vaddr(pgd_t pgd) 204 + { 205 + return pgd_val(pgd); 206 + } 207 + 208 + static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address) 209 + { 210 + return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(address); 211 + } 212 + 213 + static inline void set_pgd(pgd_t *pgd, pgd_t pgdval) 214 + { 215 + *pgd = pgdval; 216 + } 217 + 218 + #endif 176 219 177 220 #ifndef __PAGETABLE_PMD_FOLDED 178 221 /* ··· 358 281 * Initialize a new pgd / pmd table with invalid pointers. 359 282 */ 360 283 extern void pgd_init(unsigned long page); 284 + extern void pud_init(unsigned long page, unsigned long pagetable); 361 285 extern void pmd_init(unsigned long page, unsigned long pagetable); 362 286 363 287 /*
+3
arch/mips/mm/init.c
··· 537 537 * it in the linker script. 538 538 */ 539 539 pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(.bss..swapper_pg_dir); 540 + #ifndef __PAGETABLE_PUD_FOLDED 541 + pud_t invalid_pud_table[PTRS_PER_PUD] __page_aligned_bss; 542 + #endif 540 543 #ifndef __PAGETABLE_PMD_FOLDED 541 544 pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss; 542 545 EXPORT_SYMBOL_GPL(invalid_pmd_table);
+30 -3
arch/mips/mm/pgtable-64.c
··· 19 19 unsigned long *p, *end; 20 20 unsigned long entry; 21 21 22 - #ifdef __PAGETABLE_PMD_FOLDED 23 - entry = (unsigned long)invalid_pte_table; 24 - #else 22 + #if !defined(__PAGETABLE_PUD_FOLDED) 23 + entry = (unsigned long)invalid_pud_table; 24 + #elif !defined(__PAGETABLE_PMD_FOLDED) 25 25 entry = (unsigned long)invalid_pmd_table; 26 + #else 27 + entry = (unsigned long)invalid_pte_table; 26 28 #endif 27 29 28 30 p = (unsigned long *) page; ··· 66 64 EXPORT_SYMBOL_GPL(pmd_init); 67 65 #endif 68 66 67 + #ifndef __PAGETABLE_PUD_FOLDED 68 + void pud_init(unsigned long addr, unsigned long pagetable) 69 + { 70 + unsigned long *p, *end; 71 + 72 + p = (unsigned long *)addr; 73 + end = p + PTRS_PER_PUD; 74 + 75 + do { 76 + p[0] = pagetable; 77 + p[1] = pagetable; 78 + p[2] = pagetable; 79 + p[3] = pagetable; 80 + p[4] = pagetable; 81 + p += 8; 82 + p[-3] = pagetable; 83 + p[-2] = pagetable; 84 + p[-1] = pagetable; 85 + } while (p != end); 86 + } 87 + #endif 88 + 69 89 pmd_t mk_pmd(struct page *page, pgprot_t prot) 70 90 { 71 91 pmd_t pmd; ··· 111 87 112 88 /* Initialize the entire pgd. */ 113 89 pgd_init((unsigned long)swapper_pg_dir); 90 + #ifndef __PAGETABLE_PUD_FOLDED 91 + pud_init((unsigned long)invalid_pud_table, (unsigned long)invalid_pmd_table); 92 + #endif 114 93 #ifndef __PAGETABLE_PMD_FOLDED 115 94 pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); 116 95 #endif
+22
arch/mips/mm/tlbex.c
··· 865 865 866 866 uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3); 867 867 uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */ 868 + #ifndef __PAGETABLE_PUD_FOLDED 869 + uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */ 870 + uasm_i_ld(p, ptr, 0, ptr); /* get pud pointer */ 871 + uasm_i_dsrl_safe(p, tmp, tmp, PUD_SHIFT - 3); /* get pud offset in bytes */ 872 + uasm_i_andi(p, tmp, tmp, (PTRS_PER_PUD - 1) << 3); 873 + uasm_i_daddu(p, ptr, ptr, tmp); /* add in pud offset */ 874 + #endif 868 875 #ifndef __PAGETABLE_PMD_FOLDED 869 876 uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */ 870 877 uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */ ··· 1190 1183 uasm_i_daddu(p, ptr, ptr, scratch); /* add in pgd offset */ 1191 1184 uasm_i_ld(p, LOC_PTEP, 0, ptr); /* get pmd pointer */ 1192 1185 } 1186 + 1187 + #ifndef __PAGETABLE_PUD_FOLDED 1188 + /* get pud offset in bytes */ 1189 + uasm_i_dsrl_safe(p, scratch, tmp, PUD_SHIFT - 3); 1190 + uasm_i_andi(p, scratch, scratch, (PTRS_PER_PUD - 1) << 3); 1191 + 1192 + if (use_lwx_insns()) { 1193 + UASM_i_LWX(p, ptr, scratch, ptr); 1194 + } else { 1195 + uasm_i_daddu(p, ptr, ptr, scratch); /* add in pmd offset */ 1196 + UASM_i_LW(p, ptr, 0, ptr); 1197 + } 1198 + /* ptr contains a pointer to PMD entry */ 1199 + /* tmp contains the address */ 1200 + #endif 1193 1201 1194 1202 #ifndef __PAGETABLE_PMD_FOLDED 1195 1203 /* get pmd offset in bytes */