MIPS: Build fix - include <linux/smp.h> into all smp_processor_id() users.
[safe/jmp/linux-2.6] / arch / mips / sibyte / bcm1480 / irq.c
index e61760b..ba59839 100644 (file)
  * 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>
 #include <linux/interrupt.h>
+#include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #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);
+static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask);
 #endif
 
 #ifdef CONFIG_PCI
 extern unsigned long ht_eoi_space;
 #endif
 
-#ifdef CONFIG_KGDB
-#include <asm/gdb-stub.h>
-extern void breakpoint(void);
-static int kgdb_irq;
-#ifdef CONFIG_GDB_CONSOLE
-extern void register_gdb_console(void);
-#endif
-
-/* kgdb is on when configured.  Pass "nokgdb" kernel arg to turn it off */
-static int kgdb_flag = 1;
-static int __init nokgdb(char *str)
-{
-       kgdb_flag = 0;
-       return 1;
-}
-__setup("nokgdb", nokgdb);
-
-/* Default to UART1 */
-int kgdb_port = 1;
-#ifdef CONFIG_SIBYTE_SB1250_DUART
-extern char sb1250_duart_present[];
-#endif
-#endif
-
-static struct hw_interrupt_type bcm1480_irq_type = {
-       .typename = "BCM1480-IMR",
-       .startup = startup_bcm1480_irq,
-       .shutdown = shutdown_bcm1480_irq,
-       .enable = enable_bcm1480_irq,
-       .disable = disable_bcm1480_irq,
+static struct irq_chip bcm1480_irq_type = {
+       .name = "BCM1480-IMR",
        .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
@@ -104,8 +77,8 @@ DEFINE_SPINLOCK(bcm1480_imr_lock);
 
 void bcm1480_mask_irq(int cpu, int irq)
 {
-       unsigned long flags;
-       u64 cur_ints,hl_spacing;
+       unsigned long flags, hl_spacing;
+       u64 cur_ints;
 
        spin_lock_irqsave(&bcm1480_imr_lock, flags);
        hl_spacing = 0;
@@ -121,8 +94,8 @@ void bcm1480_mask_irq(int cpu, int irq)
 
 void bcm1480_unmask_irq(int cpu, int irq)
 {
-       unsigned long flags;
-       u64 cur_ints,hl_spacing;
+       unsigned long flags, hl_spacing;
+       u64 cur_ints;
 
        spin_lock_irqsave(&bcm1480_imr_lock, flags);
        hl_spacing = 0;
@@ -137,26 +110,24 @@ void bcm1480_unmask_irq(int cpu, int irq)
 }
 
 #ifdef CONFIG_SMP
-static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask)
+static int bcm1480_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        int i = 0, old_cpu, cpu, int_on, k;
        u64 cur_ints;
-       irq_desc_t *desc = irq_desc + irq;
        unsigned long flags;
        unsigned int irq_dirty;
 
-       i = first_cpu(mask);
-       if (next_cpu(i, mask) <= NR_CPUS) {
+       if (cpumask_weight(mask) != 1) {
                printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq);
-               return;
+               return -1;
        }
+       i = cpumask_first(mask);
 
        /* Convert logical CPU to physical CPU */
        cpu = cpu_logical_map(i);
 
        /* Protect against other affinity changers and IMR manipulation */
-       spin_lock_irqsave(&desc->lock, flags);
-       spin_lock(&bcm1480_imr_lock);
+       spin_lock_irqsave(&bcm1480_imr_lock, flags);
 
        /* Swizzle each CPU's IMR (but leave the IP selection alone) */
        old_cpu = bcm1480_irq_owner[irq];
@@ -181,22 +152,15 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask)
                        ____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));
                }
        }
-       spin_unlock(&bcm1480_imr_lock);
-       spin_unlock_irqrestore(&desc->lock, flags);
+       spin_unlock_irqrestore(&bcm1480_imr_lock, flags);
+
+       return 0;
 }
 #endif
 
 
 /*****************************************************************************/
 
