Skip to contentSkip to conversation

powerpc: Rework lazy-interrupt handling

PATCH Superseded Benjamin Herrenschmidt 2 participants 3 messages Feb 9, 2012 PowerPC

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 powerpc: Rework lazy-interrupt handling

Quoted 1 line

From 0ace17ba6960a8788b1bda3770df254cbbc6a244 Mon Sep 17 00:00:00 2001

From: Benjamin Herrenschmidt <[email protected]>
Date: Thu, 9 Feb 2012 15:25:04 +1100
Subject: [PATCH] powerpc: Rework lazy-interrupt handling

The current implementation of lazy interrupts handling has some issues that this tries to address.

Except on iSeries, we don't do the various workarounds we need to do on re-enable when returning from an interrupt, which can do an implicit re-enable, and thus we may still lose or get delayed decrementer or doorbell interrupts.

The current scheme also makes it much harder to handle the external "edge" interrupts provided by some BookE processors when using the EPR facility (External Proxy) and the Freescale Hypervisor.

We also hard mask on decrementer interrupts which is sub-optimal.

This is an attempt at fixing it all in one go by reworking the way we do the lazy interrupt disabling.

The base idea is to replace the "hard_enabled" field with a "irq_happened" field in which we store a bit mask of what interrupt occurred while soft-disabled.

When re-enabling, either via arch_local_irq_restore() or when returning from an interrupt, we can now decide what to do by testing bits in that field. We then implement re-emitting of the lost interrupts via either a re-use of the existing exception frame (exception exit case) or via the creation of a new one from assembly code (arch_local_irq_enable), without the need to trigger a fake one using set_dec() or similar.

In addition, this adds a few refinements:

- We no longer hard disable decrementer interrupts that occur
while soft-disabled. We now simply bump the decrementer back to max (on BookS) or leave it stopped (on BookE) and continue with hard interrupts enabled, which means that we'll potentially get better sample quality from performance monitor interrupts.

- Timer, decrementer and doorbell interrupts now hard-enable
shortly after removing the source of the interrupt, which means they no longer run entirely hard disabled. Again, this will improve perf sample quality.

- On Book3E 64-bit, we now make the performance monitor interrupt
act as an NMI like Book3S (the necessary C code for that to work appear to already be present in the FSL perf code, notably calling nmi_enter instead of irq_enter).

There are additional refinements that we can do on top of this patch:

- We could remove the ps3 workaround from arch_local_irq_enable(),
I believe that it should no longer be necessary

- We could make "masked" decrementer interrupts act as NMIs when doing
timer-based perf sampling to improve the sample quality.

- There are additional simplifications of the exception entry/exit path
that I've spotted along the way, such as merging fast_exception_return with the normal code path.

This patch needs a LOT more testing & review than it had so far !!!

Not-signed-off-by-yet: Benjamin Herrenschmidt <[email protected]>
---

v2:

- Add hard-enable to decrementer, timer and doorbells
- Fix CR clobber in masked irq handling on BookE
- Make embedded perf interrupt act as an NMI
- Add a PACA_HAPPENED_EE_EDGE for use by FSL if they want to retrigger an interrupt without preventing hard-enable

---
 arch/powerpc/include/asm/exception-64s.h        |   21 ++-
 arch/powerpc/include/asm/hw_irq.h               |   51 +++++-
 arch/powerpc/include/asm/irqflags.h             |   13 +-
 arch/powerpc/include/asm/paca.h                 |    2 +-
 arch/powerpc/kernel/asm-offsets.c               |    2 +-
 arch/powerpc/kernel/dbell.c                     |   12 ++
 arch/powerpc/kernel/entry_64.S                  |   96 ++++++-----
 arch/powerpc/kernel/exceptions-64e.S            |  210 ++++++++++++++++-------
 arch/powerpc/kernel/exceptions-64s.S            |   90 ++++++----
 arch/powerpc/kernel/head_64.S                   |    9 -
 arch/powerpc/kernel/idle_book3e.S               |    8 +-
 arch/powerpc/kernel/idle_power4.S               |   17 ++-
 arch/powerpc/kernel/idle_power7.S               |   20 ++-
 arch/powerpc/kernel/irq.c                       |  187 ++++++++++++++------
 arch/powerpc/kernel/time.c                      |   15 ++-
 arch/powerpc/platforms/iseries/Makefile         |    2 +-
 arch/powerpc/platforms/iseries/exception.S      |   11 +-
 arch/powerpc/platforms/iseries/misc.S           |   26 ---
 arch/powerpc/platforms/pseries/processor_idle.c |   24 +++-
 19 files changed, 540 insertions(+), 276 deletions(-)
 delete mode 100644 arch/powerpc/platforms/iseries/misc.S
arch/powerpc/include/asm/exception-64s.h +12 -9
index 8057f4f..b3f42e9 100644
@@ -232,23 +232,24 @@ label##_hv:						\
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,	\
 				 EXC_HV, KVMTEST, vec)
 
-#define __SOFTEN_TEST(h)						\
+#define __SOFTEN_TEST(h, vec)						\
 	lbz	r10,PACASOFTIRQEN(r13);					\
 	cmpwi	r10,0;							\
+	li	r10,(vec)>>8;						\
 	beq	masked_##h##interrupt
-#define _SOFTEN_TEST(h)	__SOFTEN_TEST(h)
+#define _SOFTEN_TEST(h, vec)	__SOFTEN_TEST(h, vec)
 
 #define SOFTEN_TEST_PR(vec)						\
 	KVMTEST_PR(vec);						\
-	_SOFTEN_TEST(EXC_STD)
+	_SOFTEN_TEST(EXC_STD, vec)
 
 #define SOFTEN_TEST_HV(vec)						\
 	KVMTEST(vec);							\
