diff options
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r-- | arch/powerpc/kernel/irq.c | 51 |
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 | |||
398 | static const u8 srr1_to_lazyirq[0x10] = { | 415 | static 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 | ||
427 | void replay_system_reset(void) | ||
428 | { | ||
429 | struct pt_regs regs; | ||
430 | |||
431 | ppc_save_regs(®s); | ||
432 | regs.trap = 0x100; | ||
433 | get_paca()->in_nmi = 1; | ||
434 | system_reset_exception(®s); | ||
435 | get_paca()->in_nmi = 0; | ||
436 | } | ||
437 | EXPORT_SYMBOL_GPL(replay_system_reset); | ||
438 | |||
410 | void irq_set_pending_from_srr1(unsigned long srr1) | 439 | void 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 | ||