sparc32: add support for run-time patching of leon/sun single instructions
authorSam Ravnborg <sam@ravnborg.org>
Fri, 25 May 2012 21:20:09 +0000 (21:20 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 May 2012 06:52:43 +0000 (23:52 -0700)
This will be used to handle that MMUREGS has different ASI for SUN and LEON.
This is the infrastructure only - users will come later.

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Daniel Hellstrom <daniel@gaisler.com>
Cc: Konrad Eisele <konrad@gaisler.com>
arch/sparc/include/asm/asmmacro.h
arch/sparc/include/asm/sections.h
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/vmlinux.lds.S

index 02a172f..a0e28ef 100644 (file)
 /* All traps low-level code here must end with this macro. */
 #define RESTORE_ALL b ret_trap_entry; clr %l6;
 
+/* Support for run-time patching of single instructions.
+ * This is used to handle the differences in the ASI for
+ * MMUREGS for LEON and SUN.
+ *
+ * Sample:
+ * LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %o0
+ * SUN_PI_(lda [%g0] ASI_M_MMUREGS, %o0
+ * PI == Patch Instruction
+ *
+ * For LEON we will use the first variant,
+ * and for all other we will use the SUN variant.
+ * The order is important.
+ */
+#define LEON_PI(...)                           \
+662:   __VA_ARGS__
+
+#define SUN_PI_(...)                           \
+       .section .leon_1insn_patch, "ax";       \
+       .word 662b;                             \
+       __VA_ARGS__;                            \
+       .previous
+
 #endif /* !(_SPARC_ASMMACRO_H) */
index 0b0553b..f300d1a 100644 (file)
@@ -7,4 +7,7 @@
 /* sparc entry point */
 extern char _start[];
 
+extern char __leon_1insn_patch[];
+extern char __leon_1insn_patch_end[];
+
 #endif
index 68dd63d..efe3e64 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/cpudata.h>
 #include <asm/setup.h>
 #include <asm/cacheflush.h>
+#include <asm/sections.h>
 
 #include "kernel.h"
 
@@ -238,11 +239,34 @@ static void __init per_cpu_patch(void)
        }
 }
 
+struct leon_1insn_patch_entry {
+       unsigned int addr;
+       unsigned int insn;
+};
+
 enum sparc_cpu sparc_cpu_model;
 EXPORT_SYMBOL(sparc_cpu_model);
 
-struct tt_entry *sparc_ttable;
+static __init void leon_patch(void)
+{
+       struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch;
+       struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end;
+
+       /* Default instruction is leon - no patching */
+       if (sparc_cpu_model == sparc_leon)
+               return;
+
+       while (start < end) {
+               unsigned long addr = start->addr;
+
+               *(unsigned int *)(addr) = start->insn;
+               flushi(addr);
+
+               start++;
+       }
+}
 
+struct tt_entry *sparc_ttable;
 struct pt_regs fake_swapper_regs;
 
 /* Called from head_32.S - before we have setup anything
@@ -251,6 +275,23 @@ struct pt_regs fake_swapper_regs;
 void __init sparc32_start_kernel(struct linux_romvec *rp)
 {
        prom_init(rp);
+
+       /* Set sparc_cpu_model */
+       sparc_cpu_model = sun_unknown;
+       if (!strcmp(&cputypval[0], "sun4m"))
+               sparc_cpu_model = sun4m;
+       if (!strcmp(&cputypval[0], "sun4s"))
+               sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+       if (!strcmp(&cputypval[0], "sun4d"))
+               sparc_cpu_model = sun4d;
+       if (!strcmp(&cputypval[0], "sun4e"))
+               sparc_cpu_model = sun4e;
+       if (!strcmp(&cputypval[0], "sun4u"))
+               sparc_cpu_model = sun4u;
+       if (!strncmp(&cputypval[0], "leon" , 4))
+               sparc_cpu_model = sparc_leon;
+
+       leon_patch();
        start_kernel();
 }
 
@@ -270,21 +311,6 @@ void __init setup_arch(char **cmdline_p)
 
        register_console(&prom_early_console);
 
-       /* Set sparc_cpu_model */
-       sparc_cpu_model = sun_unknown;
-       if (!strcmp(&cputypval[0], "sun4m"))
-               sparc_cpu_model = sun4m;
-       if (!strcmp(&cputypval[0], "sun4s"))
-               sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
-       if (!strcmp(&cputypval[0], "sun4d"))
-               sparc_cpu_model = sun4d;
-       if (!strcmp(&cputypval[0], "sun4e"))
-               sparc_cpu_model = sun4e;
-       if (!strcmp(&cputypval[0], "sun4u"))
-               sparc_cpu_model = sun4u;
-       if (!strncmp(&cputypval[0], "leon" , 4))
-               sparc_cpu_model = sparc_leon;
-
        printk("ARCH: ");
        switch(sparc_cpu_model) {
        case sun4m:
index 0e16056..89c2c29 100644 (file)
@@ -107,6 +107,11 @@ SECTIONS
                *(.sun4v_2insn_patch)
                __sun4v_2insn_patch_end = .;
        }
+       .leon_1insn_patch : {
+               __leon_1insn_patch = .;
+               *(.leon_1insn_patch)
+               __leon_1insn_patch_end = .;
+       }
        .swapper_tsb_phys_patch : {
                __swapper_tsb_phys_patch = .;
                *(.swapper_tsb_phys_patch)