-	_SOFTEN_TEST(EXC_HV)
+	_SOFTEN_TEST(EXC_HV, vec)
 
 #define SOFTEN_TEST_HV_201(vec)						\
 	KVMTEST(vec);							\
-	_SOFTEN_TEST(EXC_STD)
+	_SOFTEN_TEST(EXC_STD, vec)
 
 #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)		\
 	HMT_MEDIUM;							\
@@ -276,9 +277,9 @@ label##_hv:								\
 #define DISABLE_INTS				\
 	li	r11,0;				\
 	stb	r11,PACASOFTIRQEN(r13);		\
-BEGIN_FW_FTR_SECTION;				\
-	stb	r11,PACAHARDIRQEN(r13);		\
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES);	\
+	lbz	r11,PACAIRQHAPPENED(r13);	\
+	ori	r11,r11,PACA_HAPPENED;		\
+	stb	r11,PACAIRQHAPPENED(r13);	\
 	TRACE_DISABLE_INTS;			\
 BEGIN_FW_FTR_SECTION;				\
 	mfmsr	r10;				\
@@ -289,7 +290,9 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #define DISABLE_INTS				\
 	li	r11,0;				\
 	stb	r11,PACASOFTIRQEN(r13);		\
-	stb	r11,PACAHARDIRQEN(r13);		\
+	lbz	r11,PACAIRQHAPPENED(r13);	\
+	ori	r11,r11,PACA_HAPPENED;		\
+	stb	r11,PACAIRQHAPPENED(r13);	\
 	TRACE_DISABLE_INTS
 #endif /* CONFIG_PPC_ISERIES */
 
arch/powerpc/include/asm/hw_irq.h +45 -6

79 lines not on this page · raw message

arch/powerpc/include/asm/irqflags.h +6 -7
index b0b06d8..4bfbf0a 100644
@@ -47,16 +47,15 @@
 	b	skip;					\
 95:	TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)	\
 	li	en,1;
-#define TRACE_AND_RESTORE_IRQ(en)		\
-	TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f);	\
-	stb	en,PACASOFTIRQEN(r13);		\
-96:
 #else
 #define TRACE_ENABLE_INTS
 #define TRACE_DISABLE_INTS
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)
-#define TRACE_AND_RESTORE_IRQ(en)		\
-	stb	en,PACASOFTIRQEN(r13)
+#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip)		\
+	cmpdi	en,0;					\
+	bne	95f;					\
+	stb	en,PACASOFTIRQEN(r13);			\
+	b	skip;					\
+95:
 #endif
 #endif
 
arch/powerpc/include/asm/paca.h +1 -1
index 269c05a..daf813f 100644
@@ -132,7 +132,7 @@ struct paca_struct {
 	u64 saved_msr;			/* MSR saved here by enter_rtas */
 	u16 trap_save;			/* Used when bad stack is encountered */
 	u8 soft_enabled;		/* irq soft-enable flag */
-	u8 hard_enabled;		/* set if irqs are enabled in MSR */
+	u8 irq_happened;		/* irq happened while soft-disabled */
 	u8 io_sync;			/* writel() needs spin_unlock sync */
 	u8 irq_work_pending;		/* IRQ_WORK interrupt while soft-disable */
 	u8 nap_state_lost;		/* NV GPR values lost in power7_idle */
arch/powerpc/kernel/asm-offsets.c +1 -1
index 04caee7..cdd0d26 100644
@@ -147,7 +147,7 @@ int main(void)
 	DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase));
 	DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
 	DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
-	DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
+	DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened));
 	DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
 #ifdef CONFIG_PPC_MM_SLICES
 	DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
arch/powerpc/kernel/dbell.c +12 -0
index 2cc451a..16f0e5e 100644
@@ -37,6 +37,18 @@ void doorbell_exception(struct pt_regs *regs)
 
 	irq_enter();
 
+#ifdef CONFIG_PPC64
+	/* Let's hard enable interrupts now that we have reset
+	 * the DEC (or acked it on BookE)
+	 *
+	 * We skip that if there's a pending EE "level" interrupt
+	 * as an optimization
+	 */
+	get_paca()->irq_happened &= ~PACA_HAPPENED;
+	if (!(get_paca()->irq_happened & PACA_HAPPENED_EE))
+		__hard_irq_enable();
+#endif /* CONFIG_PPC64 */
+
 	smp_ipi_demux();
 
 	irq_exit();
arch/powerpc/kernel/entry_64.S +50 -46

149 lines not on this page · raw message

arch/powerpc/kernel/exceptions-64e.S +147 -63

345 lines not on this page · raw message

arch/powerpc/kernel/exceptions-64s.S +55 -35

126 lines not on this page · raw message

arch/powerpc/kernel/head_64.S +0 -9
index 06c7251..ffe08a6 100644
@@ -564,7 +564,6 @@ _GLOBAL(pmac_secondary_start)
 	 */
 	li	r0,0
 	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
 
 	/* Create a temp kernel stack for use before relocation is on.	*/
 	ld	r1,PACAEMERGSP(r13)
@@ -621,13 +620,8 @@ __secondary_start:
 #ifdef CONFIG_PPC_ISERIES
 BEGIN_FW_FTR_SECTION
 	ori	r4,r4,MSR_EE
-	li	r8,1
-	stb	r8,PACAHARDIRQEN(r13)
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
-BEGIN_FW_FTR_SECTION
-	stb	r7,PACAHARDIRQEN(r13)
-END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 	stb	r7,PACASOFTIRQEN(r13)
 
 	mtspr	SPRN_SRR0,r3
@@ -782,11 +776,8 @@ BEGIN_FW_FTR_SECTION
 	mfmsr	r5
 	ori	r5,r5,MSR_EE		/* Hard Enabled on iSeries*/
 	mtmsrd	r5
