diff options
author | Sam Ravnborg <sam@ravnborg.org> | 2012-05-25 17:20:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-28 02:52:43 -0400 |
commit | 5b8b93c4ab17a250a35e6db1cce094bf599a21c6 (patch) | |
tree | 9ce54b39fe8193d245a4511f23d02d4b037d0245 /arch | |
parent | 4efb55e6916628fde549b0ef1c2830593ccf19c4 (diff) |
sparc32: add support for run-time patching of leon/sun single instructions
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/include/asm/asmmacro.h | 22 | ||||
-rw-r--r-- | arch/sparc/include/asm/sections.h | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/setup_32.c | 58 | ||||
-rw-r--r-- | arch/sparc/kernel/vmlinux.lds.S | 5 |
4 files changed, 72 insertions, 16 deletions
diff --git a/arch/sparc/include/asm/asmmacro.h b/arch/sparc/include/asm/asmmacro.h index 02a172fb193a..a0e28ef02558 100644 --- a/arch/sparc/include/asm/asmmacro.h +++ b/arch/sparc/include/asm/asmmacro.h | |||
@@ -20,4 +20,26 @@ | |||
20 | /* All traps low-level code here must end with this macro. */ | 20 | /* All traps low-level code here must end with this macro. */ |
21 | #define RESTORE_ALL b ret_trap_entry; clr %l6; | 21 | #define RESTORE_ALL b ret_trap_entry; clr %l6; |
22 | 22 | ||
23 | /* Support for run-time patching of single instructions. | ||
24 | * This is used to handle the differences in the ASI for | ||
25 | * MMUREGS for LEON and SUN. | ||
26 | * | ||
27 | * Sample: | ||
28 | * LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %o0 | ||
29 | * SUN_PI_(lda [%g0] ASI_M_MMUREGS, %o0 | ||
30 | * PI == Patch Instruction | ||
31 | * | ||
32 | * For LEON we will use the first variant, | ||
33 | * and for all other we will use the SUN variant. | ||
34 | * The order is important. | ||
35 | */ | ||
36 | #define LEON_PI(...) \ | ||
37 | 662: __VA_ARGS__ | ||
38 | |||
39 | #define SUN_PI_(...) \ | ||
40 | .section .leon_1insn_patch, "ax"; \ | ||
41 | .word 662b; \ | ||
42 | __VA_ARGS__; \ | ||
43 | .previous | ||
44 | |||
23 | #endif /* !(_SPARC_ASMMACRO_H) */ | 45 | #endif /* !(_SPARC_ASMMACRO_H) */ |
diff --git a/arch/sparc/include/asm/sections.h b/arch/sparc/include/asm/sections.h index 0b0553bbd8a0..f300d1a9b2b6 100644 --- a/arch/sparc/include/asm/sections.h +++ b/arch/sparc/include/asm/sections.h | |||
@@ -7,4 +7,7 @@ | |||
7 | /* sparc entry point */ | 7 | /* sparc entry point */ |
8 | extern char _start[]; | 8 | extern char _start[]; |
9 | 9 | ||
10 | extern char __leon_1insn_patch[]; | ||
11 | extern char __leon_1insn_patch_end[]; | ||
12 | |||
10 | #endif | 13 | #endif |
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index 68dd63dea36f..efe3e64bba38 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/cpudata.h> | 46 | #include <asm/cpudata.h> |
47 | #include <asm/setup.h> | 47 | #include <asm/setup.h> |
48 | #include <asm/cacheflush.h> | 48 | #include <asm/cacheflush.h> |
49 | #include <asm/sections.h> | ||
49 | 50 | ||
50 | #include "kernel.h" | 51 | #include "kernel.h" |
51 | 52 | ||
@@ -238,11 +239,34 @@ static void __init per_cpu_patch(void) | |||
238 | } | 239 | } |
239 | } | 240 | } |
240 | 241 | ||
242 | struct leon_1insn_patch_entry { | ||
243 | unsigned int addr; | ||
244 | unsigned int insn; | ||
245 | }; | ||
246 | |||
241 | enum sparc_cpu sparc_cpu_model; | 247 | enum sparc_cpu sparc_cpu_model; |
242 | EXPORT_SYMBOL(sparc_cpu_model); | 248 | EXPORT_SYMBOL(sparc_cpu_model); |
243 | 249 | ||
244 | struct tt_entry *sparc_ttable; | 250 | static __init void leon_patch(void) |
251 | { | ||
252 | struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch; | ||
253 | struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end; | ||
254 | |||
255 | /* Default instruction is leon - no patching */ | ||
256 | if (sparc_cpu_model == sparc_leon) | ||
257 | return; | ||
258 | |||
259 | while (start < end) { | ||
260 | unsigned long addr = start->addr; | ||
261 | |||
262 | *(unsigned int *)(addr) = start->insn; | ||
263 | flushi(addr); | ||
264 | |||
265 | start++; | ||
266 | } | ||
267 | } | ||
245 | 268 | ||
269 | struct tt_entry *sparc_ttable; | ||
246 | struct pt_regs fake_swapper_regs; | 270 | struct pt_regs fake_swapper_regs; |
247 | 271 | ||
248 | /* Called from head_32.S - before we have setup anything | 272 | /* Called from head_32.S - before we have setup anything |
@@ -251,6 +275,23 @@ struct pt_regs fake_swapper_regs; | |||
251 | void __init sparc32_start_kernel(struct linux_romvec *rp) | 275 | void __init sparc32_start_kernel(struct linux_romvec *rp) |
252 | { | 276 | { |
253 | prom_init(rp); | 277 | prom_init(rp); |
278 | |||
279 | /* Set sparc_cpu_model */ | ||
280 | sparc_cpu_model = sun_unknown; | ||
281 | if (!strcmp(&cputypval[0], "sun4m")) | ||
282 | sparc_cpu_model = sun4m; | ||
283 | if (!strcmp(&cputypval[0], "sun4s")) | ||
284 | sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */ | ||
285 | if (!strcmp(&cputypval[0], "sun4d")) | ||
286 | sparc_cpu_model = sun4d; | ||
287 | if (!strcmp(&cputypval[0], "sun4e")) | ||
288 | sparc_cpu_model = sun4e; | ||
289 | if (!strcmp(&cputypval[0], "sun4u")) | ||
290 | sparc_cpu_model = sun4u; | ||
291 | if (!strncmp(&cputypval[0], "leon" , 4)) | ||
292 | sparc_cpu_model = sparc_leon; | ||
293 | |||
294 | leon_patch(); | ||
254 | start_kernel(); | 295 | start_kernel(); |
255 | } | 296 | } |
256 | 297 | ||
@@ -270,21 +311,6 @@ void __init setup_arch(char **cmdline_p) | |||
270 | 311 | ||
271 | register_console(&prom_early_console); | 312 | register_console(&prom_early_console); |
272 | 313 | ||
273 | /* Set sparc_cpu_model */ | ||
274 | sparc_cpu_model = sun_unknown; | ||
275 | if (!strcmp(&cputypval[0], "sun4m")) | ||
276 | sparc_cpu_model = sun4m; | ||
277 | if (!strcmp(&cputypval[0], "sun4s")) | ||
278 | sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */ | ||
279 | if (!strcmp(&cputypval[0], "sun4d")) | ||
280 | sparc_cpu_model = sun4d; | ||
281 | if (!strcmp(&cputypval[0], "sun4e")) | ||
282 | sparc_cpu_model = sun4e; | ||
283 | if (!strcmp(&cputypval[0], "sun4u")) | ||
284 | sparc_cpu_model = sun4u; | ||
285 | if (!strncmp(&cputypval[0], "leon" , 4)) | ||
286 | sparc_cpu_model = sparc_leon; | ||
287 | |||
288 | printk("ARCH: "); | 314 | printk("ARCH: "); |
289 | switch(sparc_cpu_model) { | 315 | switch(sparc_cpu_model) { |
290 | case sun4m: | 316 | case sun4m: |
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 0e1605697b49..89c2c29f154b 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S | |||
@@ -107,6 +107,11 @@ SECTIONS | |||
107 | *(.sun4v_2insn_patch) | 107 | *(.sun4v_2insn_patch) |
108 | __sun4v_2insn_patch_end = .; | 108 | __sun4v_2insn_patch_end = .; |
109 | } | 109 | } |
110 | .leon_1insn_patch : { | ||
111 | __leon_1insn_patch = .; | ||
112 | *(.leon_1insn_patch) | ||
113 | __leon_1insn_patch_end = .; | ||
114 | } | ||
110 | .swapper_tsb_phys_patch : { | 115 | .swapper_tsb_phys_patch : { |
111 | __swapper_tsb_phys_patch = .; | 116 | __swapper_tsb_phys_patch = .; |
112 | *(.swapper_tsb_phys_patch) | 117 | *(.swapper_tsb_phys_patch) |