bcm963xx: rewrite irq handling code
authorFelix Fietkau <nbd@openwrt.org>
Sun, 18 May 2008 17:31:25 +0000 (17:31 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 18 May 2008 17:31:25 +0000 (17:31 +0000)
This patch adds interrupt handling as on AR7. The old code was very messy and
didn't work too well. It also removes the unused file int-handler.S.

Signed-off-by: Axel Gembe <ago@bastart.eu.org>
SVN-Revision: 11178

target/linux/brcm63xx/patches-2.6.25/060-bcm963xx_rewrite_irq_handling_code.patch [new file with mode: 0644]
target/linux/brcm63xx/patches-2.6.25/080-bcm963xx_remove_unused_int_handler.patch [new file with mode: 0644]

diff --git a/target/linux/brcm63xx/patches-2.6.25/060-bcm963xx_rewrite_irq_handling_code.patch b/target/linux/brcm63xx/patches-2.6.25/060-bcm963xx_rewrite_irq_handling_code.patch
new file mode 100644 (file)
index 0000000..4f1e360
--- /dev/null
@@ -0,0 +1,460 @@
+From 9a70f2dcb24a5aab29386373c86ba035acba4891 Mon Sep 17 00:00:00 2001
+From: Axel Gembe <ago@bastart.eu.org>
+Date: Sun, 18 May 2008 12:07:21 +0200
+Subject: [PATCH] bcm963xx: rewrite irq handling code
+
+This patch adds interrupt handling as on AR7. The old code was very messy and
+didn't work too well.
+
+Signed-off-by: Axel Gembe <ago@bastart.eu.org>
+---
+ arch/mips/bcm963xx/irq.c                  |  308 ++++++++++-------------------
+ drivers/serial/bcm63xx_cons.c             |   13 +-
+ include/asm-mips/mach-bcm963xx/bcm_intr.h |   18 +--
+ 3 files changed, 119 insertions(+), 220 deletions(-)
+
+diff --git a/arch/mips/bcm963xx/irq.c b/arch/mips/bcm963xx/irq.c
+index 62a848b..11583c9 100644
+--- a/arch/mips/bcm963xx/irq.c
++++ b/arch/mips/bcm963xx/irq.c
+@@ -1,259 +1,159 @@
+ /*
+-<:copyright-gpl 
+- Copyright 2002 Broadcom Corp. All Rights Reserved. 
+- 
+- This program is free software; you can distribute it and/or modify it 
+- under the terms of the GNU General Public License (Version 2) as 
+- published by the Free Software Foundation. 
+- 
+- This program is distributed in the hope it will be useful, but WITHOUT 
+- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+- for more details. 
+- 
+- 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., 
+- 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+-:>
+-*/
+-/*
+- * Interrupt control functions for Broadcom 963xx MIPS boards
++ * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
++ * Copyright (C) 2008 Axel Gembe <ago@bastart.eu.org>
++ *
++ * 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 program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+  */
+-#include <asm/atomic.h>
+-
+-#include <linux/delay.h>
+-#include <linux/init.h>
+-#include <linux/ioport.h>
+-#include <linux/irq.h>
+ #include <linux/interrupt.h>
+-#include <linux/kernel.h>
+-#include <linux/slab.h>
+-#include <linux/module.h>
++#include <linux/io.h>
+-#include <asm/irq.h>
++#include <asm/irq_cpu.h>
+ #include <asm/mipsregs.h>
+-#include <asm/addrspace.h>
+-#include <asm/signal.h>
++
+ #include <6348_map_part.h>
+ #include <6348_intr.h>
+ #include <bcm_map_part.h>
+ #include <bcm_intr.h>
+-static void irq_dispatch_int(void)
+-{
+-      unsigned int pendingIrqs;
+-      static unsigned int irqBit;
+-      static unsigned int isrNumber = 31;
+-
+-      pendingIrqs = PERF->IrqStatus & PERF->IrqMask;
+-      if (!pendingIrqs) {
+-              return;
+-      }
++static int bcm963xx_irq_base;
+-      while (1) {
+-      irqBit <<= 1;
+-      isrNumber++;
+-      if (isrNumber == 32) {
+-              isrNumber = 0;
+-              irqBit = 0x1;
+-      }
+-      if (pendingIrqs & irqBit) {
+-                      PERF->IrqMask &= ~irqBit; // mask
+-                      do_IRQ(isrNumber + INTERNAL_ISR_TABLE_OFFSET);
+-              break;
+-      }
+-      }
++void bcm963xx_unmask_irq(unsigned int irq)
++{
++      PERF->IrqMask |= (1 << (irq - bcm963xx_irq_base));
+ }
+-static void irq_dispatch_ext(uint32 irq)
++void bcm963xx_mask_irq(unsigned int irq)
+ {
+-      if (!(PERF->ExtIrqCfg & (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)))) {
+-      printk("**** Ext IRQ mask. Should not dispatch ****\n");
+-      }
+-      /* disable and clear interrupt in the controller */
+-      PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
+-      PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
+-      do_IRQ(irq);
++      PERF->IrqMask &= ~(1 << (irq - bcm963xx_irq_base));
+ }
+-
+-//extern void brcm_timer_interrupt(struct pt_regs *regs);
+-
+-asmlinkage void plat_irq_dispatch(void)
++void bcm963xx_ack_irq(unsigned int irq)
+ {
+-      unsigned long cause;
+-
+-      cause = read_c0_status() & read_c0_cause() & ST0_IM;
+-      if (cause & CAUSEF_IP7)
+-              do_IRQ(7);
+-      else if (cause & CAUSEF_IP2)
+-              irq_dispatch_int();
+-      else if (cause & CAUSEF_IP3)
+-              irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0);
+-      else if (cause & CAUSEF_IP4)
+-              irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1);
+-      else if (cause & CAUSEF_IP5)
+-              irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2);
+-      else if (cause & CAUSEF_IP6) {
+-              irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3);
+-              local_irq_disable();
+-      }
++      PERF->IrqStatus &= ~(1 << (irq - bcm963xx_irq_base));
+ }
+-
+-void enable_brcm_irq(unsigned int irq)
++void bcm963xx_unmask_ext_irq(unsigned int irq)
+ {
+-      unsigned long flags;
+-
+-      local_irq_save(flags);
+-      if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
+-      PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
+-      }
+-      else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
+-      /* enable and clear interrupt in the controller */
+-      PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
+       PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
+-      }
+-      local_irq_restore(flags);
+ }
+-void disable_brcm_irq(unsigned int irq)
++void bcm963xx_mask_ext_irq(unsigned int irq)
+ {
+-      unsigned long flags;
+-
+-      local_irq_save(flags);
+-      if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
+-      PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
+-      }
+-      else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
+-      /* disable interrupt in the controller */
+       PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
+-      }
+-      local_irq_restore(flags);
+ }
+-void ack_brcm_irq(unsigned int irq)
++void bcm963xx_ack_ext_irq(unsigned int irq)
+ {
+-      /* Already done in brcm_irq_dispatch */
++      PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
+ }
+-unsigned int startup_brcm_irq(unsigned int irq)
++static void bcm963xx_dispatch_ext_irq(unsigned int irq)
+ {
+-      enable_brcm_irq(irq);
+-
+-      return 0; /* never anything pending */
++      bcm963xx_ack_ext_irq(irq);
++      bcm963xx_mask_ext_irq(irq);
++      do_IRQ(irq);
+ }
+-unsigned int startup_brcm_none(unsigned int irq)
++static void bcm963xx_cascade(void)
+ {
+-      return 0;
+-}
++      uint32_t pending, bit, irq;
+-void end_brcm_irq(unsigned int irq)
+-{
+-      if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+-              enable_brcm_irq(irq);
+-}
++      if (!(pending = PERF->IrqStatus & PERF->IrqMask))
++              return;
+-void end_brcm_none(unsigned int irq)
+-{
++      for (irq = 0, bit = 1; irq < 32; irq++, bit <<= 1) {
++              if (pending & bit) {
++                      bcm963xx_ack_irq(irq + bcm963xx_irq_base);
++                      bcm963xx_mask_irq(irq + bcm963xx_irq_base);
++                      do_IRQ(irq + bcm963xx_irq_base);
++                      return;
++              }
++      }
++
++      spurious_interrupt();
+ }
+-static struct hw_interrupt_type brcm_irq_type = {
+-      .typename       = "MIPS",
+-      .startup        = startup_brcm_irq,
+-      .shutdown       = disable_brcm_irq,
+-      .enable = enable_brcm_irq,
+-      .disable        = disable_brcm_irq,
+-      .ack    = ack_brcm_irq,
+-      .end    = end_brcm_irq,
+-      .set_affinity = NULL
++static struct irq_chip bcm963xx_irq_type = {
++      .name = "bcm963xx",
++      .unmask = bcm963xx_unmask_irq,
++      .mask = bcm963xx_mask_irq,
++      .ack = bcm963xx_ack_irq
+ };
+-static struct hw_interrupt_type brcm_irq_no_end_type = {
+-      .typename       = "MIPS",
+-      .startup        = startup_brcm_none,
+-      .shutdown       = disable_brcm_irq,
+-      .enable = enable_brcm_irq,
+-      .disable        = disable_brcm_irq,
+-      .ack    = ack_brcm_irq,
+-      .end    = end_brcm_none,
+-      .set_affinity = NULL
++static struct irq_chip bcm963xx_ext_irq_type = {
++      .name = "bcm963xx_ext",
++      .unmask = bcm963xx_unmask_ext_irq,
++      .mask = bcm963xx_mask_ext_irq,
++      .ack = bcm963xx_ack_ext_irq,
+ };
+-void __init arch_init_irq(void)
++static struct irqaction bcm963xx_cascade_action = {
++      .handler = no_action,
++      .name = "BCM963xx cascade interrupt"
++};
++
++static void __init bcm963xx_irq_init(int base)
+ {
+       int i;
+-      clear_c0_status(ST0_BEV);
+-      change_c0_status(ST0_IM, (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4));
+-
+-      for (i = 0; i < NR_IRQS; i++) {
+-              irq_desc[i].status = IRQ_DISABLED;
+-              irq_desc[i].action = 0;
+-              irq_desc[i].depth = 1;
+-              irq_desc[i].chip = &brcm_irq_type;
++      bcm963xx_irq_base = base;
++
++      /* External IRQs */
++      set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_0, &bcm963xx_ext_irq_type,
++                               handle_level_irq);
++      set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_1, &bcm963xx_ext_irq_type,
++                               handle_level_irq);
++      set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_2, &bcm963xx_ext_irq_type,
++                               handle_level_irq);
++      set_irq_chip_and_handler(INTERRUPT_ID_EXTERNAL_3, &bcm963xx_ext_irq_type,
++                               handle_level_irq);
++
++      for (i = 0; i < 32; i++) {
++              set_irq_chip_and_handler(base + i, &bcm963xx_irq_type,
++                                       handle_level_irq);
+       }
++
++      setup_irq(2, &bcm963xx_cascade_action);
++      setup_irq(bcm963xx_irq_base, &bcm963xx_cascade_action);
++      set_c0_status(IE_IRQ0);
+ }
+-int request_external_irq(unsigned int irq, 
+-      FN_HANDLER handler,
+-              unsigned long irqflags, 
+-              const char * devname,
+-              void *dev_id)
++asmlinkage void plat_irq_dispatch(void)
+ {
+-      unsigned long flags;
++      unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+-      local_irq_save(flags);
+-
+-      PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));      // Clear
+-      PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));      // Mask
+-      PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_INSENS_SHFT));    // Edge insesnsitive
+-      PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_LEVEL_SHFT));      // Level triggered
+-      PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_SENSE_SHFT));     // Low level
+-
+-      local_irq_restore(flags);
+-
+-      return( request_irq(irq, handler, irqflags, devname, dev_id) );
++      if (pending & STATUSF_IP7)              /* cpu timer */
++              do_IRQ(7);
++      else if (pending & STATUSF_IP2)         /* internal interrupt cascade */
++              bcm963xx_cascade();
++      else if (pending & STATUSF_IP3)
++              bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_0);
++      else if (pending & STATUSF_IP4)
++              bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_1);
++      else if (pending & STATUSF_IP5)
++              bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_2);
++      else if (pending & STATUSF_IP6)
++              bcm963xx_dispatch_ext_irq(INTERRUPT_ID_EXTERNAL_3);
++      else
++              spurious_interrupt();
+ }
+-/* VxWorks compatibility function(s). */
+-
+-unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param,
+-      unsigned int interruptId)
++void __init arch_init_irq(void)
+ {
+-      int nRet = -1;
+-      char *devname;
+-
+-      devname = kmalloc(16, GFP_KERNEL);
+-      if (devname)
+-              sprintf( devname, "brcm_%d", interruptId );
+-
+-      /* Set the IRQ description to not automatically enable the interrupt at
+-       * the end of an ISR.  The driver that handles the interrupt must
+-       * explicitly call BcmHalInterruptEnable or enable_brcm_irq.  This behavior
+-       * is consistent with interrupt handling on VxWorks.
+-       */
+-      irq_desc[interruptId].chip = &brcm_irq_no_end_type;
+-
+-      if( interruptId >= INTERNAL_ISR_TABLE_OFFSET )
+-      {       
+-              printk("BcmHalMapInterrupt : internal IRQ\n");
+-              nRet = request_irq( interruptId, pfunc, IRQF_DISABLED, devname, (void *) param );
+-      }
+-      else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3)
+-      {
+-              printk("BcmHalMapInterrupt : external IRQ\n");
+-              nRet = request_external_irq( interruptId, pfunc, IRQF_DISABLED, devname, (void *) param );
+-      }
+-
+-      return( nRet );
++      mips_cpu_irq_init();
++      bcm963xx_irq_init(INTERNAL_ISR_TABLE_OFFSET);
+ }
+-
+-
+-EXPORT_SYMBOL(enable_brcm_irq);
+-EXPORT_SYMBOL(disable_brcm_irq);
+-EXPORT_SYMBOL(request_external_irq);
+-EXPORT_SYMBOL(BcmHalMapInterrupt);
+-
+diff --git a/drivers/serial/bcm63xx_cons.c b/drivers/serial/bcm63xx_cons.c
+index 8fff16d..2302ea6 100644
+--- a/drivers/serial/bcm63xx_cons.c
++++ b/drivers/serial/bcm63xx_cons.c
+@@ -267,7 +267,7 @@ static void bcm_interrupt(int irq, void *dev, struct pt_regs *regs)
+       }
+       // Clear the interrupt
+-      enable_brcm_irq(INTERRUPT_ID_UART);
++//    bcm963xx_unmask_irq(INTERRUPT_ID_UART);
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+       return IRQ_HANDLED;
+ #endif
+@@ -880,7 +880,7 @@ static int bcm63xx_cons_open(struct tty_struct *tty, struct file *filp)
+       info->count++;
+       tty->driver_data = info;
+       info->tty = tty;
+-      enable_brcm_irq(INTERRUPT_ID_UART);
++      bcm963xx_unmask_irq(INTERRUPT_ID_UART);
+       // Start up serial port
+       retval = startup(info);
+@@ -927,7 +927,7 @@ static struct tty_operations rs_ops = {
+ -------------------------------------------------------------------------- */
+ static int __init bcm63xx_serialinit(void)
+ {
+-      int i, flags;
++      int i, flags, res;
+       struct bcm_serial *info;
+       // Print the driver version information
+@@ -981,7 +981,12 @@ static int __init bcm63xx_serialinit(void)
+                */
+               if (!info->port)
+                       return 0;
+-              BcmHalMapInterrupt(bcm_interrupt, 0, INTERRUPT_ID_UART);
++
++              res = request_irq(INTERRUPT_ID_UART, bcm_interrupt, 0, "bcm-uart", NULL);
++              if (res) {
++                      spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++                      return res;
++              }
+       }
+       /* order matters here... the trick is that flags
+diff --git a/include/asm-mips/mach-bcm963xx/bcm_intr.h b/include/asm-mips/mach-bcm963xx/bcm_intr.h
+index 8c56840..920f783 100644
+--- a/include/asm-mips/mach-bcm963xx/bcm_intr.h
++++ b/include/asm-mips/mach-bcm963xx/bcm_intr.h
+@@ -39,18 +39,12 @@ struct pt_regs;
+ typedef int (*FN_HANDLER) (int, void *);
+ /* prototypes */
+-extern void enable_brcm_irq(unsigned int irq);
+-extern void disable_brcm_irq(unsigned int irq);
+-extern int request_external_irq(unsigned int irq,
+-    FN_HANDLER handler, unsigned long irqflags, 
+-    const char * devname, void *dev_id);
+-extern unsigned int BcmHalMapInterrupt(FN_HANDLER isr, unsigned int param,
+-    unsigned int interruptId);
+-extern void dump_intr_regs(void);
+-
+-/* compatibility definitions */
+-#define BcmHalInterruptEnable(irq)      enable_brcm_irq( irq )
+-#define BcmHalInterruptDisable(irq)     disable_brcm_irq( irq )
++extern void bcm963xx_unmask_irq(unsigned int irq);
++extern void bcm963xx_mask_irq(unsigned int irq);
++extern void bcm963xx_ack_irq(unsigned int irq);
++extern void bcm963xx_unmask_ext_irq(unsigned int irq);
++extern void bcm963xx_mask_ext_irq(unsigned int irq);
++extern void bcm963xx_ack_ext_irq(unsigned int irq);
+ #ifdef __cplusplus
+     }
+-- 
+1.5.5.1
+
diff --git a/target/linux/brcm63xx/patches-2.6.25/080-bcm963xx_remove_unused_int_handler.patch b/target/linux/brcm63xx/patches-2.6.25/080-bcm963xx_remove_unused_int_handler.patch
new file mode 100644 (file)
index 0000000..ad4484e
--- /dev/null
@@ -0,0 +1,95 @@
+From e3abd028e7631ee952fe73d8f9ee97bc615526a8 Mon Sep 17 00:00:00 2001
+From: Axel Gembe <ago@bastart.eu.org>
+Date: Sat, 17 May 2008 16:07:46 +0200
+Subject: [PATCH] bcm963xx: remove unused int-handler.S
+
+The code is not used anymore.
+
+Signed-off-by: Axel Gembe <ago@bastart.eu.org>
+---
+ arch/mips/bcm963xx/Makefile      |    2 +-
+ arch/mips/bcm963xx/int-handler.S |   59 --------------------------------------
+ 2 files changed, 1 insertions(+), 60 deletions(-)
+ delete mode 100644 arch/mips/bcm963xx/int-handler.S
+
+diff --git a/arch/mips/bcm963xx/Makefile b/arch/mips/bcm963xx/Makefile
+index a9d1e55..77fbd84 100644
+--- a/arch/mips/bcm963xx/Makefile
++++ b/arch/mips/bcm963xx/Makefile
+@@ -3,7 +3,7 @@
+ #
+ # Copyright (C) 2004 Broadcom Corporation
+ #
+-obj-y           := irq.o prom.o setup.o time.o ser_init.o int-handler.o info.o wdt.o
++obj-y           := irq.o prom.o setup.o time.o ser_init.o info.o wdt.o
+ SRCBASE         := $(TOPDIR)
+ EXTRA_CFLAGS    += -I$(SRCBASE)/include
+diff --git a/arch/mips/bcm963xx/int-handler.S b/arch/mips/bcm963xx/int-handler.S
+deleted file mode 100644
+index a7a9c9d..0000000
+--- a/arch/mips/bcm963xx/int-handler.S
++++ /dev/null
+@@ -1,59 +0,0 @@
+-/*
+-<:copyright-gpl 
+- Copyright 2002 Broadcom Corp. All Rights Reserved. 
+- 
+- This program is free software; you can distribute it and/or modify it 
+- under the terms of the GNU General Public License (Version 2) as 
+- published by the Free Software Foundation. 
+- 
+- This program is distributed in the hope it will be useful, but WITHOUT 
+- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+- for more details. 
+- 
+- 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., 
+- 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
+-:>
+-*/
+-/*
+- * Generic interrupt handler for Broadcom MIPS boards
+- */
+-
+-#include <linux/autoconf.h>
+-
+-#include <asm/asm.h>
+-#include <asm/mipsregs.h>
+-#include <asm/regdef.h>
+-#include <asm/stackframe.h>
+-
+-/*
+- *    MIPS IRQ        Source
+- *      --------        ------
+- *             0      Software (ignored)
+- *             1        Software (ignored)
+- *             2        Combined hardware interrupt (hw0)
+- *             3        Hardware
+- *             4        Hardware
+- *             5        Hardware
+- *             6        Hardware
+- *             7        R4k timer
+- */
+-
+-      .text
+-      .set    noreorder
+-      .set    noat
+-      .align  5
+-      NESTED(brcmIRQ, PT_SIZE, sp)
+-      SAVE_ALL
+-      CLI
+-      .set    noreorder
+-      .set    at
+-
+-      jal             plat_irq_dispatch
+-      move    a0, sp
+-
+-      j       ret_from_irq
+-      nop
+-              
+-      END(brcmIRQ)
+-- 
+1.5.5.1
+