MIPS: bugfix of TLB refill optimisation
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Tue, 18 Nov 2014 01:44:26 +0000 (17:44 -0800)
committerRaghu Gandham <raghu.gandham@imgtec.com>
Tue, 2 Dec 2014 00:58:26 +0000 (16:58 -0800)
Patch 748e787e replaced SRL(4)->ROTR(2) sequence in TLB refill handler
during loading EntryLo from PTE by a single ROTR(6).
It prevents running MIPS32 kernel on MIPS64 CPU and even running MIPS32
kernel on system with 36 bits physical address CPU, even with 256MB.
That patch just doesn't clear 4 high-order bits 29:26 and CPU tries
to use a high memory due to SW bits in this field.

This patch restores an original SRL+ROTR sequence if CPU is able to use
that 4 bits of physical address (36:32 in 4K system).

Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu.h
arch/mips/kernel/cpu-probe.c
arch/mips/mm/tlbex.c

index da371532a1b1de5c260c985cff3224ef3c55dd3c..95feb244a4a104b93d5ebe0ee21c43ff9fec01ed 100644 (file)
 #ifndef cpu_has_rixi
 #define cpu_has_rixi           (cpu_data[0].options & MIPS_CPU_RIXI)
 #endif
+#ifndef cpu_has_himem
+#define cpu_has_himem           (cpu_data[0].options2 & MIPS_CPU_HIMEM)
+#endif
 #ifndef cpu_has_rixi_except
 #define cpu_has_rixi_except     (cpu_data[0].options & MIPS_CPU_RIXI_EXCEPT)
 #endif
index eeca04a151dd912c7487c4be26f1f4cd13c29700..be8c7e3fd9770ac38b750598f6455781944fc6e9 100644 (file)
@@ -350,6 +350,7 @@ enum cpu_type_enum {
  * CPU Option2 encodings
  */
 #define MIPS_CPU_MAAR           0x00000001      /* MAAR exists */
+#define MIPS_CPU_HIMEM          0x00000002 /* MIPS32: PA bits exceed PTE space */
 
 /*
  * CPU ASE encodings
index bc00bc440ff01e9fafe14c156ece6aedc4999a32..81b3673b36077c6cbed2436f44ebd0884fc2f686 100644 (file)
@@ -152,6 +152,17 @@ static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
 #endif
 }
 
+static inline void cpu_probe_pabits(struct cpuinfo_mips *c)
+{
+       unsigned int enlow;
+
+       write_c0_entrylo0((-1UL)>>2); /* skip RIXI bits */
+       back_to_back_c0_hazard();
+       enlow = read_c0_entrylo0();
+       if ((_MIPS_SZLONG - fls(enlow)) < ilog2(_PAGE_GLOBAL))
+               c->options2 |= MIPS_CPU_HIMEM;
+}
+
 static void __cpuinit set_isa(struct cpuinfo_mips *c, unsigned int isa)
 {
        switch (isa) {
@@ -1267,6 +1278,7 @@ __cpuinit void cpu_probe(void)
                c->srsets = 1;
 
        cpu_probe_vmbits(c);
+       cpu_probe_pabits(c);
 
 #ifdef CONFIG_64BIT
        if (cpu == 0)
index 4d8233da657aebfacfb73bd1ff62b4f4343e9398..4c7b581b22233be5a4694dd08e486dd633d905af 100644 (file)
@@ -648,7 +648,12 @@ static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
                                                                  unsigned int reg)
 {
        if (cpu_has_rixi) {
-               UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
+               if (!cpu_has_himem)
+                       UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
+               else {
+                       UASM_i_SRL(p, reg, reg, ilog2(_PAGE_NO_EXEC));
+                       UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+               }
        } else {
 #ifdef CONFIG_64BIT_PHYS_ADDR
                uasm_i_dsrl_safe(p, reg, reg, ilog2(_PAGE_GLOBAL));
@@ -1070,9 +1075,17 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
                uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
                uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
                if (cpu_has_rixi) {
-                       UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
-                       UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-                       UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
+                       if (!cpu_has_himem) {
+                               UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
+                               UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
+                               UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
+                       } else {
+                               UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_NO_EXEC));
+                               UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_NO_EXEC));
+                               UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+                               UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
+                               UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+                       }
                } else {
                        uasm_i_dsrl_safe(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
                        UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
@@ -1095,11 +1108,20 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
        if (r45k_bvahwbug())
                build_tlb_probe_entry(p);
        if (cpu_has_rixi) {
-               UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
+               if (!cpu_has_himem)
+                       UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
+               else {
+                       UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_NO_EXEC));
+                       UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_NO_EXEC));
+                       UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+               }
                if (r4k_250MHZhwbug())
                        UASM_i_MTC0(p, 0, C0_ENTRYLO0);
                UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-               UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
+               if (!cpu_has_himem)
+                       UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
+               else
+                       UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
        } else {
                UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
                if (r4k_250MHZhwbug())