[RFC PATCH 8/8] powerpc/64s: inline local_irq_enable/restore
Nicholas Piggin
npiggin at gmail.com
Thu Dec 21 01:52:06 AEDT 2017
This does increase kernel text size by about 0.4%, but code is often
improved by putting the interrupt-replay call out of line, and gcc
function "shrink wrapping" can more often avoid setting up a stack
frame, e.g., _raw_spin_unlock_irqrestore fastpath before:
<_raw_spin_unlock_irqrestore>:
addis r2,r12,63
addi r2,r2,24688
mflr r0
andi. r9,r14,256
mr r9,r3
std r0,16(r1)
stdu r1,-32(r1)
bne c0000000009fd1e0 <_raw_spin_unlock_irqrestore+0x50>
lwsync
li r10,0
mr r3,r4
stw r10,0(r9)
bl c000000000013f98 <arch_local_irq_restore+0x8>
<arch_local_irq_restore>:
addis r2,r12,222
addi r2,r2,-3472
rldimi r14,r3,0,62
cmpdi cr7,r3,0
bnelr cr7
andi. r9,r14,252
beqlr
nop
addi r1,r1,32
ld r0,16(r1)
mtlr r0
blr
And after:
<_raw_spin_unlock_irqrestore>:
addis r2,r12,64
addi r2,r2,-15200
andi. r9,r14,256
bne c000000000a06dd0 <_raw_spin_unlock_irqrestore+0x70>
lwsync
li r9,0
stw r9,0(r3)
rldimi r14,r4,0,62
cmpdi cr7,r4,0
bne cr7,c000000000a06d90 <_raw_spin_unlock_irqrestore+0x30>
andi. r9,r14,252
bne c000000000a06da0 <_raw_spin_unlock_irqrestore+0x40>
blr
GCC can still improve code size for the slow paths by avoiding aligning
branch targets too, so there is room to reduce the text size cost there.
---
arch/powerpc/include/asm/hw_irq.h | 15 +++++++++++++--
arch/powerpc/kernel/irq.c | 28 ++++++----------------------
2 files changed, 19 insertions(+), 24 deletions(-)
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index f492a7779ea3..8690e0d5605d 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -132,11 +132,22 @@ static inline void arch_local_irq_disable(void)
irq_soft_mask_set(IRQ_SOFT_MASK_STD);
}
-extern void arch_local_irq_restore(unsigned long);
+extern void __arch_local_irq_enable(void);
static inline void arch_local_irq_enable(void)
{
- arch_local_irq_restore(0);
+ __irq_soft_mask_clear(IRQ_SOFT_MASK_ALL);
+ if (unlikely(local_r14 & R14_BIT_IRQ_HAPPENED_MASK))
+ __arch_local_irq_enable();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ __irq_soft_mask_insert(flags);
+ if (!flags) {
+ if (unlikely(local_r14 & R14_BIT_IRQ_HAPPENED_MASK))
+ __arch_local_irq_enable();
+ }
}
static inline unsigned long arch_local_irq_save(void)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index ebaf210a7406..e2ff0210477e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -97,11 +97,6 @@ extern int tau_interrupts(int);
int distribute_irqs = 1;
-static inline notrace unsigned long get_irq_happened(void)
-{
- return local_r14 & R14_BIT_IRQ_HAPPENED_MASK;
-}
-
static inline notrace int decrementer_check_overflow(void)
{
u64 now = get_tb_or_rtc();
@@ -210,19 +205,10 @@ notrace unsigned int __check_irq_replay(void)
return 0;
}
-notrace void arch_local_irq_restore(unsigned long mask)
+notrace void __arch_local_irq_enable(void)
{
- unsigned char irq_happened;
unsigned int replay;
- /* Write the new soft-enabled value */
- __irq_soft_mask_insert(mask);
- /* any bits still disabled */
- if (mask)
- return;
-
- barrier();
-
/*
* From this point onward, we can take interrupts, preempt,
* etc... unless we got hard-disabled. We check if an event
@@ -236,9 +222,6 @@ notrace void arch_local_irq_restore(unsigned long mask)
* be hard-disabled, so there is no problem, we
* cannot have preempted.
*/
- irq_happened = get_irq_happened();
- if (!irq_happened)
- return;
/*
* We need to hard disable to get a trusted value from
@@ -252,10 +235,11 @@ notrace void arch_local_irq_restore(unsigned long mask)
* (expensive) mtmsrd.
* XXX: why not test & IRQ_HARD_DIS?
*/
- if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
+ if (unlikely((local_r14 & R14_BIT_IRQ_HAPPENED_MASK) !=
+ PACA_IRQ_HARD_DIS)) {
__hard_irq_disable();
#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
- else {
+ } else {
/*
* We should already be hard disabled here. We had bugs
* where that wasn't the case so let's dbl check it and
@@ -264,8 +248,8 @@ notrace void arch_local_irq_restore(unsigned long mask)
*/
if (WARN_ON(mfmsr() & MSR_EE))
__hard_irq_disable();
- }
#endif
+ }
__irq_soft_mask_set(IRQ_SOFT_MASK_ALL);
trace_hardirqs_off();
@@ -293,7 +277,7 @@ notrace void arch_local_irq_restore(unsigned long mask)
/* Finally, let's ensure we are hard enabled */
__hard_irq_enable();
}
-EXPORT_SYMBOL(arch_local_irq_restore);
+EXPORT_SYMBOL(__arch_local_irq_enable);
/*
* This is specifically called by assembly code to re-enable interrupts
--
2.15.0
More information about the Linuxppc-dev
mailing list