On systems with CM 2.5 & beyond there may be L2 prefetch units present
which are not enabled by default. Detect them, configuring & enabling
prefetching when available.

Signed-off-by: Paul Burton <[email protected]>
---

 arch/mips/include/asm/mips-cm.h | 17 ++++++++++++
 arch/mips/mm/sc-mips.c          | 61 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
index d75b75e..36530fd 100644
--- a/arch/mips/include/asm/mips-cm.h
+++ b/arch/mips/include/asm/mips-cm.h
@@ -194,6 +194,8 @@ BUILD_CM_RW(reg3_mask,              MIPS_CM_GCB_OFS + 0xc8)
 BUILD_CM_R_(gic_status,                MIPS_CM_GCB_OFS + 0xd0)
 BUILD_CM_R_(cpc_status,                MIPS_CM_GCB_OFS + 0xf0)
 BUILD_CM_RW(l2_config,         MIPS_CM_GCB_OFS + 0x130)
+BUILD_CM_RW(l2_pft_control,    MIPS_CM_GCB_OFS + 0x300)
+BUILD_CM_RW(l2_pft_control_b,  MIPS_CM_GCB_OFS + 0x308)
 
 /* Core Local & Core Other register accessor functions */
 BUILD_CM_Cx_RW(reset_release,  0x00)
@@ -244,6 +246,7 @@ BUILD_CM_Cx_R_(tcid_8_priority,     0x80)
                 ((minor) << CM_GCR_REV_MINOR_SHF))
 
 #define CM_REV_CM2                             CM_ENCODE_REV(6, 0)
+#define CM_REV_CM2_5                           CM_ENCODE_REV(7, 0)
 #define CM_REV_CM3                             CM_ENCODE_REV(8, 0)
 
 /* GCR_ERROR_CAUSE register fields */
@@ -316,6 +319,20 @@ BUILD_CM_Cx_R_(tcid_8_priority,    0x80)
 #define CM_GCR_L2_CONFIG_ASSOC_SHF             0
 #define CM_GCR_L2_CONFIG_ASSOC_MSK             (_ULCAST_(0xff) << 0)
 
+/* GCR_L2_PFT_CONTROL register fields */
+#define CM_GCR_L2_PFT_CONTROL_PAGEMASK_SHF     12
+#define CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK     (_ULCAST_(0xfffff) << 12)
+#define CM_GCR_L2_PFT_CONTROL_PFTEN_SHF                8
+#define CM_GCR_L2_PFT_CONTROL_PFTEN_MSK                (_ULCAST_(0x1) << 8)
+#define CM_GCR_L2_PFT_CONTROL_NPFT_SHF         0
+#define CM_GCR_L2_PFT_CONTROL_NPFT_MSK         (_ULCAST_(0xff) << 0)
+
+/* GCR_L2_PFT_CONTROL_B register fields */
+#define CM_GCR_L2_PFT_CONTROL_B_CEN_SHF                8
+#define CM_GCR_L2_PFT_CONTROL_B_CEN_MSK                (_ULCAST_(0x1) << 8)
+#define CM_GCR_L2_PFT_CONTROL_B_PORTID_SHF     0
+#define CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK     (_ULCAST_(0xff) << 0)
+
 /* GCR_Cx_COHERENCE register fields */
 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF    0
 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK    (_ULCAST_(0xff) << 0)
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 53ea839..95cf07c 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -51,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,
 };
 
 /*
@@ -186,6 +244,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;
-- 
2.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to