aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r--arch/powerpc/kernel/irq.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 4e65bf82f5e0..b7a84522e652 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -143,6 +143,13 @@ notrace unsigned int __check_irq_replay(void)
143 */ 143 */
144 unsigned char happened = local_paca->irq_happened; 144 unsigned char happened = local_paca->irq_happened;
145 145
146 /*
147 * We are responding to the next interrupt, so interrupt-off
148 * latencies should be reset here.
149 */
150 trace_hardirqs_on();
151 trace_hardirqs_off();
152
146 if (happened & PACA_IRQ_HARD_DIS) { 153 if (happened & PACA_IRQ_HARD_DIS) {
147 /* Clear bit 0 which we wouldn't clear otherwise */ 154 /* Clear bit 0 which we wouldn't clear otherwise */
148 local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; 155 local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
@@ -270,6 +277,7 @@ notrace void arch_local_irq_restore(unsigned long en)
270#endif /* CONFIG_TRACE_IRQFLAGS */ 277#endif /* CONFIG_TRACE_IRQFLAGS */
271 278
272 set_soft_enabled(0); 279 set_soft_enabled(0);
280 trace_hardirqs_off();
273 281
274 /* 282 /*
275 * Check if anything needs to be re-emitted. We haven't 283 * Check if anything needs to be re-emitted. We haven't
@@ -279,6 +287,7 @@ notrace void arch_local_irq_restore(unsigned long en)
279 replay = __check_irq_replay(); 287 replay = __check_irq_replay();
280 288
281 /* We can soft-enable now */ 289 /* We can soft-enable now */
290 trace_hardirqs_on();
282 set_soft_enabled(1); 291 set_soft_enabled(1);
283 292
284 /* 293 /*
@@ -394,11 +403,19 @@ bool prep_irq_for_idle_irqsoff(void)
394/* 403/*
395 * Take the SRR1 wakeup reason, index into this table to find the 404 * Take the SRR1 wakeup reason, index into this table to find the
396 * appropriate irq_happened bit. 405 * appropriate irq_happened bit.
406 *
407 * Sytem reset exceptions taken in idle state also come through here,
408 * but they are NMI interrupts so do not need to wait for IRQs to be
409 * restored, and should be taken as early as practical. These are marked
410 * with 0xff in the table. The Power ISA specifies 0100b as the system
411 * reset interrupt reason.
397 */ 412 */
413#define IRQ_SYSTEM_RESET 0xff
414
398static const u8 srr1_to_lazyirq[0x10] = { 415static const u8 srr1_to_lazyirq[0x10] = {
399 0, 0, 0, 416 0, 0, 0,
400 PACA_IRQ_DBELL, 417 PACA_IRQ_DBELL,
401 0, 418 IRQ_SYSTEM_RESET,
402 PACA_IRQ_DBELL, 419 PACA_IRQ_DBELL,
403 PACA_IRQ_DEC, 420 PACA_IRQ_DEC,
404 0, 421 0,
@@ -407,15 +424,43 @@ static const u8 srr1_to_lazyirq[0x10] = {
407 PACA_IRQ_HMI, 424 PACA_IRQ_HMI,
408 0, 0, 0, 0, 0 }; 425 0, 0, 0, 0, 0 };
409 426
427void replay_system_reset(void)
428{
429 struct pt_regs regs;
430
431 ppc_save_regs(&regs);
432 regs.trap = 0x100;
433 get_paca()->in_nmi = 1;
434 system_reset_exception(&regs);
435 get_paca()->in_nmi = 0;
436}
437EXPORT_SYMBOL_GPL(replay_system_reset);
438
410void irq_set_pending_from_srr1(unsigned long srr1) 439void irq_set_pending_from_srr1(unsigned long srr1)
411{ 440{
412 unsigned int idx = (srr1 & SRR1_WAKEMASK_P8) >> 18; 441 unsigned int idx = (srr1 & SRR1_WAKEMASK_P8) >> 18;
442 u8 reason = srr1_to_lazyirq[idx];
443
444 /*
445 * Take the system reset now, which is immediately after registers
446 * are restored from idle. It's an NMI, so interrupts need not be
447 * re-enabled before it is taken.
448 */
449 if (unlikely(reason == IRQ_SYSTEM_RESET)) {
450 replay_system_reset();
451 return;
452 }
413 453
414 /* 454 /*
415 * The 0 index (SRR1[42:45]=b0000) must always evaluate to 0, 455 * The 0 index (SRR1[42:45]=b0000) must always evaluate to 0,
416 * so this can be called unconditionally with srr1 wake reason. 456 * so this can be called unconditionally with the SRR1 wake
457 * reason as returned by the idle code, which uses 0 to mean no
458 * interrupt.
459 *
460 * If a future CPU was to designate this as an interrupt reason,
461 * then a new index for no interrupt must be assigned.
417 */ 462 */
418 local_paca->irq_happened |= srr1_to_lazyirq[idx]; 463 local_paca->irq_happened |= reason;
419} 464}
420#endif /* CONFIG_PPC_BOOK3S */ 465#endif /* CONFIG_PPC_BOOK3S */
421 466