-	li	r5,1
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
-	stb	r5,PACAHARDIRQEN(r13)	/* Hard Disabled on others */
-
 	bl	.start_kernel
 
 	/* Not reached */
arch/powerpc/kernel/idle_book3e.S +3 -5
index 16c002d..b1199f8 100644
@@ -32,11 +32,11 @@ _GLOBAL(book3e_idle)
 	 * since we may otherwise lose it (doorbells etc...). We know
 	 * that since PACAHARDIRQEN will have been cleared in that case.
 	 */
-	lbz	r3,PACAHARDIRQEN(r13)
+	lbz	r3,PACAIRQHAPPENED(r13)
 	cmpwi	cr0,r3,0
-	beqlr
+	bnelr
 
-	/* Now we are going to mark ourselves as soft and hard enables in
+	/* Now we are going to mark ourselves as soft and hard enabled in
 	 * order to be able to take interrupts while asleep. We inform lockdep
 	 * of that. We don't actually turn interrupts on just yet tho.
 	 */
@@ -46,7 +46,6 @@ _GLOBAL(book3e_idle)
 #endif
 	li	r0,1
 	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
 	
 	/* Interrupts will make use return to LR, so get something we want
 	 * in there
@@ -59,7 +58,6 @@ _GLOBAL(book3e_idle)
 	/* Mark them off again in the PACA as well */
 	li	r0,0
 	stb	r0,PACASOFTIRQEN(r13)
-	stb	r0,PACAHARDIRQEN(r13)
 
 	/* Tell lockdep about it */
 #ifdef CONFIG_TRACE_IRQFLAGS
arch/powerpc/kernel/idle_power4.S +15 -2
index ba31954..c30af92 100644
@@ -29,14 +29,27 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
 	cmpwi	0,r4,0
 	beqlr
 
-	/* Go to NAP now */
+	/* Hard disable */
 	mfmsr	r7
 	rldicl	r0,r7,48,1
 	rotldi	r0,r0,16
 	mtmsrd	r0,1			/* hard-disable interrupts */
+
+	/* Check if something happened while soft-disabled */
+	lbz	r0,PACAIRQHAPPENED(r13)
+	cmpwi	cr0,r0,0
+	bnelr
+
+	/*
+	 * Here we mark ourselves soft-enabled. We should probably
+	 * tell lockdep about it, but the interrupt will re-disable
+	 * immediately so it shouldn't be a big issue. If it becomes
+	 * one, then we should implement things the way we do on
+	 * book3e.
+	 */
 	li	r0,1
 	stb	r0,PACASOFTIRQEN(r13)	/* we'll hard-enable shortly */
-	stb	r0,PACAHARDIRQEN(r13)
+
 BEGIN_FTR_SECTION
 	DSSALL
 	sync
arch/powerpc/kernel/idle_power7.S +17 -3
index fcdff19..61f8cac 100644
@@ -1,5 +1,5 @@
 /*
- *  This file contains the power_save function for 970-family CPUs.
+ *  This file contains the power_save function for Power7 CPUs
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -51,9 +51,23 @@ _GLOBAL(power7_idle)
 	rldicl	r9,r9,48,1
 	rotldi	r9,r9,16
 	mtmsrd	r9,1			/* hard-disable interrupts */
-	li	r0,0
+
+	/* Check if something happened while soft-disabled */
+	lbz	r0,PACAIRQHAPPENED(r13)
+	cmpwi	cr0,r0,0
+	beq	1f
+	addi	r1,r1,INT_FRAME_SIZE
+	ld	r0,16(r1)
+	mtlr	r0
+	blr
+
+	/*
+	 * Here we mark ourselves soft-diasbled (we should already be
+	 * actually...). The interrupt is only going to happen after
+	 * we return to the caller and it does a local_irq_enable()
+	 */
+1:	li	r0,0
 	stb	r0,PACASOFTIRQEN(r13)	/* we'll hard-enable shortly */
-	stb	r0,PACAHARDIRQEN(r13)
 	stb	r0,PACA_NAPSTATELOST(r13)
 
 	/* Continue saving state */
arch/powerpc/kernel/irq.c +133 -54

242 lines not on this page · raw message

arch/powerpc/kernel/time.c +12 -3
index 567dd7c..39f201f 100644
@@ -259,7 +259,6 @@ void accumulate_stolen_time(void)
 	u64 sst, ust;
 
 	u8 save_soft_enabled = local_paca->soft_enabled;
-	u8 save_hard_enabled = local_paca->hard_enabled;
 
 	/* We are called early in the exception entry, before
 	 * soft/hard_enabled are sync'ed to the expected state
@@ -268,7 +267,6 @@ void accumulate_stolen_time(void)
 	 * complain
 	 */
 	local_paca->soft_enabled = 0;
-	local_paca->hard_enabled = 0;
 
 	sst = scan_dispatch_log(local_paca->starttime_user);
 	ust = scan_dispatch_log(local_paca->starttime);
@@ -277,7 +275,6 @@ void accumulate_stolen_time(void)
 	local_paca->stolen_time += ust + sst;
 
 	local_paca->soft_enabled = save_soft_enabled;
-	local_paca->hard_enabled = save_hard_enabled;
 }
 
 static inline u64 calculate_stolen_time(u64 stop_tb)
@@ -589,6 +586,18 @@ void timer_interrupt(struct pt_regs * regs)
 		do_IRQ(regs);
 #endif
 
+#ifdef CONFIG_PPC64
+	/* Let's hard enable interrupts now that we have reset
+	 * the DEC (or acked it on BookE)
+	 *
+	 * We skip that if there's a pending EE "level" interrupt
+	 * as an optimization
+	 */
+	get_paca()->irq_happened &= ~PACA_HAPPENED;
+	if (!(get_paca()->irq_happened & PACA_HAPPENED_EE))
+		__hard_irq_enable();	
+#endif /* CONFIG_PPC64 */
+
 	old_regs = set_irq_regs(regs);
 	irq_enter();
 
