interrupt.S 5.92 KB
Newer Older
Bryan Wu's avatar
Bryan Wu committed
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
/*
 * File:         arch/blackfin/mach-common/interrupt.S
 * Based on:
 * Author:       D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
 *               Kenneth Albanowski <kjahds@kjahds.com>
 *
 * Created:      ?
 * Description:  Interrupt Entries
 *
 * Modified:
 *               Copyright 2004-2006 Analog Devices Inc.
 *
 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
 *
 * 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, see the file COPYING, or write
 * to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <asm/blackfin.h>
32
#include <mach/irq.h>
Bryan Wu's avatar
Bryan Wu committed
33
34
35
#include <linux/linkage.h>
#include <asm/entry.h>
#include <asm/asm-offsets.h>
36
#include <asm/trace.h>
37
38
#include <asm/traps.h>
#include <asm/thread_info.h>
Bryan Wu's avatar
Bryan Wu committed
39

40
#include <asm/context.S>
Bryan Wu's avatar
Bryan Wu committed
41

42
43
.extern _ret_from_exception

Bryan Wu's avatar
Bryan Wu committed
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
#ifdef CONFIG_I_ENTRY_L1
.section .l1.text
#else
.text
#endif

.align 4 	/* just in case */

/* Common interrupt entry code.	 First we do CLI, then push
 * RETI, to keep interrupts disabled, but to allow this state to be changed
 * by local_bh_enable.
 * R0 contains the interrupt number, while R1 may contain the value of IPEND,
 * or garbage if IPEND won't be needed by the ISR.  */
__common_int_entry:
	[--sp] = fp;
	[--sp] = usp;

	[--sp] = i0;
	[--sp] = i1;
	[--sp] = i2;
	[--sp] = i3;

	[--sp] = m0;
	[--sp] = m1;
	[--sp] = m2;
	[--sp] = m3;

	[--sp] = l0;
	[--sp] = l1;
	[--sp] = l2;
	[--sp] = l3;

	[--sp] = b0;
	[--sp] = b1;
	[--sp] = b2;
	[--sp] = b3;
	[--sp] = a0.x;
	[--sp] = a0.w;
	[--sp] = a1.x;
	[--sp] = a1.w;

	[--sp] = LC0;
	[--sp] = LC1;
	[--sp] = LT0;
	[--sp] = LT1;
	[--sp] = LB0;
	[--sp] = LB1;

	[--sp] = ASTAT;

	[--sp] = r0;	/* Skip reserved */
	[--sp] = RETS;
	r2 = RETI;
	[--sp] = r2;
	[--sp] = RETX;
	[--sp] = RETN;
	[--sp] = RETE;
	[--sp] = SEQSTAT;
	[--sp] = r1;	/* IPEND - R1 may or may not be set up before jumping here. */

	/* Switch to other method of keeping interrupts disabled.  */
#ifdef CONFIG_DEBUG_HWERR
	r1 = 0x3f;
	sti r1;
#else
	cli r1;
#endif
	[--sp] = RETI;  /* orig_pc */
	/* Clear all L registers.  */
	r1 = 0 (x);
	l0 = r1;
	l1 = r1;
	l2 = r1;
	l3 = r1;
#ifdef CONFIG_FRAME_POINTER
	fp = 0;
#endif

122
#if ANOMALY_05000283 || ANOMALY_05000315
Bryan Wu's avatar
Bryan Wu committed
123
	cc = r7 == r7;
124
125
	p5.h = HI(CHIPID);
	p5.l = LO(CHIPID);
Bryan Wu's avatar
Bryan Wu committed
126
127
128
129
130
131
	if cc jump 1f;
	r7.l = W[p5];
1:
#endif
	r1 =  sp;
	SP += -12;
132
133
134
135
136
137
#ifdef CONFIG_IPIPE
	call ___ipipe_grab_irq
	SP += 12;
	cc = r0 == 0;
	if cc jump .Lcommon_restore_context;
#else /* CONFIG_IPIPE */
Bryan Wu's avatar
Bryan Wu committed
138
139
	call _do_irq;
	SP += 12;
140
#endif /* CONFIG_IPIPE */
Bryan Wu's avatar
Bryan Wu committed
141
142
143
144
145
146
147
	call _return_from_int;
.Lcommon_restore_context:
	RESTORE_CONTEXT
	rti;

/* interrupt routine for ivhw - 5 */
ENTRY(_evt_ivhw)
148
149
150
151
152
153
154
155
	/* In case a single action kicks off multiple memory transactions, (like
	 * a cache line fetch, - this can cause multiple hardware errors, let's
	 * catch them all. First - make sure all the actions are complete, and
	 * the core sees the hardware errors.
	 */
	SSYNC;
	SSYNC;

156
	SAVE_ALL_SYS
Bryan Wu's avatar
Bryan Wu committed
157
158
159
#ifdef CONFIG_FRAME_POINTER
	fp = 0;
