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 91struct scbvec scb_iovectab[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)]; 92static bool scb_mpsafe[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)]; 93 94void netintr(void); 95 96void scb_stray(void *, u_long); 97 98void 99scb_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 109void 110scb_stray(void *arg, u_long vec) 111{ 112 113 printf("WARNING: stray interrupt, vector 0x%lx\n", vec); 114} 115 116void 117scb_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 140u_long 141scb_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 169void 170scb_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 192void 193interrupt(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 309void 310machine_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 347fatal: 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 372int 373badaddr(void *addr, size_t size) 374{ 375 376 return (badaddr_read(addr, size, NULL)); 377} 378 379int 380badaddr_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 (uint8_t): 397 rcpt = *(volatile uint8_t *)addr; 398 break; 399 400 case sizeof (uint16_t): 401 rcpt = *(volatile uint16_t *)addr; 402 break; 403 404 case sizeof (uint32_t): 405 rcpt = *(volatile uint32_t *)addr; 406 break; 407 408 case sizeof (uint64_t): 409 rcpt = *(volatile uint64_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 (uint8_t): 433 *(volatile uint8_t *)rptr = rcpt; 434 break; 435 436 case sizeof (uint16_t): 437 *(volatile uint16_t *)rptr = rcpt; 438 break; 439 440 case sizeof (uint32_t): 441 *(volatile uint32_t *)rptr = rcpt; 442 break; 443 444 case sizeof (uint64_t): 445 *(volatile uint64_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 453volatile unsigned long ssir; 454 455/* 456 * spl0: 457 * 458 * Lower interrupt priority to IPL 0 -- must check for 459 * software interrupts. 460 */ 461void 462spl0(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 */ 478void 479softintr_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 */ 491void 492softint_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 */ 505bool 506cpu_intr_p(void) 507{ 508 509 return curcpu()->ci_intrdepth != 0; 510} 511 512/* 513 * Security sensitive rate limiting printf 514 */ 515void 516rlprintf(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 525const 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 533ipl_cookie_t 534makeiplcookie(ipl_t ipl) 535{ 536 537 return (ipl_cookie_t){._psl = ipl2psl_table[ipl]}; 538} 539