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
|
/*
* Copyright (C) 2000, 2001, 2002, 2003 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.
*/
/*
* sb1250_handle_int() is the routine that is actually called when an interrupt
* occurs. It is installed as the exception vector handler in arch_init_irq()
* in arch/mips/sibyte/sb1250/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/sb1250_regs.h>
#include <asm/sibyte/sb1250_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
.align 5
NESTED(sb1250_irq_handler, PT_SIZE, sp)
SAVE_ALL
CLI
#ifdef CONFIG_SIBYTE_SB1250_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_SB1250_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 */
mfc0 a0, CP0_EPC
jal sbprof_cpu_intr
addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
j ret_from_irq
nop
0:
#endif
/* Timer interrupt is routed to IP[4] */
andi t1, s0, CAUSEF_IP4
beqz t1, 1f
nop
jal sb1250_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 sb1250_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, 1f
nop # delay slot
jal sb1250_kgdb_interrupt
move a0, sp
j ret_from_irq
nop # delay slot
1:
#endif
and t1, s0, CAUSEF_IP2
beqz t1, 4f
nop
/*
* Default...we've hit an IP[2] interrupt, which means we've got to
* check the 1250 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_IMR_CPU0_BASE
#ifdef CONFIG_SMP
lw t1, TI_CPU($28)
sll t1, IMR_REGISTER_SPACING_SHIFT
addu v0, t1
#endif
ld s0, R_IMR_INTERRUPT_STATUS_BASE(v0) /* read IP[2] status */
beqz s0, 4f /* No interrupts. Return */
move a1, sp
3: dclz s1, s0 /* Find the next interrupt */
dsubu a0, zero, s1
daddiu a0, a0, 63
jal do_IRQ
nop
4: j ret_from_irq
nop
.set pop
END(sb1250_irq_handler)
|