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