diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-04-03 12:56:36 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-04-18 22:14:21 -0400 |
commit | e4ac58afdfac792c0583af30dbd9eae53e24c78b (patch) | |
tree | 7517bef2c515fc630e4d3d238867b91cde96f558 /arch/mips/sibyte | |
parent | d35d473c25d43d7db3e5e18b66d558d2a631cca8 (diff) |
[MIPS] Rewrite all the assembler interrupt handlers to C.
Saves like 1,600 lines of code, is way easier to debug, compilers
frequently do a better job than the cut and paste type of handlers many
boards had. And finally having all the stuff done in a single place
also means alot of bug potencial for the MT ASE is gone.
The only surviving handler in assembler is the DECstation one; I hope
Maciej will rewrite it.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/sibyte')
-rw-r--r-- | arch/mips/sibyte/bcm1480/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/sibyte/bcm1480/irq.c | 77 | ||||
-rw-r--r-- | arch/mips/sibyte/bcm1480/irq_handler.S | 165 | ||||
-rw-r--r-- | arch/mips/sibyte/sb1250/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/sibyte/sb1250/irq.c | 78 | ||||
-rw-r--r-- | arch/mips/sibyte/sb1250/irq_handler.S | 147 |
6 files changed, 147 insertions, 324 deletions
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile index 538d5a51ae94..7b36ff3873b7 100644 --- a/arch/mips/sibyte/bcm1480/Makefile +++ b/arch/mips/sibyte/bcm1480/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y := setup.o irq.o irq_handler.o time.o | 1 | obj-y := setup.o irq.o time.o |
2 | 2 | ||
3 | obj-$(CONFIG_SMP) += smp.o | 3 | obj-$(CONFIG_SMP) += smp.o |
4 | 4 | ||
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 9cf7d713b13c..e61760b14d99 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c | |||
@@ -187,9 +187,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask) | |||
187 | #endif | 187 | #endif |
188 | 188 | ||
189 | 189 | ||
190 | /* Defined in arch/mips/sibyte/bcm1480/irq_handler.S */ | ||
191 | extern void bcm1480_irq_handler(void); | ||
192 | |||
193 | /*****************************************************************************/ | 190 | /*****************************************************************************/ |
194 | 191 | ||
195 | static unsigned int startup_bcm1480_irq(unsigned int irq) | 192 | static unsigned int startup_bcm1480_irq(unsigned int irq) |
@@ -422,7 +419,6 @@ void __init arch_init_irq(void) | |||
422 | #endif | 419 | #endif |
423 | /* Enable necessary IPs, disable the rest */ | 420 | /* Enable necessary IPs, disable the rest */ |
424 | change_c0_status(ST0_IM, imask); | 421 | change_c0_status(ST0_IM, imask); |
425 | set_except_vector(0, bcm1480_irq_handler); | ||
426 | 422 | ||
427 | #ifdef CONFIG_KGDB | 423 | #ifdef CONFIG_KGDB |
428 | if (kgdb_flag) { | 424 | if (kgdb_flag) { |
@@ -473,3 +469,76 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs) | |||
473 | } | 469 | } |
474 | 470 | ||
475 | #endif /* CONFIG_KGDB */ | 471 | #endif /* CONFIG_KGDB */ |
472 | |||
473 | static inline int dclz(unsigned long long x) | ||
474 | { | ||
475 | int lz; | ||
476 | |||
477 | __asm__ ( | ||
478 | " .set push \n" | ||
479 | " .set mips64 \n" | ||
480 | " dclz %0, %1 \n" | ||
481 | " .set pop \n" | ||
482 | : "=r" (lz) | ||
483 | : "r" (x)); | ||
484 | |||
485 | return lz; | ||
486 | } | ||
487 | |||
488 | extern void bcm1480_timer_interrupt(struct pt_regs *regs); | ||
489 | extern void bcm1480_mailbox_interrupt(struct pt_regs *regs); | ||
490 | extern void bcm1480_kgdb_interrupt(struct pt_regs *regs); | ||
491 | |||
492 | asmlinkage void plat_irq_dispatch(struct pt_regs *regs) | ||
493 | { | ||
494 | unsigned int pending; | ||
495 | |||
496 | #ifdef CONFIG_SIBYTE_BCM1480_PROF | ||
497 | /* Set compare to count to silence count/compare timer interrupts */ | ||
498 | write_c0_compare(read_c0_count()); | ||
499 | #endif | ||
500 | |||
501 | pending = read_c0_cause(); | ||
502 | |||
503 | #ifdef CONFIG_SIBYTE_BCM1480_PROF | ||
504 | if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ | ||
505 | sbprof_cpu_intr(exception_epc(regs)); | ||
506 | #endif | ||
507 | |||
508 | if (pending & CAUSEF_IP4) | ||
509 | bcm1480_timer_interrupt(regs); | ||
510 | |||
511 | #ifdef CONFIG_SMP | ||
512 | if (pending & CAUSEF_IP3) | ||
513 | bcm1480_mailbox_interrupt(regs); | ||
514 | #endif | ||
515 | |||
516 | #ifdef CONFIG_KGDB | ||
517 | if (pending & CAUSEF_IP6) | ||
518 | bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */ | ||
519 | #endif | ||
520 | |||
521 | if (pending & CAUSEF_IP2) { | ||
522 | unsigned long long mask_h, mask_l; | ||
523 | unsigned long base; | ||
524 | |||
525 | /* | ||
526 | * Default...we've hit an IP[2] interrupt, which means we've | ||
527 | * got to check the 1480 interrupt registers to figure out what | ||
528 | * to do. Need to detect which CPU we're on, now that | ||
529 | * smp_affinity is supported. | ||
530 | */ | ||
531 | base = A_BCM1480_IMR_MAPPER(smp_processor_id()); | ||
532 | mask_h = __raw_readq( | ||
533 | IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); | ||
534 | mask_l = __raw_readq( | ||
535 | IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); | ||
536 | |||
537 | if (!mask_h) { | ||
538 | if (mask_h ^ 1) | ||
539 | do_IRQ(63 - dclz(mask_h), regs); | ||
540 | else | ||
541 | do_IRQ(127 - dclz(mask_l), regs); | ||
542 | } | ||
543 | } | ||
544 | } | ||
diff --git a/arch/mips/sibyte/bcm1480/irq_handler.S b/arch/mips/sibyte/bcm1480/irq_handler.S deleted file mode 100644 index 408db88d050f..000000000000 --- a/arch/mips/sibyte/bcm1480/irq_handler.S +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
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) | ||
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile index a8af84697588..a2fdbd62f8ac 100644 --- a/arch/mips/sibyte/sb1250/Makefile +++ b/arch/mips/sibyte/sb1250/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y := setup.o irq.o irq_handler.o time.o | 1 | obj-y := setup.o irq.o time.o |
2 | 2 | ||
3 | obj-$(CONFIG_SMP) += smp.o | 3 | obj-$(CONFIG_SMP) += smp.o |
4 | obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o | 4 | obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o |
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index 589537bfcc3d..0f6e54db4888 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c | |||
@@ -163,10 +163,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask) | |||
163 | } | 163 | } |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | |||
167 | /* Defined in arch/mips/sibyte/sb1250/irq_handler.S */ | ||
168 | extern void sb1250_irq_handler(void); | ||
169 | |||
170 | /*****************************************************************************/ | 166 | /*****************************************************************************/ |
171 | 167 | ||
172 | static unsigned int startup_sb1250_irq(unsigned int irq) | 168 | static unsigned int startup_sb1250_irq(unsigned int irq) |
@@ -379,7 +375,6 @@ void __init arch_init_irq(void) | |||
379 | #endif | 375 | #endif |
380 | /* Enable necessary IPs, disable the rest */ | 376 | /* Enable necessary IPs, disable the rest */ |
381 | change_c0_status(ST0_IM, imask); | 377 | change_c0_status(ST0_IM, imask); |
382 | set_except_vector(0, sb1250_irq_handler); | ||
383 | 378 | ||
384 | #ifdef CONFIG_KGDB | 379 | #ifdef CONFIG_KGDB |
385 | if (kgdb_flag) { | 380 | if (kgdb_flag) { |
@@ -409,7 +404,7 @@ void __init arch_init_irq(void) | |||
409 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) | 404 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) |
410 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) | 405 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) |
411 | 406 | ||
412 | void sb1250_kgdb_interrupt(struct pt_regs *regs) | 407 | static void sb1250_kgdb_interrupt(struct pt_regs *regs) |
413 | { | 408 | { |
414 | /* | 409 | /* |
415 | * Clear break-change status (allow some time for the remote | 410 | * Clear break-change status (allow some time for the remote |
@@ -424,3 +419,74 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs) | |||
424 | } | 419 | } |
425 | 420 | ||
426 | #endif /* CONFIG_KGDB */ | 421 | #endif /* CONFIG_KGDB */ |
422 | |||
423 | static inline int dclz(unsigned long long x) | ||
424 | { | ||
425 | int lz; | ||
426 | |||
427 | __asm__ ( | ||
428 | " .set push \n" | ||
429 | " .set mips64 \n" | ||
430 | " dclz %0, %1 \n" | ||
431 | " .set pop \n" | ||
432 | : "=r" (lz) | ||
433 | : "r" (x)); | ||
434 | |||
435 | return lz; | ||
436 | } | ||
437 | |||
438 | asmlinkage void plat_irq_dispatch(struct pt_regs *regs) | ||
439 | { | ||
440 | unsigned int pending; | ||
441 | |||
442 | #ifdef CONFIG_SIBYTE_SB1250_PROF | ||
443 | /* Set compare to count to silence count/compare timer interrupts */ | ||
444 | write_c0_count(read_c0_count()); | ||
445 | #endif | ||
446 | |||
447 | /* | ||
448 | * What a pain. We have to be really careful saving the upper 32 bits | ||
449 | * of any * register across function calls if we don't want them | ||
450 | * trashed--since were running in -o32, the calling routing never saves | ||
451 | * the full 64 bits of a register across a function call. Being the | ||
452 | * interrupt handler, we're guaranteed that interrupts are disabled | ||
453 | * during this code so we don't have to worry about random interrupts | ||
454 | * blasting the high 32 bits. | ||
455 | */ | ||
456 | |||
457 | pending = read_c0_cause(); | ||
458 | |||
459 | #ifdef CONFIG_SIBYTE_SB1250_PROF | ||
460 | if (pending & CAUSEF_IP7) { /* Cpu performance counter interrupt */ | ||
461 | sbprof_cpu_intr(exception_epc(regs)); | ||
462 | } | ||
463 | #endif | ||
464 | |||
465 | if (pending & CAUSEF_IP4) | ||
466 | sb1250_timer_interrupt(regs); | ||
467 | |||
468 | #ifdef CONFIG_SMP | ||
469 | if (pending & CAUSEF_IP3) | ||
470 | sb1250_mailbox_interrupt(regs); | ||
471 | #endif | ||
472 | |||
473 | #ifdef CONFIG_KGDB | ||
474 | if (pending & CAUSEF_IP6) /* KGDB (uart 1) */ | ||
475 | sb1250_kgdb_interrupt(regs); | ||
476 | #endif | ||
477 | |||
478 | if (pending & CAUSEF_IP2) { | ||
479 | unsigned long long mask; | ||
480 | |||
481 | /* | ||
482 | * Default...we've hit an IP[2] interrupt, which means we've | ||
483 | * got to check the 1250 interrupt registers to figure out what | ||
484 | * to do. Need to detect which CPU we're on, now that | ||
485 | ~ smp_affinity is supported. | ||
486 | */ | ||
487 | mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(), | ||
488 | R_IMR_INTERRUPT_STATUS_BASE))); | ||
489 | if (mask) | ||
490 | do_IRQ(63 - dclz(mask), regs); | ||
491 | } | ||
492 | } | ||
diff --git a/arch/mips/sibyte/sb1250/irq_handler.S b/arch/mips/sibyte/sb1250/irq_handler.S deleted file mode 100644 index 60edc8fb302b..000000000000 --- a/arch/mips/sibyte/sb1250/irq_handler.S +++ /dev/null | |||
@@ -1,147 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002, 2003 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 | * sb1250_handle_int() is the routine that is actually called when an interrupt | ||
21 | * occurs. It is installed as the exception vector handler in arch_init_irq() | ||
22 | * in arch/mips/sibyte/sb1250/irq.c | ||
23 | * | ||
24 | * In the handle we figure out which interrupts need handling, and use that to | ||
25 | * call the dispatcher, which will take care of actually calling registered | ||
26 | * 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/sb1250_regs.h> | ||
40 | #include <asm/sibyte/sb1250_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 | .align 5 | ||
57 | NESTED(sb1250_irq_handler, PT_SIZE, sp) | ||
58 | SAVE_ALL | ||
59 | CLI | ||
60 | |||
61 | #ifdef CONFIG_SIBYTE_SB1250_PROF | ||
62 | /* Set compare to count to silence count/compare timer interrupts */ | ||
63 | mfc0 t1, CP0_COUNT | ||
64 | mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */ | ||
65 | #endif | ||
66 | /* Read cause */ | ||
67 | mfc0 s0, CP0_CAUSE | ||
68 | |||
69 | #ifdef CONFIG_SIBYTE_SB1250_PROF | ||
70 | /* Cpu performance counter interrupt is routed to IP[7] */ | ||
71 | andi t1, s0, CAUSEF_IP7 | ||
72 | beqz t1, 0f | ||
73 | srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */ | ||
74 | and t1, t1, 0x4 /* mask to get just BD bit */ | ||
75 | mfc0 a0, CP0_EPC | ||
76 | jal sbprof_cpu_intr | ||
77 | addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */ | ||
78 | j ret_from_irq | ||
79 | nop | ||
80 | 0: | ||
81 | #endif | ||
82 | |||
83 | /* Timer interrupt is routed to IP[4] */ | ||
84 | andi t1, s0, CAUSEF_IP4 | ||
85 | beqz t1, 1f | ||
86 | nop | ||
87 | jal sb1250_timer_interrupt | ||
88 | move a0, sp /* Pass the registers along */ | ||
89 | j ret_from_irq | ||
90 | nop # delay slot | ||
91 | 1: | ||
92 | |||
93 | #ifdef CONFIG_SMP | ||
94 | /* Mailbox interrupt is routed to IP[3] */ | ||
95 | andi t1, s0, CAUSEF_IP3 | ||
96 | beqz t1, 2f | ||
97 | nop | ||
98 | jal sb1250_mailbox_interrupt | ||
99 | move a0, sp | ||
100 | j ret_from_irq | ||
101 | nop # delay slot | ||
102 | 2: | ||
103 | #endif | ||
104 | |||
105 | #ifdef CONFIG_KGDB | ||
106 | /* KGDB (uart 1) interrupt is routed to IP[6] */ | ||
107 | andi t1, s0, CAUSEF_IP6 | ||
108 | beqz t1, 1f | ||
109 | nop # delay slot | ||
110 | jal sb1250_kgdb_interrupt | ||
111 | move a0, sp | ||
112 | j ret_from_irq | ||
113 | nop # delay slot | ||
114 | 1: | ||
115 | #endif | ||
116 | |||
117 | and t1, s0, CAUSEF_IP2 | ||
118 | beqz t1, 4f | ||
119 | nop | ||
120 | |||
121 | /* | ||
122 | * Default...we've hit an IP[2] interrupt, which means we've got to | ||
123 | * check the 1250 interrupt registers to figure out what to do | ||
124 | * Need to detect which CPU we're on, now that smp_affinity is supported. | ||
125 | */ | ||
126 | PTR_LA v0, CKSEG1 + A_IMR_CPU0_BASE | ||
127 | #ifdef CONFIG_SMP | ||
128 | lw t1, TI_CPU($28) | ||
129 | sll t1, IMR_REGISTER_SPACING_SHIFT | ||
130 | addu v0, t1 | ||
131 | #endif | ||
132 | ld s0, R_IMR_INTERRUPT_STATUS_BASE(v0) /* read IP[2] status */ | ||
133 | |||
134 | beqz s0, 4f /* No interrupts. Return */ | ||
135 | move a1, sp | ||
136 | |||
137 | 3: dclz s1, s0 /* Find the next interrupt */ | ||
138 | dsubu a0, zero, s1 | ||
139 | daddiu a0, a0, 63 | ||
140 | jal do_IRQ | ||
141 | nop | ||
142 | |||
143 | 4: j ret_from_irq | ||
144 | nop | ||
145 | |||
146 | .set pop | ||
147 | END(sb1250_irq_handler) | ||