aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze/kernel/head.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/microblaze/kernel/head.S')
-rw-r--r--arch/microblaze/kernel/head.S165
1 files changed, 127 insertions, 38 deletions
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 14b276406153..eb889ec53a1a 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/linkage.h>
+#include <asm/entry.h>
#include <asm/thread_info.h>
#include <asm/page.h>
#include <linux/of_fdt.h> /* for OF_DT_HEADER */
@@ -38,6 +39,7 @@
#include <asm/setup.h> /* COMMAND_LINE_SIZE */
#include <asm/mmu.h>
#include <asm/processor.h>
+#include <asm/asm-offsets.h>
.section .data
.global empty_zero_page
@@ -47,7 +49,11 @@ empty_zero_page:
.global swapper_pg_dir
swapper_pg_dir:
.space PAGE_SIZE
-
+#ifdef CONFIG_SMP
+temp_boot_stack:
+ .space 1024
+#define CURRENT_SAVE CURRENT_SAVE_ADDR
+#endif /* CONFIG_SMP */
#endif /* CONFIG_MMU */
.section .rodata
@@ -79,6 +85,13 @@ real_start:
msrclr r8, 0 /* clear nothing - just read msr for test */
cmpu r8, r8, r1 /* r1 must contain msr reg content */
+#ifdef CONFIG_SMP
+ /* skip FDT copy if secondary */
+ mfs r11, rpvr0
+ andi r11, r11, 0xFF
+ bnei r11, _setup_initial_mmu
+#endif /* CONFIG_SMP */
+
/* r7 may point to an FDT, or there may be one linked in.
if it's in r7, we've got to save it away ASAP.
We ensure r7 points to a valid FDT, just in case the bootloader
@@ -147,6 +160,7 @@ _copy_bram:
#endif
/* We have to turn on the MMU right away. */
+_setup_initial_mmu:
/*
* Set up the initial MMU state so we can do the first level of
* kernel initialization. This maps the first 16 MBytes of memory 1:1
@@ -178,50 +192,51 @@ _invalidate:
tophys(r4,r3) /* Load the kernel physical address */
/* start to do TLB calculation */
- addik r12, r0, _end
+ addik r12, r0, _end_tlb_mapping
rsub r12, r3, r12
- addik r12, r12, CONFIG_LOWMEM_SIZE >> PTE_SHIFT /* that's the pad */
or r9, r0, r0 /* TLB0 = 0 */
or r10, r0, r0 /* TLB1 = 0 */
- addik r11, r12, -0x1000000
- bgei r11, GT16 /* size is greater than 16MB */
- addik r11, r12, -0x0800000
- bgei r11, GT8 /* size is greater than 8MB */
- addik r11, r12, -0x0400000
- bgei r11, GT4 /* size is greater than 4MB */
- /* size is less than 4MB */
- addik r11, r12, -0x0200000
- bgei r11, GT2 /* size is greater than 2MB */
- addik r9, r0, 0x0100000 /* TLB0 must be 1MB */
- addik r11, r12, -0x0100000
- bgei r11, GT1 /* size is greater than 1MB */
- /* TLB1 is 0 which is setup above */
- bri tlb_end
-GT4: /* r11 contains the rest - will be either 1 or 4 */
- ori r9, r0, 0x400000 /* TLB0 is 4MB */
- bri TLB1
-GT16: /* TLB0 is 16MB */
+ /*
+ * Linux is 4MB aligned that's why we can just check certain sizes.
+ * Add 12MB, 16MB and 8MB on the top of list because that's normal
+ * sizes which are often used.
+ */
+ addik r11, r12, -0xc00000 /* 12 MB */
+ beqi r11, GT12
+ addik r11, r12, -0x1000000 /* 16 MB */
+ beqi r11, GT16
+ addik r11, r12, -0x800000 /* 8 MB */
+ beqi r11, GT8
+ addik r11, r12, -0x2000000 /* 32 MB */
+ beqi r11, GT32
+ addik r11, r12, -0x1800000 /* 24 MB */
+ beqi r11, GT24
+ addik r11, r12, -0x1400000 /* 20 MB */
+ beqi r11, GT20
+ addik r11, r12, -0x400000 /* 4 MB */
+ beqi r11, GT4
+ /* if this page doesn't detect it use 32MB mapping */
+GT32:
addik r9, r0, 0x1000000 /* means TLB0 is 16MB */
-TLB1:
- /* must be used r2 because of subtract if failed */
- addik r2, r11, -0x0400000
- bgei r2, GT20 /* size is greater than 16MB */
- /* size is >16MB and <20MB */
- addik r11, r11, -0x0100000
- bgei r11, GT17 /* size is greater than 17MB */
- /* kernel is >16MB and < 17MB */
-GT1:
- addik r10, r0, 0x0100000 /* means TLB1 is 1MB */
- bri tlb_end
-GT2: /* TLB0 is 0 and TLB1 will be 4MB */
-GT17: /* TLB1 is 4MB - kernel size <20MB */
- addik r10, r0, 0x0400000 /* means TLB1 is 4MB */
- bri tlb_end
-GT8: /* TLB0 is still zero that's why I can use only TLB1 */
-GT20: /* TLB1 is 16MB - kernel size >20MB */
+GT16:
addik r10, r0, 0x1000000 /* means TLB1 is 16MB */
+ bri tlb_end
+GT24:
+ addik r9, r0, 0x1000000 /* means TLB0 is 16MB */
+GT8:
+ addik r10, r0, 0x800000 /* means TLB1 is 8MB */
+ bri tlb_end
+GT20:
+ addik r9, r0, 0x1000000 /* means TLB0 is 16MB */
+GT4:
+ addik r10, r0, 0x400000 /* means TLB1 is 4MB */
+ bri tlb_end
+GT12:
+ addik r9, r0, 0x800000 /* means TLB0 is 8MB */
+ addik r10, r0, 0x400000 /* means TLB1 is 4MB */
+ /* NOTE: No need to just to tlb_end here */
tlb_end:
/*
@@ -322,6 +337,18 @@ jump_over2:
*/
turn_on_mmu:
ori r15,r0,start_here
+#ifdef CONFIG_SMP
+ /*
+ * Read PVR and mask off all but CPU id bits to use to select
+ * boot sequence
+ */
+ mfs r4, rpvr0
+ andi r4, r4, 0xFF
+
+ beqi r4, finish
+ ori r15, r0, start_secondary_cpu
+finish:
+#endif /* CONFIG_SMP */
ori r4,r0,MSR_KERNEL_VMS
mts rmsr,r4
nop
@@ -340,6 +367,10 @@ start_here:
/* Initialize r31 with current task address */
addik r31, r0, init_task
+#ifdef CONFIG_MMU
+ /* save current for CPU 0 */
+ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
+#endif
addik r11, r0, machine_early_init
brald r15, r11
@@ -384,3 +415,61 @@ kernel_load_context:
rted r17, 0 /* enable MMU and jump to start_kernel */
nop
#endif /* CONFIG_MMU */
+
+#ifdef CONFIG_SMP
+/* Entry point for secondary processors */
+start_secondary_cpu:
+
+ /* Initialize small data anchors */
+ addik r13, r0, _KERNEL_SDA_BASE_
+ addik r2, r0, _KERNEL_SDA2_BASE_
+
+ /* Initialize stack pointer */
+ addik r1, r0, temp_boot_stack + 1024 - 4
+
+ /*
+ * Initialize the exception table.
+ */
+ addik r11, r0, secondary_machine_init
+ brald r15, r11
+ nop
+
+ lwi r1, r0, secondary_ti
+
+ /* Initialize r31 with current task address */
+ lwi CURRENT_TASK, r1, TI_TASK
+ /* save current for secondary CPU */
+ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE);
+
+ /* Initialize stack pointer */
+ addi r1, r1, THREAD_SIZE - 4
+ swi r0, r1, 0
+
+ /* Initialize MMU */
+ ori r11, r0, 0x10000000
+ mts rzpr, r11
+
+ ori r15, r0, TOPHYS(kernel_load_context_secondary)
+ ori r4, r0, MSR_KERNEL
+ mts rmsr, r4
+ nop
+ bri 4
+ rted r15, 0
+ nop
+
+ /* Load up the kernel context */
+kernel_load_context_secondary:
+ # Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
+ ori r5, r0, MICROBLAZE_LMB_TLB_ID
+ mts rtlbx, r5
+ nop
+ mts rtlbhi, r0
+ nop
+ addi r15, r0, machine_halt
+ ori r17, r0, start_secondary
+ ori r4, r0, MSR_KERNEL_VMS
+ mts rmsr, r4
+ nop
+ rted r17, 0 /* enable MMU and jump to start_kernel */
+ nop
+#endif /* CONFIG_SMP */