aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/include/asm/smp.h10
-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
4 files changed, 123 insertions, 23 deletions
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 7e34295f78e3..b1f68c19d170 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -66,4 +66,14 @@ extern volatile unsigned long secondary_holding_pen_release;
66extern void arch_send_call_function_single_ipi(int cpu); 66extern void arch_send_call_function_single_ipi(int cpu);
67extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); 67extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
68 68
69struct device_node;
70
71struct smp_enable_ops {
72 const char *name;
73 int (*init_cpu)(struct device_node *, int);
74 int (*prepare_cpu)(int);
75};
76
77extern const struct smp_enable_ops smp_spin_table_ops;
78
69#endif /* ifndef __ASM_SMP_H */ 79#endif /* ifndef __ASM_SMP_H */
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};