aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2011-09-08 04:06:10 -0400
committerArnd Bergmann <arnd@arndb.de>2012-09-13 07:49:33 -0400
commitabcee5fb0dfbb248d883a2f6bdb4820abe3ac524 (patch)
tree6a804ae4be161aa238ee4c433d6ea90a5d66fa72
parent4cbe5a555fa58a79b6ecbb6c531b8bab0650778d (diff)
ARM: SoC: add per-platform SMP operations
This adds a 'struct smp_operations' to abstract the CPU initialization and hot plugging functions on SMP systems, which otherwise conflict in a multiplatform kernel. This also helps shmobile and potentially others that have more than one method to do these. To allow the kernel to continue building, the platform hooks are defined as weak symbols which are overrided by the platform code. Once all platforms are converted, the "weak" attribute will be removed and the function made static. Unlike the original version from Marc, this new version from Arnd does not use a generalized abstraction for per-soc data structures but only tries to solve the problem for the SMP operations. This way, we can collapse the previous four data structures into a single struct, which is less systematic but also easier to follow as a causal reader. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Acked-by: Nicolas Pitre <nico@fluxnic.net> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--arch/arm/include/asm/mach/arch.h7
-rw-r--r--arch/arm/include/asm/smp.h33
-rw-r--r--arch/arm/kernel/setup.c4
-rw-r--r--arch/arm/kernel/smp.c62
4 files changed, 104 insertions, 2 deletions
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 0b1c94b8c652..917d4fcfd9b4 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -14,6 +14,12 @@ struct tag;
14struct meminfo; 14struct meminfo;
15struct sys_timer; 15struct sys_timer;
16struct pt_regs; 16struct pt_regs;
17struct smp_operations;
18#ifdef CONFIG_SMP
19#define smp_ops(ops) (&(ops))
20#else
21#define smp_ops(ops) (struct smp_operations *)NULL
22#endif
17 23
18struct machine_desc { 24struct machine_desc {
19 unsigned int nr; /* architecture number */ 25 unsigned int nr; /* architecture number */
@@ -35,6 +41,7 @@ struct machine_desc {
35 unsigned char reserve_lp1 :1; /* never has lp1 */ 41 unsigned char reserve_lp1 :1; /* never has lp1 */
36 unsigned char reserve_lp2 :1; /* never has lp2 */ 42 unsigned char reserve_lp2 :1; /* never has lp2 */
37 char restart_mode; /* default restart mode */ 43 char restart_mode; /* default restart mode */
44 struct smp_operations *smp; /* SMP operations */
38 void (*fixup)(struct tag *, char **, 45 void (*fixup)(struct tag *, char **,
39 struct meminfo *); 46 struct meminfo *);
40 void (*reserve)(void);/* reserve mem blocks */ 47 void (*reserve)(void);/* reserve mem blocks */
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index ae29293270a3..f79a9f51e322 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -93,4 +93,37 @@ extern void platform_cpu_enable(unsigned int cpu);
93extern void arch_send_call_function_single_ipi(int cpu); 93extern void arch_send_call_function_single_ipi(int cpu);
94extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); 94extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
95 95
96struct smp_operations {
97#ifdef CONFIG_SMP
98 /*
99 * Setup the set of possible CPUs (via set_cpu_possible)
100 */
101 void (*smp_init_cpus)(void);
102 /*
103 * Initialize cpu_possible map, and enable coherency
104 */
105 void (*smp_prepare_cpus)(unsigned int max_cpus);
106
107 /*
108 * Perform platform specific initialisation of the specified CPU.
109 */
110 void (*smp_secondary_init)(unsigned int cpu);
111 /*
112 * Boot a secondary CPU, and assign it the specified idle task.
113 * This also gives us the initial stack to use for this CPU.
114 */
115 int (*smp_boot_secondary)(unsigned int cpu, struct task_struct *idle);
116#ifdef CONFIG_HOTPLUG_CPU
117 int (*cpu_kill)(unsigned int cpu);
118 void (*cpu_die)(unsigned int cpu);
119 int (*cpu_disable)(unsigned int cpu);
120#endif
121#endif
122};
123
124/*
125 * set platform specific SMP operations
126 */
127extern void smp_set_ops(struct smp_operations *);
128
96#endif /* ifndef __ASM_ARM_SMP_H */ 129#endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index a81dcecc7343..725f9f2a9541 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -977,8 +977,10 @@ void __init setup_arch(char **cmdline_p)
977 unflatten_device_tree(); 977 unflatten_device_tree();
978 978
979#ifdef CONFIG_SMP 979#ifdef CONFIG_SMP
980 if (is_smp()) 980 if (is_smp()) {
981 smp_set_ops(mdesc->smp);
981 smp_init_cpus(); 982 smp_init_cpus();
983 }
982#endif 984#endif
983 reserve_crashkernel(); 985 reserve_crashkernel();
984 986
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad274d76..d9241885521b 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -19,7 +19,6 @@
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/err.h> 20#include <linux/err.h>
21#include <linux/cpu.h> 21#include <linux/cpu.h>
22#include <linux/smp.h>
23#include <linux/seq_file.h> 22#include <linux/seq_file.h>
24#include <linux/irq.h> 23#include <linux/irq.h>
25#include <linux/percpu.h> 24#include <linux/percpu.h>
@@ -27,6 +26,7 @@
27#include <linux/completion.h> 26#include <linux/completion.h>
28 27
29#include <linux/atomic.h> 28#include <linux/atomic.h>
29#include <asm/smp.h>
30#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
31#include <asm/cpu.h> 31#include <asm/cpu.h>
32#include <asm/cputype.h> 32#include <asm/cputype.h>
@@ -42,6 +42,7 @@
42#include <asm/ptrace.h> 42#include <asm/ptrace.h>
43#include <asm/localtimer.h> 43#include <asm/localtimer.h>
44#include <asm/smp_plat.h> 44#include <asm/smp_plat.h>
45#include <asm/mach/arch.h>
45 46
46/* 47/*
47 * as from 2.5, kernels no longer have an init_tasks structure 48 * as from 2.5, kernels no longer have an init_tasks structure
@@ -60,6 +61,14 @@ enum ipi_msg_type {
60 61
61static DECLARE_COMPLETION(cpu_running); 62static DECLARE_COMPLETION(cpu_running);
62 63
64static struct smp_operations smp_ops;
65
66void __init smp_set_ops(struct smp_operations *ops)
67{
68 if (ops)
69 smp_ops = *ops;
70};
71
63int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) 72int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
64{ 73{
65 int ret; 74 int ret;
@@ -100,9 +109,60 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
100 return ret; 109 return ret;
101} 110}
102 111
112/* platform specific SMP operations */
113void __attribute__((weak)) __init smp_init_cpus(void)
114{
115 if (smp_ops.smp_init_cpus)
116 smp_ops.smp_init_cpus();
117}
118
119void __attribute__((weak)) __init platform_smp_prepare_cpus(unsigned int max_cpus)
120{
121 if (smp_ops.smp_prepare_cpus)
122 smp_ops.smp_prepare_cpus(max_cpus);
123}
124
125void __attribute__((weak)) __cpuinit platform_secondary_init(unsigned int cpu)
126{
127 if (smp_ops.smp_secondary_init)
128 smp_ops.smp_secondary_init(cpu);
129}
130
131int __attribute__((weak)) __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
132{
133 if (smp_ops.smp_boot_secondary)
134 return smp_ops.smp_boot_secondary(cpu, idle);
135 return -ENOSYS;
136}
137
103#ifdef CONFIG_HOTPLUG_CPU 138#ifdef CONFIG_HOTPLUG_CPU
104static void percpu_timer_stop(void); 139static void percpu_timer_stop(void);
105 140
141int __attribute__((weak)) platform_cpu_kill(unsigned int cpu)
142{
143 if (smp_ops.cpu_kill)
144 return smp_ops.cpu_kill(cpu);
145 return 1;
146}
147
148void __attribute__((weak)) platform_cpu_die(unsigned int cpu)
149{
150 if (smp_ops.cpu_die)
151 smp_ops.cpu_die(cpu);
152}
153
154int __attribute__((weak)) platform_cpu_disable(unsigned int cpu)
155{
156 if (smp_ops.cpu_disable)
157 return smp_ops.cpu_disable(cpu);
158
159 /*
160 * By default, allow disabling all CPUs except the first one,
161 * since this is special on a lot of platforms, e.g. because
162 * of clock tick interrupts.
163 */
164 return cpu == 0 ? -EPERM : 0;
165}
106/* 166/*
107 * __cpu_disable runs on the processor to be shutdown. 167 * __cpu_disable runs on the processor to be shutdown.
108 */ 168 */