aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2006-04-03 12:56:36 -0400
committerRalf Baechle <ralf@linux-mips.org>2006-04-18 22:14:21 -0400
commite4ac58afdfac792c0583af30dbd9eae53e24c78b (patch)
tree7517bef2c515fc630e4d3d238867b91cde96f558 /arch/mips/sibyte
parentd35d473c25d43d7db3e5e18b66d558d2a631cca8 (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/Makefile2
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c77
-rw-r--r--arch/mips/sibyte/bcm1480/irq_handler.S165
-rw-r--r--arch/mips/sibyte/sb1250/Makefile2
-rw-r--r--arch/mips/sibyte/sb1250/irq.c78
-rw-r--r--arch/mips/sibyte/sb1250/irq_handler.S147
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 @@
1obj-y := setup.o irq.o irq_handler.o time.o 1obj-y := setup.o irq.o time.o
2 2
3obj-$(CONFIG_SMP) += smp.o 3obj-$(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 */
191extern void bcm1480_irq_handler(void);
192
193/*****************************************************************************/ 190/*****************************************************************************/
194 191
195static unsigned int startup_bcm1480_irq(unsigned int irq) 192static 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
473static 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
488extern void bcm1480_timer_interrupt(struct pt_regs *regs);
489extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
490extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
491
492asmlinkage 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
870:
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 */
981:
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 */
1092:
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 */
1213:
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
1619: 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 @@
1obj-y := setup.o irq.o irq_handler.o time.o 1obj-y := setup.o irq.o time.o
2 2
3obj-$(CONFIG_SMP) += smp.o 3obj-$(CONFIG_SMP) += smp.o
4obj-$(CONFIG_SIBYTE_TBPROF) += bcm1250_tbprof.o 4obj-$(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 */
168extern void sb1250_irq_handler(void);
169
170/*****************************************************************************/ 166/*****************************************************************************/
171 167
172static unsigned int startup_sb1250_irq(unsigned int irq) 168static 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
412void sb1250_kgdb_interrupt(struct pt_regs *regs) 407static 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
423static 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
438asmlinkage 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
800:
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
911:
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
1022:
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
1141:
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
1373: dclz s1, s0 /* Find the next interrupt */
138 dsubu a0, zero, s1
139 daddiu a0, a0, 63
140 jal do_IRQ
141 nop
142
1434: j ret_from_irq
144 nop
145
146 .set pop
147 END(sb1250_irq_handler)