Skip to content

Commit

Permalink
genirq: Handle pending irqs in irq_startup()
Browse files Browse the repository at this point in the history
An interrupt might be pending when irq_startup() is called, but the
startup code does not invoke the resend logic. In some cases this
prevents the device from issuing another interrupt which renders the
device non functional.

Call the resend function in irq_startup() to keep things going.

Reported-and-tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Feb 15, 2012
1 parent ac56376 commit b4bc724
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 11 deletions.
4 changes: 2 additions & 2 deletions kernel/irq/autoprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ unsigned long probe_irq_on(void)
if (desc->irq_data.chip->irq_set_type)
desc->irq_data.chip->irq_set_type(&desc->irq_data,
IRQ_TYPE_PROBE);
irq_startup(desc);
irq_startup(desc, false);
}
raw_spin_unlock_irq(&desc->lock);
}
Expand All @@ -70,7 +70,7 @@ unsigned long probe_irq_on(void)
raw_spin_lock_irq(&desc->lock);
if (!desc->action && irq_settings_can_probe(desc)) {
desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
if (irq_startup(desc))
if (irq_startup(desc, false))
desc->istate |= IRQS_PENDING;
}
raw_spin_unlock_irq(&desc->lock);
Expand Down
17 changes: 10 additions & 7 deletions kernel/irq/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,22 @@ static void irq_state_set_masked(struct irq_desc *desc)
irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
}

int irq_startup(struct irq_desc *desc)
int irq_startup(struct irq_desc *desc, bool resend)
{
int ret = 0;

irq_state_clr_disabled(desc);
desc->depth = 0;

if (desc->irq_data.chip->irq_startup) {
int ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
irq_state_clr_masked(desc);
return ret;
} else {
irq_enable(desc);
}

irq_enable(desc);
return 0;
if (resend)
check_irq_resend(desc, desc->irq_data.irq);
return ret;
}

void irq_shutdown(struct irq_desc *desc)
Expand Down Expand Up @@ -646,7 +649,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
irq_settings_set_noprobe(desc);
irq_settings_set_norequest(desc);
irq_settings_set_nothread(desc);
irq_startup(desc);
irq_startup(desc, true);
}
out:
irq_put_desc_busunlock(desc, flags);
Expand Down
2 changes: 1 addition & 1 deletion kernel/irq/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);

extern int irq_startup(struct irq_desc *desc);
extern int irq_startup(struct irq_desc *desc, bool resend);
extern void irq_shutdown(struct irq_desc *desc);
extern void irq_enable(struct irq_desc *desc);
extern void irq_disable(struct irq_desc *desc);
Expand Down
2 changes: 1 addition & 1 deletion kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
desc->istate |= IRQS_ONESHOT;

if (irq_settings_can_autoenable(desc))
irq_startup(desc);
irq_startup(desc, true);
else
/* Undo nested disables: */
desc->depth = 1;
Expand Down

0 comments on commit b4bc724

Please sign in to comment.