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); |