#endif
160

161
#if ANOMALY_05000283 || ANOMALY_05000315
Bryan Wu's avatar
Bryan Wu committed
162
	cc = r7 == r7;
163
164
	p5.h = HI(CHIPID);
	p5.l = LO(CHIPID);
Bryan Wu's avatar
Bryan Wu committed
165
166
167
168
	if cc jump 1f;
	r7.l = W[p5];
1:
#endif
169

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
	/* Handle all stacked hardware errors
	 * To make sure we don't hang forever, only do it 10 times
	 */
	R0 = 0;
	R2 = 10;
1:
	P0.L = LO(ILAT);
	P0.H = HI(ILAT);
	R1 = [P0];
	CC = BITTST(R1, EVT_IVHW_P);
	IF ! CC JUMP 2f;
	/* OK a hardware error is pending - clear it */
	R1 = EVT_IVHW_P;
	[P0] = R1;
	R0 += 1;
	CC = R1 == R2;
	if CC JUMP 2f;
	JUMP 1b;
2:
189
190
191
192
193
194
	# We are going to dump something out, so make sure we print IPEND properly
	p2.l = lo(IPEND);
	p2.h = hi(IPEND);
	r0 = [p2];
	[sp + PT_IPEND] = r0;

195
196
197
198
199
200
201
202
	/* set the EXCAUSE to HWERR for trap_c */
	r0 = [sp + PT_SEQSTAT];
	R1.L = LO(VEC_HWERR);
	R1.H = HI(VEC_HWERR);
	R0 = R0 | R1;
	[sp + PT_SEQSTAT] = R0;

	r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */
Bryan Wu's avatar
Bryan Wu committed
203
	SP += -12;
204
	call _trap_c;
Bryan Wu's avatar
Bryan Wu committed
205
	SP += 12;
206

207
208
209
210
211
212
213
214
#ifdef EBIU_ERRMST
	/* make sure EBIU_ERRMST is clear */
	p0.l = LO(EBIU_ERRMST);
	p0.h = HI(EBIU_ERRMST);
	r0.l = (CORE_ERROR | CORE_MERROR);
	w[p0] = r0.l;
#endif

215
	call _ret_from_exception;
216

217
218
.Lcommon_restore_all_sys:
	RESTORE_ALL_SYS
Bryan Wu's avatar
Bryan Wu committed
219
	rti;
220
221
ENDPROC(_evt_ivhw)

222
223
224
/* Interrupt routine for evt2 (NMI).
 * We don't actually use this, so just return.
 * For inner circle type details, please see:
Robin Getz's avatar
Robin Getz committed
225
 * http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:nmi
226
227
228
 */
ENTRY(_evt_nmi)
.weak _evt_nmi
Bryan Wu's avatar
Bryan Wu committed
229
	rtn;
230
ENDPROC(_evt_nmi)
Bryan Wu's avatar
Bryan Wu committed
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

/* interrupt routine for core timer - 6 */
ENTRY(_evt_timer)
	TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)

/* interrupt routine for evt7 - 7 */
ENTRY(_evt_evt7)
	INTERRUPT_ENTRY(EVT_IVG7_P)
ENTRY(_evt_evt8)
	INTERRUPT_ENTRY(EVT_IVG8_P)
ENTRY(_evt_evt9)
	INTERRUPT_ENTRY(EVT_IVG9_P)
ENTRY(_evt_evt10)
	INTERRUPT_ENTRY(EVT_IVG10_P)
ENTRY(_evt_evt11)
	INTERRUPT_ENTRY(EVT_IVG11_P)
ENTRY(_evt_evt12)
	INTERRUPT_ENTRY(EVT_IVG12_P)
ENTRY(_evt_evt13)
	INTERRUPT_ENTRY(EVT_IVG13_P)


 /* interrupt routine for system_call - 15 */
ENTRY(_evt_system_call)
	SAVE_CONTEXT_SYSCALL
#ifdef CONFIG_FRAME_POINTER
	fp = 0;
#endif
	call _system_call;
	jump .Lcommon_restore_context;
261
ENDPROC(_evt_system_call)
262
263
264

#ifdef CONFIG_IPIPE
ENTRY(___ipipe_call_irqtail)
265
	p0 = r0;
266
267
268
269
270
271
272
273
274
275
276
277
278
	r0.l = 1f;
	r0.h = 1f;
	reti = r0;
	rti;
1:
	[--sp] = rets;
	[--sp] = ( r7:4, p5:3 );
	sp += -12;
	call (p0);
	sp += 12;
	( r7:4, p5:3 ) = [sp++];
	rets = [sp++];

279
	r0 = 0x401f (z);
280
	sti r0;
281
	raise 14;		/* Branches to _evt_evt14 */
282
283
284
2:
	jump 2b;                /* Likely paranoid. */
ENDPROC(___ipipe_call_irqtail)
285

286
#endif /* CONFIG_IPIPE */