aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2009-06-23 05:00:31 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-06-24 13:34:40 -0400
commit1b2bc75c1bde6581d2694cb3ed7fb06b69685008 (patch)
tree800fc23052bccb1fbf8acfbaabbf5648c69daa9e /arch/mips
parent4ac4aa5cc3b00cc558575065ae71043e92d1a69a (diff)
MIPS: Add arch generic CPU hotplug
Each platform has to add support for CPU hotplugging itself by providing suitable definitions for the cpu_disable and cpu_die of the smp_ops methods and setting SYS_SUPPORTS_HOTPLUG_CPU. A platform should only set SYS_SUPPORTS_HOTPLUG_CPU once all it's smp_ops definitions have the necessary changes. This patch contains the changes to the dummy smp_ops definition for uni-processor systems. Parts of the code contributed by Cavium Inc. Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig11
-rw-r--r--arch/mips/include/asm/smp-ops.h4
-rw-r--r--arch/mips/include/asm/smp.h19
-rw-r--r--arch/mips/kernel/process.c13
-rw-r--r--arch/mips/kernel/smp-up.c16
-rw-r--r--arch/mips/kernel/smp.c17
-rw-r--r--arch/mips/kernel/topology.c5
7 files changed, 78 insertions, 7 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b29f0280d712..eb7e8d795c6a 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -784,8 +784,17 @@ config SYS_HAS_EARLY_PRINTK
784 bool 784 bool
785 785
786config HOTPLUG_CPU 786config HOTPLUG_CPU
787 bool "Support for hot-pluggable CPUs"
788 depends on SMP && HOTPLUG && SYS_SUPPORTS_HOTPLUG_CPU
789 help
790 Say Y here to allow turning CPUs off and on. CPUs can be
791 controlled through /sys/devices/system/cpu.
792 (Note: power management support will enable this option
793 automatically on SMP systems. )
794 Say N if you want to disable CPU hotplug.
795
796config SYS_SUPPORTS_HOTPLUG_CPU
787 bool 797 bool
788 default n
789 798
790config I8259 799config I8259
791 bool 800 bool
diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h
index 64ffc0290b84..fd545547b8aa 100644
--- a/arch/mips/include/asm/smp-ops.h
+++ b/arch/mips/include/asm/smp-ops.h
@@ -26,6 +26,10 @@ struct plat_smp_ops {
26 void (*boot_secondary)(int cpu, struct task_struct *idle); 26 void (*boot_secondary)(int cpu, struct task_struct *idle);
27 void (*smp_setup)(void); 27 void (*smp_setup)(void);
28 void (*prepare_cpus)(unsigned int max_cpus); 28 void (*prepare_cpus)(unsigned int max_cpus);
29#ifdef CONFIG_HOTPLUG_CPU
30 int (*cpu_disable)(void);
31 void (*cpu_die)(unsigned int cpu);
32#endif
29}; 33};
30 34
31extern void register_smp_ops(struct plat_smp_ops *ops); 35extern void register_smp_ops(struct plat_smp_ops *ops);
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index 2f83fa8631db..01f813dc3888 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -41,6 +41,7 @@ extern int __cpu_logical_map[NR_CPUS];
41/* Octeon - Tell another core to flush its icache */ 41/* Octeon - Tell another core to flush its icache */
42#define SMP_ICACHE_FLUSH 0x4 42#define SMP_ICACHE_FLUSH 0x4
43 43
44extern cpumask_t cpu_callin_map;
44 45
45extern void asmlinkage smp_bootstrap(void); 46extern void asmlinkage smp_bootstrap(void);
46 47
@@ -56,6 +57,24 @@ static inline void smp_send_reschedule(int cpu)
56 mp_ops->send_ipi_single(cpu, SMP_RESCHEDULE_YOURSELF); 57 mp_ops->send_ipi_single(cpu, SMP_RESCHEDULE_YOURSELF);
57} 58}
58 59
60#ifdef CONFIG_HOTPLUG_CPU
61static inline int __cpu_disable(void)
62{
63 extern struct plat_smp_ops *mp_ops; /* private */
64
65 return mp_ops->cpu_disable();
66}
67
68static inline void __cpu_die(unsigned int cpu)
69{
70 extern struct plat_smp_ops *mp_ops; /* private */
71
72 mp_ops->cpu_die(cpu);
73}
74
75extern void play_dead(void);
76#endif
77
59extern asmlinkage void smp_call_function_interrupt(void); 78extern asmlinkage void smp_call_function_interrupt(void);
60 79
61extern void arch_send_call_function_single_ipi(int cpu); 80extern void arch_send_call_function_single_ipi(int cpu);
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 1eaaa450e20c..c09d681b7181 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -50,10 +50,15 @@
50 */ 50 */
51void __noreturn cpu_idle(void) 51void __noreturn cpu_idle(void)
52{ 52{
53 int cpu;
54
55 /* CPU is going idle. */
56 cpu = smp_processor_id();
57
53 /* endless idle loop with no priority at all */ 58 /* endless idle loop with no priority at all */
54 while (1) { 59 while (1) {
55 tick_nohz_stop_sched_tick(1); 60 tick_nohz_stop_sched_tick(1);
56 while (!need_resched()) { 61 while (!need_resched() && cpu_online(cpu)) {
57#ifdef CONFIG_MIPS_MT_SMTC 62#ifdef CONFIG_MIPS_MT_SMTC
58 extern void smtc_idle_loop_hook(void); 63 extern void smtc_idle_loop_hook(void);
59 64
@@ -62,6 +67,12 @@ void __noreturn cpu_idle(void)
62 if (cpu_wait) 67 if (cpu_wait)
63 (*cpu_wait)(); 68 (*cpu_wait)();
64 } 69 }
70#ifdef CONFIG_HOTPLUG_CPU
71 if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) &&
72 (system_state == SYSTEM_RUNNING ||
73 system_state == SYSTEM_BOOTING))
74 play_dead();
75#endif
65 tick_nohz_restart_sched_tick(); 76 tick_nohz_restart_sched_tick();
66 preempt_enable_no_resched(); 77 preempt_enable_no_resched();
67 schedule(); 78 schedule();
diff --git a/arch/mips/kernel/smp-up.c b/arch/mips/kernel/smp-up.c
index 878e3733bbb2..2508d55d68fd 100644
--- a/arch/mips/kernel/smp-up.c
+++ b/arch/mips/kernel/smp-up.c
@@ -55,6 +55,18 @@ static void __init up_prepare_cpus(unsigned int max_cpus)
55{ 55{
56} 56}
57 57
58#ifdef CONFIG_HOTPLUG_CPU
59static int up_cpu_disable(void)
60{
61 return -ENOSYS;
62}
63
64static void up_cpu_die(unsigned int cpu)
65{
66 BUG();
67}
68#endif
69
58struct plat_smp_ops up_smp_ops = { 70struct plat_smp_ops up_smp_ops = {
59 .send_ipi_single = up_send_ipi_single, 71 .send_ipi_single = up_send_ipi_single,
60 .send_ipi_mask = up_send_ipi_mask, 72 .send_ipi_mask = up_send_ipi_mask,
@@ -64,4 +76,8 @@ struct plat_smp_ops up_smp_ops = {
64 .boot_secondary = up_boot_secondary, 76 .boot_secondary = up_boot_secondary,
65 .smp_setup = up_smp_setup, 77 .smp_setup = up_smp_setup,
66 .prepare_cpus = up_prepare_cpus, 78 .prepare_cpus = up_prepare_cpus,
79#ifdef CONFIG_HOTPLUG_CPU
80 .cpu_disable = up_cpu_disable,
81 .cpu_die = up_cpu_die,
82#endif
67}; 83};
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 58f4679bbd43..bc7d9b05e2f4 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -45,7 +45,7 @@
45#include <asm/mipsmtregs.h> 45#include <asm/mipsmtregs.h>
46#endif /* CONFIG_MIPS_MT_SMTC */ 46#endif /* CONFIG_MIPS_MT_SMTC */
47 47
48static volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ 48volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */
49int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ 49int __cpu_number_map[NR_CPUS]; /* Map physical to logical */
50int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ 50int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */
51 51
@@ -201,6 +201,8 @@ void __devinit smp_prepare_boot_cpu(void)
201 * and keep control until "cpu_online(cpu)" is set. Note: cpu is 201 * and keep control until "cpu_online(cpu)" is set. Note: cpu is
202 * physical, not logical. 202 * physical, not logical.
203 */ 203 */
204static struct task_struct *cpu_idle_thread[NR_CPUS];
205
204int __cpuinit __cpu_up(unsigned int cpu) 206int __cpuinit __cpu_up(unsigned int cpu)
205{ 207{
206 struct task_struct *idle; 208 struct task_struct *idle;
@@ -210,9 +212,16 @@ int __cpuinit __cpu_up(unsigned int cpu)
210 * The following code is purely to make sure 212 * The following code is purely to make sure
211 * Linux can schedule processes on this slave. 213 * Linux can schedule processes on this slave.
212 */ 214 */
213 idle = fork_idle(cpu); 215 if (!cpu_idle_thread[cpu]) {
214 if (IS_ERR(idle)) 216 idle = fork_idle(cpu);
215 panic(KERN_ERR "Fork failed for CPU %d", cpu); 217 cpu_idle_thread[cpu] = idle;
218
219 if (IS_ERR(idle))
220 panic(KERN_ERR "Fork failed for CPU %d", cpu);
221 } else {
222 idle = cpu_idle_thread[cpu];
223 init_idle(idle, cpu);
224 }
216 225
217 mp_ops->boot_secondary(cpu, idle); 226 mp_ops->boot_secondary(cpu, idle);
218 227
diff --git a/arch/mips/kernel/topology.c b/arch/mips/kernel/topology.c
index 660e44ed44d7..cf3eb61fad12 100644
--- a/arch/mips/kernel/topology.c
+++ b/arch/mips/kernel/topology.c
@@ -17,7 +17,10 @@ static int __init topology_init(void)
17#endif /* CONFIG_NUMA */ 17#endif /* CONFIG_NUMA */
18 18
19 for_each_present_cpu(i) { 19 for_each_present_cpu(i) {
20 ret = register_cpu(&per_cpu(cpu_devices, i), i); 20 struct cpu *c = &per_cpu(cpu_devices, i);
21
22 c->hotpluggable = 1;
23 ret = register_cpu(c, i);
21 if (ret) 24 if (ret)
22 printk(KERN_WARNING "topology_init: register_cpu %d " 25 printk(KERN_WARNING "topology_init: register_cpu %d "
23 "failed (%d)\n", i, ret); 26 "failed (%d)\n", i, ret);