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

MIPS: mm: Use scratch for PGD when !CONFIG_MIPS_PGD_C0_CONTEXT

Allow usage of scratch register for current pgd even when
MIPS_PGD_C0_CONTEXT is not configured. MIPS_PGD_C0_CONTEXT is set
for 64r2 platforms to indicate availability of Xcontext for saving
cpuid, thus freeing Context to be used for saving PGD. This option
was also tied to using a scratch register for storing PGD.

This commit will allow usage of scratch register to store the current
pgd if one can be allocated for the platform, even when
MIPS_PGD_C0_CONTEXT is not set. The cpuid will be kept in the CP0
Context register in this case.

The code to store the current pgd for the TLB miss handler is now
generated in all cases. When scratch register is available, the PGD
is also stored in the scratch register.

Signed-off-by: Jayachandran C <jchandra@broadcom.com>
Cc: linux-mips@linux-mips.org
Cc: Hauke Mehrtens <hauke@hauke-m.de>
Patchwork: https://patchwork.linux-mips.org/patch/5906/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Jayachandran C and committed by
Ralf Baechle
f4ae17aa 7f177a52

+58 -40
+1 -5
arch/mips/include/asm/mmu_context.h
··· 24 24 #endif /* SMTC */ 25 25 #include <asm-generic/mm_hooks.h> 26 26 27 - #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 28 - 29 27 #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ 30 28 do { \ 31 29 extern void tlbmiss_handler_setup_pgd(unsigned long); \ 32 30 tlbmiss_handler_setup_pgd((unsigned long)(pgd)); \ 33 31 } while (0) 34 32 33 + #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 35 34 #define TLBMISS_HANDLER_SETUP() \ 36 35 do { \ 37 36 TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir); \ ··· 46 47 * into the context register. 47 48 */ 48 49 extern unsigned long pgd_current[]; 49 - 50 - #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ 51 - pgd_current[smp_processor_id()] = (unsigned long)(pgd) 52 50 53 51 #define TLBMISS_HANDLER_SETUP() \ 54 52 write_c0_context((unsigned long) smp_processor_id() << \
-2
arch/mips/mm/tlb-funcs.S
··· 16 16 17 17 #define FASTPATH_SIZE 128 18 18 19 - #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 20 19 LEAF(tlbmiss_handler_setup_pgd) 21 20 .space 16 * 4 22 21 END(tlbmiss_handler_setup_pgd) 23 22 EXPORT(tlbmiss_handler_setup_pgd_end) 24 - #endif 25 23 26 24 LEAF(handle_tlbm) 27 25 .space FASTPATH_SIZE * 4
+57 -33
arch/mips/mm/tlbex.c
··· 799 799 } 800 800 /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ 801 801 802 - #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 803 802 if (pgd_reg != -1) { 804 803 /* pgd is in pgd_reg */ 805 804 UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); 806 805 } else { 806 + #if defined(CONFIG_MIPS_PGD_C0_CONTEXT) 807 807 /* 808 808 * &pgd << 11 stored in CONTEXT [23..63]. 809 809 */ ··· 815 815 /* 1 0 1 0 1 << 6 xkphys cached */ 816 816 uasm_i_ori(p, ptr, ptr, 0x540); 817 817 uasm_i_drotr(p, ptr, ptr, 11); 818 - } 819 818 #elif defined(CONFIG_SMP) 820 - UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG); 821 - uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT); 822 - UASM_i_LA_mostly(p, tmp, pgdc); 823 - uasm_i_daddu(p, ptr, ptr, tmp); 824 - uasm_i_dmfc0(p, tmp, C0_BADVADDR); 825 - uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); 819 + UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG); 820 + uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT); 821 + UASM_i_LA_mostly(p, tmp, pgdc); 822 + uasm_i_daddu(p, ptr, ptr, tmp); 823 + uasm_i_dmfc0(p, tmp, C0_BADVADDR); 824 + uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); 826 825 #else 827 - UASM_i_LA_mostly(p, ptr, pgdc); 828 - uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); 826 + UASM_i_LA_mostly(p, ptr, pgdc); 827 + uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); 829 828 #endif 829 + } 830 830 831 831 uasm_l_vmalloc_done(l, *p); 832 832 ··· 921 921 static void __maybe_unused 922 922 build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) 923 923 { 924 - long pgdc = (long)pgd_current; 924 + if (pgd_reg != -1) { 925 + /* pgd is in pgd_reg */ 926 + uasm_i_mfc0(p, ptr, c0_kscratch(), pgd_reg); 927 + uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */ 928 + } else { 929 + long pgdc = (long)pgd_current; 925 930 926 - /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */ 931 + /* 32 bit SMP has smp_processor_id() stored in CONTEXT. */ 927 932 #ifdef CONFIG_SMP 928 - uasm_i_mfc0(p, ptr, SMP_CPUID_REG); 929 - UASM_i_LA_mostly(p, tmp, pgdc); 930 - uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT); 931 - uasm_i_addu(p, ptr, tmp, ptr); 933 + uasm_i_mfc0(p, ptr, SMP_CPUID_REG); 934 + UASM_i_LA_mostly(p, tmp, pgdc); 935 + uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT); 936 + uasm_i_addu(p, ptr, tmp, ptr); 932 937 #else 933 - UASM_i_LA_mostly(p, ptr, pgdc); 938 + UASM_i_LA_mostly(p, ptr, pgdc); 934 939 #endif 935 - uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */ 936 - uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr); 940 + uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */ 941 + uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr); 942 + } 937 943 uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */ 938 944 uasm_i_sll(p, tmp, tmp, PGD_T_LOG2); 939 945 uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */ ··· 1413 1407 extern u32 handle_tlbl[], handle_tlbl_end[]; 1414 1408 extern u32 handle_tlbs[], handle_tlbs_end[]; 1415 1409 extern u32 handle_tlbm[], handle_tlbm_end[]; 1416 - 1417 - #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 1418 1410 extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[]; 1419 1411 1420 - static void build_r4000_setup_pgd(void) 1412 + static void build_setup_pgd(void) 1421 1413 { 1422 1414 const int a0 = 4; 1423 - const int a1 = 5; 1415 + const int __maybe_unused a1 = 5; 1416 + const int __maybe_unused a2 = 6; 1424 1417 u32 *p = tlbmiss_handler_setup_pgd; 1425 1418 const int tlbmiss_handler_setup_pgd_size = 1426 1419 tlbmiss_handler_setup_pgd_end - tlbmiss_handler_setup_pgd; 1427 - struct uasm_label *l = labels; 1428 - struct uasm_reloc *r = relocs; 1420 + #ifndef CONFIG_MIPS_PGD_C0_CONTEXT 1421 + long pgdc = (long)pgd_current; 1422 + #endif 1429 1423 1430 1424 memset(tlbmiss_handler_setup_pgd, 0, tlbmiss_handler_setup_pgd_size * 1431 1425 sizeof(tlbmiss_handler_setup_pgd[0])); 1432 1426 memset(labels, 0, sizeof(labels)); 1433 1427 memset(relocs, 0, sizeof(relocs)); 1434 - 1435 1428 pgd_reg = allocate_kscratch(); 1436 - 1429 + #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 1437 1430 if (pgd_reg == -1) { 1431 + struct uasm_label *l = labels; 1432 + struct uasm_reloc *r = relocs; 1433 + 1438 1434 /* PGD << 11 in c0_Context */ 1439 1435 /* 1440 1436 * If it is a ckseg0 address, convert to a physical ··· 1458 1450 uasm_i_jr(&p, 31); 1459 1451 UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); 1460 1452 } 1453 + #else 1454 + #ifdef CONFIG_SMP 1455 + /* Save PGD to pgd_current[smp_processor_id()] */ 1456 + UASM_i_CPUID_MFC0(&p, a1, SMP_CPUID_REG); 1457 + UASM_i_SRL_SAFE(&p, a1, a1, SMP_CPUID_PTRSHIFT); 1458 + UASM_i_LA_mostly(&p, a2, pgdc); 1459 + UASM_i_ADDU(&p, a2, a2, a1); 1460 + UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2); 1461 + #else 1462 + UASM_i_LA_mostly(&p, a2, pgdc); 1463 + UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2); 1464 + #endif /* SMP */ 1465 + uasm_i_jr(&p, 31); 1466 + 1467 + /* if pgd_reg is allocated, save PGD also to scratch register */ 1468 + if (pgd_reg != -1) 1469 + UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); 1470 + else 1471 + uasm_i_nop(&p); 1472 + #endif 1461 1473 if (p >= tlbmiss_handler_setup_pgd_end) 1462 1474 panic("tlbmiss_handler_setup_pgd space exceeded"); 1463 1475 ··· 1488 1460 dump_handler("tlbmiss_handler", tlbmiss_handler_setup_pgd, 1489 1461 tlbmiss_handler_setup_pgd_size); 1490 1462 } 1491 - #endif 1492 1463 1493 1464 static void 1494 1465 iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) ··· 2180 2153 (unsigned long)handle_tlbs_end); 2181 2154 local_flush_icache_range((unsigned long)handle_tlbm, 2182 2155 (unsigned long)handle_tlbm_end); 2183 - #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 2184 2156 local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, 2185 2157 (unsigned long)tlbmiss_handler_setup_pgd_end); 2186 - #endif 2187 2158 } 2188 2159 2189 2160 void build_tlb_refill_handler(void) ··· 2213 2188 if (!run_once) { 2214 2189 if (!cpu_has_local_ebase) 2215 2190 build_r3000_tlb_refill_handler(); 2191 + build_setup_pgd(); 2216 2192 build_r3000_tlb_load_handler(); 2217 2193 build_r3000_tlb_store_handler(); 2218 2194 build_r3000_tlb_modify_handler(); ··· 2237 2211 default: 2238 2212 if (!run_once) { 2239 2213 scratch_reg = allocate_kscratch(); 2240 - #ifdef CONFIG_MIPS_PGD_C0_CONTEXT 2241 - build_r4000_setup_pgd(); 2242 - #endif 2214 + build_setup_pgd(); 2243 2215 build_r4000_tlb_load_handler(); 2244 2216 build_r4000_tlb_store_handler(); 2245 2217 build_r4000_tlb_modify_handler();