diff options
author | Jayachandran C <jchandra@broadcom.com> | 2013-09-25 06:58:04 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2013-10-29 16:24:51 -0400 |
commit | f4ae17aa0f2122b52f642985b46210a1f2eceb0a (patch) | |
tree | fe5a21b3b0acc39f886ac744f7ed1ab935569f6b | |
parent | 7f177a52a13e3d3751b599ae2b46d3d4658985cd (diff) |
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>
-rw-r--r-- | arch/mips/include/asm/mmu_context.h | 6 | ||||
-rw-r--r-- | arch/mips/mm/tlb-funcs.S | 2 | ||||
-rw-r--r-- | arch/mips/mm/tlbex.c | 90 |
3 files changed, 58 insertions, 40 deletions
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index ab8e26051ed7..e277bbad2871 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h | |||
@@ -24,14 +24,13 @@ | |||
24 | #endif /* SMTC */ | 24 | #endif /* SMTC */ |
25 | #include <asm-generic/mm_hooks.h> | 25 | #include <asm-generic/mm_hooks.h> |
26 | 26 | ||
27 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
28 | |||
29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | 27 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
30 | do { \ | 28 | do { \ |
31 | extern void tlbmiss_handler_setup_pgd(unsigned long); \ | 29 | extern void tlbmiss_handler_setup_pgd(unsigned long); \ |
32 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)); \ | 30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)); \ |
33 | } while (0) | 31 | } while (0) |
34 | 32 | ||
33 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
35 | #define TLBMISS_HANDLER_SETUP() \ | 34 | #define TLBMISS_HANDLER_SETUP() \ |
36 | do { \ | 35 | do { \ |
37 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir); \ | 36 | TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir); \ |
@@ -48,9 +47,6 @@ do { \ | |||
48 | */ | 47 | */ |
49 | extern unsigned long pgd_current[]; | 48 | extern unsigned long pgd_current[]; |
50 | 49 | ||
51 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | ||
52 | pgd_current[smp_processor_id()] = (unsigned long)(pgd) | ||
53 | |||
54 | #define TLBMISS_HANDLER_SETUP() \ | 50 | #define TLBMISS_HANDLER_SETUP() \ |
55 | write_c0_context((unsigned long) smp_processor_id() << \ | 51 | write_c0_context((unsigned long) smp_processor_id() << \ |
56 | SMP_CPUID_REGSHIFT); \ | 52 | SMP_CPUID_REGSHIFT); \ |
diff --git a/arch/mips/mm/tlb-funcs.S b/arch/mips/mm/tlb-funcs.S index 79bca3130bd1..30a494db99c2 100644 --- a/arch/mips/mm/tlb-funcs.S +++ b/arch/mips/mm/tlb-funcs.S | |||
@@ -16,12 +16,10 @@ | |||
16 | 16 | ||
17 | #define FASTPATH_SIZE 128 | 17 | #define FASTPATH_SIZE 128 |
18 | 18 | ||
19 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
20 | LEAF(tlbmiss_handler_setup_pgd) | 19 | LEAF(tlbmiss_handler_setup_pgd) |
21 | .space 16 * 4 | 20 | .space 16 * 4 |
22 | END(tlbmiss_handler_setup_pgd) | 21 | END(tlbmiss_handler_setup_pgd) |
23 | EXPORT(tlbmiss_handler_setup_pgd_end) | 22 | EXPORT(tlbmiss_handler_setup_pgd_end) |
24 | #endif | ||
25 | 23 | ||
26 | LEAF(handle_tlbm) | 24 | LEAF(handle_tlbm) |
27 | .space FASTPATH_SIZE * 4 | 25 | .space FASTPATH_SIZE * 4 |
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 444d92108396..fffa7fe319a0 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -799,11 +799,11 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
799 | } | 799 | } |
800 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ | 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 | if (pgd_reg != -1) { | 802 | if (pgd_reg != -1) { |
804 | /* pgd is in pgd_reg */ | 803 | /* pgd is in pgd_reg */ |
805 | UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); | 804 | UASM_i_MFC0(p, ptr, c0_kscratch(), pgd_reg); |
806 | } else { | 805 | } else { |
806 | #if defined(CONFIG_MIPS_PGD_C0_CONTEXT) | ||
807 | /* | 807 | /* |
808 | * &pgd << 11 stored in CONTEXT [23..63]. | 808 | * &pgd << 11 stored in CONTEXT [23..63]. |
809 | */ | 809 | */ |
@@ -815,18 +815,18 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
815 | /* 1 0 1 0 1 << 6 xkphys cached */ | 815 | /* 1 0 1 0 1 << 6 xkphys cached */ |
816 | uasm_i_ori(p, ptr, ptr, 0x540); | 816 | uasm_i_ori(p, ptr, ptr, 0x540); |
817 | uasm_i_drotr(p, ptr, ptr, 11); | 817 | uasm_i_drotr(p, ptr, ptr, 11); |
818 | } | ||
819 | #elif defined(CONFIG_SMP) | 818 | #elif defined(CONFIG_SMP) |
820 | UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG); | 819 | UASM_i_CPUID_MFC0(p, ptr, SMP_CPUID_REG); |
821 | uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT); | 820 | uasm_i_dsrl_safe(p, ptr, ptr, SMP_CPUID_PTRSHIFT); |
822 | UASM_i_LA_mostly(p, tmp, pgdc); | 821 | UASM_i_LA_mostly(p, tmp, pgdc); |
823 | uasm_i_daddu(p, ptr, ptr, tmp); | 822 | uasm_i_daddu(p, ptr, ptr, tmp); |
824 | uasm_i_dmfc0(p, tmp, C0_BADVADDR); | 823 | uasm_i_dmfc0(p, tmp, C0_BADVADDR); |
825 | uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); | 824 | uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); |
826 | #else | 825 | #else |
827 | UASM_i_LA_mostly(p, ptr, pgdc); | 826 | UASM_i_LA_mostly(p, ptr, pgdc); |
828 | uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); | 827 | uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr); |
829 | #endif | 828 | #endif |
829 | } | ||
830 | 830 | ||
831 | uasm_l_vmalloc_done(l, *p); | 831 | uasm_l_vmalloc_done(l, *p); |
832 | 832 | ||
@@ -921,19 +921,25 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
921 | static void __maybe_unused | 921 | static void __maybe_unused |
922 | build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) | 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 | #ifdef CONFIG_SMP | 932 | #ifdef CONFIG_SMP |
928 | uasm_i_mfc0(p, ptr, SMP_CPUID_REG); | 933 | uasm_i_mfc0(p, ptr, SMP_CPUID_REG); |
929 | UASM_i_LA_mostly(p, tmp, pgdc); | 934 | UASM_i_LA_mostly(p, tmp, pgdc); |
930 | uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT); | 935 | uasm_i_srl(p, ptr, ptr, SMP_CPUID_PTRSHIFT); |
931 | uasm_i_addu(p, ptr, tmp, ptr); | 936 | uasm_i_addu(p, ptr, tmp, ptr); |
932 | #else | 937 | #else |
933 | UASM_i_LA_mostly(p, ptr, pgdc); | 938 | UASM_i_LA_mostly(p, ptr, pgdc); |
934 | #endif | 939 | #endif |
935 | uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */ | 940 | uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */ |
936 | uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr); | 941 | uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr); |
942 | } | ||
937 | uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */ | 943 | uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */ |
938 | uasm_i_sll(p, tmp, tmp, PGD_T_LOG2); | 944 | uasm_i_sll(p, tmp, tmp, PGD_T_LOG2); |
939 | uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */ | 945 | uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */ |
@@ -1407,28 +1413,30 @@ static void build_r4000_tlb_refill_handler(void) | |||
1407 | extern u32 handle_tlbl[], handle_tlbl_end[]; | 1413 | extern u32 handle_tlbl[], handle_tlbl_end[]; |
1408 | extern u32 handle_tlbs[], handle_tlbs_end[]; | 1414 | extern u32 handle_tlbs[], handle_tlbs_end[]; |
1409 | extern u32 handle_tlbm[], handle_tlbm_end[]; | 1415 | extern u32 handle_tlbm[], handle_tlbm_end[]; |
1410 | |||
1411 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
1412 | extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[]; | 1416 | extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[]; |
1413 | 1417 | ||
1414 | static void build_r4000_setup_pgd(void) | 1418 | static void build_setup_pgd(void) |
1415 | { | 1419 | { |
1416 | const int a0 = 4; | 1420 | const int a0 = 4; |
1417 | const int a1 = 5; | 1421 | const int __maybe_unused a1 = 5; |
1422 | const int __maybe_unused a2 = 6; | ||
1418 | u32 *p = tlbmiss_handler_setup_pgd; | 1423 | u32 *p = tlbmiss_handler_setup_pgd; |
1419 | const int tlbmiss_handler_setup_pgd_size = | 1424 | const int tlbmiss_handler_setup_pgd_size = |
1420 | tlbmiss_handler_setup_pgd_end - tlbmiss_handler_setup_pgd; | 1425 | tlbmiss_handler_setup_pgd_end - tlbmiss_handler_setup_pgd; |
1421 | struct uasm_label *l = labels; | 1426 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
1422 | struct uasm_reloc *r = relocs; | 1427 | long pgdc = (long)pgd_current; |
1428 | #endif | ||
1423 | 1429 | ||
1424 | memset(tlbmiss_handler_setup_pgd, 0, tlbmiss_handler_setup_pgd_size * | 1430 | memset(tlbmiss_handler_setup_pgd, 0, tlbmiss_handler_setup_pgd_size * |
1425 | sizeof(tlbmiss_handler_setup_pgd[0])); | 1431 | sizeof(tlbmiss_handler_setup_pgd[0])); |
1426 | memset(labels, 0, sizeof(labels)); | 1432 | memset(labels, 0, sizeof(labels)); |
1427 | memset(relocs, 0, sizeof(relocs)); | 1433 | memset(relocs, 0, sizeof(relocs)); |
1428 | |||
1429 | pgd_reg = allocate_kscratch(); | 1434 | pgd_reg = allocate_kscratch(); |
1430 | 1435 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | |
1431 | if (pgd_reg == -1) { | 1436 | if (pgd_reg == -1) { |
1437 | struct uasm_label *l = labels; | ||
1438 | struct uasm_reloc *r = relocs; | ||
1439 | |||
1432 | /* PGD << 11 in c0_Context */ | 1440 | /* PGD << 11 in c0_Context */ |
1433 | /* | 1441 | /* |
1434 | * If it is a ckseg0 address, convert to a physical | 1442 | * If it is a ckseg0 address, convert to a physical |
@@ -1450,6 +1458,26 @@ static void build_r4000_setup_pgd(void) | |||
1450 | uasm_i_jr(&p, 31); | 1458 | uasm_i_jr(&p, 31); |
1451 | UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); | 1459 | UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); |
1452 | } | 1460 | } |
1461 | #else | ||
1462 | #ifdef CONFIG_SMP | ||
1463 | /* Save PGD to pgd_current[smp_processor_id()] */ | ||
1464 | UASM_i_CPUID_MFC0(&p, a1, SMP_CPUID_REG); | ||
1465 | UASM_i_SRL_SAFE(&p, a1, a1, SMP_CPUID_PTRSHIFT); | ||
1466 | UASM_i_LA_mostly(&p, a2, pgdc); | ||
1467 | UASM_i_ADDU(&p, a2, a2, a1); | ||
1468 | UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2); | ||
1469 | #else | ||
1470 | UASM_i_LA_mostly(&p, a2, pgdc); | ||
1471 | UASM_i_SW(&p, a0, uasm_rel_lo(pgdc), a2); | ||
1472 | #endif /* SMP */ | ||
1473 | uasm_i_jr(&p, 31); | ||
1474 | |||
1475 | /* if pgd_reg is allocated, save PGD also to scratch register */ | ||
1476 | if (pgd_reg != -1) | ||
1477 | UASM_i_MTC0(&p, a0, c0_kscratch(), pgd_reg); | ||
1478 | else | ||
1479 | uasm_i_nop(&p); | ||
1480 | #endif | ||
1453 | if (p >= tlbmiss_handler_setup_pgd_end) | 1481 | if (p >= tlbmiss_handler_setup_pgd_end) |
1454 | panic("tlbmiss_handler_setup_pgd space exceeded"); | 1482 | panic("tlbmiss_handler_setup_pgd space exceeded"); |
1455 | 1483 | ||
@@ -1460,7 +1488,6 @@ static void build_r4000_setup_pgd(void) | |||
1460 | dump_handler("tlbmiss_handler", tlbmiss_handler_setup_pgd, | 1488 | dump_handler("tlbmiss_handler", tlbmiss_handler_setup_pgd, |
1461 | tlbmiss_handler_setup_pgd_size); | 1489 | tlbmiss_handler_setup_pgd_size); |
1462 | } | 1490 | } |
1463 | #endif | ||
1464 | 1491 | ||
1465 | static void | 1492 | static void |
1466 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) | 1493 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) |
@@ -2153,10 +2180,8 @@ static void flush_tlb_handlers(void) | |||
2153 | (unsigned long)handle_tlbs_end); | 2180 | (unsigned long)handle_tlbs_end); |
2154 | local_flush_icache_range((unsigned long)handle_tlbm, | 2181 | local_flush_icache_range((unsigned long)handle_tlbm, |
2155 | (unsigned long)handle_tlbm_end); | 2182 | (unsigned long)handle_tlbm_end); |
2156 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
2157 | local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, | 2183 | local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, |
2158 | (unsigned long)tlbmiss_handler_setup_pgd_end); | 2184 | (unsigned long)tlbmiss_handler_setup_pgd_end); |
2159 | #endif | ||
2160 | } | 2185 | } |
2161 | 2186 | ||
2162 | void build_tlb_refill_handler(void) | 2187 | void build_tlb_refill_handler(void) |
@@ -2188,6 +2213,7 @@ void build_tlb_refill_handler(void) | |||
2188 | if (!run_once) { | 2213 | if (!run_once) { |
2189 | if (!cpu_has_local_ebase) | 2214 | if (!cpu_has_local_ebase) |
2190 | build_r3000_tlb_refill_handler(); | 2215 | build_r3000_tlb_refill_handler(); |
2216 | build_setup_pgd(); | ||
2191 | build_r3000_tlb_load_handler(); | 2217 | build_r3000_tlb_load_handler(); |
2192 | build_r3000_tlb_store_handler(); | 2218 | build_r3000_tlb_store_handler(); |
2193 | build_r3000_tlb_modify_handler(); | 2219 | build_r3000_tlb_modify_handler(); |
@@ -2211,9 +2237,7 @@ void build_tlb_refill_handler(void) | |||
2211 | default: | 2237 | default: |
2212 | if (!run_once) { | 2238 | if (!run_once) { |
2213 | scratch_reg = allocate_kscratch(); | 2239 | scratch_reg = allocate_kscratch(); |
2214 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | 2240 | build_setup_pgd(); |
2215 | build_r4000_setup_pgd(); | ||
2216 | #endif | ||
2217 | build_r4000_tlb_load_handler(); | 2241 | build_r4000_tlb_load_handler(); |
2218 | build_r4000_tlb_store_handler(); | 2242 | build_r4000_tlb_store_handler(); |
2219 | build_r4000_tlb_modify_handler(); | 2243 | build_r4000_tlb_modify_handler(); |