Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2525db04 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/powernv: Simplify lazy IRQ handling in CPU offline



Rather than concern ourselves with any soft-mask logic in the CPU
hotplug handler, just hard disable interrupts. This ensures there
are no lazy-irqs pending, which means we can call directly to idle
instruction in order to sleep.

Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 2201f994
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -352,25 +352,31 @@ void power9_idle(void)
/*
 * pnv_cpu_offline: A function that puts the CPU into the deepest
 * available platform idle state on a CPU-Offline.
 * interrupts hard disabled and no lazy irq pending.
 */
unsigned long pnv_cpu_offline(unsigned int cpu)
{
	unsigned long srr1;

	u32 idle_states = pnv_get_supported_cpuidle_states();

	ppc64_runlatch_off();

	if (cpu_has_feature(CPU_FTR_ARCH_300) && deepest_stop_found) {
		srr1 = __power9_idle_type(pnv_deepest_stop_psscr_val,
					pnv_deepest_stop_psscr_mask);
		unsigned long psscr;

		psscr = mfspr(SPRN_PSSCR);
		psscr = (psscr & ~pnv_deepest_stop_psscr_mask) |
						pnv_deepest_stop_psscr_val;
		srr1 = power9_idle_stop(psscr);

	} else if (idle_states & OPAL_PM_WINKLE_ENABLED) {
		srr1 = __power7_idle_type(PNV_THREAD_WINKLE);
		srr1 = power7_idle_insn(PNV_THREAD_WINKLE);
	} else if ((idle_states & OPAL_PM_SLEEP_ENABLED) ||
		   (idle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
		srr1 = __power7_idle_type(PNV_THREAD_SLEEP);
		srr1 = power7_idle_insn(PNV_THREAD_SLEEP);
	} else if (idle_states & OPAL_PM_NAP_ENABLED) {
		srr1 = __power7_idle_type(PNV_THREAD_NAP);
		srr1 = power7_idle_insn(PNV_THREAD_NAP);
	} else {
		ppc64_runlatch_off();
		/* This is the fallback method. We emulate snooze */
		while (!generic_check_cpu_restart(cpu)) {
			HMT_low();
@@ -378,9 +384,10 @@ unsigned long pnv_cpu_offline(unsigned int cpu)
		}
		srr1 = 0;
		HMT_medium();
		ppc64_runlatch_on();
	}

	ppc64_runlatch_on();

	return srr1;
}
#endif
+14 −15
Original line number Diff line number Diff line
@@ -144,7 +144,14 @@ static void pnv_smp_cpu_kill_self(void)
	unsigned long srr1, wmask;

	/* Standard hot unplug procedure */
	local_irq_disable();
	/*
	 * This hard disables local interurpts, ensuring we have no lazy
	 * irqs pending.
	 */
	WARN_ON(irqs_disabled());
	hard_irq_disable();
	WARN_ON(lazy_irq_pending());

	idle_task_exit();
	current->active_mm = NULL; /* for sanity */
	cpu = smp_processor_id();
@@ -162,16 +169,6 @@ static void pnv_smp_cpu_kill_self(void)
	 */
	mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);

	/*
	 * Hard-disable interrupts, and then clear irq_happened flags
	 * that we can safely ignore while off-line, since they
	 * are for things for which we do no processing when off-line
	 * (or in the case of HMI, all the processing we need to do
	 * is done in lower-level real-mode code).
	 */
	hard_irq_disable();
	local_paca->irq_happened &= ~(PACA_IRQ_DEC | PACA_IRQ_HMI);

	while (!generic_check_cpu_restart(cpu)) {
		/*
		 * Clear IPI flag, since we don't handle IPIs while
@@ -184,6 +181,8 @@ static void pnv_smp_cpu_kill_self(void)

		srr1 = pnv_cpu_offline(cpu);

		WARN_ON(lazy_irq_pending());

		/*
		 * If the SRR1 value indicates that we woke up due to
		 * an external interrupt, then clear the interrupt.
@@ -196,8 +195,7 @@ static void pnv_smp_cpu_kill_self(void)
		 * contains 0.
		 */
		if (((srr1 & wmask) == SRR1_WAKEEE) ||
		    ((srr1 & wmask) == SRR1_WAKEHVI) ||
		    (local_paca->irq_happened & PACA_IRQ_EE)) {
		    ((srr1 & wmask) == SRR1_WAKEHVI)) {
			if (cpu_has_feature(CPU_FTR_ARCH_300)) {
				if (xive_enabled())
					xive_flush_interrupt();
@@ -209,14 +207,15 @@ static void pnv_smp_cpu_kill_self(void)
			unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
			asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
		}
		local_paca->irq_happened &= ~(PACA_IRQ_EE | PACA_IRQ_DBELL);
		smp_mb();

		if (cpu_core_split_required())
			continue;

		if (srr1 && !generic_check_cpu_restart(cpu))
			DBG("CPU%d Unexpected exit while offline !\n", cpu);
			DBG("CPU%d Unexpected exit while offline srr1=%lx!\n",
					cpu, srr1);

	}

	/* Re-enable decrementer interrupts */