aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2013-01-02 10:24:22 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2013-01-29 11:56:37 -0500
commitd329de3f2ada413c7cd16e1dc1d70d4abc7309e9 (patch)
treeae7880c26aa4bc2ac1ac5b3b983e992638e49f67 /arch/arm64/kernel
parent75e424620a4f8247e8877c224d0457efadf88201 (diff)
arm64: SMP: rework the SMP code to be enabling method agnostic
In order to introduce PSCI support, let the SMP code handle multiple enabling methods. This also allow CPUs to be booted using different methods (though this feels a bit weird...). In the process, move the spin-table code to its own file. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/Makefile2
-rw-r--r--arch/arm64/kernel/smp.c68
-rw-r--r--arch/arm64/kernel/smp_spin_table.c66
3 files changed, 113 insertions, 23 deletions
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index a1cace45e970..ac1b6823334c 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -14,7 +14,7 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
14arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ 14arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
15 sys_compat.o 15 sys_compat.o
16arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o 16arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
17arm64-obj-$(CONFIG_SMP) += smp.o 17arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o
18arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o 18arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
19arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o 19arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
20arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 20arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 538300f2273d..7776922945af 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -233,7 +233,27 @@ void __init smp_prepare_boot_cpu(void)
233} 233}
234 234
235static void (*smp_cross_call)(const struct cpumask *, unsigned int); 235static void (*smp_cross_call)(const struct cpumask *, unsigned int);
236static phys_addr_t cpu_release_addr[NR_CPUS]; 236
237static const struct smp_enable_ops *enable_ops[] __initconst = {
238 &smp_spin_table_ops,
239 NULL,
240};
241
242static const struct smp_enable_ops *smp_enable_ops[NR_CPUS];
243
244static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
245{
246 const struct smp_enable_ops *ops = enable_ops[0];
247
248 while (ops) {
249 if (!strcmp(name, ops->name))
250 return ops;
251
252 ops++;
253 }
254
255 return NULL;
256}
237 257
238/* 258/*
239 * Enumerate the possible CPU set from the device tree. 259 * Enumerate the possible CPU set from the device tree.
@@ -252,22 +272,22 @@ void __init smp_init_cpus(void)
252 * We currently support only the "spin-table" enable-method. 272 * We currently support only the "spin-table" enable-method.
253 */ 273 */
254 enable_method = of_get_property(dn, "enable-method", NULL); 274 enable_method = of_get_property(dn, "enable-method", NULL);
255 if (!enable_method || strcmp(enable_method, "spin-table")) { 275 if (!enable_method) {
256 pr_err("CPU %d: missing or invalid enable-method property: %s\n", 276 pr_err("CPU %d: missing enable-method property\n", cpu);
257 cpu, enable_method);
258 goto next; 277 goto next;
259 } 278 }
260 279
261 /* 280 smp_enable_ops[cpu] = smp_get_enable_ops(enable_method);
262 * Determine the address from which the CPU is polling. 281
263 */ 282 if (!smp_enable_ops[cpu]) {
264 if (of_property_read_u64(dn, "cpu-release-addr", 283 pr_err("CPU %d: invalid enable-method property: %s\n",
265 &cpu_release_addr[cpu])) { 284 cpu, enable_method);
266 pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
267 cpu);
268 goto next; 285 goto next;
269 } 286 }
270 287
288 if (smp_enable_ops[cpu]->init_cpu(dn, cpu))
289 goto next;
290
271 set_cpu_possible(cpu, true); 291 set_cpu_possible(cpu, true);
272next: 292next:
273 cpu++; 293 cpu++;
@@ -281,8 +301,7 @@ next:
281 301
282void __init smp_prepare_cpus(unsigned int max_cpus) 302void __init smp_prepare_cpus(unsigned int max_cpus)
283{ 303{
284 int cpu; 304 int cpu, err;
285 void **release_addr;
286 unsigned int ncores = num_possible_cpus(); 305 unsigned int ncores = num_possible_cpus();
287 306
288 /* 307 /*
@@ -291,30 +310,35 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
291 if (max_cpus > ncores) 310 if (max_cpus > ncores)
292 max_cpus = ncores; 311 max_cpus = ncores;
293 312
313 /* Don't bother if we're effectively UP */
314 if (max_cpus <= 1)
315 return;
316
294 /* 317 /*
295 * Initialise the present map (which describes the set of CPUs 318 * Initialise the present map (which describes the set of CPUs
296 * actually populated at the present time) and release the 319 * actually populated at the present time) and release the
297 * secondaries from the bootloader. 320 * secondaries from the bootloader.
321 *
322 * Make sure we online at most (max_cpus - 1) additional CPUs.
298 */ 323 */
324 max_cpus--;
299 for_each_possible_cpu(cpu) { 325 for_each_possible_cpu(cpu) {
300 if (max_cpus == 0) 326 if (max_cpus == 0)
301 break; 327 break;
302 328
303 if (!cpu_release_addr[cpu]) 329 if (cpu == smp_processor_id())
330 continue;
331
332 if (!smp_enable_ops[cpu])
304 continue; 333 continue;
305 334
306 release_addr = __va(cpu_release_addr[cpu]); 335 err = smp_enable_ops[cpu]->prepare_cpu(cpu);
307 release_addr[0] = (void *)__pa(secondary_holding_pen); 336 if (err)
308 __flush_dcache_area(release_addr, sizeof(release_addr[0])); 337 continue;
309 338
310 set_cpu_present(cpu, true); 339 set_cpu_present(cpu, true);
311 max_cpus--; 340 max_cpus--;
312 } 341 }
313
314 /*
315 * Send an event to wake up the secondaries.
316 */
317 sev();
318} 342}
319 343
320 344
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
new file mode 100644
index 000000000000..7c35fa682f76
--- /dev/null
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -0,0 +1,66 @@
1/*
2 * Spin Table SMP initialisation
3 *
4 * Copyright (C) 2013 ARM Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/init.h>
20#include <linux/of.h>
21#include <linux/smp.h>
22
23#include <asm/cacheflush.h>
24
25static phys_addr_t cpu_release_addr[NR_CPUS];
26
27static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu)
28{
29 /*
30 * Determine the address from which the CPU is polling.
31 */
32 if (of_property_read_u64(dn, "cpu-release-addr",
33 &cpu_release_addr[cpu])) {
34 pr_err("CPU %d: missing or invalid cpu-release-addr property\n",
35 cpu);
36
37 return -1;
38 }
39
40 return 0;
41}
42
43static int __init smp_spin_table_prepare_cpu(int cpu)
44{
45 void **release_addr;
46
47 if (!cpu_release_addr[cpu])
48 return -ENODEV;
49
50 release_addr = __va(cpu_release_addr[cpu]);
51 release_addr[0] = (void *)__pa(secondary_holding_pen);
52 __flush_dcache_area(release_addr, sizeof(release_addr[0]));
53
54 /*
55 * Send an event to wake up the secondary CPU.
56 */
57 sev();
58
59 return 0;
60}
61
62const struct smp_enable_ops smp_spin_table_ops __initconst = {
63 .name = "spin-table",
64 .init_cpu = smp_spin_table_init_cpu,
65 .prepare_cpu = smp_spin_table_prepare_cpu,
66};