Skip to content

Commit

Permalink
genirq: Allow check_wakeup_irqs to notice level-triggered interrupts
Browse files Browse the repository at this point in the history
Level triggered interrupts do not cause IRQS_PENDING to be set when
they fire while "disabled" as the 'pending' state is always present in
the level - they automatically refire where re-enabled.

However the IRQS_PENDING flag is also used to abort a suspend cycle -
if any 'is_wakeup_set' interrupt is PENDING, check_wakeup_irqs() will
cause suspend to abort. Without IRQS_PENDING, suspend won't abort.

Consequently, level-triggered interrupts that fire during the 'noirq'
phase of suspend do not currently abort suspend.

So set IRQS_PENDING even for level triggered interrupts, and make sure
to clear the flag in check_irq_resend.

[ Changelog by courtesy of Neil ]

Tested-by: NeilBrown <neilb@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed May 4, 2012
1 parent f5d8947 commit d4dc0f9
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 3 deletions.
4 changes: 3 additions & 1 deletion kernel/irq/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
* If its disabled or no action available
* keep it masked and get out of here
*/
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data)))
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
desc->istate |= IRQS_PENDING;
goto out_unlock;
}

handle_irq_event(desc);

Expand Down
7 changes: 5 additions & 2 deletions kernel/irq/resend.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,13 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)
/*
* We do not resend level type interrupts. Level type
* interrupts are resent by hardware when they are still
* active.
* active. Clear the pending bit so suspend/resume does not
* get confused.
*/
if (irq_settings_is_level(desc))
if (irq_settings_is_level(desc)) {
desc->istate &= ~IRQS_PENDING;
return;
}
if (desc->istate & IRQS_REPLAY)
return;
if (desc->istate & IRQS_PENDING) {
Expand Down

0 comments on commit d4dc0f9

Please sign in to comment.