aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>2013-11-14 11:12:31 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-01-22 14:19:00 -0500
commit75b5b5e0a262790fa11043fe45700499c7e3d818 (patch)
tree3c5af9caa9c5478668159ff34db0ab34b51d7511 /arch
parent601cfa7b6fb657cff9e8f77bbcce79f75dd7ab74 (diff)
MIPS: Add support for FTLBs
The Fixed Page Size TLB (FTLB) is a set-associative dual entry TLB. Its purpose is to reduce the number of TLB misses by increasing the effective TLB size and keep the implementation complexity to minimum levels. A supported core can have both VTLB and FTLB. Reviewed-by: James Hogan <james.hogan@imgtec.com> Reviewed-by: Paul Burton <paul.burton@imgtec.com> Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Signed-off-by: John Crispin <blogic@openwrt.org> Patchwork: http://patchwork.linux-mips.org/patch/6139/
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/include/asm/cpu-info.h3
-rw-r--r--arch/mips/include/asm/mipsregs.h2
-rw-r--r--arch/mips/include/asm/page.h25
-rw-r--r--arch/mips/kernel/cpu-probe.c79
-rw-r--r--arch/mips/kernel/genex.S1
-rw-r--r--arch/mips/kernel/traps.c30
-rw-r--r--arch/mips/mm/tlb-r4k.c29
7 files changed, 155 insertions, 14 deletions
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
index 21c8e29c8f91..8f7adf0ac1e3 100644
--- a/arch/mips/include/asm/cpu-info.h
+++ b/arch/mips/include/asm/cpu-info.h
@@ -52,6 +52,9 @@ struct cpuinfo_mips {
52 unsigned int cputype; 52 unsigned int cputype;
53 int isa_level; 53 int isa_level;
54 int tlbsize; 54 int tlbsize;
55 int tlbsizevtlb;
56 int tlbsizeftlbsets;
57 int tlbsizeftlbways;
55 struct cache_desc icache; /* Primary I-cache */ 58 struct cache_desc icache; /* Primary I-cache */
56 struct cache_desc dcache; /* Primary D or combined I/D cache */ 59 struct cache_desc dcache; /* Primary D or combined I/D cache */
57 struct cache_desc scache; /* Secondary cache */ 60 struct cache_desc scache; /* Secondary cache */
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index d9910a1e754a..cb57e07faa24 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -645,6 +645,8 @@
645#define MIPS_CONF5_K (_ULCAST_(1) << 30) 645#define MIPS_CONF5_K (_ULCAST_(1) << 30)
646 646
647#define MIPS_CONF6_SYND (_ULCAST_(1) << 13) 647#define MIPS_CONF6_SYND (_ULCAST_(1) << 13)
648/* proAptiv FTLB on/off bit */
649#define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15)
648 650
649#define MIPS_CONF7_WII (_ULCAST_(1) << 31) 651#define MIPS_CONF7_WII (_ULCAST_(1) << 31)
650 652
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index f6be4741f7e8..5e08bcc74897 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -11,6 +11,8 @@
11 11
12#include <spaces.h> 12#include <spaces.h>
13#include <linux/const.h> 13#include <linux/const.h>
14#include <linux/kernel.h>
15#include <asm/mipsregs.h>
14 16
15/* 17/*
16 * PAGE_SHIFT determines the page size 18 * PAGE_SHIFT determines the page size
@@ -33,6 +35,29 @@
33#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 35#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
34#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) 36#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
35 37
38/*
39 * This is used for calculating the real page sizes
40 * for FTLB or VTLB + FTLB confugrations.
41 */
42static inline unsigned int page_size_ftlb(unsigned int mmuextdef)
43{
44 switch (mmuextdef) {
45 case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
46 if (PAGE_SIZE == (1 << 30))
47 return 5;
48 if (PAGE_SIZE == (1llu << 32))
49 return 6;
50 if (PAGE_SIZE > (256 << 10))
51 return 7; /* reserved */
52 /* fall through */
53 case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
54 return (PAGE_SHIFT - 10) / 2;
55 default:
56 panic("Invalid FTLB configuration with Conf4_mmuextdef=%d value\n",
57 mmuextdef >> 14);
58 }
59}
60
36#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT 61#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
37#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3) 62#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3)
38#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) 63#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index f86414ebe05e..65b61bb8882d 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -163,6 +163,25 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
163static char unknown_isa[] = KERN_ERR \ 163static char unknown_isa[] = KERN_ERR \
164 "Unsupported ISA type, c0.config0: %d."; 164 "Unsupported ISA type, c0.config0: %d.";
165 165
166static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
167{
168 unsigned int config6;
169 /*
170 * Config6 is implementation dependent and it's currently only
171 * used by proAptiv
172 */
173 if (c->cputype == CPU_PROAPTIV) {
174 config6 = read_c0_config6();
175 if (enable)
176 /* Enable FTLB */
177 write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
178 else
179 /* Disable FTLB */
180 write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN);
181 back_to_back_c0_hazard();
182 }
183}
184
166static inline unsigned int decode_config0(struct cpuinfo_mips *c) 185static inline unsigned int decode_config0(struct cpuinfo_mips *c)
167{ 186{
168 unsigned int config0; 187 unsigned int config0;
@@ -170,8 +189,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
170 189
171 config0 = read_c0_config(); 190 config0 = read_c0_config();
172 191
173 if (((config0 & MIPS_CONF_MT) >> 7) == 1) 192 /*
193 * Look for Standard TLB or Dual VTLB and FTLB
194 */
195 if ((((config0 & MIPS_CONF_MT) >> 7) == 1) ||
196 (((config0 & MIPS_CONF_MT) >> 7) == 4))
174 c->options |= MIPS_CPU_TLB; 197 c->options |= MIPS_CPU_TLB;
198
175 isa = (config0 & MIPS_CONF_AT) >> 13; 199 isa = (config0 & MIPS_CONF_AT) >> 13;
176 switch (isa) { 200 switch (isa) {
177 case 0: 201 case 0:
@@ -226,8 +250,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c)
226 c->options |= MIPS_CPU_FPU; 250 c->options |= MIPS_CPU_FPU;
227 c->options |= MIPS_CPU_32FPR; 251 c->options |= MIPS_CPU_32FPR;
228 } 252 }
229 if (cpu_has_tlb) 253 if (cpu_has_tlb) {
230 c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; 254 c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
255 c->tlbsizevtlb = c->tlbsize;
256 c->tlbsizeftlbsets = 0;
257 }
231 258
232 return config1 & MIPS_CONF_M; 259 return config1 & MIPS_CONF_M;
233} 260}
@@ -281,16 +308,50 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
281static inline unsigned int decode_config4(struct cpuinfo_mips *c) 308static inline unsigned int decode_config4(struct cpuinfo_mips *c)
282{ 309{
283 unsigned int config4; 310 unsigned int config4;
311 unsigned int newcf4;
312 unsigned int mmuextdef;
313 unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE;
284 314
285 config4 = read_c0_config4(); 315 config4 = read_c0_config4();
286 316
287 if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
288 && cpu_has_tlb)
289 c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
290
291 if (cpu_has_tlb) { 317 if (cpu_has_tlb) {
292 if (((config4 & MIPS_CONF4_IE) >> 29) == 2) 318 if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
293 c->options |= MIPS_CPU_TLBINV; 319 c->options |= MIPS_CPU_TLBINV;
320 mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
321 switch (mmuextdef) {
322 case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
323 c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
324 c->tlbsizevtlb = c->tlbsize;
325 break;
326 case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
327 c->tlbsizevtlb +=
328 ((config4 & MIPS_CONF4_VTLBSIZEEXT) >>
329 MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
330 c->tlbsize = c->tlbsizevtlb;
331 ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
332 /* fall through */
333 case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
334 newcf4 = (config4 & ~ftlb_page) |
335 (page_size_ftlb(mmuextdef) <<
336 MIPS_CONF4_FTLBPAGESIZE_SHIFT);
337 write_c0_config4(newcf4);
338 back_to_back_c0_hazard();
339 config4 = read_c0_config4();
340 if (config4 != newcf4) {
341 pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n",
342 PAGE_SIZE, config4);
343 /* Switch FTLB off */
344 set_ftlb_enable(c, 0);
345 break;
346 }
347 c->tlbsizeftlbsets = 1 <<
348 ((config4 & MIPS_CONF4_FTLBSETS) >>
349 MIPS_CONF4_FTLBSETS_SHIFT);
350 c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
351 MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
352 c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
353 break;
354 }
294 } 355 }
295 356
296 c->kscratch_mask = (config4 >> 16) & 0xff; 357 c->kscratch_mask = (config4 >> 16) & 0xff;
@@ -319,6 +380,9 @@ static void decode_configs(struct cpuinfo_mips *c)
319 380
320 c->scache.flags = MIPS_CACHE_NOT_PRESENT; 381 c->scache.flags = MIPS_CACHE_NOT_PRESENT;
321 382
383 /* Enable FTLB if present */
384 set_ftlb_enable(c, 1);
385
322 ok = decode_config0(c); /* Read Config registers. */ 386 ok = decode_config0(c); /* Read Config registers. */
323 BUG_ON(!ok); /* Arch spec violation! */ 387 BUG_ON(!ok); /* Arch spec violation! */
324 if (ok) 388 if (ok)
@@ -682,7 +746,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
682 746
683static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) 747static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
684{ 748{
685 decode_configs(c);
686 switch (c->processor_id & PRID_IMP_MASK) { 749 switch (c->processor_id & PRID_IMP_MASK) {
687 case PRID_IMP_4KC: 750 case PRID_IMP_4KC:
688 c->cputype = CPU_4KC; 751 c->cputype = CPU_4KC;
@@ -756,6 +819,8 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
756 break; 819 break;
757 } 820 }
758 821
822 decode_configs(c);
823
759 spram_config(); 824 spram_config();
760} 825}
761 826
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 47d7583cd67f..d84f6a509502 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -476,6 +476,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
476 BUILD_HANDLER ov ov sti silent /* #12 */ 476 BUILD_HANDLER ov ov sti silent /* #12 */
477 BUILD_HANDLER tr tr sti silent /* #13 */ 477 BUILD_HANDLER tr tr sti silent /* #13 */
478 BUILD_HANDLER fpe fpe fpe silent /* #15 */ 478 BUILD_HANDLER fpe fpe fpe silent /* #15 */
479 BUILD_HANDLER ftlb ftlb none silent /* #16 */
479 BUILD_HANDLER mdmx mdmx sti silent /* #22 */ 480 BUILD_HANDLER mdmx mdmx sti silent /* #22 */
480#ifdef CONFIG_HARDWARE_WATCHPOINTS 481#ifdef CONFIG_HARDWARE_WATCHPOINTS
481 /* 482 /*
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index e98f3ab2a018..39370e1d4362 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -78,6 +78,7 @@ extern asmlinkage void handle_cpu(void);
78extern asmlinkage void handle_ov(void); 78extern asmlinkage void handle_ov(void);
79extern asmlinkage void handle_tr(void); 79extern asmlinkage void handle_tr(void);
80extern asmlinkage void handle_fpe(void); 80extern asmlinkage void handle_fpe(void);
81extern asmlinkage void handle_ftlb(void);
81extern asmlinkage void handle_mdmx(void); 82extern asmlinkage void handle_mdmx(void);
82extern asmlinkage void handle_watch(void); 83extern asmlinkage void handle_watch(void);
83extern asmlinkage void handle_mt(void); 84extern asmlinkage void handle_mt(void);
@@ -1460,6 +1461,34 @@ asmlinkage void cache_parity_error(void)
1460 panic("Can't handle the cache error!"); 1461 panic("Can't handle the cache error!");
1461} 1462}
1462 1463
1464asmlinkage void do_ftlb(void)
1465{
1466 const int field = 2 * sizeof(unsigned long);
1467 unsigned int reg_val;
1468
1469 /* For the moment, report the problem and hang. */
1470 if (cpu_has_mips_r2 &&
1471 ((current_cpu_data.processor_id && 0xff0000) == PRID_COMP_MIPS)) {
1472 pr_err("FTLB error exception, cp0_ecc=0x%08x:\n",
1473 read_c0_ecc());
1474 pr_err("cp0_errorepc == %0*lx\n", field, read_c0_errorepc());
1475 reg_val = read_c0_cacheerr();
1476 pr_err("c0_cacheerr == %08x\n", reg_val);
1477
1478 if ((reg_val & 0xc0000000) == 0xc0000000) {
1479 pr_err("Decoded c0_cacheerr: FTLB parity error\n");
1480 } else {
1481 pr_err("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
1482 reg_val & (1<<30) ? "secondary" : "primary",
1483 reg_val & (1<<31) ? "data" : "insn");
1484 }
1485 } else {
1486 pr_err("FTLB error exception\n");
1487 }
1488 /* Just print the cacheerr bits for now */
1489 cache_parity_error();
1490}
1491
1463/* 1492/*
1464 * SDBBP EJTAG debug exception handler. 1493 * SDBBP EJTAG debug exception handler.
1465 * We skip the instruction and return to the next instruction. 1494 * We skip the instruction and return to the next instruction.
@@ -2009,6 +2038,7 @@ void __init trap_init(void)
2009 if (cpu_has_fpu && !cpu_has_nofpuex) 2038 if (cpu_has_fpu && !cpu_has_nofpuex)
2010 set_except_vector(15, handle_fpe); 2039 set_except_vector(15, handle_fpe);
2011 2040
2041 set_except_vector(16, handle_ftlb);
2012 set_except_vector(22, handle_mdmx); 2042 set_except_vector(22, handle_mdmx);
2013 2043
2014 if (cpu_has_mcheck) 2044 if (cpu_has_mcheck)
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 427dcacca586..ae4ca2450707 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -72,7 +72,7 @@ void local_flush_tlb_all(void)
72{ 72{
73 unsigned long flags; 73 unsigned long flags;
74 unsigned long old_ctx; 74 unsigned long old_ctx;
75 int entry; 75 int entry, ftlbhighset;
76 76
77 ENTER_CRITICAL(flags); 77 ENTER_CRITICAL(flags);
78 /* Save old context and create impossible VPN2 value */ 78 /* Save old context and create impossible VPN2 value */
@@ -83,10 +83,21 @@ void local_flush_tlb_all(void)
83 entry = read_c0_wired(); 83 entry = read_c0_wired();
84 84
85 /* Blast 'em all away. */ 85 /* Blast 'em all away. */
86 if (cpu_has_tlbinv && current_cpu_data.tlbsize) { 86 if (cpu_has_tlbinv) {
87 write_c0_index(0); 87 if (current_cpu_data.tlbsizevtlb) {
88 mtc0_tlbw_hazard(); 88 write_c0_index(0);
89 tlbinvf(); /* invalidate VTLB */ 89 mtc0_tlbw_hazard();
90 tlbinvf(); /* invalidate VTLB */
91 }
92 ftlbhighset = current_cpu_data.tlbsizevtlb +
93 current_cpu_data.tlbsizeftlbsets;
94 for (entry = current_cpu_data.tlbsizevtlb;
95 entry < ftlbhighset;
96 entry++) {
97 write_c0_index(entry);
98 mtc0_tlbw_hazard();
99 tlbinvf(); /* invalidate one FTLB set */
100 }
90 } else { 101 } else {
91 while (entry < current_cpu_data.tlbsize) { 102 while (entry < current_cpu_data.tlbsize) {
92 /* Make sure all entries differ. */ 103 /* Make sure all entries differ. */
@@ -134,7 +145,9 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
134 start = round_down(start, PAGE_SIZE << 1); 145 start = round_down(start, PAGE_SIZE << 1);
135 end = round_up(end, PAGE_SIZE << 1); 146 end = round_up(end, PAGE_SIZE << 1);
136 size = (end - start) >> (PAGE_SHIFT + 1); 147 size = (end - start) >> (PAGE_SHIFT + 1);
137 if (size <= current_cpu_data.tlbsize/2) { 148 if (size <= (current_cpu_data.tlbsizeftlbsets ?
149 current_cpu_data.tlbsize / 8 :
150 current_cpu_data.tlbsize / 2)) {
138 int oldpid = read_c0_entryhi(); 151 int oldpid = read_c0_entryhi();
139 int newpid = cpu_asid(cpu, mm); 152 int newpid = cpu_asid(cpu, mm);
140 153
@@ -173,7 +186,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
173 ENTER_CRITICAL(flags); 186 ENTER_CRITICAL(flags);
174 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 187 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
175 size = (size + 1) >> 1; 188 size = (size + 1) >> 1;
176 if (size <= current_cpu_data.tlbsize / 2) { 189 if (size <= (current_cpu_data.tlbsizeftlbsets ?
190 current_cpu_data.tlbsize / 8 :
191 current_cpu_data.tlbsize / 2)) {
177 int pid = read_c0_entryhi(); 192 int pid = read_c0_entryhi();
178 193
179 start &= (PAGE_MASK << 1); 194 start &= (PAGE_MASK << 1);