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/
这个提交包含在:
@@ -163,6 +163,25 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
|
||||
static char unknown_isa[] = KERN_ERR \
|
||||
"Unsupported ISA type, c0.config0: %d.";
|
||||
|
||||
static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
|
||||
{
|
||||
unsigned int config6;
|
||||
/*
|
||||
* Config6 is implementation dependent and it's currently only
|
||||
* used by proAptiv
|
||||
*/
|
||||
if (c->cputype == CPU_PROAPTIV) {
|
||||
config6 = read_c0_config6();
|
||||
if (enable)
|
||||
/* Enable FTLB */
|
||||
write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
|
||||
else
|
||||
/* Disable FTLB */
|
||||
write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN);
|
||||
back_to_back_c0_hazard();
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned int decode_config0(struct cpuinfo_mips *c)
|
||||
{
|
||||
unsigned int config0;
|
||||
@@ -170,8 +189,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
|
||||
|
||||
config0 = read_c0_config();
|
||||
|
||||
if (((config0 & MIPS_CONF_MT) >> 7) == 1)
|
||||
/*
|
||||
* Look for Standard TLB or Dual VTLB and FTLB
|
||||
*/
|
||||
if ((((config0 & MIPS_CONF_MT) >> 7) == 1) ||
|
||||
(((config0 & MIPS_CONF_MT) >> 7) == 4))
|
||||
c->options |= MIPS_CPU_TLB;
|
||||
|
||||
isa = (config0 & MIPS_CONF_AT) >> 13;
|
||||
switch (isa) {
|
||||
case 0:
|
||||
@@ -226,8 +250,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c)
|
||||
c->options |= MIPS_CPU_FPU;
|
||||
c->options |= MIPS_CPU_32FPR;
|
||||
}
|
||||
if (cpu_has_tlb)
|
||||
if (cpu_has_tlb) {
|
||||
c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
|
||||
c->tlbsizevtlb = c->tlbsize;
|
||||
c->tlbsizeftlbsets = 0;
|
||||
}
|
||||
|
||||
return config1 & MIPS_CONF_M;
|
||||
}
|
||||
@@ -281,16 +308,50 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
|
||||
static inline unsigned int decode_config4(struct cpuinfo_mips *c)
|
||||
{
|
||||
unsigned int config4;
|
||||
unsigned int newcf4;
|
||||
unsigned int mmuextdef;
|
||||
unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE;
|
||||
|
||||
config4 = read_c0_config4();
|
||||
|
||||
if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
|
||||
&& cpu_has_tlb)
|
||||
c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
|
||||
|
||||
if (cpu_has_tlb) {
|
||||
if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
|
||||
c->options |= MIPS_CPU_TLBINV;
|
||||
mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
|
||||
switch (mmuextdef) {
|
||||
case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
|
||||
c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
|
||||
c->tlbsizevtlb = c->tlbsize;
|
||||
break;
|
||||
case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
|
||||
c->tlbsizevtlb +=
|
||||
((config4 & MIPS_CONF4_VTLBSIZEEXT) >>
|
||||
MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
|
||||
c->tlbsize = c->tlbsizevtlb;
|
||||
ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
|
||||
/* fall through */
|
||||
case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
|
||||
newcf4 = (config4 & ~ftlb_page) |
|
||||
(page_size_ftlb(mmuextdef) <<
|
||||
MIPS_CONF4_FTLBPAGESIZE_SHIFT);
|
||||
write_c0_config4(newcf4);
|
||||
back_to_back_c0_hazard();
|
||||
config4 = read_c0_config4();
|
||||
if (config4 != newcf4) {
|
||||
pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n",
|
||||
PAGE_SIZE, config4);
|
||||
/* Switch FTLB off */
|
||||
set_ftlb_enable(c, 0);
|
||||
break;
|
||||
}
|
||||
c->tlbsizeftlbsets = 1 <<
|
||||
((config4 & MIPS_CONF4_FTLBSETS) >>
|
||||
MIPS_CONF4_FTLBSETS_SHIFT);
|
||||
c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
|
||||
MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
|
||||
c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c->kscratch_mask = (config4 >> 16) & 0xff;
|
||||
@@ -319,6 +380,9 @@ static void decode_configs(struct cpuinfo_mips *c)
|
||||
|
||||
c->scache.flags = MIPS_CACHE_NOT_PRESENT;
|
||||
|
||||
/* Enable FTLB if present */
|
||||
set_ftlb_enable(c, 1);
|
||||
|
||||
ok = decode_config0(c); /* Read Config registers. */
|
||||
BUG_ON(!ok); /* Arch spec violation! */
|
||||
if (ok)
|
||||
@@ -682,7 +746,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
|
||||
static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
{
|
||||
decode_configs(c);
|
||||
switch (c->processor_id & PRID_IMP_MASK) {
|
||||
case PRID_IMP_4KC:
|
||||
c->cputype = CPU_4KC;
|
||||
@@ -756,6 +819,8 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
break;
|
||||
}
|
||||
|
||||
decode_configs(c);
|
||||
|
||||
spram_config();
|
||||
}
|
||||
|
||||
|
@@ -476,6 +476,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
|
||||
BUILD_HANDLER ov ov sti silent /* #12 */
|
||||
BUILD_HANDLER tr tr sti silent /* #13 */
|
||||
BUILD_HANDLER fpe fpe fpe silent /* #15 */
|
||||
BUILD_HANDLER ftlb ftlb none silent /* #16 */
|
||||
BUILD_HANDLER mdmx mdmx sti silent /* #22 */
|
||||
#ifdef CONFIG_HARDWARE_WATCHPOINTS
|
||||
/*
|
||||
|
@@ -78,6 +78,7 @@ extern asmlinkage void handle_cpu(void);
|
||||
extern asmlinkage void handle_ov(void);
|
||||
extern asmlinkage void handle_tr(void);
|
||||
extern asmlinkage void handle_fpe(void);
|
||||
extern asmlinkage void handle_ftlb(void);
|
||||
extern asmlinkage void handle_mdmx(void);
|
||||
extern asmlinkage void handle_watch(void);
|
||||
extern asmlinkage void handle_mt(void);
|
||||
@@ -1460,6 +1461,34 @@ asmlinkage void cache_parity_error(void)
|
||||
panic("Can't handle the cache error!");
|
||||
}
|
||||
|
||||
asmlinkage void do_ftlb(void)
|
||||
{
|
||||
const int field = 2 * sizeof(unsigned long);
|
||||
unsigned int reg_val;
|
||||
|
||||
/* For the moment, report the problem and hang. */
|
||||
if (cpu_has_mips_r2 &&
|
||||
((current_cpu_data.processor_id && 0xff0000) == PRID_COMP_MIPS)) {
|
||||
pr_err("FTLB error exception, cp0_ecc=0x%08x:\n",
|
||||
read_c0_ecc());
|
||||
pr_err("cp0_errorepc == %0*lx\n", field, read_c0_errorepc());
|
||||
reg_val = read_c0_cacheerr();
|
||||
pr_err("c0_cacheerr == %08x\n", reg_val);
|
||||
|
||||
if ((reg_val & 0xc0000000) == 0xc0000000) {
|
||||
pr_err("Decoded c0_cacheerr: FTLB parity error\n");
|
||||
} else {
|
||||
pr_err("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
|
||||
reg_val & (1<<30) ? "secondary" : "primary",
|
||||
reg_val & (1<<31) ? "data" : "insn");
|
||||
}
|
||||
} else {
|
||||
pr_err("FTLB error exception\n");
|
||||
}
|
||||
/* Just print the cacheerr bits for now */
|
||||
cache_parity_error();
|
||||
}
|
||||
|
||||
/*
|
||||
* SDBBP EJTAG debug exception handler.
|
||||
* We skip the instruction and return to the next instruction.
|
||||
@@ -2009,6 +2038,7 @@ void __init trap_init(void)
|
||||
if (cpu_has_fpu && !cpu_has_nofpuex)
|
||||
set_except_vector(15, handle_fpe);
|
||||
|
||||
set_except_vector(16, handle_ftlb);
|
||||
set_except_vector(22, handle_mdmx);
|
||||
|
||||
if (cpu_has_mcheck)
|
||||
|
在新工单中引用
屏蔽一个用户