spapr: Clean up handling of LPCR power-saving exit bits

To prevent spurious wakeups on cpus that are supposed to be disabled, we
need to clear the LPCR bits which control certain wakeup events.
spapr_cpu_reset() has separate cases here for boot and non-boot (initially
inactive) cpus.  rtas_start_cpu() then turns the LPCR bits on when the
non-boot cpus are activated.

But explicit checks against first_cpu are not how we usually do things:
instead spapr_cpu_reset() generally sets things up for non-boot (inactive)
cpus, then spapr_machine_reset() and/or rtas_start_cpu() override as
necessary.

So, do that instead.  Because the LPCR activation is identical for boot
cpus and non-boot cpus just activated with rtas_start_cpu() we can put the
code common in spapr_cpu_set_entry_state().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Tested-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
David Gibson 2018-04-05 16:27:18 +10:00
parent da20aed12a
commit 47a9b55154
2 changed files with 8 additions and 16 deletions

View File

@ -54,28 +54,17 @@ static void spapr_cpu_reset(void *opaque)
* Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
* real mode accesses, which thankfully defaults to 0 and isn't
* accessible in guest mode.
*
* Disable Power-saving mode Exit Cause exceptions for the CPU, so
* we don't get spurious wakups before an RTAS start-cpu call.
*/
lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV);
lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
lpcr |= LPCR_LPES0 | LPCR_LPES1;
/* Set RMLS to the max (ie, 16G) */
lpcr &= ~LPCR_RMLS;
lpcr |= 1ull << LPCR_RMLS_SHIFT;
/* Only enable Power-saving mode Exit Cause exceptions on the boot
* CPU. The RTAS command start-cpu will enable them on secondaries.
*/
if (cs == first_cpu) {
lpcr |= pcc->lpcr_pm;
}
/* Disable Power-saving mode Exit Cause exceptions for the CPU.
* This can cause issues when rebooting the guest if a secondary
* is awaken */
if (cs != first_cpu) {
lpcr &= ~pcc->lpcr_pm;
}
ppc_store_lpcr(cpu, lpcr);
/* Set a full AMOR so guest can use the AMR as it sees fit */
@ -84,11 +73,14 @@ static void spapr_cpu_reset(void *opaque)
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
env->nip = nip;
env->gpr[3] = r3;
CPU(cpu)->halted = 0;
/* Enable Power-saving mode Exit Cause exceptions */
ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
}
static void spapr_cpu_destroy(PowerPCCPU *cpu)

View File

@ -162,7 +162,7 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr,
env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
/* Enable Power-saving mode Exit Cause exceptions for the new CPU */
lpcr = env->spr[SPR_LPCR] | pcc->lpcr_pm;
lpcr = env->spr[SPR_LPCR];
if (!pcc->interrupts_big_endian(callcpu)) {
lpcr |= LPCR_ILE;
}