-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);
@@ -271,54 +235,10 @@ 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;
-               }
-       }
-}
-
-
-static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id,
-       struct pt_regs *regs)
-{
-       return IRQ_NONE;
-}
-
-static struct irqaction bcm1480_dummy_action = {
-       .handler = bcm1480_dummy_handler,
-       .flags   = 0,
-       .mask    = CPU_MASK_NONE,
-       .name    = "bcm1480-private",
-       .next    = NULL,
-       .dev_id  = 0
-};
-
-int bcm1480_steal_irq(int irq)
-{
-       irq_desc_t *desc = irq_desc + irq;
-       unsigned long flags;
-       int retval = 0;
-
-       if (irq >= BCM1480_NR_IRQS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&desc->lock,flags);
-       /* Don't allow sharing at all for these */
-       if (desc->action != NULL)
-               retval = -EBUSY;
-       else {
-               desc->action = &bcm1480_dummy_action;
-               desc->depth = 0;
+       for (i = 0; i < BCM1480_NR_IRQS; i++) {
+               set_irq_chip_and_handler(i, &bcm1480_irq_type, handle_level_irq);
+               bcm1480_irq_owner[i] = 0;
        }
-       spin_unlock_irqrestore(&desc->lock,flags);
-       return 0;
 }
 
 /*
@@ -349,7 +269,6 @@ int bcm1480_steal_irq(int irq)
 
 void __init arch_init_irq(void)
 {
-
        unsigned int i, cpu;
        u64 tmp;
        unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
@@ -406,91 +325,46 @@ void __init arch_init_irq(void)
                __raw_writeq(tmp, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MASK_L)));
        }
 
-       bcm1480_steal_irq(K_BCM1480_INT_MBOX_0_0);
-
        /*
         * Note that the timer interrupts are also mapped, but this is
         * done in bcm1480_time_init().  Also, the profiling driver
         * does its own management of IP7.
         */
 
-#ifdef CONFIG_KGDB
-       imask |= STATUSF_IP6;
-#endif
        /* Enable necessary IPs, disable the rest */
        change_c0_status(ST0_IM, imask);
-
-#ifdef CONFIG_KGDB
-       if (kgdb_flag) {
-               kgdb_irq = K_BCM1480_INT_UART_0 + kgdb_port;
-
-#ifdef CONFIG_SIBYTE_SB1250_DUART
-               sb1250_duart_present[kgdb_port] = 0;
-#endif
-               /* Setup uart 1 settings, mapper */
-               /* QQQ FIXME */
-               __raw_writeq(M_DUART_IMR_BRK, IO_SPACE_BASE + A_DUART_IMRREG(kgdb_port));
-
-               bcm1480_steal_irq(kgdb_irq);
-               __raw_writeq(IMR_IP6_VAL,
-                            IO_SPACE_BASE + A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) +
-                            (kgdb_irq<<3));
-               bcm1480_unmask_irq(0, kgdb_irq);
-
-#ifdef CONFIG_GDB_CONSOLE
-               register_gdb_console();
-#endif
-               prom_printf("Waiting for GDB on UART port %d\n", kgdb_port);
-               set_debug_traps();
-               breakpoint();
-       }
-#endif
 }
 
-#ifdef CONFIG_KGDB
-
-#include <linux/delay.h>
+extern void bcm1480_mailbox_interrupt(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 inline void dispatch_ip2(void)
 {
+       unsigned long long mask_h, mask_l;
+       unsigned int cpu = smp_processor_id();
+       unsigned long base;
+
        /*
-        * Clear break-change status (allow some time for the remote
-        * host to stop the break, since we would see another
-        * interrupt on the end-of-break too)
+        * 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.
         */
-       kstat.irqs[smp_processor_id()][kgdb_irq]++;
-       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);
-}
-
-#endif         /* CONFIG_KGDB */
-
-static inline int dclz(unsigned long long x)
-{
-       int lz;
-
-       __asm__ (
-       "       .set    push                                            \n"
-       "       .set    mips64                                          \n"
-       "       dclz    %0, %1                                          \n"
-       "       .set    pop                                             \n"
-       : "=r" (lz)
-       : "r" (x));
-
-       return lz;
+       base = A_BCM1480_IMR_MAPPER(cpu);
+       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 if (mask_l)
+                       do_IRQ(63 + fls64(mask_l));
+       }
 }
 
-extern void bcm1480_timer_interrupt(struct pt_regs *regs);
-extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
-extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
-
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
 {
+       unsigned int cpu = smp_processor_id();
        unsigned int pending;
 
 #ifdef CONFIG_SIBYTE_BCM1480_PROF
@@ -498,47 +372,21 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
        write_c0_compare(read_c0_count());
 #endif
 
-       pending = read_c0_cause();
+       pending = read_c0_cause() & read_c0_status();
 
 #ifdef CONFIG_SIBYTE_BCM1480_PROF
        if (pending & CAUSEF_IP7)       /* Cpu performance counter interrupt */
-               sbprof_cpu_intr(exception_epc(regs));
+               sbprof_cpu_intr();
+       else
 #endif
 
        if (pending & CAUSEF_IP4)
-               bcm1480_timer_interrupt(regs);
-
+               do_IRQ(K_BCM1480_INT_TIMER_0 + cpu);
 #ifdef CONFIG_SMP
-       if (pending & CAUSEF_IP3)
-               bcm1480_mailbox_interrupt(regs);
+       else if (pending & CAUSEF_IP3)
+               bcm1480_mailbox_interrupt();
 #endif
 
-#ifdef CONFIG_KGDB
-       if (pending & CAUSEF_IP6)
-               bcm1480_kgdb_interrupt(regs);           /* KGDB (uart 1) */
-#endif
-
-       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(63 - dclz(mask_h), regs);
-                       else
-                               do_IRQ(127 - dclz(mask_l), regs);
-               }
-       }
+       else if (pending & CAUSEF_IP2)
+               dispatch_ip2();
 }