diff options
Diffstat (limited to 'arch/csky/kernel/smp.c')
-rw-r--r-- | arch/csky/kernel/smp.c | 71 |
1 files changed, 56 insertions, 15 deletions
diff --git a/arch/csky/kernel/smp.c b/arch/csky/kernel/smp.c index 74d627300c55..ddc4dd79f282 100644 --- a/arch/csky/kernel/smp.c +++ b/arch/csky/kernel/smp.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/sched/task_stack.h> #include <linux/sched/mm.h> +#include <linux/sched/hotplug.h> #include <asm/irq.h> #include <asm/traps.h> #include <asm/sections.h> @@ -112,12 +113,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) { } -static void __init enable_smp_ipi(void) -{ - enable_percpu_irq(ipi_irq, 0); -} - static int ipi_dummy_dev; + void __init setup_smp_ipi(void) { int rc; @@ -130,7 +127,7 @@ void __init setup_smp_ipi(void) if (rc) panic("%s IRQ request failed\n", __func__); - enable_smp_ipi(); + enable_percpu_irq(ipi_irq, 0); } void __init setup_smp(void) @@ -161,12 +158,10 @@ volatile unsigned int secondary_stack; int __cpu_up(unsigned int cpu, struct task_struct *tidle) { - unsigned int tmp; - - secondary_stack = (unsigned int)tidle->stack + THREAD_SIZE; + unsigned long mask = 1 << cpu; + secondary_stack = (unsigned int)tidle->stack + THREAD_SIZE - 8; secondary_hint = mfcr("cr31"); - secondary_ccr = mfcr("cr18"); /* @@ -176,10 +171,13 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) */ mtcr("cr17", 0x22); - /* Enable cpu in SMP reset ctrl reg */ - tmp = mfcr("cr<29, 0>"); - tmp |= 1 << cpu; - mtcr("cr<29, 0>", tmp); + if (mask & mfcr("cr<29, 0>")) { + send_arch_ipi(cpumask_of(cpu)); + } else { + /* Enable cpu in SMP reset ctrl reg */ + mask |= mfcr("cr<29, 0>"); + mtcr("cr<29, 0>", mask); + } /* Wait for the cpu online */ while (!cpu_online(cpu)); @@ -219,7 +217,7 @@ void csky_start_secondary(void) init_fpu(); #endif - enable_smp_ipi(); + enable_percpu_irq(ipi_irq, 0); mmget(mm); mmgrab(mm); @@ -235,3 +233,46 @@ void csky_start_secondary(void) preempt_disable(); cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); } + +#ifdef CONFIG_HOTPLUG_CPU +int __cpu_disable(void) +{ + unsigned int cpu = smp_processor_id(); + + set_cpu_online(cpu, false); + + irq_migrate_all_off_this_cpu(); + + clear_tasks_mm_cpumask(cpu); + + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + if (!cpu_wait_death(cpu, 5)) { + pr_crit("CPU%u: shutdown failed\n", cpu); + return; + } + pr_notice("CPU%u: shutdown\n", cpu); +} + +void arch_cpu_idle_dead(void) +{ + idle_task_exit(); + + cpu_report_death(); + + while (!secondary_stack) + arch_cpu_idle(); + + local_irq_disable(); + + asm volatile( + "mov sp, %0\n" + "mov r8, %0\n" + "jmpi csky_start_secondary" + : + : "r" (secondary_stack)); +} +#endif |