fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / mips / sibyte / bcm1480 / irq.c
index 9cf7d71..2e8f6b2 100644 (file)
@@ -15,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
@@ -26,9 +25,9 @@
 #include <linux/kernel_stat.h>
 
 #include <asm/errno.h>
+#include <asm/irq_regs.h>
 #include <asm/signal.h>
 #include <asm/system.h>
-#include <asm/ptrace.h>
 #include <asm/io.h>
 
 #include <asm/sibyte/bcm1480_regs.h>
  */
 
 
-#define shutdown_bcm1480_irq   disable_bcm1480_irq
 static void end_bcm1480_irq(unsigned int irq);
 static void enable_bcm1480_irq(unsigned int irq);
 static void disable_bcm1480_irq(unsigned int irq);
-static unsigned int startup_bcm1480_irq(unsigned int irq);
 static void ack_bcm1480_irq(unsigned int irq);
 #ifdef CONFIG_SMP
 static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask);
@@ -84,13 +81,12 @@ extern char sb1250_duart_present[];
 #endif
 #endif
 
-static struct hw_interrupt_type bcm1480_irq_type = {
+static struct irq_chip bcm1480_irq_type = {
        .typename = "BCM1480-IMR",
-       .startup = startup_bcm1480_irq,
-       .shutdown = shutdown_bcm1480_irq,
-       .enable = enable_bcm1480_irq,
-       .disable = disable_bcm1480_irq,
        .ack = ack_bcm1480_irq,
+       .mask = disable_bcm1480_irq,
+       .mask_ack = ack_bcm1480_irq,
+       .unmask = enable_bcm1480_irq,
        .end = end_bcm1480_irq,
 #ifdef CONFIG_SMP
        .set_affinity = bcm1480_set_affinity
@@ -141,7 +137,7 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask)
 {
        int i = 0, old_cpu, cpu, int_on, k;
        u64 cur_ints;
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
        unsigned int irq_dirty;
 
@@ -187,19 +183,8 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask)
 #endif
 
 
-/* Defined in arch/mips/sibyte/bcm1480/irq_handler.S */
-extern void bcm1480_irq_handler(void);
-
 /*****************************************************************************/
 
-static unsigned int startup_bcm1480_irq(unsigned int irq)
-{
-       bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);
-
-       return 0;               /* never anything pending */
-}
-
-
 static void disable_bcm1480_irq(unsigned int irq)
 {
        bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);
@@ -274,22 +259,14 @@ void __init init_bcm1480_irqs(void)
 {
        int i;
 
-       for (i = 0; i < NR_IRQS; i++) {
-               irq_desc[i].status = IRQ_DISABLED;
-               irq_desc[i].action = 0;
-               irq_desc[i].depth = 1;
-               if (i < BCM1480_NR_IRQS) {
-                       irq_desc[i].handler = &bcm1480_irq_type;
-                       bcm1480_irq_owner[i] = 0;
-               } else {
-                       irq_desc[i].handler = &no_irq_type;
-               }
+       for (i = 0; i < BCM1480_NR_IRQS; i++) {
+               set_irq_chip(i, &bcm1480_irq_type);
+               bcm1480_irq_owner[i] = 0;
        }
 }
 
 
-static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id,
-       struct pt_regs *regs)
+static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id)
 {
        return IRQ_NONE;
 }
@@ -305,7 +282,7 @@ static struct irqaction bcm1480_dummy_action = {
 
 int bcm1480_steal_irq(int irq)
 {
-       irq_desc_t *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_desc + irq;
        unsigned long flags;
        int retval = 0;
 
@@ -422,7 +399,6 @@ void __init arch_init_irq(void)
 #endif
        /* Enable necessary IPs, disable the rest */
        change_c0_status(ST0_IM, imask);
-       set_except_vector(0, bcm1480_irq_handler);
 
 #ifdef CONFIG_KGDB
        if (kgdb_flag) {
@@ -458,7 +434,7 @@ void __init arch_init_irq(void)
 #define duart_out(reg, val)     csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
 #define duart_in(reg)           csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
 
-void bcm1480_kgdb_interrupt(struct pt_regs *regs)
+static void bcm1480_kgdb_interrupt(void)
 {
        /*
         * Clear break-change status (allow some time for the remote
@@ -469,7 +445,65 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs)
        mdelay(500);
        duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
                                M_DUART_RX_EN | M_DUART_TX_EN);
-       set_async_breakpoint(&regs->cp0_epc);
+       set_async_breakpoint(&get_irq_regs()->cp0_epc);
 }
 
 #endif         /* CONFIG_KGDB */
+
+extern void bcm1480_timer_interrupt(void);
+extern void bcm1480_mailbox_interrupt(void);
+
+asmlinkage void plat_irq_dispatch(void)
+{
+       unsigned int pending;
+
+#ifdef CONFIG_SIBYTE_BCM1480_PROF
+       /* Set compare to count to silence count/compare timer interrupts */
+       write_c0_compare(read_c0_count());
+#endif
+
+       pending = read_c0_cause() & read_c0_status();
+
+#ifdef CONFIG_SIBYTE_BCM1480_PROF
+       if (pending & CAUSEF_IP7)       /* Cpu performance counter interrupt */
+               sbprof_cpu_intr();
+       else
+#endif
+
+       if (pending & CAUSEF_IP4)
+               bcm1480_timer_interrupt();
+
+#ifdef CONFIG_SMP
+       else if (pending & CAUSEF_IP3)
+               bcm1480_mailbox_interrupt();
+#endif
+
+#ifdef CONFIG_KGDB
+       else if (pending & CAUSEF_IP6)
+               bcm1480_kgdb_interrupt();               /* KGDB (uart 1) */
+#endif
+
+       else if (pending & CAUSEF_IP2) {
+               unsigned long long mask_h, mask_l;
+               unsigned long base;
+
+               /*
+                * Default...we've hit an IP[2] interrupt, which means we've
+                * got to check the 1480 interrupt registers to figure out what
+                * to do.  Need to detect which CPU we're on, now that
+                * smp_affinity is supported.
+                */
+               base = A_BCM1480_IMR_MAPPER(smp_processor_id());
+               mask_h = __raw_readq(
+                       IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
+               mask_l = __raw_readq(
+                       IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
+
+               if (mask_h) {
+                       if (mask_h ^ 1)
+                               do_IRQ(fls64(mask_h) - 1);
+                       else
+                               do_IRQ(63 + fls64(mask_l));
+               }
+       }
+}