arch/powerpc/platforms/iseries/Makefile +1 -1
index a7602b1..7208589 100644
@@ -2,7 +2,7 @@ ccflags-y	:= -mno-minimal-toc
 
 obj-y += exception.o
 obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
-	hvcall.o proc.o htab.o iommu.o misc.o irq.o
+	hvcall.o proc.o htab.o iommu.o irq.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_SMP) += smp.o
 obj-$(CONFIG_VIOPATH) += viopath.o vio.o
arch/powerpc/platforms/iseries/exception.S +8 -3
index f519ee1..508f863 100644
@@ -32,6 +32,7 @@
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
 #include <asm/mmu.h>
+#include <asm/hw_irq.h>
 
 #include "exception.h"
 
@@ -261,16 +262,20 @@ system_call_iSeries:
 
 decrementer_iSeries_masked:
 	/* We may not have a valid TOC pointer in here. */
-	li	r11,1
+	li	r11,PACA_HAPPENED_DEC
 	ld	r12,PACALPPACAPTR(r13)
 	stb	r11,LPPACADECRINT(r12)
 	li	r12,-1
 	clrldi	r12,r12,33	/* set DEC to 0x7fffffff */
 	mtspr	SPRN_DEC,r12
-	/* fall through */
+	b	1f
 
 hardware_interrupt_iSeries_masked:
-	mtcrf	0x80,r9		/* Restore regs */
+	li	r11,PACA_HAPPENED_EE
+1:	mtcrf	0x80,r9		/* Restore regs */
+	lbz	r10,PACAIRQHAPPENED(r13)
+	or	r11,r10,r11
+	stb	r11,PACAIRQHAPPENED(r13)
 	ld	r12,PACALPPACAPTR(r13)
 	ld	r11,LPPACASRR0(r12)
 	ld	r12,LPPACASRR1(r12)
arch/powerpc/platforms/iseries/misc.S deleted +0 -26
deleted file mode 100644
index 2c6ff0f..0000000
@@ -1,26 +0,0 @@
-/*
- * This file contains miscellaneous low-level functions.
- *    Copyright (C) 1995-2005 IBM Corp
- *
- * Largely rewritten by Cort Dougan ([email protected])
- * and Paul Mackerras.
- * Adapted for iSeries by Mike Corrigan ([email protected])
- * PPC64 updates by Dave Engebretsen ([email protected])
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/processor.h>
-#include <asm/asm-offsets.h>
-#include <asm/ppc_asm.h>
-
-	.text
-
-/* Handle pending interrupts in interrupt context */
-_GLOBAL(iseries_handle_interrupts)
-	li	r0,0x5555
-	sc
-	blr
arch/powerpc/platforms/pseries/processor_idle.c +22 -2
index 085fd3f..019a529 100644
@@ -96,6 +96,25 @@ out:
 	return index;
 }
 
+static int check_and_cede_processor(void)
+{
+	/*
+	 * Interrupts are soft-disabled at this point,
+	 * but not hard disabled. So an interrupt might have
+	 * occurred before entering NAP, and would be potentially
+	 * lost (edge events, decrementer events, etc...) unless
+	 * we first hard disable then check.
+	 *
+	 * We must use the low level __hard_irq_disable() and not
+	 * hard_irq_disable() as the later will set a bit in
+	 * paca->irq_happened (to force re-enable later) which we
+	 * don't need nor want here.
+	 */
+	__hard_irq_disable();
+	if (get_paca()->irq_happened == 0)
+		cede_processor();
+}
+
 static int dedicated_cede_loop(struct cpuidle_device *dev,
 				struct cpuidle_driver *drv,
 				int index)
@@ -108,7 +127,8 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
 
 	ppc64_runlatch_off();
 	HMT_medium();
-	cede_processor();
+
+	check_and_cede_processor();
 
 	get_lppaca()->donate_dedicated_cpu = 0;
 	dev->last_residency =
@@ -132,7 +152,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,
 	 * processor. When returning here, external interrupts
 	 * are enabled.
 	 */
-	cede_processor();
+	check_and_cede_processor();
 
 	dev->last_residency =
 		(int)idle_loop_epilog(in_purr, kt_before);
Signature · 1 line
1.7.7.3
#1 lore raw

Hi Ben,

Small comment inline.

Quoted 100 lines · Benjamin Herrenschmidt

From 0ace17ba6960a8788b1bda3770df254cbbc6a244 Mon Sep 17 00:00:00 2001
From: Benjamin Herrenschmidt<[email protected]>
Date: Thu, 9 Feb 2012 15:25:04 +1100
Subject: [PATCH] powerpc: Rework lazy-interrupt handling

The current implementation of lazy interrupts handling has some issues that this tries to address.

Except on iSeries, we don't do the various workarounds we need to do on re-enable when returning from an interrupt, which can do an implicit re-enable, and thus we may still lose or get delayed decrementer or doorbell interrupts.

The current scheme also makes it much harder to handle the external "edge" interrupts provided by some BookE processors when using the EPR facility (External Proxy) and the Freescale Hypervisor.

We also hard mask on decrementer interrupts which is sub-optimal.

This is an attempt at fixing it all in one go by reworking the way we do the lazy interrupt disabling.

The base idea is to replace the "hard_enabled" field with a "irq_happened" field in which we store a bit mask of what interrupt occurred while soft-disabled.

When re-enabling, either via arch_local_irq_restore() or when returning from an interrupt, we can now decide what to do by testing bits in that field. We then implement re-emitting of the lost interrupts via either a re-use of the existing exception frame (exception exit case) or via the creation of a new one from assembly code (arch_local_irq_enable), without the need to trigger a fake one using set_dec() or similar.

In addition, this adds a few refinements:

- We no longer hard disable decrementer interrupts that occur
while soft-disabled. We now simply bump the decrementer back to max (on BookS) or leave it stopped (on BookE) and continue with hard interrupts enabled, which means that we'll potentially get better sample quality from performance monitor interrupts.

- Timer, decrementer and doorbell interrupts now hard-enable
shortly after removing the source of the interrupt, which means they no longer run entirely hard disabled. Again, this will improve perf sample quality.

- On Book3E 64-bit, we now make the performance monitor interrupt
act as an NMI like Book3S (the necessary C code for that to work appear to already be present in the FSL perf code, notably calling nmi_enter instead of irq_enter).

There are additional refinements that we can do on top of this patch:

- We could remove the ps3 workaround from arch_local_irq_enable(),
I believe that it should no longer be necessary

- We could make "masked" decrementer interrupts act as NMIs when doing
timer-based perf sampling to improve the sample quality.

- There are additional simplifications of the exception entry/exit path
that I've spotted along the way, such as merging fast_exception_return with the normal code path.

This patch needs a LOT more testing& review than it had so far !!!

Not-signed-off-by-yet: Benjamin Herrenschmidt<[email protected]>
---

v2:

- Add hard-enable to decrementer, timer and doorbells
- Fix CR clobber in masked irq handling on BookE
- Make embedded perf interrupt act as an NMI
- Add a PACA_HAPPENED_EE_EDGE for use by FSL if they want to retrigger an interrupt without preventing hard-enable

---
  arch/powerpc/include/asm/exception-64s.h        |   21 ++-
  arch/powerpc/include/asm/hw_irq.h               |   51 +++++-
  arch/powerpc/include/asm/irqflags.h             |   13 +-
  arch/powerpc/include/asm/paca.h                 |    2 +-
  arch/powerpc/kernel/asm-offsets.c               |    2 +-
  arch/powerpc/kernel/dbell.c                     |   12 ++
  arch/powerpc/kernel/entry_64.S                  |   96 ++++++-----
  arch/powerpc/kernel/exceptions-64e.S            |  210 ++++++++++++++++-------
  arch/powerpc/kernel/exceptions-64s.S            |   90 ++++++----
  arch/powerpc/kernel/head_64.S                   |    9 -
  arch/powerpc/kernel/idle_book3e.S               |    8 +-
  arch/powerpc/kernel/idle_power4.S               |   17 ++-
  arch/powerpc/kernel/idle_power7.S               |   20 ++-
  arch/powerpc/kernel/irq.c                       |  187 ++++++++++++++------
  arch/powerpc/kernel/time.c                      |   15 ++-
  arch/powerpc/platforms/iseries/Makefile         |    2 +-
  arch/powerpc/platforms/iseries/exception.S      |   11 +-
  arch/powerpc/platforms/iseries/misc.S           |   26 ---
  arch/powerpc/platforms/pseries/processor_idle.c |   24 +++-
  19 files changed, 540 insertions(+), 276 deletions(-)

delete mode 100644 arch/powerpc/platforms/iseries/misc.S

[snip]

Quoted 288 lines
arch/powerpc/kernel/exceptions-64e.S +97 -60
index 429983c..7fa4096 100644
@@ -21,6 +21,7 @@
  #include<asm/exception-64e.h>
  #include<asm/bug.h>
  #include<asm/irqflags.h>
+#include<asm/hw_irq.h>
  #include<asm/ptrace.h>
  #include<asm/ppc-opcode.h>
  #include<asm/mmu.h>
@@ -77,59 +78,55 @@
  #define SPRN_MC_SRR1	SPRN_MCSRR1
 
  #define NORMAL_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, GEN, addition##_GEN)
+	EXCEPTION_PROLOG(n, GEN, addition##_GEN(n))
 
  #define CRIT_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, CRIT, addition##_CRIT)
+	EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n))
 
  #define DBG_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, DBG, addition##_DBG)
