diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2009-06-23 05:00:31 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-06-24 13:34:40 -0400 |
commit | 1b2bc75c1bde6581d2694cb3ed7fb06b69685008 (patch) | |
tree | 800fc23052bccb1fbf8acfbaabbf5648c69daa9e | |
parent | 4ac4aa5cc3b00cc558575065ae71043e92d1a69a (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>
-rw-r--r-- | arch/mips/Kconfig | 11 | ||||
-rw-r--r-- | arch/mips/include/asm/smp-ops.h | 4 | ||||
-rw-r--r-- | arch/mips/include/asm/smp.h | 19 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 13 | ||||
-rw-r--r-- | arch/mips/kernel/smp-up.c | 16 | ||||
-rw-r--r-- | arch/mips/kernel/smp.c | 17 | ||||
-rw-r--r-- | arch/mips/kernel/topology.c | 5 |
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 | ||
786 | config HOTPLUG_CPU | 786 | config 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 | |||
796 | config SYS_SUPPORTS_HOTPLUG_CPU | ||
787 | bool | 797 | bool |
788 | default n | ||
789 | 798 | ||
790 | config I8259 | 799 | config 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 | ||
31 | extern void register_smp_ops(struct plat_smp_ops *ops); | 35 | extern 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 | ||
44 | extern cpumask_t cpu_callin_map; | ||
44 | 45 | ||
45 | extern void asmlinkage smp_bootstrap(void); | 46 | extern 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 | ||
61 | static inline int __cpu_disable(void) | ||
62 | { | ||
63 | extern struct plat_smp_ops *mp_ops; /* private */ | ||
64 | |||
65 | return mp_ops->cpu_disable(); | ||
66 | } | ||
67 | |||
68 | static 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 | |||
75 | extern void play_dead(void); | ||
76 | #endif | ||
77 | |||
59 | extern asmlinkage void smp_call_function_interrupt(void); | 78 | extern asmlinkage void smp_call_function_interrupt(void); |
60 | 79 | ||
61 | extern void arch_send_call_function_single_ipi(int cpu); | 80 | extern 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 | */ |
51 | void __noreturn cpu_idle(void) | 51 | void __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 | ||
59 | static int up_cpu_disable(void) | ||
60 | { | ||
61 | return -ENOSYS; | ||
62 | } | ||
63 | |||
64 | static void up_cpu_die(unsigned int cpu) | ||
65 | { | ||
66 | BUG(); | ||
67 | } | ||
68 | #endif | ||
69 | |||
58 | struct plat_smp_ops up_smp_ops = { | 70 | struct 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 | ||
48 | static volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ | 48 | volatile cpumask_t cpu_callin_map; /* Bitmask of started secondaries */ |
49 | int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ | 49 | int __cpu_number_map[NR_CPUS]; /* Map physical to logical */ |
50 | int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ | 50 | int __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 | */ |
204 | static struct task_struct *cpu_idle_thread[NR_CPUS]; | ||
205 | |||
204 | int __cpuinit __cpu_up(unsigned int cpu) | 206 | int __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); |