These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / mips / mm / sc-mips.c
index 4ceafd1..ddb8154 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 #include <asm/r4kcache.h>
+#include <asm/mips-cm.h>
 
 /*
  * MIPS32/MIPS64 L2 cache handling
@@ -50,11 +51,69 @@ static void mips_sc_disable(void)
        /* L2 cache is permanently enabled */
 }
 
+static void mips_sc_prefetch_enable(void)
+{
+       unsigned long pftctl;
+
+       if (mips_cm_revision() < CM_REV_CM2_5)
+               return;
+
+       /*
+        * If there is one or more L2 prefetch unit present then enable
+        * prefetching for both code & data, for all ports.
+        */
+       pftctl = read_gcr_l2_pft_control();
+       if (pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK) {
+               pftctl &= ~CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK;
+               pftctl |= PAGE_MASK & CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK;
+               pftctl |= CM_GCR_L2_PFT_CONTROL_PFTEN_MSK;
+               write_gcr_l2_pft_control(pftctl);
+
+               pftctl = read_gcr_l2_pft_control_b();
+               pftctl |= CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK;
+               pftctl |= CM_GCR_L2_PFT_CONTROL_B_CEN_MSK;
+               write_gcr_l2_pft_control_b(pftctl);
+       }
+}
+
+static void mips_sc_prefetch_disable(void)
+{
+       unsigned long pftctl;
+
+       if (mips_cm_revision() < CM_REV_CM2_5)
+               return;
+
+       pftctl = read_gcr_l2_pft_control();
+       pftctl &= ~CM_GCR_L2_PFT_CONTROL_PFTEN_MSK;
+       write_gcr_l2_pft_control(pftctl);
+
+       pftctl = read_gcr_l2_pft_control_b();
+       pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK;
+       pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_CEN_MSK;
+       write_gcr_l2_pft_control_b(pftctl);
+}
+
+static bool mips_sc_prefetch_is_enabled(void)
+{
+       unsigned long pftctl;
+
+       if (mips_cm_revision() < CM_REV_CM2_5)
+               return false;
+
+       pftctl = read_gcr_l2_pft_control();
+       if (!(pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK))
+               return false;
+       return !!(pftctl & CM_GCR_L2_PFT_CONTROL_PFTEN_MSK);
+}
+
 static struct bcache_ops mips_sc_ops = {
        .bc_enable = mips_sc_enable,
        .bc_disable = mips_sc_disable,
        .bc_wback_inv = mips_sc_wback_inv,
-       .bc_inv = mips_sc_inv
+       .bc_inv = mips_sc_inv,
+       .bc_prefetch_enable = mips_sc_prefetch_enable,
+       .bc_prefetch_disable = mips_sc_prefetch_disable,
+       .bc_prefetch_is_enabled = mips_sc_prefetch_is_enabled,
 };
 
 /*
@@ -94,6 +153,43 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
        return 1;
 }
 
+static int __init mips_sc_probe_cm3(void)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+       unsigned long cfg = read_gcr_l2_config();
+       unsigned long sets, line_sz, assoc;
+
+       if (cfg & CM_GCR_L2_CONFIG_BYPASS_MSK)
+               return 0;
+
+       sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK;
+       sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF;
+       if (sets)
+               c->scache.sets = 64 << sets;
+
+       line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK;
+       line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF;
+       if (line_sz)
+               c->scache.linesz = 2 << line_sz;
+
+       assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK;
+       assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF;
+       c->scache.ways = assoc + 1;
+       c->scache.waysize = c->scache.sets * c->scache.linesz;
+       c->scache.waybit = __ffs(c->scache.waysize);
+
+       if (c->scache.linesz) {
+               c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+               return 1;
+       }
+
+       return 0;
+}
+
+void __weak platform_early_l2_init(void)
+{
+}
+
 static inline int __init mips_sc_probe(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
@@ -103,6 +199,15 @@ static inline int __init mips_sc_probe(void)
        /* Mark as not present until probe completed */
        c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
 
+       /*
+        * Do we need some platform specific probing before
+        * we configure L2?
+        */
+       platform_early_l2_init();
+
+       if (mips_cm_revision() >= CM_REV_CM3)
+               return mips_sc_probe_cm3();
+
        /* Ignore anything but MIPSxx processors */
        if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
                              MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 |
@@ -120,13 +225,13 @@ static inline int __init mips_sc_probe(void)
                return 0;
 
        tmp = (config2 >> 8) & 0x0f;
-       if (0 <= tmp && tmp <= 7)
+       if (tmp <= 7)
                c->scache.sets = 64 << tmp;
        else
                return 0;
 
        tmp = (config2 >> 0) & 0x0f;
-       if (0 <= tmp && tmp <= 7)
+       if (tmp <= 7)
                c->scache.ways = tmp + 1;
        else
                return 0;
@@ -144,6 +249,7 @@ int mips_sc_init(void)
        int found = mips_sc_probe();
        if (found) {
                mips_sc_enable();
+               mips_sc_prefetch_enable();
                bcops = &mips_sc_ops;
        }
        return found;