+	EXCEPTION_PROLOG(n, DBG, addition##_DBG(n))
 
  #define MC_EXCEPTION_PROLOG(n, addition)				    \
-	EXCEPTION_PROLOG(n, MC, addition##_MC)
+	EXCEPTION_PROLOG(n, MC, addition##_MC(n))
 
 
  /* Variants of the "addition" argument for the prolog
   */
-#define PROLOG_ADDITION_NONE_GEN
-#define PROLOG_ADDITION_NONE_CRIT
-#define PROLOG_ADDITION_NONE_DBG
-#define PROLOG_ADDITION_NONE_MC
+#define PROLOG_ADDITION_NONE_GEN(n)
+#define PROLOG_ADDITION_NONE_CRIT(n)
+#define PROLOG_ADDITION_NONE_DBG(n)
+#define PROLOG_ADDITION_NONE_MC(n)
 
-#define PROLOG_ADDITION_MASKABLE_GEN					    \
+#define PROLOG_ADDITION_MASKABLE_GEN(n)					    \
  	lbz	r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */	    \
  	cmpwi	cr0,r11,0;		/* yes ->  go out of line */	    \
-	beq	masked_interrupt_book3e;
+	beq	masked_interrupt_book3e_##n;
 
-#define PROLOG_ADDITION_2REGS_GEN					    \
+#define PROLOG_ADDITION_2REGS_GEN(n)					    \
  	std	r14,PACA_EXGEN+EX_R14(r13);				    \
  	std	r15,PACA_EXGEN+EX_R15(r13)
 
-#define PROLOG_ADDITION_1REG_GEN					    \
+#define PROLOG_ADDITION_1REG_GEN(n)					    \
  	std	r14,PACA_EXGEN+EX_R14(r13);
 
-#define PROLOG_ADDITION_2REGS_CRIT					    \
+#define PROLOG_ADDITION_2REGS_CRIT(n)					    \
  	std	r14,PACA_EXCRIT+EX_R14(r13);				    \
  	std	r15,PACA_EXCRIT+EX_R15(r13)
 
-#define PROLOG_ADDITION_2REGS_DBG					    \
+#define PROLOG_ADDITION_2REGS_DBG(n)					    \
  	std	r14,PACA_EXDBG+EX_R14(r13);				    \
  	std	r15,PACA_EXDBG+EX_R15(r13)
 
-#define PROLOG_ADDITION_2REGS_MC					    \
+#define PROLOG_ADDITION_2REGS_MC(n)					    \
  	std	r14,PACA_EXMC+EX_R14(r13);				    \
  	std	r15,PACA_EXMC+EX_R15(r13)
 
-#define PROLOG_ADDITION_DOORBELL_GEN					    \
-	lbz	r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */	    \
-	cmpwi	cr0,r11,0;		/* yes ->  go out of line */	    \
-	beq	masked_doorbell_book3e
-
 
  /* Core exception code for all exceptions except TLB misses.
   * XXX: Needs to make SPRN_SPRG_GEN depend on exception type
   */
  #define EXCEPTION_COMMON(n, excf, ints)					    \
+exc_##n##_common:							    \
  	std	r0,GPR0(r1);		/* save r0 in stackframe */	    \
  	std	r2,GPR2(r1);		/* save r2 in stackframe */	    \
  	SAVE_4GPRS(3, r1);		/* save r3 - r6 in stackframe */    \
@@ -167,19 +164,25 @@
  	std	r0,RESULT(r1);		/* clear regs->result */	    \
  	ints;
 
-/* Variants for the "ints" argument */
-#define INTS_KEEP
-#define INTS_DISABLE_SOFT						    \
+/* Variants for the "ints" argument. We know r0 is 0 on entry */
+#define INTS_KEEP							    \
  	stb	r0,PACASOFTIRQEN(r13);	/* mark interrupts soft-disabled */ \
  	TRACE_DISABLE_INTS;
-#define INTS_DISABLE_HARD						    \
-	stb	r0,PACAHARDIRQEN(r13); /* and hard disabled */
-#define INTS_DISABLE_ALL						    \
-	INTS_DISABLE_SOFT						    \
-	INTS_DISABLE_HARD
-
-/* This is called by exceptions that used INTS_KEEP (that is did not clear
- * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE
+
+/* This second version is meant for exceptions that don't immediately
+ * hard-enable. We set a bit in paca->irq_happened to ensure that
+ * a subsequent call to arch_local_irq_restore() will properly
+ * hard-enable and avoid the fast-path
+ */
+#define INTS_DISABLE							    \
+	stb	r0,PACASOFTIRQEN(r13);	/* mark interrupts soft-disabled */ \
+	lbz	r0,PACAIRQHAPPENED(r13);				    \
+	ori	r0,r0,PACA_HAPPENED;					    \
+	stb	r0,PACAIRQHAPPENED(r13);				    \
+	TRACE_DISABLE_INTS;
+
+/* This is called by exceptions that used INTS_KEEP (that is did
+ * not set hard IRQ indicators in the PACA). This will restore MSR:EE
   * to it's previous value
   *
   * XXX In the long run, we may want to open-code it in order to separate the
@@ -238,7 +241,7 @@ exc_##n##_bad_stack:							    \
  #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack)			\
  	START_EXCEPTION(label);						\
  	NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE)	\
-	EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL)		\
+	EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE)		\
  	ack(r8);							\
  	CHECK_NAPPING();						\
  	addi	r3,r1,STACK_FRAME_OVERHEAD;				\
@@ -289,7 +292,7 @@ interrupt_end_book3e:
  /* Critical Input Interrupt */
  	START_EXCEPTION(critical_input);
  	CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
+//	EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE)
  //	bl	special_reg_save_crit
  //	CHECK_NAPPING();
  //	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -300,7 +303,7 @@ interrupt_end_book3e:
  /* Machine Check Interrupt */
  	START_EXCEPTION(machine_check);
  	CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
+//	EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE)
  //	bl	special_reg_save_mc
  //	addi	r3,r1,STACK_FRAME_OVERHEAD
  //	CHECK_NAPPING();
@@ -339,7 +342,7 @@ interrupt_end_book3e:
  	START_EXCEPTION(program);
  	NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG)
  	mfspr	r14,SPRN_ESR
-	EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT)
+	EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_KEEP)
  	std	r14,_DSISR(r1)
  	addi	r3,r1,STACK_FRAME_OVERHEAD
  	ld	r14,PACA_EXGEN+EX_R14(r13)
@@ -372,7 +375,7 @@ interrupt_end_book3e:
  /* Watchdog Timer Interrupt */
  	START_EXCEPTION(watchdog);
  	CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
+//	EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE)
  //	bl	special_reg_save_crit
  //	CHECK_NAPPING();
  //	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -450,7 +453,7 @@ interrupt_end_book3e:
  	mfspr	r15,SPRN_SPRG_CRIT_SCRATCH
  	mtspr	SPRN_SPRG_GEN_SCRATCH,r15
  	mfspr	r14,SPRN_DBSR
-	EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL)
+	EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE)
  	std	r14,_DSISR(r1)
  	addi	r3,r1,STACK_FRAME_OVERHEAD
  	mr	r4,r14
@@ -515,7 +518,7 @@ kernel_dbg_exc:
  	mfspr	r15,SPRN_SPRG_DBG_SCRATCH
  	mtspr	SPRN_SPRG_GEN_SCRATCH,r15
  	mfspr	r14,SPRN_DBSR
-	EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL)
+	EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE)
  	std	r14,_DSISR(r1)
  	addi	r3,r1,STACK_FRAME_OVERHEAD
  	mr	r4,r14
@@ -525,21 +528,22 @@ kernel_dbg_exc:
  	bl	.DebugException
  	b	.ret_from_except
 
