Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

csky: CPU-hotplug supported for SMP

This is a simple implement of CPU-hotplug for power saving. CPU use
wait instruction to enter power saving mode and waiting for IPI wakeup
signal.

Signed-off-by: Guo Ren <ren_guo@c-sky.com>

Guo Ren 859e5f45 1d95fe4d

+69 -15
+9
arch/csky/Kconfig
··· 198 198 hex "DRAM start addr (the same with memory-section in dts)" 199 199 default 0x0 200 200 201 + config HOTPLUG_CPU 202 + bool "Support for hot-pluggable CPUs" 203 + select GENERIC_IRQ_MIGRATION 204 + depends on SMP 205 + help 206 + Say Y here to allow turning CPUs off and on. CPUs can be 207 + controlled through /sys/devices/system/cpu/cpu1/hotplug/target. 208 + 209 + Say N if you want to disable CPU hotplug. 201 210 endmenu 202 211 203 212 source "kernel/Kconfig.hz"
+4
arch/csky/include/asm/smp.h
··· 21 21 22 22 #define raw_smp_processor_id() (current_thread_info()->cpu) 23 23 24 + int __cpu_disable(void); 25 + 26 + void __cpu_die(unsigned int cpu); 27 + 24 28 #endif /* CONFIG_SMP */ 25 29 26 30 #endif /* __ASM_CSKY_SMP_H */
+56 -15
arch/csky/kernel/smp.c
··· 16 16 #include <linux/of.h> 17 17 #include <linux/sched/task_stack.h> 18 18 #include <linux/sched/mm.h> 19 + #include <linux/sched/hotplug.h> 19 20 #include <asm/irq.h> 20 21 #include <asm/traps.h> 21 22 #include <asm/sections.h> ··· 113 112 { 114 113 } 115 114 116 - static void __init enable_smp_ipi(void) 117 - { 118 - enable_percpu_irq(ipi_irq, 0); 119 - } 120 - 121 115 static int ipi_dummy_dev; 116 + 122 117 void __init setup_smp_ipi(void) 123 118 { 124 119 int rc; ··· 127 130 if (rc) 128 131 panic("%s IRQ request failed\n", __func__); 129 132 130 - enable_smp_ipi(); 133 + enable_percpu_irq(ipi_irq, 0); 131 134 } 132 135 133 136 void __init setup_smp(void) ··· 158 161 159 162 int __cpu_up(unsigned int cpu, struct task_struct *tidle) 160 163 { 161 - unsigned int tmp; 164 + unsigned long mask = 1 << cpu; 162 165 163 - secondary_stack = (unsigned int)tidle->stack + THREAD_SIZE; 164 - 166 + secondary_stack = (unsigned int)tidle->stack + THREAD_SIZE - 8; 165 167 secondary_hint = mfcr("cr31"); 166 - 167 168 secondary_ccr = mfcr("cr18"); 168 169 169 170 /* ··· 171 176 */ 172 177 mtcr("cr17", 0x22); 173 178 174 - /* Enable cpu in SMP reset ctrl reg */ 175 - tmp = mfcr("cr<29, 0>"); 176 - tmp |= 1 << cpu; 177 - mtcr("cr<29, 0>", tmp); 179 + if (mask & mfcr("cr<29, 0>")) { 180 + send_arch_ipi(cpumask_of(cpu)); 181 + } else { 182 + /* Enable cpu in SMP reset ctrl reg */ 183 + mask |= mfcr("cr<29, 0>"); 184 + mtcr("cr<29, 0>", mask); 185 + } 178 186 179 187 /* Wait for the cpu online */ 180 188 while (!cpu_online(cpu)); ··· 217 219 init_fpu(); 218 220 #endif 219 221 220 - enable_smp_ipi(); 222 + enable_percpu_irq(ipi_irq, 0); 221 223 222 224 mmget(mm); 223 225 mmgrab(mm); ··· 233 235 preempt_disable(); 234 236 cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); 235 237 } 238 + 239 + #ifdef CONFIG_HOTPLUG_CPU 240 + int __cpu_disable(void) 241 + { 242 + unsigned int cpu = smp_processor_id(); 243 + 244 + set_cpu_online(cpu, false); 245 + 246 + irq_migrate_all_off_this_cpu(); 247 + 248 + clear_tasks_mm_cpumask(cpu); 249 + 250 + return 0; 251 + } 252 + 253 + void __cpu_die(unsigned int cpu) 254 + { 255 + if (!cpu_wait_death(cpu, 5)) { 256 + pr_crit("CPU%u: shutdown failed\n", cpu); 257 + return; 258 + } 259 + pr_notice("CPU%u: shutdown\n", cpu); 260 + } 261 + 262 + void arch_cpu_idle_dead(void) 263 + { 264 + idle_task_exit(); 265 + 266 + cpu_report_death(); 267 + 268 + while (!secondary_stack) 269 + arch_cpu_idle(); 270 + 271 + local_irq_disable(); 272 + 273 + asm volatile( 274 + "mov sp, %0\n" 275 + "mov r8, %0\n" 276 + "jmpi csky_start_secondary" 277 + : 278 + : "r" (secondary_stack)); 279 + } 280 + #endif