diff options
author | Matt Redfearn <matt.redfearn@imgtec.com> | 2016-07-07 08:50:39 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2018-02-05 08:58:35 -0800 |
commit | 63a30ac54ee77099ebeae3c524d664c602f5b730 (patch) | |
tree | 4d7ec12d694526294d45aedabb0b9cd8efb88b02 | |
parent | 0466b2e7a4d7f582580640c6fde5b06a1df9772f (diff) |
UPSTREAM: MIPS: smp-cps: Add support for CPU hotplug of MIPSr6 processors
Introduce support for hotplug of Virtual Processors in MIPSr6 systems.
The method is simpler than the VPE parallel from the now-deprecated MT
ASE, it can now simply write the VP_STOP register with the mask of VPs
to halt, and use the VP_RUNNING register to determine when the VP has
halted.
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
Reviewed-by: Paul Burton <paul.burton@imgtec.com>
Cc: Matt Redfearn <matt.redfearn@imgtec.com>
Cc: Qais Yousef <qais.yousef@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/13752/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
(cherry picked from commit 0d2808f338c7cb0ccf6b087dd7be0e4fa0c865e0)
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
-rw-r--r-- | arch/mips/kernel/smp-cps.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 651233e709f4..a211bbe82d0d 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -404,14 +404,16 @@ static enum { void play_dead(void) { - unsigned cpu, core; + unsigned int cpu, core, vpe_id; local_irq_disable(); idle_task_exit(); cpu = smp_processor_id(); cpu_death = CPU_DEATH_POWER; - if (cpu_has_mipsmt) { + pr_debug("CPU%d going offline\n", cpu); + + if (cpu_has_mipsmt || cpu_has_vp) { core = cpu_data[cpu].core; /* Look for another online VPE within the core */ @@ -432,10 +434,21 @@ void play_dead(void) complete(&cpu_death_chosen); if (cpu_death == CPU_DEATH_HALT) { - /* Halt this TC */ - write_c0_tchalt(TCHALT_H); - instruction_hazard(); + 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); } @@ -462,6 +475,7 @@ static void wait_for_sibling_halt(void *ptr_cpu) static void cps_cpu_die(unsigned int cpu) { unsigned core = cpu_data[cpu].core; + unsigned int vpe_id = cpu_vpe_id(&cpu_data[cpu]); unsigned stat; int err; @@ -490,10 +504,12 @@ static void cps_cpu_die(unsigned int cpu) * in which case the CPC will refuse to power down the core. */ do { + mips_cm_lock_other(core, vpe_id); mips_cpc_lock_other(core); stat = read_cpc_co_stat_conf(); stat &= CPC_Cx_STAT_CONF_SEQSTATE_MSK; mips_cpc_unlock_other(); + mips_cm_unlock_other(); } while (stat != CPC_Cx_STAT_CONF_SEQSTATE_D0 && stat != CPC_Cx_STAT_CONF_SEQSTATE_D2 && stat != CPC_Cx_STAT_CONF_SEQSTATE_U2); @@ -510,6 +526,12 @@ static void cps_cpu_die(unsigned int cpu) (void *)(unsigned long)cpu, 1); if (err) panic("Failed to call remote sibling CPU\n"); + } else if (cpu_has_vp) { + do { + mips_cm_lock_other(core, vpe_id); + stat = read_cpc_co_vp_running(); + mips_cm_unlock_other(); + } while (stat & (1 << vpe_id)); } } |