|
@@ -412,14 +412,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 */
|
|
@@ -440,10 +442,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);
|
|
|
}
|
|
@@ -470,6 +483,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;
|
|
|
|
|
@@ -498,10 +512,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);
|
|
@@ -518,6 +534,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));
|
|
|
}
|
|
|
}
|
|
|
|