MIPS: cpu: Add 'noftlb' kernel command line option to disable the FTLB
authorMarkos Chandras <markos.chandras@imgtec.com>
Fri, 29 Aug 2014 08:37:26 +0000 (09:37 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Mon, 24 Nov 2014 06:44:51 +0000 (07:44 +0100)
Add new 'noftlb' kernel command line option to disable the FTLB.
Since the kernel command line is not available when probing and
enabling the CPU features in cpu_probe(), we let the kernel configure
the FTLB during the config4 decode operation and we disable the FTLB later
on, once the command line has become available to us. This should have
no negative effects since FTLB isn't used so early in the boot process.
FTLB increases the effective TLB size leading to less TLB misses. However,
sometimes it's useful to be able to disable it when debugging memory related
core features or other hardware components.

Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/7586/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/cpu-probe.c

index 793c86beffa2e0c00d1721d7a133f5320db21d73..b27e7ffd1112ac2e28cc943b61e643fcae7d8027 100644 (file)
@@ -69,6 +69,63 @@ static int __init htw_disable(char *s)
 
 __setup("nohtw", htw_disable);
 
+static int mips_ftlb_disabled;
+static int mips_has_ftlb_configured;
+
+static void set_ftlb_enable(struct cpuinfo_mips *c, int enable);
+
+static int __init ftlb_disable(char *s)
+{
+       unsigned int config4, mmuextdef;
+
+       /*
+        * If the core hasn't done any FTLB configuration, there is nothing
+        * for us to do here.
+        */
+       if (!mips_has_ftlb_configured)
+               return 1;
+
+       /* Disable it in the boot cpu */
+       set_ftlb_enable(&cpu_data[0], 0);
+
+       back_to_back_c0_hazard();
+
+       config4 = read_c0_config4();
+
+       /* Check that FTLB has been disabled */
+       mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
+       /* MMUSIZEEXT == VTLB ON, FTLB OFF */
+       if (mmuextdef == MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT) {
+               /* This should never happen */
+               pr_warn("FTLB could not be disabled!\n");
+               return 1;
+       }
+
+       mips_ftlb_disabled = 1;
+       mips_has_ftlb_configured = 0;
+
+       /*
+        * noftlb is mainly used for debug purposes so print
+        * an informative message instead of using pr_debug()
+        */
+       pr_info("FTLB has been disabled\n");
+
+       /*
+        * Some of these bits are duplicated in the decode_config4.
+        * MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT is the only possible case
+        * once FTLB has been disabled so undo what decode_config4 did.
+        */
+       cpu_data[0].tlbsize -= cpu_data[0].tlbsizeftlbways *
+                              cpu_data[0].tlbsizeftlbsets;
+       cpu_data[0].tlbsizeftlbsets = 0;
+       cpu_data[0].tlbsizeftlbways = 0;
+
+       return 1;
+}
+
+__setup("noftlb", ftlb_disable);
+
+
 static inline void check_errata(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
@@ -368,6 +425,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
                        ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
                        /* fall through */
                case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
+                       if (mips_ftlb_disabled)
+                               break;
                        newcf4 = (config4 & ~ftlb_page) |
                                (page_size_ftlb(mmuextdef) <<
                                 MIPS_CONF4_FTLBPAGESIZE_SHIFT);
@@ -387,6 +446,7 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
                        c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
                                              MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
                        c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
+                       mips_has_ftlb_configured = 1;
                        break;
                }
        }
@@ -422,8 +482,8 @@ static void decode_configs(struct cpuinfo_mips *c)
 
        c->scache.flags = MIPS_CACHE_NOT_PRESENT;
 
-       /* Enable FTLB if present */
-       set_ftlb_enable(c, 1);
+       /* Enable FTLB if present and not disabled */
+       set_ftlb_enable(c, !mips_ftlb_disabled);
 
        ok = decode_config0(c);                 /* Read Config registers.  */
        BUG_ON(!ok);                            /* Arch spec violation!  */