lantiq: fix spurious irq storm
authorFelix Fietkau <nbd@nbd.name>
Thu, 19 Jan 2017 11:31:34 +0000 (12:31 +0100)
committerFelix Fietkau <nbd@nbd.name>
Thu, 19 Jan 2017 11:33:15 +0000 (12:33 +0100)
Since the MIPS IRQ stack patches, lantiq devices were emitting a storm
of messages like this:

[  567.872172] Spurious IRQ: CAUSE=0x1100c300

Fix this by reworking the IRQ dispatch code

Signed-off-by: Felix Fietkau <nbd@nbd.name>
target/linux/lantiq/patches-4.4/0050-MIPS-Lantiq-Fix-cascaded-IRQ-setup.patch [new file with mode: 0644]

diff --git a/target/linux/lantiq/patches-4.4/0050-MIPS-Lantiq-Fix-cascaded-IRQ-setup.patch b/target/linux/lantiq/patches-4.4/0050-MIPS-Lantiq-Fix-cascaded-IRQ-setup.patch
new file mode 100644 (file)
index 0000000..c0d7afc
--- /dev/null
@@ -0,0 +1,87 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 19 Jan 2017 12:14:44 +0100
+Subject: [PATCH] MIPS: Lantiq: Fix cascaded IRQ setup
+
+With the IRQ stack changes integrated, the XRX200 devices started
+emitting a constant stream of kernel messages like this:
+
+[  565.415310] Spurious IRQ: CAUSE=0x1100c300
+
+This appears to be caused by IP0 firing for some reason without being
+handled. Fix this by setting up IP2-6 as a proper chained IRQ handler and
+calling do_IRQ for all MIPS CPU interrupts.
+
+Cc: john@phrozen.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -271,6 +271,11 @@ static void ltq_hw5_irqdispatch(void)
+ DEFINE_HWx_IRQDISPATCH(5)
+ #endif
++static void ltq_hw_irq_handler(struct irq_desc *desc)
++{
++      ltq_hw_irqdispatch(irq_desc_get_irq(desc) - 2);
++}
++
+ #ifdef CONFIG_MIPS_MT_SMP
+ void __init arch_init_ipiirq(int irq, struct irqaction *action)
+ {
+@@ -315,23 +320,19 @@ static struct irqaction irq_call = {
+ asmlinkage void plat_irq_dispatch(void)
+ {
+       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+-      unsigned int i;
++      int irq;
+-      if ((MIPS_CPU_TIMER_IRQ == 7) && (pending & CAUSEF_IP7)) {
+-              do_IRQ(MIPS_CPU_TIMER_IRQ);
+-              goto out;
+-      } else {
+-              for (i = 0; i < MAX_IM; i++) {
+-                      if (pending & (CAUSEF_IP2 << i)) {
+-                              ltq_hw_irqdispatch(i);
+-                              goto out;
+-                      }
+-              }
++      if (!pending) {
++              spurious_interrupt();
++              return;
+       }
+-      pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+-out:
+-      return;
++      pending >>= CAUSEB_IP;
++      while (pending) {
++              irq = fls(pending) - 1;
++              do_IRQ(MIPS_CPU_IRQ_BASE + irq);
++              pending &= ~BIT(irq);
++      }
+ }
+ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+@@ -356,11 +357,6 @@ static const struct irq_domain_ops irq_d
+       .map = icu_map,
+ };
+-static struct irqaction cascade = {
+-      .handler = no_action,
+-      .name = "cascade",
+-};
+-
+ int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ {
+       struct device_node *eiu_node;
+@@ -392,7 +388,7 @@ int __init icu_of_init(struct device_nod
+       mips_cpu_irq_init();
+       for (i = 0; i < MAX_IM; i++)
+-              setup_irq(i + 2, &cascade);
++              irq_set_chained_handler(i + 2, ltq_hw_irq_handler);
+       if (cpu_has_vint) {
+               pr_info("Setting up vectored interrupts\n");