forked from Minki/linux
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: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
2201f994a5
commit
2525db04d1
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user