aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte/sb1250
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/sb1250
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/sb1250')
-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
3 files changed, 73 insertions, 154 deletions
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)