rewrite of platform irq handler
[openwrt.git] / target / linux / aruba-2.6 / patches / 002-irq.patch
index 94e68cf..f6b9425 100644 (file)
@@ -1,137 +1,7 @@
-diff -Nur linux-2.6.15/arch/mips/aruba/idtIRQ.S linux-2.6.15-openwrt/arch/mips/aruba/idtIRQ.S
---- linux-2.6.15/arch/mips/aruba/idtIRQ.S      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-openwrt/arch/mips/aruba/idtIRQ.S      2006-01-10 00:32:32.000000000 +0100
-@@ -0,0 +1,87 @@
-+/**************************************************************************
-+ *
-+ *  BRIEF MODULE DESCRIPTION
-+ *     Intterrupt dispatcher code for IDT boards
-+ *
-+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
-+ *         
-+ *  This program is free software; you can redistribute  it and/or modify it
-+ *  under  the terms of  the GNU General  Public License as published by the
-+ *  Free Software Foundation;  either version 2 of the  License, or (at your
-+ *  option) any later version.
-+ *
-+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
-+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
-+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
-+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
-+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
-+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
-+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ *  You should have received a copy of the  GNU General Public License along
-+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
-+ *  675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ **************************************************************************
-+ * May 2004 rkt, neb
-+ *
-+ * Initial Release
-+ *
-+ * 
-+ *
-+ **************************************************************************
-+ */
-+              
-+      
-+#include <asm/asm.h>
-+#include <asm/mipsregs.h>
-+#include <asm/regdef.h>
-+#include <asm/stackframe.h>
-+
-+      .text
-+      .set    noreorder
-+      .set    noat
-+      .align  5
-+      NESTED(idtIRQ, PT_SIZE, sp)
-+      .set noat
-+      SAVE_ALL
-+      CLI
-+
-+      .set    at
-+      .set    noreorder
-+
-+      /* Get the pending interrupts */
-+      mfc0    t0, CP0_CAUSE
-+      nop
-+                       
-+      /* Isolate the allowed ones by anding the irq mask */
-+      mfc0    t2, CP0_STATUS
-+      move    a1, sp          /* need a nop here, hence we anticipate */
-+      andi    t0, CAUSEF_IP
-+      and     t0, t2
-+                                                                
-+      /* check for r4k counter/timer IRQ. */
-+      
-+      andi    t1, t0, CAUSEF_IP7
-+      beqz    t1, 1f
-+      nop
-+
-+      jal     aruba_timer_interrupt   
-+
-+      li      a0, 7
-+
-+      j       ret_from_irq
-+      nop
-+1:
-+      jal     aruba_irqdispatch
-+      move    a0, t0
-+      j       ret_from_irq
-+      nop
-+
-+      END(idtIRQ)
-+
-+
-diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/aruba/irq.c
---- linux-2.6.15/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.15-openwrt/arch/mips/aruba/irq.c 2006-01-10 00:32:32.000000000 +0100
-@@ -0,0 +1,447 @@
-+/**************************************************************************
-+ *
-+ *  BRIEF MODULE DESCRIPTION
-+ *     Interrupt routines for IDT EB434 boards / Atheros boards
-+ *     Modified by Aruba Networks
-+ *
-+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
-+ *         
-+ *  This program is free software; you can redistribute  it and/or modify it
-+ *  under  the terms of  the GNU General  Public License as published by the
-+ *  Free Software Foundation;  either version 2 of the  License, or (at your
-+ *  option) any later version.
-+ *
-+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
-+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
-+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
-+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
-+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
-+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
-+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ *  You should have received a copy of the  GNU General Public License along
-+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
-+ *  675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ *
-+ **************************************************************************
-+ * May 2004 rkt, neb
-+ *
-+ * Initial Release
-+ *
-+ * 
-+ *
-+ **************************************************************************
-+ */
-+
+diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c
+--- linux-2.6.17/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c 2006-10-12 14:32:40.026285000 -0700
+@@ -0,0 +1,282 @@
 +#include <linux/errno.h>
 +#include <linux/init.h>
 +#include <linux/kernel_stat.h>