-	MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE)
+	START_EXCEPTION(perfmon);
+	NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE)
+	EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	ld	r14,PACA_EXGEN+EX_R14(r13)
+	bl	.save_nvgprs
+	bl	.performance_monitor_exception
+	b	.ret_from_except
 
  /* Doorbell interrupt */
-	START_EXCEPTION(doorbell)
-	NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL)
-	EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL)
-	CHECK_NAPPING()
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	.doorbell_exception
-	b	.ret_from_except_lite
+	MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE)
 
  /* Doorbell critical Interrupt */
  	START_EXCEPTION(doorbell_crit);
-	CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)
-//	EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)
+	CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE)
+//	EXCEPTION_COMMON(0x280, PACA_EXCRIT, INTS_DISABLE)
  //	bl	special_reg_save_crit
  //	CHECK_NAPPING();
  //	addi	r3,r1,STACK_FRAME_OVERHEAD
@@ -547,38 +551,116 @@ kernel_dbg_exc:
  //	b	ret_from_crit_except
  	b	.
 
+/* Guest Doorbell */
  	MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE)
-	MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE)
-	MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE)
-	MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE)
+
+/* Guest Doorbell critical Interrupt */
+	START_EXCEPTION(guest_doorbell_crit);
+	CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE)
+//	EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE)
+//	bl	special_reg_save_crit
+//	CHECK_NAPPING();
+//	addi	r3,r1,STACK_FRAME_OVERHEAD
+//	bl	.guest_doorbell_critical_exception
+//	b	ret_from_crit_except
+	b	.
+
+/* Hypervisor call */
+	START_EXCEPTION(hypercall);
+	NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE)
+	EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.save_nvgprs
+	INTS_RESTORE_HARD
+	bl	.unknown_exception
+	b	.ret_from_except
+
+/* Embedded Hypervisor priviledged  */
+	START_EXCEPTION(ehpriv);
+	NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE)
+	EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.save_nvgprs
+	INTS_RESTORE_HARD
+	bl	.unknown_exception
+	b	.ret_from_except
 
 
  /*
- * An interrupt came in while soft-disabled; clear EE in SRR1,
- * clear paca->hard_enabled and return.
+ * An interrupt came in while soft-disabled; We mark paca->irq_happened
+ * accordingly and if the interrupt is level sensitive, we hard disable
   */
-masked_doorbell_book3e:
-	mtcr	r10
-	/* Resend the doorbell to fire again when ints enabled */
-	mfspr	r10,SPRN_PIR
-	PPC_MSGSND(r10)
-	b	masked_interrupt_book3e_common
 
-masked_interrupt_book3e:
+masked_interrupt_book3e_0x500:
+	li	r11,PACA_HAPPENED_EE
+	b	masked_interrupt_book3e_full_mask
+
+masked_interrupt_book3e_0x900:
+	ACK_DEC(r11);
+	li	r11,PACA_HAPPENED_DEC
+	b	masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x980:
+	ACK_FIT(r11);
+	li	r11,PACA_HAPPENED_DEC

arch/powerpc/kernel/exceptions-64e.S kernel_dbg_exc: · line 614

Quoted 10 lines
arch/powerpc/kernel/exceptions-64e.S +10 -0
+	b	masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x280:
+masked_interrupt_book3e_0x2c0:
+	li	r11,PACA_HAPPENED_DBELL
+	b	masked_interrupt_book3e_no_mask
+
+masked_interrupt_book3e_no_mask:
+	mtcr	r10
+	lbz	r10,PACAIRQHAPPENED(r13)
+	ori	r10,r10,r11

Shouldn't this be an 'or'?

arch/powerpc/kernel/exceptions-64e.S kernel_dbg_exc: · line 620

Quoted 8 lines
arch/powerpc/kernel/exceptions-64e.S +5 -2
+	stb	r10,PACAIRQHAPPENED(r13)
+	b	1f
+masked_interrupt_book3e_full_mask:
  	mtcr	r10
-masked_interrupt_book3e_common:
-	stb	r11,PACAHARDIRQEN(r13)
+	lbz	r10,PACAIRQHAPPENED(r13)
+	ori	r10,r10,r11

Same comment.

Quoted 48 lines
arch/powerpc/kernel/exceptions-64e.S +33 -1
+	stb	r10,PACAIRQHAPPENED(r13)
  	mfspr	r10,SPRN_SRR1
  	rldicl	r11,r10,48,1		/* clear MSR_EE */
  	rotldi	r10,r11,16
  	mtspr	SPRN_SRR1,r10
