diff options
author | Dengcheng Zhu <dzhu@wavecomp.com> | 2018-09-11 17:49:22 -0400 |
---|---|---|
committer | Paul Burton <paul.burton@mips.com> | 2018-09-22 13:32:33 -0400 |
commit | 1447864bee4cd9ea96fe793ea8fb49a8ea784412 (patch) | |
tree | 8c5dfb1d22b4257fcf855016fe239201f7deac71 | |
parent | 62cac480f33f8f9413d609cb1601b0ee521a86b8 (diff) |
MIPS: kexec: CPS systems to halt nonboot CPUs
Share code between play_dead() and cps_kexec_nonboot_cpu(). Register the
latter to mp_ops for kexec.
Signed-off-by: Dengcheng Zhu <dzhu@wavecomp.com>
Signed-off-by: Paul Burton <paul.burton@mips.com>
Patchwork: https://patchwork.linux-mips.org/patch/20567/
Cc: pburton@wavecomp.com
Cc: ralf@linux-mips.org
Cc: linux-mips@linux-mips.org
Cc: rachel.mozes@intel.com
-rw-r--r-- | arch/mips/kernel/smp-cps.c | 80 |
1 files changed, 55 insertions, 25 deletions
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 03f1026ad148..faccfa4b280b 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c | |||
@@ -398,6 +398,55 @@ static void cps_smp_finish(void) | |||
398 | local_irq_enable(); | 398 | local_irq_enable(); |
399 | } | 399 | } |
400 | 400 | ||
401 | #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC) | ||
402 | |||
403 | enum cpu_death { | ||
404 | CPU_DEATH_HALT, | ||
405 | CPU_DEATH_POWER, | ||
406 | }; | ||
407 | |||
408 | static void cps_shutdown_this_cpu(enum cpu_death death) | ||
409 | { | ||
410 | unsigned int cpu, core, vpe_id; | ||
411 | |||
412 | cpu = smp_processor_id(); | ||
413 | core = cpu_core(&cpu_data[cpu]); | ||
414 | |||
415 | if (death == CPU_DEATH_HALT) { | ||
416 | vpe_id = cpu_vpe_id(&cpu_data[cpu]); | ||
417 | |||
418 | pr_debug("Halting core %d VP%d\n", core, vpe_id); | ||
419 | if (cpu_has_mipsmt) { | ||
420 | /* Halt this TC */ | ||
421 | write_c0_tchalt(TCHALT_H); | ||
422 | instruction_hazard(); | ||
423 | } else if (cpu_has_vp) { | ||
424 | write_cpc_cl_vp_stop(1 << vpe_id); | ||
425 | |||
426 | /* Ensure that the VP_STOP register is written */ | ||
427 | wmb(); | ||
428 | } | ||
429 | } else { | ||
430 | pr_debug("Gating power to core %d\n", core); | ||
431 | /* Power down the core */ | ||
432 | cps_pm_enter_state(CPS_PM_POWER_GATED); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | #ifdef CONFIG_KEXEC | ||
437 | |||
438 | static void cps_kexec_nonboot_cpu(void) | ||
439 | { | ||
440 | if (cpu_has_mipsmt || cpu_has_vp) | ||
441 | cps_shutdown_this_cpu(CPU_DEATH_HALT); | ||
442 | else | ||
443 | cps_shutdown_this_cpu(CPU_DEATH_POWER); | ||
444 | } | ||
445 | |||
446 | #endif /* CONFIG_KEXEC */ | ||
447 | |||
448 | #endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */ | ||
449 | |||
401 | #ifdef CONFIG_HOTPLUG_CPU | 450 | #ifdef CONFIG_HOTPLUG_CPU |
402 | 451 | ||
403 | static int cps_cpu_disable(void) | 452 | static int cps_cpu_disable(void) |
@@ -421,19 +470,15 @@ static int cps_cpu_disable(void) | |||
421 | } | 470 | } |
422 | 471 | ||
423 | static unsigned cpu_death_sibling; | 472 | static unsigned cpu_death_sibling; |
424 | static enum { | 473 | static enum cpu_death cpu_death; |
425 | CPU_DEATH_HALT, | ||
426 | CPU_DEATH_POWER, | ||
427 | } cpu_death; | ||
428 | 474 | ||
429 | void play_dead(void) | 475 | void play_dead(void) |
430 | { | 476 | { |
431 | unsigned int cpu, core, vpe_id; | 477 | unsigned int cpu; |
432 | 478 | ||
433 | local_irq_disable(); | 479 | local_irq_disable(); |
434 | idle_task_exit(); | 480 | idle_task_exit(); |
435 | cpu = smp_processor_id(); | 481 | cpu = smp_processor_id(); |
436 | core = cpu_core(&cpu_data[cpu]); | ||
437 | cpu_death = CPU_DEATH_POWER; | 482 | cpu_death = CPU_DEATH_POWER; |
438 | 483 | ||
439 | pr_debug("CPU%d going offline\n", cpu); | 484 | pr_debug("CPU%d going offline\n", cpu); |
@@ -456,25 +501,7 @@ void play_dead(void) | |||
456 | /* This CPU has chosen its way out */ | 501 | /* This CPU has chosen its way out */ |
457 | (void)cpu_report_death(); | 502 | (void)cpu_report_death(); |
458 | 503 | ||
459 | if (cpu_death == CPU_DEATH_HALT) { | 504 | cps_shutdown_this_cpu(cpu_death); |
460 | vpe_id = cpu_vpe_id(&cpu_data[cpu]); | ||
461 | |||
462 | pr_debug("Halting core %d VP%d\n", core, vpe_id); | ||
463 | if (cpu_has_mipsmt) { | ||
464 | /* Halt this TC */ | ||
465 | write_c0_tchalt(TCHALT_H); | ||
466 | instruction_hazard(); | ||
467 | } else if (cpu_has_vp) { | ||
468 | write_cpc_cl_vp_stop(1 << vpe_id); | ||
469 | |||
470 | /* Ensure that the VP_STOP register is written */ | ||
471 | wmb(); | ||
472 | } | ||
473 | } else { | ||
474 | pr_debug("Gating power to core %d\n", core); | ||
475 | /* Power down the core */ | ||
476 | cps_pm_enter_state(CPS_PM_POWER_GATED); | ||
477 | } | ||
478 | 505 | ||
479 | /* This should never be reached */ | 506 | /* This should never be reached */ |
480 | panic("Failed to offline CPU %u", cpu); | 507 | panic("Failed to offline CPU %u", cpu); |
@@ -593,6 +620,9 @@ static const struct plat_smp_ops cps_smp_ops = { | |||
593 | .cpu_disable = cps_cpu_disable, | 620 | .cpu_disable = cps_cpu_disable, |
594 | .cpu_die = cps_cpu_die, | 621 | .cpu_die = cps_cpu_die, |
595 | #endif | 622 | #endif |
623 | #ifdef CONFIG_KEXEC | ||
624 | .kexec_nonboot_cpu = cps_kexec_nonboot_cpu, | ||
625 | #endif | ||
596 | }; | 626 | }; |
597 | 627 | ||
598 | bool mips_cps_smp_in_use(void) | 628 | bool mips_cps_smp_in_use(void) |