diff options
-rw-r--r-- | arch/powerpc/kernel/head_fsl_booke.S | 70 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/85xx/smp.c | 104 |
3 files changed, 176 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 2b5760580254..9a4639c459e6 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -92,6 +92,7 @@ _ENTRY(_start); | |||
92 | * if needed | 92 | * if needed |
93 | */ | 93 | */ |
94 | 94 | ||
95 | _ENTRY(__early_start) | ||
95 | /* 1. Find the index of the entry we're executing in */ | 96 | /* 1. Find the index of the entry we're executing in */ |
96 | bl invstr /* Find our address */ | 97 | bl invstr /* Find our address */ |
97 | invstr: mflr r6 /* Make it accessible */ | 98 | invstr: mflr r6 /* Make it accessible */ |
@@ -348,6 +349,15 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
348 | mtspr SPRN_DBSR,r2 | 349 | mtspr SPRN_DBSR,r2 |
349 | #endif | 350 | #endif |
350 | 351 | ||
352 | #ifdef CONFIG_SMP | ||
353 | /* Check to see if we're the second processor, and jump | ||
354 | * to the secondary_start code if so | ||
355 | */ | ||
356 | mfspr r24,SPRN_PIR | ||
357 | cmpwi r24,0 | ||
358 | bne __secondary_start | ||
359 | #endif | ||
360 | |||
351 | /* | 361 | /* |
352 | * This is where the main kernel code starts. | 362 | * This is where the main kernel code starts. |
353 | */ | 363 | */ |
@@ -740,6 +750,9 @@ finish_tlb_load: | |||
740 | #else | 750 | #else |
741 | rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ | 751 | rlwimi r12, r11, 26, 27, 31 /* extract WIMGE from pte */ |
742 | #endif | 752 | #endif |
753 | #ifdef CONFIG_SMP | ||
754 | ori r12, r12, MAS2_M | ||
755 | #endif | ||
743 | mtspr SPRN_MAS2, r12 | 756 | mtspr SPRN_MAS2, r12 |
744 | 757 | ||
745 | li r10, (_PAGE_HWEXEC | _PAGE_PRESENT) | 758 | li r10, (_PAGE_HWEXEC | _PAGE_PRESENT) |
@@ -1042,6 +1055,63 @@ _GLOBAL(flush_dcache_L1) | |||
1042 | 1055 | ||
1043 | blr | 1056 | blr |
1044 | 1057 | ||
1058 | #ifdef CONFIG_SMP | ||
1059 | /* When we get here, r24 needs to hold the CPU # */ | ||
1060 | .globl __secondary_start | ||
1061 | __secondary_start: | ||
1062 | lis r3,__secondary_hold_acknowledge@h | ||
1063 | ori r3,r3,__secondary_hold_acknowledge@l | ||
1064 | stw r24,0(r3) | ||
1065 | |||
1066 | li r3,0 | ||
1067 | mr r4,r24 /* Why? */ | ||
1068 | bl call_setup_cpu | ||
1069 | |||
1070 | lis r3,tlbcam_index@ha | ||
1071 | lwz r3,tlbcam_index@l(r3) | ||
1072 | mtctr r3 | ||
1073 | li r26,0 /* r26 safe? */ | ||
1074 | |||
1075 | /* Load each CAM entry */ | ||
1076 | 1: mr r3,r26 | ||
1077 | bl loadcam_entry | ||
1078 | addi r26,r26,1 | ||
1079 | bdnz 1b | ||
1080 | |||
1081 | /* get current_thread_info and current */ | ||
1082 | lis r1,secondary_ti@ha | ||
1083 | lwz r1,secondary_ti@l(r1) | ||
1084 | lwz r2,TI_TASK(r1) | ||
1085 | |||
1086 | /* stack */ | ||
1087 | addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD | ||
1088 | li r0,0 | ||
1089 | stw r0,0(r1) | ||
1090 | |||
1091 | /* ptr to current thread */ | ||
1092 | addi r4,r2,THREAD /* address of our thread_struct */ | ||
1093 | mtspr SPRN_SPRG3,r4 | ||
1094 | |||
1095 | /* Setup the defaults for TLB entries */ | ||
1096 | li r4,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l | ||
1097 | mtspr SPRN_MAS4,r4 | ||
1098 | |||
1099 | /* Jump to start_secondary */ | ||
1100 | lis r4,MSR_KERNEL@h | ||
1101 | ori r4,r4,MSR_KERNEL@l | ||
1102 | lis r3,start_secondary@h | ||
1103 | ori r3,r3,start_secondary@l | ||
1104 | mtspr SPRN_SRR0,r3 | ||
1105 | mtspr SPRN_SRR1,r4 | ||
1106 | sync | ||
1107 | rfi | ||
1108 | sync | ||
1109 | |||
1110 | .globl __secondary_hold_acknowledge | ||
1111 | __secondary_hold_acknowledge: | ||
1112 | .long -1 | ||
1113 | #endif | ||
1114 | |||
1045 | /* | 1115 | /* |
1046 | * We put a few things here that have to be page-aligned. This stuff | 1116 | * We put a few things here that have to be page-aligned. This stuff |
1047 | * goes at the beginning of the data segment, which is page-aligned. | 1117 | * goes at the beginning of the data segment, which is page-aligned. |
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index cb3054e1001d..f0798c09980f 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile | |||
@@ -1,6 +1,8 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the PowerPC 85xx linux kernel. | 2 | # Makefile for the PowerPC 85xx linux kernel. |
3 | # | 3 | # |
4 | obj-$(CONFIG_SMP) += smp.o | ||
5 | |||
4 | obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o | 6 | obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o |
5 | obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o | 7 | obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o |
6 | obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o | 8 | obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o |
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c new file mode 100644 index 000000000000..d652c713f496 --- /dev/null +++ b/arch/powerpc/platforms/85xx/smp.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Author: Andy Fleming <afleming@freescale.com> | ||
3 | * Kumar Gala <galak@kernel.crashing.org> | ||
4 | * | ||
5 | * Copyright 2006-2008 Freescale Semiconductor Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/of.h> | ||
18 | |||
19 | #include <asm/machdep.h> | ||
20 | #include <asm/pgtable.h> | ||
21 | #include <asm/page.h> | ||
22 | #include <asm/mpic.h> | ||
23 | #include <asm/cacheflush.h> | ||
24 | |||
25 | #include <sysdev/fsl_soc.h> | ||
26 | |||
27 | extern volatile unsigned long __secondary_hold_acknowledge; | ||
28 | extern void __early_start(void); | ||
29 | |||
30 | #define BOOT_ENTRY_ADDR_UPPER 0 | ||
31 | #define BOOT_ENTRY_ADDR_LOWER 1 | ||
32 | #define BOOT_ENTRY_R3_UPPER 2 | ||
33 | #define BOOT_ENTRY_R3_LOWER 3 | ||
34 | #define BOOT_ENTRY_RESV 4 | ||
35 | #define BOOT_ENTRY_PIR 5 | ||
36 | #define BOOT_ENTRY_R6_UPPER 6 | ||
37 | #define BOOT_ENTRY_R6_LOWER 7 | ||
38 | #define NUM_BOOT_ENTRY 8 | ||
39 | #define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32)) | ||
40 | |||
41 | static void __init | ||
42 | smp_85xx_kick_cpu(int nr) | ||
43 | { | ||
44 | unsigned long flags; | ||
45 | const u64 *cpu_rel_addr; | ||
46 | __iomem u32 *bptr_vaddr; | ||
47 | struct device_node *np; | ||
48 | int n = 0; | ||
49 | |||
50 | WARN_ON (nr < 0 || nr >= NR_CPUS); | ||
51 | |||
52 | pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr); | ||
53 | |||
54 | local_irq_save(flags); | ||
55 | |||
56 | np = of_get_cpu_node(nr, NULL); | ||
57 | cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL); | ||
58 | |||
59 | if (cpu_rel_addr == NULL) { | ||
60 | printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr); | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | /* Map the spin table */ | ||
65 | bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY); | ||
66 | |||
67 | out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); | ||
68 | out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); | ||
69 | |||
70 | /* Wait a bit for the CPU to ack. */ | ||
71 | while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) | ||
72 | mdelay(1); | ||
73 | |||
74 | iounmap(bptr_vaddr); | ||
75 | |||
76 | local_irq_restore(flags); | ||
77 | |||
78 | pr_debug("waited %d msecs for CPU #%d.\n", n, nr); | ||
79 | } | ||
80 | |||
81 | static void __init | ||
82 | smp_85xx_setup_cpu(int cpu_nr) | ||
83 | { | ||
84 | mpic_setup_this_cpu(); | ||
85 | |||
86 | /* Clear any pending timer interrupts */ | ||
87 | mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); | ||
88 | |||
89 | /* Enable decrementer interrupt */ | ||
90 | mtspr(SPRN_TCR, TCR_DIE); | ||
91 | } | ||
92 | |||
93 | struct smp_ops_t smp_85xx_ops = { | ||
94 | .message_pass = smp_mpic_message_pass, | ||
95 | .probe = smp_mpic_probe, | ||
96 | .kick_cpu = smp_85xx_kick_cpu, | ||
97 | .setup_cpu = smp_85xx_setup_cpu, | ||
98 | }; | ||
99 | |||
100 | void __init | ||
101 | mpc85xx_smp_init(void) | ||
102 | { | ||
103 | smp_ops = &smp_85xx_ops; | ||
104 | } | ||