aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-04-02 00:58:40 -0400
committerPaul Mackerras <paulus@samba.org>2008-04-03 07:10:34 -0400
commitff3da2e0938bae36d10d69c22bce0177b067a9e2 (patch)
tree4df635b6bc9298fbf455ab2be23aaec04324c3f0
parent025306f30948836a743eb68a7cbaf4ab0bfb5f47 (diff)
[POWERPC] Fix iSeries hard irq enabling regression
A subtle bug sneaked into iSeries recently. On this platform, we must not normally clear MSR:EE (the hardware external interrupt enable) except for short periods of time. Taking an interrupt while soft-disabled doesn't cause us to clear it for example. The iSeries kernel expects to mostly run with MSR:EE enabled at all times except in a few exception entry/exit code paths. Thus local_irq_enable() doesn't check if it needs to hard-enable as it expects this to be unnecessary on iSeries. However, hard_irq_disable() _does_ cause MSR:EE to be cleared, including on iSeries. A call to it was recently added to the context switch code, thus causing interrupts to become disabled for a long periods of time, causing the iSeries watchdog to kick in under some circumstances and other nasty things. This patch fixes it by making local_irq_enable() properly re-enable MSR:EE on iSeries. It basically removes a return statement here to make iSeries use the same code path as everybody else. That does mean that we might occasionally get spurious decrementer interrupts but I don't think that matters. Another option would have been to make hard_irq_disable() a nop on iSeries but I didn't like it much, in case we have good reasons to hard-disable. Part of the patch is fixes to make sure the hard_enabled PACA field is properly set on iSeries as it used not to be before, since it was mostly unused. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/head_64.S13
-rw-r--r--arch/powerpc/kernel/irq.c1
2 files changed, 7 insertions, 7 deletions
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 11b4f6d9ffce..d3aee08e6814 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -1387,12 +1387,14 @@ __secondary_start:
1387#ifdef CONFIG_PPC_ISERIES 1387#ifdef CONFIG_PPC_ISERIES
1388BEGIN_FW_FTR_SECTION 1388BEGIN_FW_FTR_SECTION
1389 ori r4,r4,MSR_EE 1389 ori r4,r4,MSR_EE
1390 li r8,1
1391 stb r8,PACAHARDIRQEN(r13)
1390END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 1392END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
1391#endif 1393#endif
1392BEGIN_FW_FTR_SECTION 1394BEGIN_FW_FTR_SECTION
1393 stb r7,PACASOFTIRQEN(r13)
1394 stb r7,PACAHARDIRQEN(r13) 1395 stb r7,PACAHARDIRQEN(r13)
1395END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) 1396END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
1397 stb r7,PACASOFTIRQEN(r13)
1396 1398
1397 mtspr SPRN_SRR0,r3 1399 mtspr SPRN_SRR0,r3
1398 mtspr SPRN_SRR1,r4 1400 mtspr SPRN_SRR1,r4
@@ -1520,15 +1522,14 @@ _INIT_GLOBAL(start_here_common)
1520#ifdef CONFIG_PPC_ISERIES 1522#ifdef CONFIG_PPC_ISERIES
1521BEGIN_FW_FTR_SECTION 1523BEGIN_FW_FTR_SECTION
1522 mfmsr r5 1524 mfmsr r5
1523 ori r5,r5,MSR_EE /* Hard Enabled */ 1525 ori r5,r5,MSR_EE /* Hard Enabled on iSeries*/
1524 mtmsrd r5 1526 mtmsrd r5
1527 li r5,1
1525END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 1528END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
1526#endif 1529#endif
1527BEGIN_FW_FTR_SECTION 1530 stb r5,PACAHARDIRQEN(r13) /* Hard Disabled on others */
1528 stb r5,PACAHARDIRQEN(r13)
1529END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
1530 1531
1531 bl .start_kernel 1532 bl .start_kernel
1532 1533
1533 /* Not reached */ 1534 /* Not reached */
1534 BUG_OPCODE 1535 BUG_OPCODE
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index b0e5deb4274f..292163f5b39a 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -143,7 +143,6 @@ void local_irq_restore(unsigned long en)
143 */ 143 */
144 if (local_paca->lppaca_ptr->int_dword.any_int) 144 if (local_paca->lppaca_ptr->int_dword.any_int)
145 iseries_handle_interrupts(); 145 iseries_handle_interrupts();
146 return;
147 } 146 }
148 147
149 /* 148 /*