diff options
author | David Daney <ddaney@caviumnetworks.com> | 2010-12-21 17:19:11 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-01-18 13:30:22 -0500 |
commit | 3d8bfdd0307223de678962f1c1907a7cec549136 (patch) | |
tree | 007146d1452d054e5e676b5a930d48292b0ae4b6 /arch | |
parent | c42aef0947d717849f31965ecc0778707839bfe0 (diff) |
MIPS: Use C0_KScratch (if present) to hold PGD pointer.
Decide at runtime to use either Context or KScratch to hold the PGD
pointer.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/1876/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/include/asm/mmu_context.h | 8 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 2 | ||||
-rw-r--r-- | arch/mips/mm/tlbex.c | 116 |
3 files changed, 108 insertions, 18 deletions
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index d9592733a7ba..73c0d45798de 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h | |||
@@ -29,13 +29,7 @@ | |||
29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ | 29 | #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ |
30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)) | 30 | tlbmiss_handler_setup_pgd((unsigned long)(pgd)) |
31 | 31 | ||
32 | static inline void tlbmiss_handler_setup_pgd(unsigned long pgd) | 32 | extern void tlbmiss_handler_setup_pgd(unsigned long pgd); |
33 | { | ||
34 | /* Check for swapper_pg_dir and convert to physical address. */ | ||
35 | if ((pgd & CKSEG3) == CKSEG0) | ||
36 | pgd = CPHYSADDR(pgd); | ||
37 | write_c0_context(pgd << 11); | ||
38 | } | ||
39 | 33 | ||
40 | #define TLBMISS_HANDLER_SETUP() \ | 34 | #define TLBMISS_HANDLER_SETUP() \ |
41 | do { \ | 35 | do { \ |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e97104302541..71350f7f2d88 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -1592,7 +1592,6 @@ void __cpuinit per_cpu_trap_init(void) | |||
1592 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1592 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1593 | 1593 | ||
1594 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1594 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
1595 | TLBMISS_HANDLER_SETUP(); | ||
1596 | 1595 | ||
1597 | atomic_inc(&init_mm.mm_count); | 1596 | atomic_inc(&init_mm.mm_count); |
1598 | current->active_mm = &init_mm; | 1597 | current->active_mm = &init_mm; |
@@ -1614,6 +1613,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
1614 | write_c0_wired(0); | 1613 | write_c0_wired(0); |
1615 | } | 1614 | } |
1616 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1615 | #endif /* CONFIG_MIPS_MT_SMTC */ |
1616 | TLBMISS_HANDLER_SETUP(); | ||
1617 | } | 1617 | } |
1618 | 1618 | ||
1619 | /* Install CPU exception handler */ | 1619 | /* Install CPU exception handler */ |
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 93816f3bca67..0bb4c3b89c78 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -26,8 +26,10 @@ | |||
26 | #include <linux/smp.h> | 26 | #include <linux/smp.h> |
27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/cache.h> | ||
29 | 30 | ||
30 | #include <asm/mmu_context.h> | 31 | #include <asm/cacheflush.h> |
32 | #include <asm/pgtable.h> | ||
31 | #include <asm/war.h> | 33 | #include <asm/war.h> |
32 | #include <asm/uasm.h> | 34 | #include <asm/uasm.h> |
33 | 35 | ||
@@ -173,11 +175,38 @@ static struct uasm_reloc relocs[128] __cpuinitdata; | |||
173 | static int check_for_high_segbits __cpuinitdata; | 175 | static int check_for_high_segbits __cpuinitdata; |
174 | #endif | 176 | #endif |
175 | 177 | ||
176 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 178 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT |
179 | |||
180 | static unsigned int kscratch_used_mask __cpuinitdata; | ||
181 | |||
182 | static int __cpuinit allocate_kscratch(void) | ||
183 | { | ||
184 | int r; | ||
185 | unsigned int a = cpu_data[0].kscratch_mask & ~kscratch_used_mask; | ||
186 | |||
187 | r = ffs(a); | ||
188 | |||
189 | if (r == 0) | ||
190 | return -1; | ||
191 | |||
192 | r--; /* make it zero based */ | ||
193 | |||
194 | kscratch_used_mask |= (1 << r); | ||
195 | |||
196 | return r; | ||
197 | } | ||
198 | |||
199 | static int pgd_reg __cpuinitdata; | ||
200 | |||
201 | #else /* !CONFIG_MIPS_PGD_C0_CONTEXT*/ | ||
177 | /* | 202 | /* |
178 | * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, | 203 | * CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current, |
179 | * we cannot do r3000 under these circumstances. | 204 | * we cannot do r3000 under these circumstances. |
205 | * | ||
206 | * Declare pgd_current here instead of including mmu_context.h to avoid type | ||
207 | * conflicts for tlbmiss_handler_setup_pgd | ||
180 | */ | 208 | */ |
209 | extern unsigned long pgd_current[]; | ||
181 | 210 | ||
182 | /* | 211 | /* |
183 | * The R3000 TLB handler is simple. | 212 | * The R3000 TLB handler is simple. |
@@ -573,13 +602,22 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, | |||
573 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ | 602 | /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */ |
574 | 603 | ||
575 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | 604 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT |
576 | /* | 605 | if (pgd_reg != -1) { |
577 | * &pgd << 11 stored in CONTEXT [23..63]. | 606 | /* pgd is in pgd_reg */ |
578 | */ | 607 | UASM_i_MFC0(p, ptr, 31, pgd_reg); |
579 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | 608 | } else { |
580 | uasm_i_dins(p, ptr, 0, 0, 23); /* Clear lower 23 bits of context. */ | 609 | /* |
581 | uasm_i_ori(p, ptr, ptr, 0x540); /* 1 0 1 0 1 << 6 xkphys cached */ | 610 | * &pgd << 11 stored in CONTEXT [23..63]. |
582 | uasm_i_drotr(p, ptr, ptr, 11); | 611 | */ |
612 | UASM_i_MFC0(p, ptr, C0_CONTEXT); | ||
613 | |||
614 | /* Clear lower 23 bits of context. */ | ||
615 | uasm_i_dins(p, ptr, 0, 0, 23); | ||
616 | |||
617 | /* 1 0 1 0 1 << 6 xkphys cached */ | ||
618 | uasm_i_ori(p, ptr, ptr, 0x540); | ||
619 | uasm_i_drotr(p, ptr, ptr, 11); | ||
620 | } | ||
583 | #elif defined(CONFIG_SMP) | 621 | #elif defined(CONFIG_SMP) |
584 | # ifdef CONFIG_MIPS_MT_SMTC | 622 | # ifdef CONFIG_MIPS_MT_SMTC |
585 | /* | 623 | /* |
@@ -1014,6 +1052,55 @@ static void __cpuinit build_r4000_tlb_refill_handler(void) | |||
1014 | u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; | 1052 | u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; |
1015 | u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; | 1053 | u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; |
1016 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; | 1054 | u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; |
1055 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
1056 | u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned; | ||
1057 | |||
1058 | static void __cpuinit build_r4000_setup_pgd(void) | ||
1059 | { | ||
1060 | const int a0 = 4; | ||
1061 | const int a1 = 5; | ||
1062 | u32 *p = tlbmiss_handler_setup_pgd; | ||
1063 | struct uasm_label *l = labels; | ||
1064 | struct uasm_reloc *r = relocs; | ||
1065 | |||
1066 | memset(tlbmiss_handler_setup_pgd, 0, sizeof(tlbmiss_handler_setup_pgd)); | ||
1067 | memset(labels, 0, sizeof(labels)); | ||
1068 | memset(relocs, 0, sizeof(relocs)); | ||
1069 | |||
1070 | pgd_reg = allocate_kscratch(); | ||
1071 | |||
1072 | if (pgd_reg == -1) { | ||
1073 | /* PGD << 11 in c0_Context */ | ||
1074 | /* | ||
1075 | * If it is a ckseg0 address, convert to a physical | ||
1076 | * address. Shifting right by 29 and adding 4 will | ||
1077 | * result in zero for these addresses. | ||
1078 | * | ||
1079 | */ | ||
1080 | UASM_i_SRA(&p, a1, a0, 29); | ||
1081 | UASM_i_ADDIU(&p, a1, a1, 4); | ||
1082 | uasm_il_bnez(&p, &r, a1, label_tlbl_goaround1); | ||
1083 | uasm_i_nop(&p); | ||
1084 | uasm_i_dinsm(&p, a0, 0, 29, 64 - 29); | ||
1085 | uasm_l_tlbl_goaround1(&l, p); | ||
1086 | UASM_i_SLL(&p, a0, a0, 11); | ||
1087 | uasm_i_jr(&p, 31); | ||
1088 | UASM_i_MTC0(&p, a0, C0_CONTEXT); | ||
1089 | } else { | ||
1090 | /* PGD in c0_KScratch */ | ||
1091 | uasm_i_jr(&p, 31); | ||
1092 | UASM_i_MTC0(&p, a0, 31, pgd_reg); | ||
1093 | } | ||
1094 | if (p - tlbmiss_handler_setup_pgd > ARRAY_SIZE(tlbmiss_handler_setup_pgd)) | ||
1095 | panic("tlbmiss_handler_setup_pgd space exceeded"); | ||
1096 | uasm_resolve_relocs(relocs, labels); | ||
1097 | pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n", | ||
1098 | (unsigned int)(p - tlbmiss_handler_setup_pgd)); | ||
1099 | |||
1100 | dump_handler(tlbmiss_handler_setup_pgd, | ||
1101 | ARRAY_SIZE(tlbmiss_handler_setup_pgd)); | ||
1102 | } | ||
1103 | #endif | ||
1017 | 1104 | ||
1018 | static void __cpuinit | 1105 | static void __cpuinit |
1019 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) | 1106 | iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) |
@@ -1161,6 +1248,8 @@ build_pte_modifiable(u32 **p, struct uasm_reloc **r, | |||
1161 | } | 1248 | } |
1162 | 1249 | ||
1163 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT | 1250 | #ifndef CONFIG_MIPS_PGD_C0_CONTEXT |
1251 | |||
1252 | |||
1164 | /* | 1253 | /* |
1165 | * R3000 style TLB load/store/modify handlers. | 1254 | * R3000 style TLB load/store/modify handlers. |
1166 | */ | 1255 | */ |
@@ -1623,13 +1712,16 @@ void __cpuinit build_tlb_refill_handler(void) | |||
1623 | break; | 1712 | break; |
1624 | 1713 | ||
1625 | default: | 1714 | default: |
1626 | build_r4000_tlb_refill_handler(); | ||
1627 | if (!run_once) { | 1715 | if (!run_once) { |
1716 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
1717 | build_r4000_setup_pgd(); | ||
1718 | #endif | ||
1628 | build_r4000_tlb_load_handler(); | 1719 | build_r4000_tlb_load_handler(); |
1629 | build_r4000_tlb_store_handler(); | 1720 | build_r4000_tlb_store_handler(); |
1630 | build_r4000_tlb_modify_handler(); | 1721 | build_r4000_tlb_modify_handler(); |
1631 | run_once++; | 1722 | run_once++; |
1632 | } | 1723 | } |
1724 | build_r4000_tlb_refill_handler(); | ||
1633 | } | 1725 | } |
1634 | } | 1726 | } |
1635 | 1727 | ||
@@ -1641,4 +1733,8 @@ void __cpuinit flush_tlb_handlers(void) | |||
1641 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); | 1733 | (unsigned long)handle_tlbs + sizeof(handle_tlbs)); |
1642 | local_flush_icache_range((unsigned long)handle_tlbm, | 1734 | local_flush_icache_range((unsigned long)handle_tlbm, |
1643 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); | 1735 | (unsigned long)handle_tlbm + sizeof(handle_tlbm)); |
1736 | #ifdef CONFIG_MIPS_PGD_C0_CONTEXT | ||
1737 | local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd, | ||
1738 | (unsigned long)tlbmiss_handler_setup_pgd + sizeof(handle_tlbm)); | ||
1739 | #endif | ||
1644 | } | 1740 | } |