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
|
* pnv_cpu_offline: A function that puts the CPU into the deepest
|
||||||
* available platform idle state on a CPU-Offline.
|
* 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 pnv_cpu_offline(unsigned int cpu)
|
||||||
{
|
{
|
||||||
unsigned long srr1;
|
unsigned long srr1;
|
||||||
|
|
||||||
u32 idle_states = pnv_get_supported_cpuidle_states();
|
u32 idle_states = pnv_get_supported_cpuidle_states();
|
||||||
|
|
||||||
|
ppc64_runlatch_off();
|
||||||
|
|
||||||
if (cpu_has_feature(CPU_FTR_ARCH_300) && deepest_stop_found) {
|
if (cpu_has_feature(CPU_FTR_ARCH_300) && deepest_stop_found) {
|
||||||
srr1 = __power9_idle_type(pnv_deepest_stop_psscr_val,
|
unsigned long psscr;
|
||||||
pnv_deepest_stop_psscr_mask);
|
|
||||||
|
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) {
|
} 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) ||
|
} else if ((idle_states & OPAL_PM_SLEEP_ENABLED) ||
|
||||||
(idle_states & OPAL_PM_SLEEP_ENABLED_ER1)) {
|
(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) {
|
} else if (idle_states & OPAL_PM_NAP_ENABLED) {
|
||||||
srr1 = __power7_idle_type(PNV_THREAD_NAP);
|
srr1 = power7_idle_insn(PNV_THREAD_NAP);
|
||||||
} else {
|
} else {
|
||||||
ppc64_runlatch_off();
|
|
||||||
/* This is the fallback method. We emulate snooze */
|
/* This is the fallback method. We emulate snooze */
|
||||||
while (!generic_check_cpu_restart(cpu)) {
|
while (!generic_check_cpu_restart(cpu)) {
|
||||||
HMT_low();
|
HMT_low();
|
||||||
|
@ -378,9 +384,10 @@ unsigned long pnv_cpu_offline(unsigned int cpu)
|
||||||
}
|
}
|
||||||
srr1 = 0;
|
srr1 = 0;
|
||||||
HMT_medium();
|
HMT_medium();
|
||||||
ppc64_runlatch_on();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ppc64_runlatch_on();
|
||||||
|
|
||||||
return srr1;
|
return srr1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -144,7 +144,14 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
unsigned long srr1, wmask;
|
unsigned long srr1, wmask;
|
||||||
|
|
||||||
/* Standard hot unplug procedure */
|
/* 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();
|
idle_task_exit();
|
||||||
current->active_mm = NULL; /* for sanity */
|
current->active_mm = NULL; /* for sanity */
|
||||||
cpu = smp_processor_id();
|
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);
|
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)) {
|
while (!generic_check_cpu_restart(cpu)) {
|
||||||
/*
|
/*
|
||||||
* Clear IPI flag, since we don't handle IPIs while
|
* 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);
|
srr1 = pnv_cpu_offline(cpu);
|
||||||
|
|
||||||
|
WARN_ON(lazy_irq_pending());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the SRR1 value indicates that we woke up due to
|
* If the SRR1 value indicates that we woke up due to
|
||||||
* an external interrupt, then clear the interrupt.
|
* an external interrupt, then clear the interrupt.
|
||||||
|
@ -196,8 +195,7 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
* contains 0.
|
* contains 0.
|
||||||
*/
|
*/
|
||||||
if (((srr1 & wmask) == SRR1_WAKEEE) ||
|
if (((srr1 & wmask) == SRR1_WAKEEE) ||
|
||||||
((srr1 & wmask) == SRR1_WAKEHVI) ||
|
((srr1 & wmask) == SRR1_WAKEHVI)) {
|
||||||
(local_paca->irq_happened & PACA_IRQ_EE)) {
|
|
||||||
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
|
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
|
||||||
if (xive_enabled())
|
if (xive_enabled())
|
||||||
xive_flush_interrupt();
|
xive_flush_interrupt();
|
||||||
|
@ -209,14 +207,15 @@ static void pnv_smp_cpu_kill_self(void)
|
||||||
unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
|
unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
|
||||||
asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
|
asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
|
||||||
}
|
}
|
||||||
local_paca->irq_happened &= ~(PACA_IRQ_EE | PACA_IRQ_DBELL);
|
|
||||||
smp_mb();
|
smp_mb();
|
||||||
|
|
||||||
if (cpu_core_split_required())
|
if (cpu_core_split_required())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (srr1 && !generic_check_cpu_restart(cpu))
|
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 */
|
/* Re-enable decrementer interrupts */
|
||||||
|
|
Loading…
Reference in New Issue