diff --git a/core/cpu.c b/core/cpu.c
index 2cafa4301..98f5a7202 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -377,57 +377,21 @@ enum cpu_wake_cause {
 static unsigned int cpu_idle_p8(enum cpu_wake_cause wake_on)
 {
 	uint64_t lpcr = mfspr(SPR_LPCR) & ~SPR_LPCR_P8_PECE;
-	struct cpu_thread *cpu = this_cpu();
-	unsigned int vec = 0;
-
-	if (!pm_enabled) {
-		prlog_once(PR_DEBUG, "cpu_idle_p8 called pm disabled\n");
-		return vec;
-	}
+	unsigned int vec;
 
 	/* Clean up ICP, be ready for IPIs */
 	icp_prep_for_pm();
 
-	/* Synchronize with wakers */
-	if (wake_on == cpu_wake_on_job) {
-		/* Mark ourselves in idle so other CPUs know to send an IPI */
-		cpu->in_sleep = true;
-		cpu->in_job_sleep = true;
-		sync();
-
-		/* Check for jobs again */
-		if (cpu_check_jobs(cpu) || reconfigure_idle)
-			goto skip_sleep;
-
-		/* Setup wakup cause in LPCR: EE (for IPI) */
-		lpcr |= SPR_LPCR_P8_PECE2;
-		mtspr(SPR_LPCR, lpcr);
-
-	} else {
-		/* Mark outselves sleeping so cpu_set_pm_enable knows to
-		 * send an IPI
-		 */
-		cpu->in_sleep = true;
-		sync();
-
-		/* Check if PM got disabled */
-		if (reconfigure_idle)
-			goto skip_sleep;
-
-		/* EE and DEC */
-		lpcr |= SPR_LPCR_P8_PECE2 | SPR_LPCR_P8_PECE3;
-		mtspr(SPR_LPCR, lpcr);
-	}
+	/* Setup wakup cause in LPCR: EE (for IPI) */
+	lpcr |= SPR_LPCR_P8_PECE2;
+	if (wake_on == cpu_wake_on_dec)
+		lpcr |= SPR_LPCR_P8_PECE3; /* DEC */
+	mtspr(SPR_LPCR, lpcr);
 	isync();
 
 	/* Enter nap */
 	vec = enter_p8_pm_state(false);
 
-skip_sleep:
-	/* Restore */
-	sync();
-	cpu->in_sleep = false;
-	cpu->in_job_sleep = false;
 	reset_cpu_icp();
 
 	return vec;
@@ -437,42 +401,11 @@ static unsigned int cpu_idle_p9(enum cpu_wake_cause wake_on)
 {
 	uint64_t lpcr = mfspr(SPR_LPCR) & ~SPR_LPCR_P9_PECE;
 	uint64_t psscr;
-	struct cpu_thread *cpu = this_cpu();
-	unsigned int vec = 0;
-
-	if (!pm_enabled) {
-		prlog(PR_DEBUG, "cpu_idle_p9 called on cpu 0x%04x with pm disabled\n", cpu->pir);
-		return vec;
-	}
-
-	/* Synchronize with wakers */
-	if (wake_on == cpu_wake_on_job) {
-		/* Mark ourselves in idle so other CPUs know to send an IPI */
-		cpu->in_sleep = true;
-		cpu->in_job_sleep = true;
-		sync();
-
-		/* Check for jobs again */
-		if (cpu_check_jobs(cpu) || reconfigure_idle)
-			goto skip_sleep;
-
-		/* HV DBELL for IPI */
-		lpcr |= SPR_LPCR_P9_PECEL1;
-	} else {
-		/* Mark outselves sleeping so cpu_set_pm_enable knows to
-		 * send an IPI
-		 */
-		cpu->in_sleep = true;
-		sync();
-
-		/* Check if PM got disabled */
-		if (reconfigure_idle)
-			goto skip_sleep;
-
-		/* HV DBELL and DEC */
-		lpcr |= SPR_LPCR_P9_PECEL1 | SPR_LPCR_P9_PECEL3;
-	}
+	unsigned int vec;
 
+	lpcr |= SPR_LPCR_P9_PECEL1; /* HV DBELL for IPI */
+	if (wake_on == cpu_wake_on_dec)
+		lpcr |= SPR_LPCR_P9_PECEL3; /* DEC */
 	mtspr(SPR_LPCR, lpcr);
 	isync();
 
@@ -487,39 +420,46 @@ static unsigned int cpu_idle_p9(enum cpu_wake_cause wake_on)
 		/* PSSCR SD=0 ESL=0 EC=0 PSSL=0 TR=3 MTL=0 RL=1 */
 		psscr = PPC_BITMASK(54, 55) | PPC_BIT(63);
 		enter_p9_pm_lite_state(psscr);
+		vec = 0;
 	}
 
 	/* Clear doorbell */
 	p9_dbell_receive();
 
- skip_sleep:
-	/* Restore */
-	sync();
-	cpu->in_sleep = false;
-	cpu->in_job_sleep = false;
-
 	return vec;
 }
 
 static void cpu_idle_pm(enum cpu_wake_cause wake_on)
 {
+	struct cpu_thread *cpu = this_cpu();
 	unsigned int vec;
 
-	switch(proc_gen) {
-	case proc_gen_p8:
+	if (!pm_enabled) {
+		prlog_once(PR_DEBUG, "cpu_idle_pm called pm disabled\n");
+		return;
+	}
+
+	/*
+	 * Mark ourselves in sleep so other CPUs know to send an IPI,
+	 * then re-check the wake conditions. This is ordered against
+	 * queue_job_on_cpu() and reconfigure_idle_start() which first
+	 * set the wake conditions (either queue a job or set
+	 * reconfigure_idle = true), issue a sync(), then test if the
+	 * target is in_sleep / in_job_sleep.
+	 */
+	cpu->in_sleep = true;
+	if (wake_on == cpu_wake_on_job)
+		cpu->in_job_sleep = true;
+	sync();
+	if (reconfigure_idle)
+		goto skip_sleep;
+	if (wake_on == cpu_wake_on_job && cpu_check_jobs(cpu))
+		goto skip_sleep;
+
+	if (proc_gen == proc_gen_p8)
 		vec = cpu_idle_p8(wake_on);
-		break;
-	case proc_gen_p9:
-		vec = cpu_idle_p9(wake_on);
-		break;
-	case proc_gen_p10:
+	else
 		vec = cpu_idle_p9(wake_on);
-		break;
-	default:
-		vec = 0;
-		prlog_once(PR_DEBUG, "cpu_idle_pm called with bad processor type\n");
-		break;
-	}
 
 	if (vec == 0x100) {
 		unsigned long srr1 = mfspr(SPR_SRR1);
@@ -538,6 +478,12 @@ static void cpu_idle_pm(enum cpu_wake_cause wake_on)
 		enable_machine_check();
 		mtmsrd(MSR_RI, 1);
 	}
+
+skip_sleep:
+	sync();
+	cpu->in_sleep = false;
+	if (wake_on == cpu_wake_on_job)
+		cpu->in_job_sleep = false;
 }
 
 static struct lock idle_lock = LOCK_UNLOCKED;
