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