===================================================================
@@ -385,10 +385,23 @@ setup_affinity(unsigned int irq, struct
void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
{
if (suspend) {
- if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)
- || irqd_has_set(&desc->irq_data, IRQD_WAKEUP_STATE))
+ struct irqaction *action = desc->action;
+ unsigned int no_suspend, flags;
+
+ if (!action || (desc->istate & IRQS_SPURIOUS_DISABLED))
+ return;
+ no_suspend = IRQF_NO_SUSPEND;
+ flags = 0;
+ do {
+ no_suspend &= action->flags;
+ flags |= action->flags;
+ action = action->next;
+ } while (action);
+ if (no_suspend)
return;
desc->istate |= IRQS_SUSPENDED;
+ if (flags & IRQF_NO_SUSPEND)
+ return;
}
if (!desc->depth++)
@@ -446,7 +459,16 @@ EXPORT_SYMBOL(disable_irq);
void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
{
if (resume) {
- if (!(desc->istate & IRQS_SUSPENDED)) {
+ if (desc->istate & IRQS_SUSPENDED) {
+ desc->istate &= ~IRQS_SUSPENDED;
+ if (desc->istate & IRQS_SPURIOUS_DISABLED) {
+ pr_err("Re-enabling emergency disabled IRQ %d\n",
+ irq);
+ desc->istate &= ~IRQS_SPURIOUS_DISABLED;
+ } else if (desc->depth == 0) {
+ return;
+ }
+ } else {
if (!desc->action)
return;
if (!(desc->action->flags & IRQF_FORCE_RESUME))
@@ -454,7 +476,6 @@ void __enable_irq(struct irq_desc *desc,
/* Pretend that it got disabled ! */
desc->depth++;
}
- desc->istate &= ~IRQS_SUSPENDED;
}
switch (desc->depth) {
@@ -1079,7 +1100,7 @@ __setup_irq(unsigned int irq, struct irq
*/
#define IRQF_MISMATCH \
- (IRQF_TRIGGER_MASK | IRQF_ONESHOT | IRQF_NO_SUSPEND)
+ (IRQF_TRIGGER_MASK | IRQF_ONESHOT)
if (!((old->flags & new->flags) & IRQF_SHARED) ||
((old->flags ^ new->flags) & IRQF_MISMATCH))
===================================================================
@@ -131,6 +131,23 @@ void __irq_wake_thread(struct irq_desc *
}
irqreturn_t
+do_irqaction(struct irq_desc *desc, struct irqaction *action,
+ unsigned int irq, void *dev_id)
+{
+ irqreturn_t ret;
+
+ if (unlikely((desc->istate & IRQS_SUSPENDED) &&
+ !(action->flags & IRQF_NO_SUSPEND)))
+ return IRQ_NONE;
+
+ trace_irq_handler_entry(irq, action);
+ ret = action->handler(irq, dev_id);
+ trace_irq_handler_exit(irq, action, ret);
+
+ return ret;
+}
+
+irqreturn_t
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
irqreturn_t retval = IRQ_NONE;
@@ -139,9 +156,7 @@ handle_irq_event_percpu(struct irq_desc
do {
irqreturn_t res;
- trace_irq_handler_entry(irq, action);
- res = action->handler(irq, action->dev_id);
- trace_irq_handler_exit(irq, action, res);
+ res = do_irqaction(desc, action, irq, action->dev_id);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
irq, action->handler))
===================================================================
@@ -275,6 +275,8 @@ try_misrouted_irq(unsigned int irq, stru
void note_interrupt(unsigned int irq, struct irq_desc *desc,
irqreturn_t action_ret)
{
+ int misrouted;
+
if (desc->istate & IRQS_POLL_INPROGRESS ||
irq_settings_is_polled(desc))
return;
@@ -384,6 +386,9 @@ void note_interrupt(unsigned int irq, st
}
}
+ misrouted = unlikely(try_misrouted_irq(irq, desc, action_ret)) ?
+ misrouted_irq(irq) : 0;
+
if (unlikely(action_ret == IRQ_NONE)) {
/*
* If we are seeing only the odd spurious IRQ caused by
@@ -391,19 +396,23 @@ void note_interrupt(unsigned int irq, st
* otherwise the counter becomes a doomsday timer for otherwise
* working systems
*/
- if (time_after(jiffies, desc->last_unhandled + HZ/10))
- desc->irqs_unhandled = 1;
- else
+ if (time_after(jiffies, desc->last_unhandled + HZ/10)) {
+ desc->irqs_unhandled = 1 - misrouted;
+ } else if (!misrouted) {
desc->irqs_unhandled++;
+ if (unlikely(desc->istate & IRQS_SUSPENDED)) {
+ /*
+ * That shouldn't happen. It means IRQs from
+ * a device that is supposed to be suspended at
+ * this point. Decay faster.
+ */
+ desc->irqs_unhandled += 999;
+ desc->irq_count += 999;
+ }
+ }
desc->last_unhandled = jiffies;
}
- if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
- int ok = misrouted_irq(irq);
- if (action_ret == IRQ_NONE)
- desc->irqs_unhandled -= ok;
- }
-
desc->irq_count++;
if (likely(desc->irq_count < 100000))
return;