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
This commit is contained in:
Dengcheng Zhu 2018-09-11 14:49:22 -07:00 committed by Paul Burton
parent 62cac480f3
commit 1447864bee
No known key found for this signature in database
GPG Key ID: 3EA79FACB57500DD

View File

@ -398,6 +398,55 @@ static void cps_smp_finish(void)
local_irq_enable(); local_irq_enable();
} }
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
enum cpu_death {
CPU_DEATH_HALT,
CPU_DEATH_POWER,
};
static void cps_shutdown_this_cpu(enum cpu_death death)
{
unsigned int cpu, core, vpe_id;
cpu = smp_processor_id();
core = cpu_core(&cpu_data[cpu]);
if (death == CPU_DEATH_HALT) {
vpe_id = cpu_vpe_id(&cpu_data[cpu]);
pr_debug("Halting core %d VP%d\n", core, vpe_id);
if (cpu_has_mipsmt) {
/* Halt this TC */
write_c0_tchalt(TCHALT_H);
instruction_hazard();
} else if (cpu_has_vp) {
write_cpc_cl_vp_stop(1 << vpe_id);
/* Ensure that the VP_STOP register is written */
wmb();
}
} else {
pr_debug("Gating power to core %d\n", core);
/* Power down the core */
cps_pm_enter_state(CPS_PM_POWER_GATED);
}
}
#ifdef CONFIG_KEXEC
static void cps_kexec_nonboot_cpu(void)
{
if (cpu_has_mipsmt || cpu_has_vp)
cps_shutdown_this_cpu(CPU_DEATH_HALT);
else
cps_shutdown_this_cpu(CPU_DEATH_POWER);
}
#endif /* CONFIG_KEXEC */
#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static int cps_cpu_disable(void) static int cps_cpu_disable(void)
@ -421,19 +470,15 @@ static int cps_cpu_disable(void)
} }
static unsigned cpu_death_sibling; static unsigned cpu_death_sibling;
static enum { static enum cpu_death cpu_death;
CPU_DEATH_HALT,
CPU_DEATH_POWER,
} cpu_death;
void play_dead(void) void play_dead(void)
{ {
unsigned int cpu, core, vpe_id; unsigned int cpu;
local_irq_disable(); local_irq_disable();
idle_task_exit(); idle_task_exit();
cpu = smp_processor_id(); cpu = smp_processor_id();
core = cpu_core(&cpu_data[cpu]);
cpu_death = CPU_DEATH_POWER; cpu_death = CPU_DEATH_POWER;
pr_debug("CPU%d going offline\n", cpu); pr_debug("CPU%d going offline\n", cpu);
@ -456,25 +501,7 @@ void play_dead(void)
/* This CPU has chosen its way out */ /* This CPU has chosen its way out */
(void)cpu_report_death(); (void)cpu_report_death();
if (cpu_death == CPU_DEATH_HALT) { cps_shutdown_this_cpu(cpu_death);
vpe_id = cpu_vpe_id(&cpu_data[cpu]);
pr_debug("Halting core %d VP%d\n", core, vpe_id);
if (cpu_has_mipsmt) {
/* Halt this TC */
write_c0_tchalt(TCHALT_H);
instruction_hazard();
} else if (cpu_has_vp) {
write_cpc_cl_vp_stop(1 << vpe_id);
/* Ensure that the VP_STOP register is written */
wmb();
}
} else {
pr_debug("Gating power to core %d\n", core);
/* Power down the core */
cps_pm_enter_state(CPS_PM_POWER_GATED);
}
/* This should never be reached */ /* This should never be reached */
panic("Failed to offline CPU %u", cpu); panic("Failed to offline CPU %u", cpu);
@ -593,6 +620,9 @@ static const struct plat_smp_ops cps_smp_ops = {
.cpu_disable = cps_cpu_disable, .cpu_disable = cps_cpu_disable,
.cpu_die = cps_cpu_die, .cpu_die = cps_cpu_die,
#endif #endif
#ifdef CONFIG_KEXEC
.kexec_nonboot_cpu = cps_kexec_nonboot_cpu,
#endif
}; };
bool mips_cps_smp_in_use(void) bool mips_cps_smp_in_use(void)