aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-12-21 17:19:11 -0500
committerRalf Baechle <ralf@linux-mips.org>2011-01-18 13:30:22 -0500
commit3d8bfdd0307223de678962f1c1907a7cec549136 (patch)
tree007146d1452d054e5e676b5a930d48292b0ae4b6 /arch
parentc42aef0947d717849f31965ecc0778707839bfe0 (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.h8
-rw-r--r--arch/mips/kernel/traps.c2
-rw-r--r--arch/mips/mm/tlbex.c116
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
32static inline void tlbmiss_handler_setup_pgd(unsigned long pgd) 32extern 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;
173static int check_for_high_segbits __cpuinitdata; 175static 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
180static unsigned int kscratch_used_mask __cpuinitdata;
181
182static 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
199static 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 */
209extern 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)
1014u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned; 1052u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned;
1015u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned; 1053u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned;
1016u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned; 1054u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
1055#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
1056u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned;
1057
1058static 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
1018static void __cpuinit 1105static void __cpuinit
1019iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr) 1106iPTE_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}