Skip to content

Commit 78adf6c

Browse files
npigginmpe
authored andcommitted
powerpc/64s: Implement system reset idle wakeup reason
It is possible to wake from idle due to a system reset exception, in which case the CPU takes a system reset interrupt to wake from idle, with system reset as the wakeup reason. The regular (not idle wakeup) system reset interrupt handler must be invoked in this case, otherwise the system reset interrupt is lost. Handle the system reset interrupt immediately after CPU state has been restored. Signed-off-by: Nicholas Piggin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 064996d commit 78adf6c

File tree

1 file changed

+38
-3
lines changed

1 file changed

+38
-3
lines changed

arch/powerpc/kernel/irq.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,19 @@ bool prep_irq_for_idle_irqsoff(void)
394394
/*
395395
* Take the SRR1 wakeup reason, index into this table to find the
396396
* appropriate irq_happened bit.
397+
*
398+
* Sytem reset exceptions taken in idle state also come through here,
399+
* but they are NMI interrupts so do not need to wait for IRQs to be
400+
* restored, and should be taken as early as practical. These are marked
401+
* with 0xff in the table. The Power ISA specifies 0100b as the system
402+
* reset interrupt reason.
397403
*/
404+
#define IRQ_SYSTEM_RESET 0xff
405+
398406
static const u8 srr1_to_lazyirq[0x10] = {
399407
0, 0, 0,
400408
PACA_IRQ_DBELL,
401-
0,
409+
IRQ_SYSTEM_RESET,
402410
PACA_IRQ_DBELL,
403411
PACA_IRQ_DEC,
404412
0,
@@ -407,15 +415,42 @@ static const u8 srr1_to_lazyirq[0x10] = {
407415
PACA_IRQ_HMI,
408416
0, 0, 0, 0, 0 };
409417

418+
static noinline void replay_system_reset(void)
419+
{
420+
struct pt_regs regs;
421+
422+
ppc_save_regs(&regs);
423+
regs.trap = 0x100;
424+
get_paca()->in_nmi = 1;
425+
system_reset_exception(&regs);
426+
get_paca()->in_nmi = 0;
427+
}
428+
410429
void irq_set_pending_from_srr1(unsigned long srr1)
411430
{
412431
unsigned int idx = (srr1 & SRR1_WAKEMASK_P8) >> 18;
432+
u8 reason = srr1_to_lazyirq[idx];
433+
434+
/*
435+
* Take the system reset now, which is immediately after registers
436+
* are restored from idle. It's an NMI, so interrupts need not be
437+
* re-enabled before it is taken.
438+
*/
439+
if (unlikely(reason == IRQ_SYSTEM_RESET)) {
440+
replay_system_reset();
441+
return;
442+
}
413443

414444
/*
415445
* The 0 index (SRR1[42:45]=b0000) must always evaluate to 0,
416-
* so this can be called unconditionally with srr1 wake reason.
446+
* so this can be called unconditionally with the SRR1 wake
447+
* reason as returned by the idle code, which uses 0 to mean no
448+
* interrupt.
449+
*
450+
* If a future CPU was to designate this as an interrupt reason,
451+
* then a new index for no interrupt must be assigned.
417452
*/
418-
local_paca->irq_happened |= srr1_to_lazyirq[idx];
453+
local_paca->irq_happened |= reason;
419454
}
420455
#endif /* CONFIG_PPC_BOOK3S */
421456

0 commit comments

Comments
 (0)