diff options
-rw-r--r-- | arch/powerpc/include/asm/hw_irq.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 29 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/idle.c | 10 |
3 files changed, 38 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index f06112cf8734..c1dd1929342d 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -130,6 +130,7 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs) extern bool prep_irq_for_idle(void); extern bool prep_irq_for_idle_irqsoff(void); +extern void irq_set_pending_from_srr1(unsigned long srr1); #define fini_irq_for_idle_irqsoff() trace_hardirqs_off(); diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 58dcac88bc79..0bcec745a672 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -348,6 +348,7 @@ bool prep_irq_for_idle(void) return true; } +#ifdef CONFIG_PPC_BOOK3S /* * This is for idle sequences that return with IRQs off, but the * idle state itself wakes on interrupt. Tell the irq tracer that @@ -379,6 +380,34 @@ bool prep_irq_for_idle_irqsoff(void) } /* + * Take the SRR1 wakeup reason, index into this table to find the + * appropriate irq_happened bit. + */ +static const u8 srr1_to_lazyirq[0x10] = { + 0, 0, 0, + PACA_IRQ_DBELL, + 0, + PACA_IRQ_DBELL, + PACA_IRQ_DEC, + 0, + PACA_IRQ_EE, + PACA_IRQ_EE, + PACA_IRQ_HMI, + 0, 0, 0, 0, 0 }; + +void irq_set_pending_from_srr1(unsigned long srr1) +{ + unsigned int idx = (srr1 & SRR1_WAKEMASK_P8) >> 18; + + /* + * The 0 index (SRR1[42:45]=b0000) must always evaluate to 0, + * so this can be called unconditionally with srr1 wake reason. + */ + local_paca->irq_happened |= srr1_to_lazyirq[idx]; +} +#endif /* CONFIG_PPC_BOOK3S */ + +/* * Force a replay of the external interrupt handler on this CPU. */ void force_external_irq_replay(void) diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c index f188d84d9c59..1028df82cd2f 100644 --- a/arch/powerpc/platforms/powernv/idle.c +++ b/arch/powerpc/platforms/powernv/idle.c @@ -302,7 +302,10 @@ static unsigned long __power7_idle_type(unsigned long type) void power7_idle_type(unsigned long type) { - __power7_idle_type(type); + unsigned long srr1; + + srr1 = __power7_idle_type(type); + irq_set_pending_from_srr1(srr1); } void power7_idle(void) @@ -337,7 +340,10 @@ static unsigned long __power9_idle_type(unsigned long stop_psscr_val, void power9_idle_type(unsigned long stop_psscr_val, unsigned long stop_psscr_mask) { - __power9_idle_type(stop_psscr_val, stop_psscr_mask); + unsigned long srr1; + + srr1 = __power9_idle_type(stop_psscr_val, stop_psscr_mask); + irq_set_pending_from_srr1(srr1); } /* |