-	ld	r10,PACA_EXGEN+EX_R10(r13);	/* restore registers */
+1:	ld	r10,PACA_EXGEN+EX_R10(r13);
  	ld	r11,PACA_EXGEN+EX_R11(r13);
  	mfspr	r13,SPRN_SPRG_GEN_SCRATCH;
  	rfi
  	b	.
 
  /*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280
+ * to indicate the kind of interrupt. MSR:EE is already off.
+ * We generate a stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__reemit_interrupt)
+	/* We are going to jump to the exception common code which
+	 * will retrieve various register values from the PACA which
+	 * we don't give a damn about.
+	 */
+	mflr	r10
+	mfmsr	r11
+	mfcr	r4;
+	mtspr	SPRN_SPRG_GEN_SCRATCH,r13;
+	std	r1,PACA_EXGEN+EX_R1(r13);
+	stw	r4,PACA_EXGEN+EX_CR(r13);
+	ori	r11,r11,MSR_EE
+	subi	r1,r1,INT_FRAME_SIZE;
+	cmpwi	cr0,r3,0x500
+	beq	exc_0x500_common
+	cmpwi	cr0,r3,0x900
+	beq+	exc_0x900_common
+	cmpwi	cr0,r3,0x280
+	beq+	exc_0x280_common
+	blr
+
+/*
   * This is called from 0x300 and 0x400 handlers after the prologs with
   * r14 and r15 containing the fault address and error code, with the
   * original values stashed away in the PACA

arch/powerpc/kernel/exceptions-64e.S BAD_STACK_TRAMPOLINE(0x000) · line 769

Quoted 8 lines
arch/powerpc/kernel/exceptions-64e.S +2 -0
@@ -680,6 +762,8 @@ BAD_STACK_TRAMPOLINE(0x000)
  BAD_STACK_TRAMPOLINE(0x100)
  BAD_STACK_TRAMPOLINE(0x200)
  BAD_STACK_TRAMPOLINE(0x260)
+BAD_STACK_TRAMPOLINE(0x280)
+BAD_STACK_TRAMPOLINE(0x2a0)
  BAD_STACK_TRAMPOLINE(0x2c0)
  BAD_STACK_TRAMPOLINE(0x2e0)
  BAD_STACK_TRAMPOLINE(0x300)

---
Best Regards, Laurentiu

#2 lore raw
Quoted 11 lines · Tudor Laurentiu
Quoted 11 lines
arch/powerpc/kernel/exceptions-64e.S +11 -0
+masked_interrupt_book3e_0x900:
+	ACK_DEC(r11);
+	li	r11,PACA_HAPPENED_DEC
+	b	masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x980:
+	ACK_FIT(r11);
+	li	r11,PACA_HAPPENED_DEC
+	b	masked_interrupt_book3e_no_mask
+masked_interrupt_book3e_0x280:
+masked_interrupt_book3e_0x2c0:
+	li	r11,PACA_HAPPENED_DBELL
Quoted 8 lines

arch/powerpc/kernel/exceptions-64e.S kernel_dbg_exc: · line 614

Quoted 6 lines
arch/powerpc/kernel/exceptions-64e.S +6 -0
+	b	masked_interrupt_book3e_no_mask
+
+masked_interrupt_book3e_no_mask:
+	mtcr	r10
+	lbz	r10,PACAIRQHAPPENED(r13)
+	ori	r10,r10,r11

Shouldn't this be an 'or'?

Yes, absolutely. This is a typo/thinko I do all the time ... oops.

Quoted 10 lines

arch/powerpc/kernel/exceptions-64e.S kernel_dbg_exc: · line 620

Quoted 8 lines
arch/powerpc/kernel/exceptions-64e.S +5 -2
+	stb	r10,PACAIRQHAPPENED(r13)
+	b	1f
+masked_interrupt_book3e_full_mask:
  	mtcr	r10
-masked_interrupt_book3e_common:
-	stb	r11,PACAHARDIRQEN(r13)
+	lbz	r10,PACAIRQHAPPENED(r13)
+	ori	r10,r10,r11

Same comment.

I'll respin and fix.

Cheers,
Ben

Quoted 59 lines
Quoted 48 lines
arch/powerpc/kernel/exceptions-64e.S +33 -1
+	stb	r10,PACAIRQHAPPENED(r13)
  	mfspr	r10,SPRN_SRR1
  	rldicl	r11,r10,48,1		/* clear MSR_EE */
  	rotldi	r10,r11,16
  	mtspr	SPRN_SRR1,r10
-	ld	r10,PACA_EXGEN+EX_R10(r13);	/* restore registers */
+1:	ld	r10,PACA_EXGEN+EX_R10(r13);
  	ld	r11,PACA_EXGEN+EX_R11(r13);
  	mfspr	r13,SPRN_SPRG_GEN_SCRATCH;
  	rfi
  	b	.
 
  /*
+ * Called from arch_local_irq_enable when an interrupt needs
+ * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280
+ * to indicate the kind of interrupt. MSR:EE is already off.
+ * We generate a stackframe like if a real interrupt had happened.
+ *
+ * Note: While MSR:EE is off, we need to make sure that _MSR
+ * in the generated frame has EE set to 1 or the exception
+ * handler will not properly re-enable them.
+ */
+_GLOBAL(__reemit_interrupt)
+	/* We are going to jump to the exception common code which
+	 * will retrieve various register values from the PACA which
+	 * we don't give a damn about.
+	 */
+	mflr	r10
+	mfmsr	r11
+	mfcr	r4;
+	mtspr	SPRN_SPRG_GEN_SCRATCH,r13;
+	std	r1,PACA_EXGEN+EX_R1(r13);
+	stw	r4,PACA_EXGEN+EX_CR(r13);
+	ori	r11,r11,MSR_EE
+	subi	r1,r1,INT_FRAME_SIZE;
+	cmpwi	cr0,r3,0x500
+	beq	exc_0x500_common
+	cmpwi	cr0,r3,0x900
+	beq+	exc_0x900_common
+	cmpwi	cr0,r3,0x280
+	beq+	exc_0x280_common
+	blr
+
+/*
   * This is called from 0x300 and 0x400 handlers after the prologs with
   * r14 and r15 containing the fault address and error code, with the
   * original values stashed away in the PACA

arch/powerpc/kernel/exceptions-64e.S BAD_STACK_TRAMPOLINE(0x000) · line 769

Quoted 8 lines
arch/powerpc/kernel/exceptions-64e.S +2 -0
@@ -680,6 +762,8 @@ BAD_STACK_TRAMPOLINE(0x000)
  BAD_STACK_TRAMPOLINE(0x100)
  BAD_STACK_TRAMPOLINE(0x200)
  BAD_STACK_TRAMPOLINE(0x260)
+BAD_STACK_TRAMPOLINE(0x280)
+BAD_STACK_TRAMPOLINE(0x2a0)
  BAD_STACK_TRAMPOLINE(0x2c0)
  BAD_STACK_TRAMPOLINE(0x2e0)
  BAD_STACK_TRAMPOLINE(0x300)

---
Best Regards, Laurentiu