Add support for BCM1480 family of chips.
[linux-2.6.git] / arch / mips / sibyte / bcm1480 / irq_handler.S
1 /*
2  * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19 /*
20  * bcm1480_irq_handler() is the routine that is actually called when an
21  * interrupt occurs.  It is installed as the exception vector handler in
22  * init_IRQ() in arch/mips/sibyte/bcm1480/irq.c
23  *
24  * In the handle we figure out which interrupts need handling, and use that
25  * to call the dispatcher, which will take care of actually calling
26  * registered handlers
27  *
28  * Note that we take care of all raised interrupts in one go at the handler.
29  * This is more BSDish than the Indy code, and also, IMHO, more sane.
30  */
31 #include <linux/config.h>
32
33 #include <asm/addrspace.h>
34 #include <asm/asm.h>
35 #include <asm/mipsregs.h>
36 #include <asm/regdef.h>
37 #include <asm/stackframe.h>
38 #include <asm/sibyte/sb1250_defs.h>
39 #include <asm/sibyte/bcm1480_regs.h>
40 #include <asm/sibyte/bcm1480_int.h>
41
42 /*
43  * What a pain. We have to be really careful saving the upper 32 bits of any
44  * register across function calls if we don't want them trashed--since were
45  * running in -o32, the calling routing never saves the full 64 bits of a
46  * register across a function call.  Being the interrupt handler, we're
47  * guaranteed that interrupts are disabled during this code so we don't have
48  * to worry about random interrupts blasting the high 32 bits.
49  */
50
51         .text
52         .set    push
53         .set    noreorder
54         .set    noat
55         .set    mips64
56         #.set   mips4
57         .align  5
58         NESTED(bcm1480_irq_handler, PT_SIZE, sp)
59         SAVE_ALL
60         CLI
61
62 #ifdef CONFIG_SIBYTE_BCM1480_PROF
63         /* Set compare to count to silence count/compare timer interrupts */
64         mfc0    t1, CP0_COUNT
65         mtc0    t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
66 #endif
67         /* Read cause */
68         mfc0    s0, CP0_CAUSE
69
70 #ifdef CONFIG_SIBYTE_BCM1480_PROF
71         /* Cpu performance counter interrupt is routed to IP[7] */
72         andi    t1, s0, CAUSEF_IP7
73         beqz    t1, 0f
74          srl    t1, s0, (CAUSEB_BD-2)   /* Shift BD bit to bit 2 */
75         and     t1, t1, 0x4             /* mask to get just BD bit */
76 #ifdef CONFIG_MIPS64
77         dmfc0   a0, CP0_EPC
78         daddu   a0, a0, t1              /* a0 = EPC + (BD ? 4 : 0) */
79 #else
80         mfc0    a0, CP0_EPC
81         addu    a0, a0, t1              /* a0 = EPC + (BD ? 4 : 0) */
82 #endif
83         jal     sbprof_cpu_intr
84          nop
85         j       ret_from_irq
86          nop
87 0:
88 #endif
89
90         /* Timer interrupt is routed to IP[4] */
91         andi    t1, s0, CAUSEF_IP4
92         beqz    t1, 1f
93          nop
94         jal     bcm1480_timer_interrupt
95          move   a0, sp                  /* Pass the registers along */
96         j       ret_from_irq
97          nop                            /* delay slot  */
98 1:
99
100 #ifdef CONFIG_SMP
101         /* Mailbox interrupt is routed to IP[3] */
102         andi     t1, s0, CAUSEF_IP3
103         beqz     t1, 2f
104          nop
105         jal      bcm1480_mailbox_interrupt
106          move    a0, sp
107         j        ret_from_irq
108          nop                            /* delay slot  */
109 2:
110 #endif
111
112 #ifdef CONFIG_KGDB
113         /* KGDB (uart 1) interrupt is routed to IP[6] */
114         andi     t1, s0, CAUSEF_IP6
115         beqz     t1, 3f
116          nop                            /* delay slot  */
117         jal      bcm1480_kgdb_interrupt
118          move    a0, sp
119         j        ret_from_irq
120          nop                            /* delay slot  */
121 3:
122 #endif
123
124         and      t1, s0, CAUSEF_IP2
125         beqz     t1, 9f
126          nop
127
128         /*
129          * Default...we've hit an IP[2] interrupt, which means we've got
130          * to check the 1480 interrupt registers to figure out what to do
131          * Need to detect which CPU we're on, now that smp_affinity is
132          * supported.
133          */
134         PTR_LA   v0, CKSEG1 + A_BCM1480_IMR_CPU0_BASE
135 #ifdef CONFIG_SMP
136         lw       t1, TI_CPU($28)
137         sll      t1, t1, BCM1480_IMR_REGISTER_SPACING_SHIFT
138         addu     v0, v0, t1
139 #endif
140
141         /* Read IP[2] status (get both high and low halves of status) */
142         ld       s0, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H(v0)
143         ld       s1, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L(v0)
144
145         move     s2, zero       /* intr number  */
146         li       s3, 64
147
148         beqz     s0, 9f         /* No interrupts.  Return.  */
149          move    a1, sp
150
151         xori     s4, s0, 1      /* if s0 (_H) == 1, it's a low intr, so...  */
152         movz     s2, s3, s4     /* start the intr number at 64, and  */
153         movz     s0, s1, s4     /* look at the low status value.  */
154
155         dclz     s1, s0         /* Find the next interrupt.  */
156         dsubu    a0, zero, s1
157         daddiu   a0, a0, 63
158         jal      do_IRQ
159          daddu   a0, a0, s2
160
161 9:      j        ret_from_irq
162          nop
163
164         .set pop
165         END(bcm1480_irq_handler)