[PATCH] genirq: handle unhandled irqs when the handler is threaded

From: Uwe Kleine-KÃnig
Date: Tue Oct 19 2010 - 04:23:25 EST


This helps detecting stuck irq lines for threaded irqs.

Signed-off-by: Uwe Kleine-KÃnig <u.kleine-koenig@xxxxxxxxxxxxxx>
---
include/linux/irq.h | 2 ++
kernel/irq/handle.c | 6 ------
kernel/irq/manage.c | 7 ++++++-
kernel/irq/spurious.c | 17 +++++++++++++++--
4 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index c03243a..fea4dc0 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -324,6 +324,8 @@ static inline void generic_handle_irq(unsigned int irq)
}

/* Handling of unhandled and spurious interrupts: */
+extern void note_threaded_interrupt(unsigned int irq, struct irq_desc *desc,
+ irqreturn_t action_ret);
extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
irqreturn_t action_ret);

diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 27e5c69..439cb78 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -378,12 +378,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
switch (ret) {
case IRQ_WAKE_THREAD:
/*
- * Set result to handled so the spurious check
- * does not trigger.
- */
- ret = IRQ_HANDLED;
-
- /*
* Catch drivers which return WAKE_THREAD but
* did not set up a thread function
*/
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index c3003e9..361fe54 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -598,12 +598,17 @@ static int irq_thread(void *data)
desc->status |= IRQ_PENDING;
raw_spin_unlock_irq(&desc->lock);
} else {
+ irqreturn_t action_ret;
+
raw_spin_unlock_irq(&desc->lock);

- action->thread_fn(action->irq, action->dev_id);
+ action_ret = action->thread_fn(action->irq, action->dev_id);

if (oneshot)
irq_finalize_oneshot(action->irq, desc);
+
+ if (!noirqdebug)
+ note_threaded_interrupt(action->irq, desc, action_ret);
}

wake = atomic_dec_and_test(&desc->threads_active);
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index d819a3d6..079648f 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -215,8 +215,8 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc,
return action && (action->flags & IRQF_IRQPOLL);
}

-void note_interrupt(unsigned int irq, struct irq_desc *desc,
- irqreturn_t action_ret)
+void note_threaded_interrupt(unsigned int irq, struct irq_desc *desc,
+ irqreturn_t action_ret)
{
if (unlikely(action_ret != IRQ_HANDLED)) {
/*
@@ -264,6 +264,19 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
desc->irqs_unhandled = 0;
}

+void note_interrupt(unsigned int irq, struct irq_desc *desc,
+ irqreturn_t action_ret)
+{
+ if (action_ret == IRQ_WAKE_THREAD)
+ /* handle when the thread function returns */
+ return;
+
+ /* don't report IRQ_WAKE_THREAD | IRQ_HANDLED as bogus return value */
+ action_ret &= ~IRQ_WAKE_THREAD;
+
+ note_threaded_interrupt(irq, desc, action_ret);
+}
+
int noirqdebug __read_mostly;

int noirqdebug_setup(char *str)
--
1.7.2.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/