The original spurious.c already provides the functionality of
detect & disable screaming interrupts.  But under some situation
the code won't work.  When irq_poll is on and the system has some
ISRs that don’t do sanity check and return IRQ_NONE.  This will
come into a loop:  device A is screaming, keeps generates large
amount of interrupts,  while device B's ISR keep being executed by
misrouted irq code (because B's ISR have problem and won't return
as IRQ_NONE.  In this situation the original code to detect the
screaming interrupts will not have a chance to be called.  And the
system performance will be very poor.

This RFC patch tries to solve this problem, by adding a counter for
maximum misrouted interrupts we should handle per second.  And if
we reached the maximum number we simply skip the misrounted irq.

This patch is based on tag v3.12, please give comments on it, all
kinds of comments are welcome.

Signed-off-by: Warner Wang <warner.w...@hp.com>
---
 include/linux/irqdesc.h |    1 +
 kernel/irq/irqdesc.c    |    1 +
 kernel/irq/manage.c     |    1 +
 kernel/irq/spurious.c   |   14 +++++++++++---
 4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 56fb646..1b777e3 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -52,6 +52,7 @@ struct irq_desc {
        unsigned int            irq_count;      /* For detecting broken IRQs */
        unsigned long           last_unhandled; /* Aging timer for unhandled 
count */
        unsigned int            irqs_unhandled;
+       unsigned int            handled_in_jiff;
        raw_spinlock_t          lock;
        struct cpumask          *percpu_enabled;
 #ifdef CONFIG_SMP
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 192a302..0fcbb55 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -86,6 +86,7 @@ static void desc_set_defaults(unsigned int irq, struct 
irq_desc *desc, int node,
        desc->depth = 1;
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
+       desc->handled_in_jiff = 0;
        desc->name = NULL;
        desc->owner = owner;
        for_each_possible_cpu(cpu)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 514bcfd..31b2cb0 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1146,6 +1146,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, 
struct irqaction *new)
        /* Reset broken irq detection when installing new handler */
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
+       desc->handled_in_jiff = 0;
 
        /*
         * Check whether we disabled the irq via the spurious handler
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 7b5f012..817d5a8 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -265,6 +265,7 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc,
        return action && (action->flags & IRQF_IRQPOLL);
 }
 
+static int irq_in_sec = 5000;
 void note_interrupt(unsigned int irq, struct irq_desc *desc,
                    irqreturn_t action_ret)
 {
@@ -295,9 +296,16 @@ void note_interrupt(unsigned int irq, struct irq_desc 
*desc,
        }
 
        if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
-               int ok = misrouted_irq(irq);
-               if (action_ret == IRQ_NONE)
-                       desc->irqs_unhandled -= ok;
+               if (desc->handled_in_jiff < (irq_in_sec / HZ)) {
+                       int ok = misrouted_irq(irq);
+                       if (action_ret == IRQ_NONE) {
+                               desc->irqs_unhandled -= ok;
+                               if (time_after_eq(desc->last_unhandled, 
jiffies))
+                                       desc->handled_in_jiff++;
+                               else
+                                       desc->handled_in_jiff = 0;
+                       }
+               }
        }
 
        desc->irq_count++;
-- 
1.7.1

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

Reply via email to