Patchwork powerpc: Fix missing doorbell IPIs during nap power saving

login
register
mail settings
Submitter Ian Munsie
Date April 29, 2013, 8:17 a.m.
Message ID <1367223460-4931-1-git-send-email-imunsie@au1.ibm.com>
Download mbox | patch
Permalink /patch/240338/
State Not Applicable
Headers show

Comments

Ian Munsie - April 29, 2013, 8:17 a.m.
From: Ian Munsie <imunsie@au1.ibm.com>

If a doorbell IPI comes in while a thread is in nap power saving, the
doorbell interrupt won't be replayed by the hardware since it is edge
sensitive. Currently we are not replaying these interrupts in software,
which can cause threads to miss IPIs that come in during power saving
and eventually will result in an RCU warning from rcu_sched that it has
detected a stalled CPU.

This patch fixes the issue by testing if a doorbell caused the thread to
come out of power saving and sets the corresponding bit in the paca to
indicate a doorbell happened, which will then be handled by the existing
interrupt replay code.

This is not an issue with other interrupts that can wake a thread
(external, decrementer) as they are level sensitive and will continue to
be asserted by the hardware.

Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
---
 arch/powerpc/include/asm/reg.h    |    5 ++++-
 arch/powerpc/kernel/idle_power7.S |   23 +++++++++++++++++++----
 2 files changed, 23 insertions(+), 5 deletions(-)
Benjamin Herrenschmidt - April 29, 2013, 9:05 a.m.
On Mon, 2013-04-29 at 18:17 +1000, Ian Munsie wrote:
> This is not an issue with other interrupts that can wake a thread
> (external, decrementer) as they are level sensitive and will continue to
> be asserted by the hardware.

However, it might be worth experimenting setting the corresponding
bits in the PACA as well, as this will diminish the latency of
processing them.

IE. local_irq_enable() will see the bit, generate an interrupt
frame and call the handler which is a faster path than re-enabling
MSR:EE and then taking an external interrupt.

Cheers,
Ben.
Greg KH - April 29, 2013, 2:06 p.m.
On Mon, Apr 29, 2013 at 06:17:40PM +1000, Ian Munsie wrote:
> From: Ian Munsie <imunsie@au1.ibm.com>
> 
> If a doorbell IPI comes in while a thread is in nap power saving, the
> doorbell interrupt won't be replayed by the hardware since it is edge
> sensitive. Currently we are not replaying these interrupts in software,
> which can cause threads to miss IPIs that come in during power saving
> and eventually will result in an RCU warning from rcu_sched that it has
> detected a stalled CPU.
> 
> This patch fixes the issue by testing if a doorbell caused the thread to
> come out of power saving and sets the corresponding bit in the paca to
> indicate a doorbell happened, which will then be handled by the existing
> interrupt replay code.
> 
> This is not an issue with other interrupts that can wake a thread
> (external, decrementer) as they are level sensitive and will continue to
> be asserted by the hardware.
> 
> Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>


<formletter>

This is not the correct way to submit patches for inclusion in the
stable kernel tree.  Please read Documentation/stable_kernel_rules.txt
for how to do this properly.

</formletter>

Patch

diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 5c6fbe2..dd8a071 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -549,14 +549,17 @@ 
 #define   SRR1_ISI_NOPT		0x40000000 /* ISI: Not found in hash */
 #define   SRR1_ISI_N_OR_G	0x10000000 /* ISI: Access is no-exec or G */
 #define   SRR1_ISI_PROT		0x08000000 /* ISI: Other protection fault */
-#define   SRR1_WAKEMASK		0x00380000 /* reason for wakeup */
+#define   SRR1_WAKEMASK		0x003c0000 /* reason for wakeup [42:45] */
+#define   SRR1_WAKESHIFT	18
 #define   SRR1_WAKESYSERR	0x00300000 /* System error */
 #define   SRR1_WAKEEE		0x00200000 /* External interrupt */
 #define   SRR1_WAKEMT		0x00280000 /* mtctrl */
 #define	  SRR1_WAKEHMI		0x00280000 /* Hypervisor maintenance */
 #define   SRR1_WAKEDEC		0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKEDBELLP	0x00140000 /* Privileged Doorbell */
 #define   SRR1_WAKETHERM	0x00100000 /* Thermal management interrupt */
 #define	  SRR1_WAKERESET	0x00100000 /* System reset */
+#define   SRR1_WAKEDBELLH	0x000c0000 /* Hypervisor Doorbell */
 #define	  SRR1_WAKESTATE	0x00030000 /* Powersave exit mask [46:47] */
 #define	  SRR1_WS_DEEPEST	0x00030000 /* Some resources not maintained,
 					  * may not be recoverable */
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index e11863f..c80bb4b 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -108,9 +108,7 @@  _GLOBAL(power7_wakeup_loss)
 	ld	r5,_NIP(r1)
 	addi	r1,r1,INT_FRAME_SIZE
 	mtcr	r3
-	mtspr	SPRN_SRR1,r4
-	mtspr	SPRN_SRR0,r5
-	rfid
+	b	power7_wakeup_common
 
 _GLOBAL(power7_wakeup_noloss)
 	lbz	r0,PACA_NAPSTATELOST(r13)
@@ -120,6 +118,23 @@  _GLOBAL(power7_wakeup_noloss)
 	ld	r4,_MSR(r1)
 	ld	r5,_NIP(r1)
 	addi	r1,r1,INT_FRAME_SIZE
-	mtspr	SPRN_SRR1,r4
+	/* Fall through */
+
+power7_wakeup_common:
+BEGIN_FTR_SECTION
+	mfspr	r3,SPRN_SRR1
+	extrdi	r3,r3,4,42 /* Extract SRR1_WAKEMASK */
+	cmpwi	r3,SRR1_WAKEDBELLH >> SRR1_WAKESHIFT
+	beq	1f
+	cmpwi	r3,SRR1_WAKEDBELLP >> SRR1_WAKESHIFT
+	bne	2f
+
+1:	/* Woken by a doorbell, set doorbell happened in paca */
+	lbz	r3,PACAIRQHAPPENED(r13)
+	ori	r3,r3,PACA_IRQ_DBELL
+	stb	r3,PACAIRQHAPPENED(r13)
+END_FTR_SECTION_IFSET(CPU_FTR_DBELL)
+
+2:	mtspr   SPRN_SRR1,r4
 	mtspr	SPRN_SRR0,r5
 	rfid