@@ -156,22 +26,7 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +
 +#include <asm/irq.h>
 +
-+#undef DEBUG_IRQ
-+#ifdef DEBUG_IRQ
-+/* note: prints function name for you */
-+#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
-+#else
-+#define DPRINTK(fmt, args...)
-+#endif
-+
-+extern asmlinkage void idtIRQ(void);
-+static unsigned int startup_irq(unsigned int irq);
-+static void end_irq(unsigned int irq_nr);
-+static void mask_and_ack_irq(unsigned int irq_nr);
-+static void aruba_enable_irq(unsigned int irq_nr);
-+static void aruba_disable_irq(unsigned int irq_nr);
-+
-+extern void __init init_generic_irq(void);
++extern void aruba_timer_interrupt(struct pt_regs *regs);
 +
 +typedef struct {
 +      u32 mask;
@@ -179,12 +34,12 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +} intr_group_t;
 +
 +static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = {
-+      {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
++      {0x00000000, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
 +};
 +
 +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
-+#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003010 + 4)))
-+#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)((0xbc003010) + 4))) = (val))
++#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014)))
++#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT())
 +
 +static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = {
 +      {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
@@ -198,18 +53,6 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +#define READ_MASK_MUSCAT(base) (*(base + 2))
 +#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
 +
-+static inline int irq_to_group(unsigned int irq_nr)
-+{
-+      switch (mips_machtype) {
-+              case MACH_ARUBA_AP70:
-+                      return ((irq_nr - GROUP0_IRQ_BASE) >> 5);
-+              case MACH_ARUBA_AP65:
-+              case MACH_ARUBA_AP60:
-+              default:
-+                      return 0;
-+      }
-+}
-+
 +static inline int group_to_ip(unsigned int group)
 +{
 +      switch (mips_machtype) {
@@ -222,219 +65,146 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +      }
 +}
 +
-+static inline void enable_local_irq(unsigned int ip)
++static inline void enable_local_irq(unsigned int irq)
 +{
-+      int ipnum = 0x100 << ip;
-+      clear_c0_cause(ipnum);
-+      set_c0_status(ipnum);
++      clear_c0_cause(0x100 << irq);
++      set_c0_status(0x100 << irq);
++      irq_enable_hazard();
 +}
 +
-+static inline void disable_local_irq(unsigned int ip)
++static inline void disable_local_irq(unsigned int irq)
 +{
-+      int ipnum = 0x100 << ip;
-+      clear_c0_status(ipnum);
++      clear_c0_status(0x100 << irq);
++      clear_c0_cause(0x100 << irq);
++      irq_disable_hazard();
 +}
 +
-+static inline void ack_local_irq(unsigned int ip)
-+{
-+      int ipnum = 0x100 << ip;
-+      clear_c0_cause(ipnum);
-+}
-+
-+static void aruba_enable_irq(unsigned int irq_nr)
++static inline void aruba_irq_enable(unsigned int irq)
 +{
 +      unsigned long flags;
-+      int ip = irq_nr - GROUP0_IRQ_BASE;
-+      unsigned int group, intr_bit;
-+      volatile unsigned int *addr;
-+
++      unsigned int  group, intr_bit;
++      volatile unsigned int  *addr;
 +
 +      local_irq_save(flags);
-+      
-+      if (ip < 0) {
-+              enable_local_irq(irq_nr);
++
++      if (irq < GROUP0_IRQ_BASE) {
++              enable_local_irq(irq);
 +      } else {
-+              // calculate group
++              int ip = irq - GROUP0_IRQ_BASE;
 +              switch (mips_machtype) {
 +                      case MACH_ARUBA_AP70:
++                              // irqs are in groups of 32
++                              // ip is set to the remainder
 +                              group = ip >> 5;
-+                              break;
-+                      case MACH_ARUBA_AP65:
-+                      case MACH_ARUBA_AP60:
-+                      default:
-+                              group = 0;
-+                              break;
-+              }
-+
-+              // calc interrupt bit within group
-+              ip -= (group << 5);
-+              intr_bit = 1 << ip;
-+
-+              // first enable the IP mapped to this IRQ
-+              enable_local_irq(group_to_ip(group));
++                              ip &= 0x1f;
 +
-+              switch (mips_machtype) {
-+                      case MACH_ARUBA_AP70:
++                              // bit -> 0 = unmask
++                              intr_bit = 1 << ip;
 +                              addr = intr_group_muscat[group].base_addr;
 +                              WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
 +                              break;
++
 +                      case MACH_ARUBA_AP65:
 +                      case MACH_ARUBA_AP60:
-+                      default:
++                              group = 0;
++
++                              // bit -> 1 = unmasked
++                              intr_bit = 1 << ip;
 +                              addr = intr_group_merlot[group].base_addr;
 +                              WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
 +                              break;
 +              }
++              enable_local_irq(group_to_ip(group));
 +      }
 +
++      back_to_back_c0_hazard();
 +      local_irq_restore(flags);
-+
 +}
 +
-+static void aruba_disable_irq(unsigned int irq_nr)
++static void aruba_irq_disable(unsigned int irq)
 +{
 +      unsigned long flags;
-+      int ip = irq_nr - GROUP0_IRQ_BASE;
-+      unsigned int group, intr_bit, mask;
-+      volatile unsigned int *addr;
++      unsigned int  group, intr_bit, mask;
++      volatile unsigned int  *addr;
 +
 +      local_irq_save(flags);
 +
-+      if (ip < 0) {
-+              disable_local_irq(irq_nr);
++      if (irq < GROUP0_IRQ_BASE) {
++              disable_local_irq(irq);
 +      } else {
-+              // calculate group
++              int ip = irq - GROUP0_IRQ_BASE;
 +              switch (mips_machtype) {
 +                      case MACH_ARUBA_AP70:
-+                              group = ip >> 5;
-+                              break;
-+                      case MACH_ARUBA_AP65:
-+                      case MACH_ARUBA_AP60:
-+                      default:
-+                              group = 0;
-+                              break;
-+              }
++                              idt_gpio->gpioistat &= ~(1 << ip);
 +
-+              // calc interrupt bit within group
-+              ip -= group << 5;
-+              intr_bit = 1 << ip;
++                              // irqs are in groups of 32
++                              // ip is set to the remainder
++                              group = ip >> 5;
++                              ip &= 0x1f;
 +
-+              switch (mips_machtype) {
-+                      case MACH_ARUBA_AP70:
++                              // bit -> 1 = mask
++                              intr_bit = 1 << ip;
 +                              addr = intr_group_muscat[group].base_addr;
-+                              // mask intr within group
++
 +                              mask = READ_MASK_MUSCAT(addr);
 +                              mask |= intr_bit;
 +                              WRITE_MASK_MUSCAT(addr, mask);
-+      
-+                              /*
-+                                 if there are no more interrupts enabled in this
-+                                 group, disable corresponding IP
-+                               */
-+                              if (mask == intr_group_muscat[group].mask)
++
++                              if (mask == intr_group_muscat[group].mask) {
 +                                      disable_local_irq(group_to_ip(group));
++                              }
 +                              break;
++
 +                      case MACH_ARUBA_AP65:
 +                      case MACH_ARUBA_AP60:
-+                      default:
++                              group = 0;
++
++                              // bit -> 0 = masked
++                              intr_bit = 1 << ip;
 +                              addr = intr_group_merlot[group].base_addr;
-+                              // mask intr within group
++
 +                              mask = READ_MASK_MERLOT(addr);
 +                              mask &= ~intr_bit;
 +                              WRITE_MASK_MERLOT(addr, mask);
-+                              if (READ_MASK_MERLOT(addr))
++
++                              if (mask == intr_group_merlot[group].mask) {
 +                                      disable_local_irq(group_to_ip(group));
++                              }
 +                              break;
 +              }
 +      }
 +
++      back_to_back_c0_hazard();
 +      local_irq_restore(flags);
-+
 +}
 +
-+static unsigned int startup_irq(unsigned int irq_nr)
++static unsigned int aruba_irq_startup(unsigned int irq)
 +{
-+      aruba_enable_irq(irq_nr);
++      aruba_irq_enable(irq);
 +      return 0;
 +}
 +
-+static void shutdown_irq(unsigned int irq_nr)
-+{
-+      aruba_disable_irq(irq_nr);
-+      return;
-+}
++#define aruba_irq_shutdown aruba_irq_disable
 +
-+static void mask_and_ack_irq(unsigned int irq_nr)
++static void aruba_irq_ack(unsigned int irq)
 +{
-+      aruba_disable_irq(irq_nr);
-+      ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
++      aruba_irq_disable(irq);
 +}
 +
-+static void end_irq(unsigned int irq_nr)
++static void aruba_irq_end(unsigned int irq)
 +{
-+
-+      unsigned long flags;
-+      int ip = irq_nr - GROUP0_IRQ_BASE;
-+      unsigned int intr_bit, group;
-+      volatile unsigned int *addr;
-+
-+
-+      local_irq_save(flags);
-+      if (irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)) {
-+              printk("warning: end_irq %d did not enable (%x)\n",
-+                     irq_nr, irq_desc[irq_nr].status);
-+      } else if (ip<0) {
-+              enable_local_irq(irq_nr);
-+      } else {
-+
-+              switch (mips_machtype) {
-+                      case MACH_ARUBA_AP70:
-+                              if (irq_nr == GROUP4_IRQ_BASE + 9)       idt_gpio->gpioistat &= 0xfffffdff;
-+                              else if (irq_nr == GROUP4_IRQ_BASE + 10) idt_gpio->gpioistat &= 0xfffffbff;
-+                              else if (irq_nr == GROUP4_IRQ_BASE + 11) idt_gpio->gpioistat &= 0xfffff7ff;
-+                              else if (irq_nr == GROUP4_IRQ_BASE + 12) idt_gpio->gpioistat &= 0xffffefff;
-+              
-+                              group = ip >> 5;
-+                      
-+                              // calc interrupt bit within group
-+                              ip -= (group << 5);
-+                              intr_bit = 1 << ip;
-+              
-+                              // first enable the IP mapped to this IRQ
-+                              enable_local_irq(group_to_ip(group));
-+              
-+                              addr = intr_group_muscat[group].base_addr;
-+                              // unmask intr within group
-+                              WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
-+                              break;
-+
-+                      case MACH_ARUBA_AP65:
-+                              case MACH_ARUBA_AP60:
-+                              group = 0;
-+      
-+                              // calc interrupt bit within group
-+                              intr_bit = 1 << ip;
-+      
-+                              // first enable the IP mapped to this IRQ
-+                              enable_local_irq(group_to_ip(group));
-+      
-+                              addr = intr_group_merlot[group].base_addr;
-+                              // unmask intr within group
-+                              WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
-+                              break;
-+              }
-+      }
-+      local_irq_restore(flags);
++      if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
++              aruba_irq_enable(irq);
 +}
 +
 +static struct hw_interrupt_type aruba_irq_type = {
-+      .typename = "IDT434",
-+      .startup = startup_irq,
-+      .shutdown = shutdown_irq,
-+      .enable = aruba_enable_irq,
-+      .disable = aruba_disable_irq,
-+      .ack = mask_and_ack_irq,
-+      .end = end_irq,
++      .typename       = "ARUBA",
++      .startup        = aruba_irq_startup,
++      .shutdown       = aruba_irq_shutdown,
++      .enable         = aruba_irq_enable,
++      .disable        = aruba_irq_disable,
++      .ack            = aruba_irq_ack,
++      .end            = aruba_irq_end,
 +};
 +
 +void __init arch_init_irq(void)
@@ -442,10 +212,6 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +      int i;
 +      printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
 +      memset(irq_desc, 0, sizeof(irq_desc));
-+      set_except_vector(0, idtIRQ);
-+
-+
-+      set_c0_status(0xFF00);
 +
 +      for (i = 0; i < RC32434_NR_IRQS; i++) {
 +              irq_desc[i].status = IRQ_DISABLED;
@@ -454,28 +220,22 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +              irq_desc[i].handler = &aruba_irq_type;
 +              spin_lock_init(&irq_desc[i].lock);
 +      }
-+
-+      switch (mips_machtype) {
-+              case MACH_ARUBA_AP70:
-+                      break;
-+              case MACH_ARUBA_AP65:
-+              case MACH_ARUBA_AP60:
-+              default:
-+                      WRITE_MASK_MERLOT(intr_group_merlot[0].base_addr, 0);
-+                      *((volatile unsigned long *)0xbc003014) = 0x10;
-+                      break;
-+      }
 +}
 +
 +/* Main Interrupt dispatcher */
-+void aruba_irqdispatch(unsigned long cp0_cause, struct pt_regs *regs)
++
++void plat_irq_dispatch(struct pt_regs *regs)
 +{
 +      unsigned int pend, group, ip;
 +      volatile unsigned int *addr;
++      unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
++
++      if (cp0_cause & CAUSEF_IP7)
++              return aruba_timer_interrupt(regs);
 +
 +      if(cp0_cause == 0) {
 +              printk("INTERRUPT(S) FIRED WHILE MASKED\n");
-+
++#ifdef ARUBA_DEBUG
 +              // debuging use -- figure out which interrupt(s) fired
 +              cp0_cause = read_c0_cause() & CAUSEF_IP;
 +              while (cp0_cause) {
@@ -486,11 +246,10 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +                      printk(" ---> MASKED IRQ %d\n",irq_nr);
 +                      cp0_cause &= ~(1 << intr_bit);
 +              }
-+
++#endif
 +              return;
 +      }
 +
-+      
 +      switch (mips_machtype) {
 +              case MACH_ARUBA_AP70:
 +                      if ((ip = (cp0_cause & 0x7c00))) {
@@ -499,9 +258,9 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +                              addr = intr_group_muscat[group].base_addr;
 +              
 +                              pend = READ_PEND_MUSCAT(addr);
-+                              pend &= ~READ_MASK_MUSCAT(addr);        // only unmasked interrupts
++                              pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts
 +                              pend = 39 - rc32434_clz(pend);
-+                              do_IRQ((group << 5) + pend, regs);
++                              do_IRQ(pend + (group << 5), regs);
 +                      }
 +                      break;
 +              case MACH_ARUBA_AP65:
@@ -510,32 +269,17 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub
 +                      if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6
 +                              // Misc Interrupt
 +                              group = 0;
++
 +                              addr = intr_group_merlot[group].base_addr;
++
 +                              pend = READ_PEND_MERLOT(addr);
 +                              pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts
-+                              /* handle one misc interrupt at a time */
-+                              while (pend) {
-+                                      unsigned long intr_bit;
-+                                      unsigned int irq_nr;
-+
-+                                      intr_bit = (31 - rc32434_clz(pend));
-+                                      irq_nr = intr_bit + GROUP0_IRQ_BASE;
-+
-+                                      do_IRQ(irq_nr, regs);
-+                                      pend &= ~(1 << intr_bit);
-+                              }
++                              pend = 31 - rc32434_clz(pend);
++                              do_IRQ(pend + GROUP0_IRQ_BASE, regs);
 +                      }
-+                      if (cp0_cause & 0x3c00) { // irq 2-5
-+                              while (cp0_cause) {
-+                                      unsigned long intr_bit;
-+                                      unsigned int irq_nr;
-+
-+                                      intr_bit = (31 - rc32434_clz(cp0_cause));
-+                                      irq_nr = intr_bit - GROUP0_IRQ_BASE;
-+
-+                                      do_IRQ(irq_nr, regs);
-+                                      cp0_cause &= ~(1 << intr_bit);
-+                              }
++                      if ((ip = (cp0_cause & 0x3c00))) { // irq 2-5
++                              pend = 31 - rc32434_clz(ip);
++                              do_IRQ(pend - GROUP0_IRQ_BASE, regs);
 +                      }
 +                      break;
 +      }