xref: /netbsd/sys/arch/alpha/alpha/interrupt.c (revision 6550d01e)
1 /* $NetBSD: interrupt.c,v 1.79 2010/12/20 00:25:24 matt Exp $ */
2 
3 /*-
4  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
34  * All rights reserved.
35  *
36  * Authors: Keith Bostic, Chris G. Demetriou
37  *
38  * Permission to use, copy, modify and distribute this software and
39  * its documentation is hereby granted, provided that both the copyright
40  * notice and this permission notice appear in all copies of the
41  * software, derivative works or modified versions, and any portions
42  * thereof, and that both notices appear in supporting documentation.
43  *
44  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
46  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47  *
48  * Carnegie Mellon requests users of this software to return to
49  *
50  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
51  *  School of Computer Science
52  *  Carnegie Mellon University
53  *  Pittsburgh PA 15213-3890
54  *
55  * any improvements or extensions that they make and grant Carnegie the
56  * rights to redistribute these changes.
57  */
58 /*
59  * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center.
60  * Redistribute and modify at will, leaving only this additional copyright
61  * notice.
62  */
63 
64 #include "opt_multiprocessor.h"
65 
66 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
67 
68 __KERNEL_RCSID(0, "$NetBSD: interrupt.c,v 1.79 2010/12/20 00:25:24 matt Exp $");
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/proc.h>
73 #include <sys/vmmeter.h>
74 #include <sys/sched.h>
75 #include <sys/malloc.h>
76 #include <sys/kernel.h>
77 #include <sys/time.h>
78 #include <sys/intr.h>
79 #include <sys/device.h>
80 #include <sys/cpu.h>
81 #include <sys/atomic.h>
82 
83 #include <machine/cpuvar.h>
84 #include <machine/autoconf.h>
85 #include <machine/reg.h>
86 #include <machine/rpb.h>
87 #include <machine/frame.h>
88 #include <machine/cpuconf.h>
89 #include <machine/alpha.h>
90 
91 struct scbvec scb_iovectab[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)];
92 static bool scb_mpsafe[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)];
93 
94 void	netintr(void);
95 
96 void	scb_stray(void *, u_long);
97 
98 void
99 scb_init(void)
100 {
101 	u_long i;
102 
103 	for (i = 0; i < SCB_NIOVECS; i++) {
104 		scb_iovectab[i].scb_func = scb_stray;
105 		scb_iovectab[i].scb_arg = NULL;
106 	}
107 }
108 
109 void
110 scb_stray(void *arg, u_long vec)
111 {
112 
113 	printf("WARNING: stray interrupt, vector 0x%lx\n", vec);
114 }
115 
116 void
117 scb_set(u_long vec, void (*func)(void *, u_long), void *arg, int level)
118 {
119 	u_long idx;
120 	int s;
121 
122 	s = splhigh();
123 
124 	if (vec < SCB_IOVECBASE || vec >= SCB_SIZE ||
125 	    (vec & (SCB_VECSIZE - 1)) != 0)
126 		panic("scb_set: bad vector 0x%lx", vec);
127 
128 	idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
129 
130 	if (scb_iovectab[idx].scb_func != scb_stray)
131 		panic("scb_set: vector 0x%lx already occupied", vec);
132 
133 	scb_iovectab[idx].scb_func = func;
134 	scb_iovectab[idx].scb_arg = arg;
135 	scb_mpsafe[idx] = (level != IPL_VM);
136 
137 	splx(s);
138 }
139 
140 u_long
141 scb_alloc(void (*func)(void *, u_long), void *arg)
142 {
143 	u_long vec, idx;
144 	int s;
145 
146 	s = splhigh();
147 
148 	/*
149 	 * Allocate "downwards", to avoid bumping into
150 	 * interrupts which are likely to be at the lower
151 	 * vector numbers.
152 	 */
153 	for (vec = SCB_SIZE - SCB_VECSIZE;
154 	     vec >= SCB_IOVECBASE; vec -= SCB_VECSIZE) {
155 		idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
156 		if (scb_iovectab[idx].scb_func == scb_stray) {
157 			scb_iovectab[idx].scb_func = func;
158 			scb_iovectab[idx].scb_arg = arg;
159 			splx(s);
160 			return (vec);
161 		}
162 	}
163 
164 	splx(s);
165 
166 	return (SCB_ALLOC_FAILED);
167 }
168 
169 void
170 scb_free(u_long vec)
171 {
172 	u_long idx;
173 	int s;
174 
175 	s = splhigh();
176 
177 	if (vec < SCB_IOVECBASE || vec >= SCB_SIZE ||
178 	    (vec & (SCB_VECSIZE - 1)) != 0)
179 		panic("scb_free: bad vector 0x%lx", vec);
180 
181 	idx = SCB_VECTOIDX(vec - SCB_IOVECBASE);
182 
183 	if (scb_iovectab[idx].scb_func == scb_stray)
184 		panic("scb_free: vector 0x%lx is empty", vec);
185 
186 	scb_iovectab[idx].scb_func = scb_stray;
187 	scb_iovectab[idx].scb_arg = (void *) vec;
188 
189 	splx(s);
190 }
191 
192 void
193 interrupt(unsigned long a0, unsigned long a1, unsigned long a2,
194     struct trapframe *framep)
195 {
196 	struct cpu_info *ci = curcpu();
197 	struct cpu_softc *sc = ci->ci_softc;
198 
199 	switch (a0) {
200 	case ALPHA_INTR_XPROC:	/* interprocessor interrupt */
201 #if defined(MULTIPROCESSOR)
202 		atomic_inc_ulong(&ci->ci_intrdepth);
203 
204 		alpha_ipi_process(ci, framep);
205 
206 		/*
207 		 * Handle inter-console messages if we're the primary
208 		 * CPU.
209 		 */
210 		if (ci->ci_cpuid == hwrpb->rpb_primary_cpu_id &&
211 		    hwrpb->rpb_txrdy != 0)
212 			cpu_iccb_receive();
213 
214 		atomic_dec_ulong(&ci->ci_intrdepth);
215 #else
216 		printf("WARNING: received interprocessor interrupt!\n");
217 #endif /* MULTIPROCESSOR */
218 		break;
219 
220 	case ALPHA_INTR_CLOCK:	/* clock interrupt */
221 		/*
222 		 * We don't increment the interrupt depth for the
223 		 * clock interrupt, since it is *sampled* from
224 		 * the clock interrupt, so if we did, all system
225 		 * time would be counted as interrupt time.
226 		 */
227 		sc->sc_evcnt_clock.ev_count++;
228 		ci->ci_data.cpu_nintr++;
229 		if (platform.clockintr) {
230 			/*
231 			 * Call hardclock().  This will also call
232 			 * statclock(). On the primary CPU, it
233 			 * will also deal with time-of-day stuff.
234 			 */
235 			(*platform.clockintr)((struct clockframe *)framep);
236 
237 			/*
238 			 * If it's time to call the scheduler clock,
239 			 * do so.
240 			 */
241 			if ((++ci->ci_schedstate.spc_schedticks & 0x3f) == 0 &&
242 			    schedhz != 0)
243 				schedclock(ci->ci_curlwp);
244 		}
245 		break;
246 
247 	case ALPHA_INTR_ERROR:	/* Machine Check or Correctable Error */
248 		atomic_inc_ulong(&ci->ci_intrdepth);
249 		a0 = alpha_pal_rdmces();
250 		if (platform.mcheck_handler != NULL &&
251 		    (void *)framep->tf_regs[FRAME_PC] != XentArith)
252 			(*platform.mcheck_handler)(a0, framep, a1, a2);
253 		else
254 			machine_check(a0, framep, a1, a2);
255 		atomic_dec_ulong(&ci->ci_intrdepth);
256 		break;
257 
258 	case ALPHA_INTR_DEVICE:	/* I/O device interrupt */
259 	    {
260 		struct scbvec *scb;
261 		int idx = SCB_VECTOIDX(a1 - SCB_IOVECBASE);
262 		bool mpsafe = scb_mpsafe[idx];
263 
264 		KDASSERT(a1 >= SCB_IOVECBASE && a1 < SCB_SIZE);
265 
266 		atomic_inc_ulong(&sc->sc_evcnt_device.ev_count);
267 		atomic_inc_ulong(&ci->ci_intrdepth);
268 
269 		if (!mpsafe) {
270 			KERNEL_LOCK(1, NULL);
271 		}
272 		ci->ci_data.cpu_nintr++;
273 		scb = &scb_iovectab[idx];
274 		(*scb->scb_func)(scb->scb_arg, a1);
275 		if (!mpsafe)
276 			KERNEL_UNLOCK_ONE(NULL);
277 
278 		atomic_dec_ulong(&ci->ci_intrdepth);
279 		break;
280 	    }
281 
282 	case ALPHA_INTR_PERF:	/* performance counter interrupt */
283 		printf("WARNING: received performance counter interrupt!\n");
284 		break;
285 
286 	case ALPHA_INTR_PASSIVE:
287 #if 0
288 		printf("WARNING: received passive release interrupt vec "
289 		    "0x%lx\n", a1);
290 #endif
291 		break;
292 
293 	default:
294 		printf("unexpected interrupt: type 0x%lx vec 0x%lx "
295 		    "a2 0x%lx"
296 #if defined(MULTIPROCESSOR)
297 		    " cpu %lu"
298 #endif
299 		    "\n", a0, a1, a2
300 #if defined(MULTIPROCESSOR)
301 		    , ci->ci_cpuid
302 #endif
303 		    );
304 		panic("interrupt");
305 		/* NOTREACHED */
306 	}
307 }
308 
309 void
310 machine_check(unsigned long mces, struct trapframe *framep,
311     unsigned long vector, unsigned long param)
312 {
313 	const char *type;
314 	struct mchkinfo *mcp;
315 	static struct timeval ratelimit[1];
316 
317 	mcp = &curcpu()->ci_mcinfo;
318 	/* Make sure it's an error we know about. */
319 	if ((mces & (ALPHA_MCES_MIP|ALPHA_MCES_SCE|ALPHA_MCES_PCE)) == 0) {
320 		type = "fatal machine check or error (unknown type)";
321 		goto fatal;
322 	}
323 
324 	/* Machine checks. */
325 	if (mces & ALPHA_MCES_MIP) {
326 		/* If we weren't expecting it, then we punt. */
327 		if (!mcp->mc_expected) {
328 			type = "unexpected machine check";
329 			goto fatal;
330 		}
331 		mcp->mc_expected = 0;
332 		mcp->mc_received = 1;
333 	}
334 
335 	/* System correctable errors. */
336 	if (mces & ALPHA_MCES_SCE)
337 		printf("Warning: received system correctable error.\n");
338 
339 	/* Processor correctable errors. */
340 	if (mces & ALPHA_MCES_PCE)
341 		printf("Warning: received processor correctable error.\n");
342 
343 	/* Clear pending machine checks and correctable errors */
344 	alpha_pal_wrmces(mces);
345 	return;
346 
347 fatal:
348 	alpha_pal_wrmces(mces);
349 	if ((void *)framep->tf_regs[FRAME_PC] == XentArith) {
350 		rlprintf(ratelimit, "Stray machine check\n");
351 		return;
352 	}
353 
354 	printf("\n");
355 	printf("%s:\n", type);
356 	printf("\n");
357 	printf("    mces    = 0x%lx\n", mces);
358 	printf("    vector  = 0x%lx\n", vector);
359 	printf("    param   = 0x%lx\n", param);
360 	printf("    pc      = 0x%lx\n", framep->tf_regs[FRAME_PC]);
361 	printf("    ra      = 0x%lx\n", framep->tf_regs[FRAME_RA]);
362 	printf("    code    = 0x%lx\n", *(unsigned long *)(param + 0x10));
363 	printf("    curlwp = %p\n", curlwp);
364 	if (curlwp != NULL)
365 		printf("        pid = %d.%d, comm = %s\n",
366 		    curproc->p_pid, curlwp->l_lid,
367 		    curproc->p_comm);
368 	printf("\n");
369 	panic("machine check");
370 }
371 
372 int
373 badaddr(void *addr, size_t size)
374 {
375 
376 	return (badaddr_read(addr, size, NULL));
377 }
378 
379 int
380 badaddr_read(void *addr, size_t size, void *rptr)
381 {
382 	struct mchkinfo *mcp = &curcpu()->ci_mcinfo;
383 	long rcpt;
384 	int rv;
385 
386 	/* Get rid of any stale machine checks that have been waiting.  */
387 	alpha_pal_draina();
388 
389 	/* Tell the trap code to expect a machine check. */
390 	mcp->mc_received = 0;
391 	mcp->mc_expected = 1;
392 
393 	/* Read from the test address, and make sure the read happens. */
394 	alpha_mb();
395 	switch (size) {
396 	case sizeof (u_int8_t):
397 		rcpt = *(volatile u_int8_t *)addr;
398 		break;
399 
400 	case sizeof (u_int16_t):
401 		rcpt = *(volatile u_int16_t *)addr;
402 		break;
403 
404 	case sizeof (u_int32_t):
405 		rcpt = *(volatile u_int32_t *)addr;
406 		break;
407 
408 	case sizeof (u_int64_t):
409 		rcpt = *(volatile u_int64_t *)addr;
410 		break;
411 
412 	default:
413 		panic("badaddr: invalid size (%ld)", size);
414 	}
415 	alpha_mb();
416 	alpha_mb();	/* MAGIC ON SOME SYSTEMS */
417 
418 	/* Make sure we took the machine check, if we caused one. */
419 	alpha_pal_draina();
420 
421 	/* disallow further machine checks */
422 	mcp->mc_expected = 0;
423 
424 	rv = mcp->mc_received;
425 	mcp->mc_received = 0;
426 
427 	/*
428 	 * And copy back read results (if no fault occurred).
429 	 */
430 	if (rptr && rv == 0) {
431 		switch (size) {
432 		case sizeof (u_int8_t):
433 			*(volatile u_int8_t *)rptr = rcpt;
434 			break;
435 
436 		case sizeof (u_int16_t):
437 			*(volatile u_int16_t *)rptr = rcpt;
438 			break;
439 
440 		case sizeof (u_int32_t):
441 			*(volatile u_int32_t *)rptr = rcpt;
442 			break;
443 
444 		case sizeof (u_int64_t):
445 			*(volatile u_int64_t *)rptr = rcpt;
446 			break;
447 		}
448 	}
449 	/* Return non-zero (i.e. true) if it's a bad address. */
450 	return (rv);
451 }
452 
453 volatile unsigned long ssir;
454 
455 /*
456  * spl0:
457  *
458  *	Lower interrupt priority to IPL 0 -- must check for
459  *	software interrupts.
460  */
461 void
462 spl0(void)
463 {
464 
465 	if (ssir) {
466 		(void) alpha_pal_swpipl(ALPHA_PSL_IPL_SOFT);
467 		softintr_dispatch();
468 	}
469 
470 	(void) alpha_pal_swpipl(ALPHA_PSL_IPL_0);
471 }
472 
473 /*
474  * softintr_dispatch:
475  *
476  *	Process pending software interrupts.
477  */
478 void
479 softintr_dispatch(void)
480 {
481 
482 	/* XXX Nothing until alpha gets __HAVE_FAST_SOFTINTS */
483 }
484 
485 #ifdef __HAVE_FAST_SOFTINTS
486 /*
487  * softint_trigger:
488  *
489  *	Trigger a soft interrupt.
490  */
491 void
492 softint_trigger(uintptr_t machdep)
493 {
494 
495 	/* XXX Needs to be per-CPU */
496 	atomic_or_ulong(&ssir, 1 << (x))
497 }
498 #endif
499 
500 /*
501  * cpu_intr_p:
502  *
503  *	Return non-zero if executing in interrupt context.
504  */
505 bool
506 cpu_intr_p(void)
507 {
508 
509 	return curcpu()->ci_intrdepth != 0;
510 }
511 
512 /*
513  * Security sensitive rate limiting printf
514  */
515 void
516 rlprintf(struct timeval *t, const char *fmt, ...)
517 {
518 	va_list ap;
519 	static const struct timeval msgperiod[1] = {{ 5, 0 }};
520 
521 	if (ratecheck(t, msgperiod))
522 		vprintf(fmt, ap);
523 }
524 
525 const static uint8_t ipl2psl_table[] = {
526 	[IPL_NONE] = ALPHA_PSL_IPL_0,
527 	[IPL_SOFTCLOCK] = ALPHA_PSL_IPL_SOFT,
528 	[IPL_VM] = ALPHA_PSL_IPL_IO,
529 	[IPL_CLOCK] = ALPHA_PSL_IPL_CLOCK,
530 	[IPL_HIGH] = ALPHA_PSL_IPL_HIGH,
531 };
532 
533 ipl_cookie_t
534 makeiplcookie(ipl_t ipl)
535 {
536 
537 	return (ipl_cookie_t){._psl = ipl2psl_table[ipl]};
538 }
539