MIPS: Loongson: Invalidate special TLBs when needed
authorHuacai Chen <chenhc@lemote.com>
Thu, 3 Mar 2016 01:45:11 +0000 (09:45 +0800)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 13 May 2016 12:02:14 +0000 (14:02 +0200)
Loongson-2 has a 4 entry itlb which is a subset of jtlb, Loongson-3 has
a 4 entry itlb and a 4 entry dtlb which are subsets of jtlb. We should
write diag register to invalidate itlb/dtlb when flushing jtlb because
itlb/dtlb are not totally transparent to software.

For Loongson-3A R2 (and newer), we should invalidate ITLB, DTLB, VTLB
and FTLB before we enable/disable FTLB.

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Steven J . Hill <sjhill@realitydiluted.com>
Cc: Fuxin Zhang <zhangfx@lemote.com>
Cc: Zhangjin Wu <wuzhangjin@gmail.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/12753/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/mipsregs.h
arch/mips/kernel/cpu-probe.c
arch/mips/mm/tlb-r4k.c

index 28ded49..0d0bd16 100644 (file)
 /* Disable Branch Return Cache */
 #define R10K_DIAG_D_BRC                (_ULCAST_(1) << 22)
 
+/* Flush ITLB */
+#define LOONGSON_DIAG_ITLB     (_ULCAST_(1) << 2)
+/* Flush DTLB */
+#define LOONGSON_DIAG_DTLB     (_ULCAST_(1) << 3)
+/* Flush VTLB */
+#define LOONGSON_DIAG_VTLB     (_ULCAST_(1) << 12)
+/* Flush FTLB */
+#define LOONGSON_DIAG_FTLB     (_ULCAST_(1) << 13)
+
 /*
  * Coprocessor 1 (FPU) register names
  */
index 2bfd483..515dd1f 100644 (file)
@@ -563,6 +563,9 @@ static int set_ftlb_enable(struct cpuinfo_mips *c, int enable)
                                           << MIPS_CONF7_FTLBP_SHIFT));
                break;
        case CPU_LOONGSON3:
+               /* Flush ITLB, DTLB, VTLB and FTLB */
+               write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB |
+                             LOONGSON_DIAG_VTLB | LOONGSON_DIAG_FTLB);
                /* Loongson-3 cores use Config6 to enable the FTLB */
                config = read_c0_config6();
                if (enable)
index c17d762..4c3362b 100644 (file)
 extern void build_tlb_refill_handler(void);
 
 /*
- * LOONGSON2/3 has a 4 entry itlb which is a subset of dtlb,
- * unfortunately, itlb is not totally transparent to software.
+ * LOONGSON-2 has a 4 entry itlb which is a subset of jtlb, LOONGSON-3 has
+ * a 4 entry itlb and a 4 entry dtlb which are subsets of jtlb. Unfortunately,
+ * itlb/dtlb are not totally transparent to software.
  */
-static inline void flush_itlb(void)
+static inline void flush_micro_tlb(void)
 {
        switch (current_cpu_type()) {
        case CPU_LOONGSON2:
+               write_c0_diag(LOONGSON_DIAG_ITLB);
+               break;
        case CPU_LOONGSON3:
-               write_c0_diag(4);
+               write_c0_diag(LOONGSON_DIAG_ITLB | LOONGSON_DIAG_DTLB);
                break;
        default:
                break;
        }
 }
 
-static inline void flush_itlb_vm(struct vm_area_struct *vma)
+static inline void flush_micro_tlb_vm(struct vm_area_struct *vma)
 {
        if (vma->vm_flags & VM_EXEC)
-               flush_itlb();
+               flush_micro_tlb();
 }
 
 void local_flush_tlb_all(void)
@@ -93,7 +96,7 @@ void local_flush_tlb_all(void)
        tlbw_use_hazard();
        write_c0_entryhi(old_ctx);
        htw_start();
-       flush_itlb();
+       flush_micro_tlb();
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(local_flush_tlb_all);
@@ -159,7 +162,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                } else {
                        drop_mmu_context(mm, cpu);
                }
-               flush_itlb();
+               flush_micro_tlb();
                local_irq_restore(flags);
        }
 }
@@ -205,7 +208,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
        } else {
                local_flush_tlb_all();
        }
-       flush_itlb();
+       flush_micro_tlb();
        local_irq_restore(flags);
 }
 
@@ -240,7 +243,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        finish:
                write_c0_entryhi(oldpid);
                htw_start();
-               flush_itlb_vm(vma);
+               flush_micro_tlb_vm(vma);
                local_irq_restore(flags);
        }
 }
@@ -274,7 +277,7 @@ void local_flush_tlb_one(unsigned long page)
        }
        write_c0_entryhi(oldpid);
        htw_start();
-       flush_itlb();
+       flush_micro_tlb();
        local_irq_restore(flags);
 }
 
@@ -357,7 +360,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
        }
        tlbw_use_hazard();
        htw_start();
-       flush_itlb_vm(vma);
+       flush_micro_tlb_vm(vma);
        local_irq_restore(flags);
 }