Merge tag 'powerpc-5.11-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fix from Michael Ellerman:
"One fix for a bug in our soft interrupt masking, which could lead to
interrupt replaying recursing, causing spurious interrupts.

Thanks to Nicholas Piggin"

* tag 'powerpc-5.11-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
powerpc/64s: prevent recursive replay_soft_interrupts causing superfluous interrupt

+17 -13
+17 -13
arch/powerpc/kernel/irq.c
··· 180 180 181 181 void replay_soft_interrupts(void) 182 182 { 183 - /* 184 - * We use local_paca rather than get_paca() to avoid all 185 - * the debug_smp_processor_id() business in this low level 186 - * function 187 - */ 188 - unsigned char happened = local_paca->irq_happened; 189 183 struct pt_regs regs; 184 + 185 + /* 186 + * Be careful here, calling these interrupt handlers can cause 187 + * softirqs to be raised, which they may run when calling irq_exit, 188 + * which will cause local_irq_enable() to be run, which can then 189 + * recurse into this function. Don't keep any state across 190 + * interrupt handler calls which may change underneath us. 191 + * 192 + * We use local_paca rather than get_paca() to avoid all the 193 + * debug_smp_processor_id() business in this low level function. 194 + */ 190 195 191 196 ppc_save_regs(&regs); 192 197 regs.softe = IRQS_ENABLED; ··· 214 209 * This is a higher priority interrupt than the others, so 215 210 * replay it first. 216 211 */ 217 - if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_HMI)) { 212 + if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_HMI)) { 218 213 local_paca->irq_happened &= ~PACA_IRQ_HMI; 219 214 regs.trap = 0xe60; 220 215 handle_hmi_exception(&regs); ··· 222 217 hard_irq_disable(); 223 218 } 224 219 225 - if (happened & PACA_IRQ_DEC) { 220 + if (local_paca->irq_happened & PACA_IRQ_DEC) { 226 221 local_paca->irq_happened &= ~PACA_IRQ_DEC; 227 222 regs.trap = 0x900; 228 223 timer_interrupt(&regs); ··· 230 225 hard_irq_disable(); 231 226 } 232 227 233 - if (happened & PACA_IRQ_EE) { 228 + if (local_paca->irq_happened & PACA_IRQ_EE) { 234 229 local_paca->irq_happened &= ~PACA_IRQ_EE; 235 230 regs.trap = 0x500; 236 231 do_IRQ(&regs); ··· 238 233 hard_irq_disable(); 239 234 } 240 235 241 - if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (happened & PACA_IRQ_DBELL)) { 236 + if (IS_ENABLED(CONFIG_PPC_DOORBELL) && (local_paca->irq_happened & PACA_IRQ_DBELL)) { 242 237 local_paca->irq_happened &= ~PACA_IRQ_DBELL; 243 238 if (IS_ENABLED(CONFIG_PPC_BOOK3E)) 244 239 regs.trap = 0x280; ··· 250 245 } 251 246 252 247 /* Book3E does not support soft-masking PMI interrupts */ 253 - if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (happened & PACA_IRQ_PMI)) { 248 + if (IS_ENABLED(CONFIG_PPC_BOOK3S) && (local_paca->irq_happened & PACA_IRQ_PMI)) { 254 249 local_paca->irq_happened &= ~PACA_IRQ_PMI; 255 250 regs.trap = 0xf00; 256 251 performance_monitor_exception(&regs); ··· 258 253 hard_irq_disable(); 259 254 } 260 255 261 - happened = local_paca->irq_happened; 262 - if (happened & ~PACA_IRQ_HARD_DIS) { 256 + if (local_paca->irq_happened & ~PACA_IRQ_HARD_DIS) { 263 257 /* 264 258 * We are responding to the next interrupt, so interrupt-off 265 259 * latencies should be reset here.