diff options
Diffstat (limited to 'arch/arm/mach-vexpress/platsmp.c')
-rw-r--r-- | arch/arm/mach-vexpress/platsmp.c | 74 |
1 files changed, 26 insertions, 48 deletions
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index dfb591031d17..b1687b6abe63 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | 18 | ||
19 | #include <asm/cacheflush.h> | 19 | #include <asm/cacheflush.h> |
20 | #include <asm/localtimer.h> | ||
21 | #include <asm/smp_scu.h> | 20 | #include <asm/smp_scu.h> |
22 | #include <asm/unified.h> | 21 | #include <asm/unified.h> |
23 | 22 | ||
@@ -35,6 +34,19 @@ extern void vexpress_secondary_startup(void); | |||
35 | */ | 34 | */ |
36 | volatile int __cpuinitdata pen_release = -1; | 35 | volatile int __cpuinitdata pen_release = -1; |
37 | 36 | ||
37 | /* | ||
38 | * Write pen_release in a way that is guaranteed to be visible to all | ||
39 | * observers, irrespective of whether they're taking part in coherency | ||
40 | * or not. This is necessary for the hotplug code to work reliably. | ||
41 | */ | ||
42 | static void write_pen_release(int val) | ||
43 | { | ||
44 | pen_release = val; | ||
45 | smp_wmb(); | ||
46 | __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); | ||
47 | outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); | ||
48 | } | ||
49 | |||
38 | static void __iomem *scu_base_addr(void) | 50 | static void __iomem *scu_base_addr(void) |
39 | { | 51 | { |
40 | return MMIO_P2V(A9_MPCORE_SCU); | 52 | return MMIO_P2V(A9_MPCORE_SCU); |
@@ -44,8 +56,6 @@ static DEFINE_SPINLOCK(boot_lock); | |||
44 | 56 | ||
45 | void __cpuinit platform_secondary_init(unsigned int cpu) | 57 | void __cpuinit platform_secondary_init(unsigned int cpu) |
46 | { | 58 | { |
47 | trace_hardirqs_off(); | ||
48 | |||
49 | /* | 59 | /* |
50 | * if any interrupts are already enabled for the primary | 60 | * if any interrupts are already enabled for the primary |
51 | * core (e.g. timer irq), then they will not have been enabled | 61 | * core (e.g. timer irq), then they will not have been enabled |
@@ -57,8 +67,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) | |||
57 | * let the primary processor know we're out of the | 67 | * let the primary processor know we're out of the |
58 | * pen, then head off into the C entry point | 68 | * pen, then head off into the C entry point |
59 | */ | 69 | */ |
60 | pen_release = -1; | 70 | write_pen_release(-1); |
61 | smp_wmb(); | ||
62 | 71 | ||
63 | /* | 72 | /* |
64 | * Synchronise with the boot thread. | 73 | * Synchronise with the boot thread. |
@@ -83,16 +92,14 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
83 | * since we haven't sent them a soft interrupt, they shouldn't | 92 | * since we haven't sent them a soft interrupt, they shouldn't |
84 | * be there. | 93 | * be there. |
85 | */ | 94 | */ |
86 | pen_release = cpu; | 95 | write_pen_release(cpu); |
87 | __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); | ||
88 | outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); | ||
89 | 96 | ||
90 | /* | 97 | /* |
91 | * Send the secondary CPU a soft interrupt, thereby causing | 98 | * Send the secondary CPU a soft interrupt, thereby causing |
92 | * the boot monitor to read the system wide flags register, | 99 | * the boot monitor to read the system wide flags register, |
93 | * and branch to the address found there. | 100 | * and branch to the address found there. |
94 | */ | 101 | */ |
95 | smp_cross_call(cpumask_of(cpu)); | 102 | smp_cross_call(cpumask_of(cpu), 1); |
96 | 103 | ||
97 | timeout = jiffies + (1 * HZ); | 104 | timeout = jiffies + (1 * HZ); |
98 | while (time_before(jiffies, timeout)) { | 105 | while (time_before(jiffies, timeout)) { |
@@ -124,13 +131,6 @@ void __init smp_init_cpus(void) | |||
124 | ncores = scu_base ? scu_get_core_count(scu_base) : 1; | 131 | ncores = scu_base ? scu_get_core_count(scu_base) : 1; |
125 | 132 | ||
126 | /* sanity check */ | 133 | /* sanity check */ |
127 | if (ncores == 0) { | ||
128 | printk(KERN_ERR | ||
129 | "vexpress: strange CM count of 0? Default to 1\n"); | ||
130 | |||
131 | ncores = 1; | ||
132 | } | ||
133 | |||
134 | if (ncores > NR_CPUS) { | 134 | if (ncores > NR_CPUS) { |
135 | printk(KERN_WARNING | 135 | printk(KERN_WARNING |
136 | "vexpress: no. of cores (%d) greater than configured " | 136 | "vexpress: no. of cores (%d) greater than configured " |
@@ -143,20 +143,10 @@ void __init smp_init_cpus(void) | |||
143 | set_cpu_possible(i, true); | 143 | set_cpu_possible(i, true); |
144 | } | 144 | } |
145 | 145 | ||
146 | void __init smp_prepare_cpus(unsigned int max_cpus) | 146 | void __init platform_smp_prepare_cpus(unsigned int max_cpus) |
147 | { | 147 | { |
148 | unsigned int ncores = num_possible_cpus(); | ||
149 | unsigned int cpu = smp_processor_id(); | ||
150 | int i; | 148 | int i; |
151 | 149 | ||
152 | smp_store_cpu_info(cpu); | ||
153 | |||
154 | /* | ||
155 | * are we trying to boot more cores than exist? | ||
156 | */ | ||
157 | if (max_cpus > ncores) | ||
158 | max_cpus = ncores; | ||
159 | |||
160 | /* | 150 | /* |
161 | * Initialise the present map, which describes the set of CPUs | 151 | * Initialise the present map, which describes the set of CPUs |
162 | * actually populated at the present time. | 152 | * actually populated at the present time. |
@@ -164,27 +154,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
164 | for (i = 0; i < max_cpus; i++) | 154 | for (i = 0; i < max_cpus; i++) |
165 | set_cpu_present(i, true); | 155 | set_cpu_present(i, true); |
166 | 156 | ||
157 | scu_enable(scu_base_addr()); | ||
158 | |||
167 | /* | 159 | /* |
168 | * Initialise the SCU if there are more than one CPU and let | 160 | * Write the address of secondary startup into the |
169 | * them know where to start. | 161 | * system-wide flags register. The boot monitor waits |
162 | * until it receives a soft interrupt, and then the | ||
163 | * secondary CPU branches to this address. | ||
170 | */ | 164 | */ |
171 | if (max_cpus > 1) { | 165 | writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); |
172 | /* | 166 | writel(BSYM(virt_to_phys(vexpress_secondary_startup)), |
173 | * Enable the local timer or broadcast device for the | 167 | MMIO_P2V(V2M_SYS_FLAGSSET)); |
174 | * boot CPU, but only if we have more than one CPU. | ||
175 | */ | ||
176 | percpu_timer_setup(); | ||
177 | |||
178 | scu_enable(scu_base_addr()); | ||
179 | |||
180 | /* | ||
181 | * Write the address of secondary startup into the | ||
182 | * system-wide flags register. The boot monitor waits | ||
183 | * until it receives a soft interrupt, and then the | ||
184 | * secondary CPU branches to this address. | ||
185 | */ | ||
186 | writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); | ||
187 | writel(BSYM(virt_to_phys(vexpress_secondary_startup)), | ||
188 | MMIO_P2V(V2M_SYS_FLAGSSET)); | ||
189 | } | ||
190 | } | 168 | } |