xref: /netbsd/sys/arch/sparc64/sparc64/intr.c (revision bf9ec67e)
1 /*	$NetBSD: intr.c,v 1.42 2002/05/06 19:19:48 eeh Exp $ */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT OT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)intr.c	8.3 (Berkeley) 11/11/93
45  */
46 
47 #include "opt_ddb.h"
48 #include "pcons.h"
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/malloc.h>
54 
55 #include <dev/cons.h>
56 
57 #include <net/netisr.h>
58 
59 #include <machine/cpu.h>
60 #include <machine/ctlreg.h>
61 #include <machine/instr.h>
62 #include <machine/trap.h>
63 
64 /*
65  * The following array is to used by locore.s to map interrupt packets
66  * to the proper IPL to send ourselves a softint.  It should be filled
67  * in as the devices are probed.  We should eventually change this to a
68  * vector table and call these things directly.
69  */
70 struct intrhand *intrlev[MAXINTNUM];
71 
72 void	strayintr __P((const struct trapframe64 *, int));
73 int	softintr __P((void *));
74 int	softnet __P((void *));
75 int	intr_list_handler __P((void *));
76 
77 /*
78  * Stray interrupt handler.  Clear it if possible.
79  * If not, and if we get 10 interrupts in 10 seconds, panic.
80  */
81 int ignore_stray = 1;
82 int straycnt[16];
83 
84 void
85 strayintr(fp, vectored)
86 	const struct trapframe64 *fp;
87 	int vectored;
88 {
89 	static int straytime, nstray;
90 	int timesince;
91 	char buf[256];
92 #if 0
93 	extern int swallow_zsintrs;
94 #endif
95 
96 	if (fp->tf_pil < 16)
97 		straycnt[(int)fp->tf_pil]++;
98 
99 	if (ignore_stray)
100 		return;
101 
102 	/* If we're in polled mode ignore spurious interrupts */
103 	if ((fp->tf_pil == PIL_SER) /* && swallow_zsintrs */) return;
104 
105 	printf("stray interrupt ipl %u pc=%llx npc=%llx pstate=%s vecttored=%d\n",
106 	    fp->tf_pil, (unsigned long long)fp->tf_pc,
107 	    (unsigned long long)fp->tf_npc,
108 	    bitmask_snprintf((fp->tf_tstate>>TSTATE_PSTATE_SHIFT),
109 	      PSTATE_BITS, buf, sizeof(buf)), vectored);
110 
111 	timesince = time.tv_sec - straytime;
112 	if (timesince <= 10) {
113 		if (++nstray > 500)
114 			panic("crazy interrupts");
115 	} else {
116 		straytime = time.tv_sec;
117 		nstray = 1;
118 	}
119 #ifdef DDB
120 	Debugger();
121 #endif
122 }
123 
124 /*
125  * Level 1 software interrupt (could also be Sbus level 1 interrupt).
126  * Three possible reasons:
127  *	Network software interrupt
128  *	Soft clock interrupt
129  */
130 int
131 softintr(fp)
132 	void *fp;
133 {
134 #if NPCONS >0
135 	extern void pcons_dopoll __P((void));
136 
137 	pcons_dopoll();
138 #endif
139 	return (1);
140 }
141 
142 int
143 softnet(fp)
144 	void *fp;
145 {
146 	int n, s;
147 
148 	s = splhigh();
149 	n = netisr;
150 	netisr = 0;
151 	splx(s);
152 
153 #define DONETISR(bit, fn) do {		\
154 	if (n & (1 << bit))		\
155 		fn();			\
156 } while (0)
157 #include <net/netisr_dispatch.h>
158 #undef DONETISR
159 	return (1);
160 }
161 
162 struct intrhand soft01intr = { softintr, NULL, 1 };
163 struct intrhand soft01net = { softnet, NULL, 1 };
164 
165 #if 1
166 void
167 setsoftint() {
168 	send_softint(-1, IPL_SOFTINT, &soft01intr);
169 }
170 void
171 setsoftnet() {
172 	send_softint(-1, IPL_SOFTNET, &soft01net);
173 }
174 #endif
175 
176 /*
177  * Level 15 interrupts are special, and not vectored here.
178  * Only `prewired' interrupts appear here; boot-time configured devices
179  * are attached via intr_establish() below.
180  */
181 struct intrhand *intrhand[16] = {
182 	NULL,			/*  0 = error */
183 	&soft01intr,		/*  1 = software level 1 + Sbus */
184 	NULL,	 		/*  2 = Sbus level 2 (4m: Sbus L1) */
185 	NULL,			/*  3 = SCSI + DMA + Sbus level 3 (4m: L2,lpt)*/
186 	NULL,			/*  4 = software level 4 (tty softint) (scsi) */
187 	NULL,			/*  5 = Ethernet + Sbus level 4 (4m: Sbus L3) */
188 	NULL,			/*  6 = software level 6 (not used) (4m: enet)*/
189 	NULL,			/*  7 = video + Sbus level 5 */
190 	NULL,			/*  8 = Sbus level 6 */
191 	NULL,			/*  9 = Sbus level 7 */
192 	NULL,			/* 10 = counter 0 = clock */
193 	NULL,			/* 11 = floppy */
194 	NULL,			/* 12 = zs hardware interrupt */
195 	NULL,			/* 13 = audio chip */
196 	NULL,			/* 14 = counter 1 = profiling timer */
197 	NULL			/* 15 = async faults */
198 };
199 
200 int fastvec = 0;
201 
202 /*
203  * PCI devices can share interrupts so we need to have
204  * a handler to hand out interrupts.
205  */
206 int
207 intr_list_handler(arg)
208 	void * arg;
209 {
210 	int claimed = 0;
211 	struct intrhand *ih = (struct intrhand *)arg;
212 
213 	if (!arg) panic("intr_list_handler: no handlers!");
214 	while (ih && !claimed) {
215 		claimed = (*ih->ih_fun)(ih->ih_arg);
216 #ifdef DEBUG
217 		{
218 			extern int intrdebug;
219 			if (intrdebug & 1)
220 				printf("intr %p %x arg %p %s\n",
221 					ih, ih->ih_number, ih->ih_arg,
222 					claimed ? "claimed" : "");
223 		}
224 #endif
225 		ih = ih->ih_next;
226 	}
227 	return (claimed);
228 }
229 
230 
231 /*
232  * Attach an interrupt handler to the vector chain for the given level.
233  * This is not possible if it has been taken away as a fast vector.
234  */
235 void
236 intr_establish(level, ih)
237 	int level;
238 	struct intrhand *ih;
239 {
240 	register struct intrhand **p, *q = NULL;
241 	int s;
242 
243 	s = splhigh();
244 	/*
245 	 * This is O(N^2) for long chains, but chains are never long
246 	 * and we do want to preserve order.
247 	 */
248 	ih->ih_pil = level; /* XXXX caller should have done this before */
249 	ih->ih_pending = 0; /* XXXX caller should have done this before */
250 	ih->ih_next = NULL;
251 
252 	/*
253 	 * Store in fast lookup table
254 	 */
255 #ifdef NOT_DEBUG
256 	if (!ih->ih_number) {
257 		printf("\nintr_establish: NULL vector fun %p arg %p pil %p\n",
258 			  ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil);
259 		Debugger();
260 	}
261 #endif
262 	if (ih->ih_number < MAXINTNUM && ih->ih_number >= 0) {
263 		if ((q = intrlev[ih->ih_number])) {
264 			struct intrhand *nih;
265 			/*
266 			 * Interrupt is already there.  We need to create a
267 			 * new interrupt handler and interpose it.
268 			 */
269 #ifdef DEBUG
270 			printf("intr_establish: intr reused %x\n",
271 				ih->ih_number);
272 #endif
273 			if (q->ih_fun != intr_list_handler) {
274 				nih = (struct intrhand *)
275 					malloc(sizeof(struct intrhand),
276 						M_DEVBUF, M_NOWAIT);
277 				/* Point the old IH at the new handler */
278 				*nih = *q;
279 				q->ih_fun = intr_list_handler;
280 				q->ih_arg = (void *)nih;
281 				nih->ih_next = NULL;
282 			}
283 			/* Add the ih to the head of the list */
284 			ih->ih_next = (struct intrhand *)q->ih_arg;
285 			q->ih_arg = (void *)ih;
286 		} else {
287 			intrlev[ih->ih_number] = ih;
288 		}
289 #ifdef NOT_DEBUG
290 		printf("\nintr_establish: vector %x pil %x mapintr %p "
291 			"clrintr %p fun %p arg %p\n",
292 			ih->ih_number, ih->ih_pil, (void *)ih->ih_map,
293 			(void *)ih->ih_clr, (void *)ih->ih_fun,
294 			(void *)ih->ih_arg);
295 		/*Debugger();*/
296 #endif
297 	} else
298 		panic("intr_establish: bad intr number %x", ih->ih_number);
299 
300 	/* If it's not shared, stick it in the intrhand list for that level. */
301 	if (q != NULL) {
302 		for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next)
303 			;
304 		*p = ih;
305 	}
306 
307 	splx(s);
308 }
309 
310 void *
311 softintr_establish(level, fun, arg)
312 	int level;
313 	void (*fun) __P((void *));
314 	void *arg;
315 {
316 	struct intrhand *ih;
317 
318 	ih = malloc(sizeof(*ih), M_DEVBUF, 0);
319 	bzero(ih, sizeof(*ih));
320 	ih->ih_fun = (int (*) __P((void *)))fun;	/* XXX */
321 	ih->ih_arg = arg;
322 	ih->ih_pil = level;
323 	ih->ih_pending = 0;
324 	ih->ih_clr = NULL;
325 	return (void *)ih;
326 }
327 
328 void
329 softintr_disestablish(cookie)
330 	void *cookie;
331 {
332 	free(cookie, M_DEVBUF);
333 }
334 
335 void
336 softintr_schedule(cookie)
337 	void *cookie;
338 {
339 	struct intrhand *ih = (struct intrhand *)cookie;
340 
341 	send_softint(-1, ih->ih_pil, ih);
342 }
343