Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / metag / mm / l2cache.c
diff --git a/kernel/arch/metag/mm/l2cache.c b/kernel/arch/metag/mm/l2cache.c
new file mode 100644 (file)
index 0000000..c64ee61
--- /dev/null
@@ -0,0 +1,192 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/l2cache.h>
+#include <asm/metag_isa.h>
+
+/* If non-0, then initialise the L2 cache */
+static int l2cache_init = 1;
+/* If non-0, then initialise the L2 cache prefetch */
+static int l2cache_init_pf = 1;
+
+int l2c_pfenable;
+
+static volatile u32 l2c_testdata[16] __initdata __aligned(64);
+
+static int __init parse_l2cache(char *p)
+{
+       char *cp = p;
+
+       if (get_option(&cp, &l2cache_init) != 1) {
+               pr_err("Bad l2cache parameter (%s)\n", p);
+               return 1;
+       }
+       return 0;
+}
+early_param("l2cache", parse_l2cache);
+
+static int __init parse_l2cache_pf(char *p)
+{
+       char *cp = p;
+
+       if (get_option(&cp, &l2cache_init_pf) != 1) {
+               pr_err("Bad l2cache_pf parameter (%s)\n", p);
+               return 1;
+       }
+       return 0;
+}
+early_param("l2cache_pf", parse_l2cache_pf);
+
+static int __init meta_l2c_setup(void)
+{
+       /*
+        * If the L2 cache isn't even present, don't do anything, but say so in
+        * the log.
+        */
+       if (!meta_l2c_is_present()) {
+               pr_info("L2 Cache: Not present\n");
+               return 0;
+       }
+
+       /*
+        * Check whether the line size is recognised.
+        */
+       if (!meta_l2c_linesize()) {
+               pr_warn_once("L2 Cache: unknown line size id (config=0x%08x)\n",
+                            meta_l2c_config());
+       }
+
+       /*
+        * Initialise state.
+        */
+       l2c_pfenable = _meta_l2c_pf_is_enabled();
+
+       /*
+        * Enable the L2 cache and print to log whether it was already enabled
+        * by the bootloader.
+        */
+       if (l2cache_init) {
+               pr_info("L2 Cache: Enabling... ");
+               if (meta_l2c_enable())
+                       pr_cont("already enabled\n");
+               else
+                       pr_cont("done\n");
+       } else {
+               pr_info("L2 Cache: Not enabling\n");
+       }
+
+       /*
+        * Enable L2 cache prefetch.
+        */
+       if (l2cache_init_pf) {
+               pr_info("L2 Cache: Enabling prefetch... ");
+               if (meta_l2c_pf_enable(1))
+                       pr_cont("already enabled\n");
+               else
+                       pr_cont("done\n");
+       } else {
+               pr_info("L2 Cache: Not enabling prefetch\n");
+       }
+
+       return 0;
+}
+core_initcall(meta_l2c_setup);
+
+int meta_l2c_disable(void)
+{
+       unsigned long flags;
+       int en;
+
+       if (!meta_l2c_is_present())
+               return 1;
+
+       /*
+        * Prevent other threads writing during the writeback, otherwise the
+        * writes will get "lost" when the L2 is disabled.
+        */
+       __global_lock2(flags);
+       en = meta_l2c_is_enabled();
+       if (likely(en)) {
+               _meta_l2c_pf_enable(0);
+               wr_fence();
+               _meta_l2c_purge();
+               _meta_l2c_enable(0);
+       }
+       __global_unlock2(flags);
+
+       return !en;
+}
+
+int meta_l2c_enable(void)
+{
+       unsigned long flags;
+       int en;
+
+       if (!meta_l2c_is_present())
+               return 0;
+
+       /*
+        * Init (clearing the L2) can happen while the L2 is disabled, so other
+        * threads are safe to continue executing, however we must not init the
+        * cache if it's already enabled (dirty lines would be discarded), so
+        * this operation should still be atomic with other threads.
+        */
+       __global_lock1(flags);
+       en = meta_l2c_is_enabled();
+       if (likely(!en)) {
+               _meta_l2c_init();
+               _meta_l2c_enable(1);
+               _meta_l2c_pf_enable(l2c_pfenable);
+       }
+       __global_unlock1(flags);
+
+       return en;
+}
+
+int meta_l2c_pf_enable(int pfenable)
+{
+       unsigned long flags;
+       int en = l2c_pfenable;
+
+       if (!meta_l2c_is_present())
+               return 0;
+
+       /*
+        * We read modify write the enable register, so this operation must be
+        * atomic with other threads.
+        */
+       __global_lock1(flags);
+       en = l2c_pfenable;
+       l2c_pfenable = pfenable;
+       if (meta_l2c_is_enabled())
+               _meta_l2c_pf_enable(pfenable);
+       __global_unlock1(flags);
+
+       return en;
+}
+
+int meta_l2c_flush(void)
+{
+       unsigned long flags;
+       int en;
+
+       /*
+        * Prevent other threads writing during the writeback. This also
+        * involves read modify writes.
+        */
+       __global_lock2(flags);
+       en = meta_l2c_is_enabled();
+       if (likely(en)) {
+               _meta_l2c_pf_enable(0);
+               wr_fence();
+               _meta_l2c_purge();
+               _meta_l2c_enable(0);
+               _meta_l2c_init();
+               _meta_l2c_enable(1);
+               _meta_l2c_pf_enable(l2c_pfenable);
+       }
+       __global_unlock2(flags);
+
+       return !en;
+}