aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJayachandran C <jchandra@broadcom.com>2013-09-25 06:58:04 -0400
committerRalf Baechle <ralf@linux-mips.org>2013-10-29 16:24:51 -0400
commitf4ae17aa0f2122b52f642985b46210a1f2eceb0a (patch)
treefe5a21b3b0acc39f886ac744f7ed1ab935569f6b
parent7f177a52a13e3d3751b599ae2b46d3d4658985cd (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.h6
-rw-r--r--arch/mips/mm/tlb-funcs.S2
-rw-r--r--arch/mips/mm/tlbex.c90
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) \
30do { \ 28do { \
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 */
49extern unsigned long pgd_current[]; 48extern 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
20LEAF(tlbmiss_handler_setup_pgd) 19LEAF(tlbmiss_handler_setup_pgd)
21 .space 16 * 4 20 .space 16 * 4
22END(tlbmiss_handler_setup_pgd) 21END(tlbmiss_handler_setup_pgd)
23EXPORT(tlbmiss_handler_setup_pgd_end) 22EXPORT(tlbmiss_handler_setup_pgd_end)
24#endif
25 23
26LEAF(handle_tlbm) 24LEAF(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,
921static void __maybe_unused 921static void __maybe_unused
922build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr) 922build_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)
1407extern u32 handle_tlbl[], handle_tlbl_end[]; 1413extern u32 handle_tlbl[], handle_tlbl_end[];
1408extern u32 handle_tlbs[], handle_tlbs_end[]; 1414extern u32 handle_tlbs[], handle_tlbs_end[];
1409extern u32 handle_tlbm[], handle_tlbm_end[]; 1415extern u32 handle_tlbm[], handle_tlbm_end[];
1410
1411#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
1412extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[]; 1416extern u32 tlbmiss_handler_setup_pgd[], tlbmiss_handler_setup_pgd_end[];
1413 1417
1414static void build_r4000_setup_pgd(void) 1418static 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
1465static void 1492static void
1466iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) 1493iPTE_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
2162void build_tlb_refill_handler(void) 2187void 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();