diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-09-04 10:47:48 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-10-04 20:23:36 +0100 |
commit | f00ec48fadf5e37e7889f14cff900aa70d18b644 (patch) | |
tree | 421cbce97167a78532aa825624f380caade3c0d2 /arch/arm/kernel | |
parent | 067173526c3bbc2eaeefcf6b7b2a9d998b9e8042 (diff) | |
download | talos-obmc-linux-f00ec48fadf5e37e7889f14cff900aa70d18b644.tar.gz talos-obmc-linux-f00ec48fadf5e37e7889f14cff900aa70d18b644.zip |
ARM: Allow SMP kernels to boot on UP systems
UP systems do not implement all the instructions that SMP systems have,
so in order to boot a SMP kernel on a UP system, we need to rewrite
parts of the kernel.
Do this using an 'alternatives' scheme, where the kernel code and data
is modified prior to initialization to replace the SMP instructions,
thereby rendering the problematical code ineffectual. We use the linker
to generate a list of 32-bit word locations and their replacement values,
and run through these replacements when we detect a UP system.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 11 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 50 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 11 |
4 files changed, 69 insertions, 7 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index bb8e93a76407..c09e3573c5de 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -46,7 +46,8 @@ * this macro assumes that irqstat (r6) and base (r5) are * preserved from get_irqnr_and_base above */ - test_for_ipi r0, r6, r5, lr + ALT_SMP(test_for_ipi r0, r6, r5, lr) + ALT_UP_B(9997f) movne r0, sp adrne lr, BSYM(1b) bne do_IPI @@ -57,6 +58,7 @@ adrne lr, BSYM(1b) bne do_local_timer #endif +9997: #endif .endm @@ -965,11 +967,8 @@ kuser_cmpxchg_fixup: beq 1b rsbs r0, r3, #0 /* beware -- each __kuser slot must be 8 instructions max */ -#ifdef CONFIG_SMP - b __kuser_memory_barrier -#else - usr_ret lr -#endif + ALT_SMP(b __kuser_memory_barrier) + ALT_UP(usr_ret lr) #endif diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index eb62bf947212..b44d21e1e344 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -86,6 +86,9 @@ ENTRY(stext) movs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error 'a' bl __vet_atags +#ifdef CONFIG_SMP_ON_UP + bl __fixup_smp +#endif bl __create_page_tables /* @@ -333,4 +336,51 @@ __create_page_tables: ENDPROC(__create_page_tables) .ltorg +#ifdef CONFIG_SMP_ON_UP +__fixup_smp: + mov r7, #0x00070000 + orr r6, r7, #0xff000000 @ mask 0xff070000 + orr r7, r7, #0x41000000 @ val 0x41070000 + and r0, r9, r6 + teq r0, r7 @ ARM CPU and ARMv6/v7? + bne __fixup_smp_on_up @ no, assume UP + + orr r6, r6, #0x0000ff00 + orr r6, r6, #0x000000f0 @ mask 0xff07fff0 + orr r7, r7, #0x0000b000 + orr r7, r7, #0x00000020 @ val 0x4107b020 + and r0, r9, r6 + teq r0, r7 @ ARM 11MPCore? + moveq pc, lr @ yes, assume SMP + + mrc p15, 0, r0, c0, c0, 5 @ read MPIDR + tst r0, #1 << 31 + movne pc, lr @ bit 31 => SMP + +__fixup_smp_on_up: + adr r0, 1f + ldmia r0, {r3, r6, r7} + sub r3, r0, r3 + add r6, r6, r3 + add r7, r7, r3 +2: cmp r6, r7 + ldmia r6!, {r0, r4} + strlo r4, [r0, r3] + blo 2b + mov pc, lr +ENDPROC(__fixup_smp) + +1: .word . + .word __smpalt_begin + .word __smpalt_end + + .pushsection .data + .globl smp_on_up +smp_on_up: + ALT_SMP(.long 1) + ALT_UP(.long 0) + .popsection + +#endif + #include "head-common.S" diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index d5231ae7355a..5a82c39ca85e 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -36,6 +36,7 @@ #include <asm/procinfo.h> #include <asm/sections.h> #include <asm/setup.h> +#include <asm/smp_plat.h> #include <asm/mach-types.h> #include <asm/cacheflush.h> #include <asm/cachetype.h> @@ -825,7 +826,8 @@ void __init setup_arch(char **cmdline_p) request_standard_resources(&meminfo, mdesc); #ifdef CONFIG_SMP - smp_init_cpus(); + if (is_smp()) + smp_init_cpus(); #endif reserve_crashkernel(); diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index b16c07914b55..fd5750b8ac84 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -40,6 +40,11 @@ SECTIONS __tagtable_begin = .; *(.taglist.init) __tagtable_end = .; +#ifdef CONFIG_SMP_ON_UP + __smpalt_begin = .; + *(.alt.smp.init) + __smpalt_end = .; +#endif INIT_SETUP(16) @@ -237,6 +242,12 @@ SECTIONS /* Default discards */ DISCARDS + +#ifndef CONFIG_SMP_ON_UP + /DISCARD/ : { + *(.alt.smp.init) + } +#endif } /* |