diff options
Diffstat (limited to 'arch/mips/mm/tlbex.c')
-rw-r--r-- | arch/mips/mm/tlbex.c | 97 |
1 files changed, 62 insertions, 35 deletions
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 323d1d302f2b..32e0be27673f 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -311,6 +311,7 @@ static struct uasm_label labels[128]; | |||
311 | static struct uasm_reloc relocs[128]; | 311 | static struct uasm_reloc relocs[128]; |
312 | 312 | ||
313 | static int check_for_high_segbits; | 313 | static int check_for_high_segbits; |
314 | static bool fill_includes_sw_bits; | ||
314 | 315 | ||
315 | static unsigned int kscratch_used_mask; | 316 | static unsigned int kscratch_used_mask; |
316 | 317 | ||
@@ -630,8 +631,14 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l, | |||
630 | static __maybe_unused void build_convert_pte_to_entrylo(u32 **p, | 631 | static __maybe_unused void build_convert_pte_to_entrylo(u32 **p, |
631 | unsigned int reg) | 632 | unsigned int reg) |
632 | { | 633 | { |
633 | if (cpu_has_rixi) { | 634 | if (cpu_has_rixi && _PAGE_NO_EXEC) { |
634 | UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL)); | 635 | if (fill_includes_sw_bits) { |
636 | UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL)); | ||
637 | } else { | ||
638 | UASM_i_SRL(p, reg, reg, ilog2(_PAGE_NO_EXEC)); | ||
639 | UASM_i_ROTR(p, reg, reg, | ||
640 | ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC)); | ||
641 | } | ||
635 | } else { | 642 | } else { |
636 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | 643 | #ifdef CONFIG_PHYS_ADDR_T_64BIT |
637 | uasm_i_dsrl_safe(p, reg, reg, ilog2(_PAGE_GLOBAL)); | 644 | uasm_i_dsrl_safe(p, reg, reg, ilog2(_PAGE_GLOBAL)); |
@@ -1005,21 +1012,7 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep) | |||
1005 | * 64bit address support (36bit on a 32bit CPU) in a 32bit | 1012 | * 64bit address support (36bit on a 32bit CPU) in a 32bit |
1006 | * Kernel is a special case. Only a few CPUs use it. | 1013 | * Kernel is a special case. Only a few CPUs use it. |
1007 | */ | 1014 | */ |
1008 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | 1015 | if (config_enabled(CONFIG_PHYS_ADDR_T_64BIT) && !cpu_has_64bits) { |
1009 | if (cpu_has_64bits) { | ||
1010 | uasm_i_ld(p, tmp, 0, ptep); /* get even pte */ | ||
1011 | uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ | ||
1012 | if (cpu_has_rixi) { | ||
1013 | UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); | ||
1014 | UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ | ||
1015 | UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); | ||
1016 | } else { | ||
1017 | uasm_i_dsrl_safe(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */ | ||
1018 | UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ | ||
1019 | uasm_i_dsrl_safe(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */ | ||
1020 | } | ||
1021 | UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ | ||
1022 | } else { | ||
1023 | int pte_off_even = sizeof(pte_t) / 2; | 1016 | int pte_off_even = sizeof(pte_t) / 2; |
1024 | int pte_off_odd = pte_off_even + sizeof(pte_t); | 1017 | int pte_off_odd = pte_off_even + sizeof(pte_t); |
1025 | #ifdef CONFIG_XPA | 1018 | #ifdef CONFIG_XPA |
@@ -1043,31 +1036,23 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep) | |||
1043 | uasm_i_mthc0(p, tmp, C0_ENTRYLO0); | 1036 | uasm_i_mthc0(p, tmp, C0_ENTRYLO0); |
1044 | uasm_i_mthc0(p, ptep, C0_ENTRYLO1); | 1037 | uasm_i_mthc0(p, ptep, C0_ENTRYLO1); |
1045 | #endif | 1038 | #endif |
1039 | return; | ||
1046 | } | 1040 | } |
1047 | #else | 1041 | |
1048 | UASM_i_LW(p, tmp, 0, ptep); /* get even pte */ | 1042 | UASM_i_LW(p, tmp, 0, ptep); /* get even pte */ |
1049 | UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ | 1043 | UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */ |
1050 | if (r45k_bvahwbug()) | 1044 | if (r45k_bvahwbug()) |
1051 | build_tlb_probe_entry(p); | 1045 | build_tlb_probe_entry(p); |
1052 | if (cpu_has_rixi) { | 1046 | build_convert_pte_to_entrylo(p, tmp); |
1053 | UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); | 1047 | if (r4k_250MHZhwbug()) |
1054 | if (r4k_250MHZhwbug()) | 1048 | UASM_i_MTC0(p, 0, C0_ENTRYLO0); |
1055 | UASM_i_MTC0(p, 0, C0_ENTRYLO0); | 1049 | UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ |
1056 | UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ | 1050 | build_convert_pte_to_entrylo(p, ptep); |
1057 | UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); | 1051 | if (r45k_bvahwbug()) |
1058 | } else { | 1052 | uasm_i_mfc0(p, tmp, C0_INDEX); |
1059 | UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */ | ||
1060 | if (r4k_250MHZhwbug()) | ||
1061 | UASM_i_MTC0(p, 0, C0_ENTRYLO0); | ||
1062 | UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */ | ||
1063 | UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */ | ||
1064 | if (r45k_bvahwbug()) | ||
1065 | uasm_i_mfc0(p, tmp, C0_INDEX); | ||
1066 | } | ||
1067 | if (r4k_250MHZhwbug()) | 1053 | if (r4k_250MHZhwbug()) |
1068 | UASM_i_MTC0(p, 0, C0_ENTRYLO1); | 1054 | UASM_i_MTC0(p, 0, C0_ENTRYLO1); |
1069 | UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ | 1055 | UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */ |
1070 | #endif | ||
1071 | } | 1056 | } |
1072 | 1057 | ||
1073 | struct mips_huge_tlb_info { | 1058 | struct mips_huge_tlb_info { |
@@ -2299,6 +2284,10 @@ static void config_htw_params(void) | |||
2299 | /* re-initialize the PTI field including the even/odd bit */ | 2284 | /* re-initialize the PTI field including the even/odd bit */ |
2300 | pwfield &= ~MIPS_PWFIELD_PTI_MASK; | 2285 | pwfield &= ~MIPS_PWFIELD_PTI_MASK; |
2301 | pwfield |= PAGE_SHIFT << MIPS_PWFIELD_PTI_SHIFT; | 2286 | pwfield |= PAGE_SHIFT << MIPS_PWFIELD_PTI_SHIFT; |
2287 | if (CONFIG_PGTABLE_LEVELS >= 3) { | ||
2288 | pwfield &= ~MIPS_PWFIELD_MDI_MASK; | ||
2289 | pwfield |= PMD_SHIFT << MIPS_PWFIELD_MDI_SHIFT; | ||
2290 | } | ||
2302 | /* Set the PTEI right shift */ | 2291 | /* Set the PTEI right shift */ |
2303 | ptei = _PAGE_GLOBAL_SHIFT << MIPS_PWFIELD_PTEI_SHIFT; | 2292 | ptei = _PAGE_GLOBAL_SHIFT << MIPS_PWFIELD_PTEI_SHIFT; |
2304 | pwfield |= ptei; | 2293 | pwfield |= ptei; |
@@ -2320,9 +2309,11 @@ static void config_htw_params(void) | |||
2320 | 2309 | ||
2321 | pwsize = ilog2(PTRS_PER_PGD) << MIPS_PWSIZE_GDW_SHIFT; | 2310 | pwsize = ilog2(PTRS_PER_PGD) << MIPS_PWSIZE_GDW_SHIFT; |
2322 | pwsize |= ilog2(PTRS_PER_PTE) << MIPS_PWSIZE_PTW_SHIFT; | 2311 | pwsize |= ilog2(PTRS_PER_PTE) << MIPS_PWSIZE_PTW_SHIFT; |
2312 | if (CONFIG_PGTABLE_LEVELS >= 3) | ||
2313 | pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT; | ||
2323 | 2314 | ||
2324 | /* If XPA has been enabled, PTEs are 64-bit in size. */ | 2315 | /* If XPA has been enabled, PTEs are 64-bit in size. */ |
2325 | if (read_c0_pagegrain() & PG_ELPA) | 2316 | if (config_enabled(CONFIG_64BITS) || (read_c0_pagegrain() & PG_ELPA)) |
2326 | pwsize |= 1; | 2317 | pwsize |= 1; |
2327 | 2318 | ||
2328 | write_c0_pwsize(pwsize); | 2319 | write_c0_pwsize(pwsize); |
@@ -2360,6 +2351,41 @@ static void config_xpa_params(void) | |||
2360 | #endif | 2351 | #endif |
2361 | } | 2352 | } |
2362 | 2353 | ||
2354 | static void check_pabits(void) | ||
2355 | { | ||
2356 | unsigned long entry; | ||
2357 | unsigned pabits, fillbits; | ||
2358 | |||
2359 | if (!cpu_has_rixi || !_PAGE_NO_EXEC) { | ||
2360 | /* | ||
2361 | * We'll only be making use of the fact that we can rotate bits | ||
2362 | * into the fill if the CPU supports RIXI, so don't bother | ||
2363 | * probing this for CPUs which don't. | ||
2364 | */ | ||
2365 | return; | ||
2366 | } | ||
2367 | |||
2368 | write_c0_entrylo0(~0ul); | ||
2369 | back_to_back_c0_hazard(); | ||
2370 | entry = read_c0_entrylo0(); | ||
2371 | |||
2372 | /* clear all non-PFN bits */ | ||
2373 | entry &= ~((1 << MIPS_ENTRYLO_PFN_SHIFT) - 1); | ||
2374 | entry &= ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); | ||
2375 | |||
2376 | /* find a lower bound on PABITS, and upper bound on fill bits */ | ||
2377 | pabits = fls_long(entry) + 6; | ||
2378 | fillbits = max_t(int, (int)BITS_PER_LONG - pabits, 0); | ||
2379 | |||
2380 | /* minus the RI & XI bits */ | ||
2381 | fillbits -= min_t(unsigned, fillbits, 2); | ||
2382 | |||
2383 | if (fillbits >= ilog2(_PAGE_NO_EXEC)) | ||
2384 | fill_includes_sw_bits = true; | ||
2385 | |||
2386 | pr_debug("Entry* registers contain %u fill bits\n", fillbits); | ||
2387 | } | ||
2388 | |||
2363 | void build_tlb_refill_handler(void) | 2389 | void build_tlb_refill_handler(void) |
2364 | { | 2390 | { |
2365 | /* | 2391 | /* |
@@ -2370,6 +2396,7 @@ void build_tlb_refill_handler(void) | |||
2370 | static int run_once = 0; | 2396 | static int run_once = 0; |
2371 | 2397 | ||
2372 | output_pgtable_bits_defines(); | 2398 | output_pgtable_bits_defines(); |
2399 | check_pabits(); | ||
2373 | 2400 | ||
2374 | #ifdef CONFIG_64BIT | 2401 | #ifdef CONFIG_64BIT |
2375 | check_for_high_segbits = current_cpu_data.vmbits > (PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3); | 2402 | check_for_high_segbits = current_cpu_data.vmbits > (PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3); |