1/* $NetBSD: intr.c,v 1.72 2024/01/15 08:13:45 andvar 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. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT OT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)intr.c 8.3 (Berkeley) 11/11/93 41 */ 42 43#include <sys/cdefs.h> 44__KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.72 2024/01/15 08:13:45 andvar Exp $"); 45 46#include "opt_ddb.h" 47#include "opt_multiprocessor.h" 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/kmem.h> 53 54#include <dev/cons.h> 55 56#include <machine/cpu.h> 57#include <machine/ctlreg.h> 58#include <machine/instr.h> 59#include <machine/trap.h> 60 61#ifdef DEBUG 62#define INTRDB_ESTABLISH 0x01 63#define INTRDB_REUSE 0x02 64static int sparc_intr_debug = 0x0; 65#define DPRINTF(l, s) do { if (sparc_intr_debug & l) printf s; } while (0) 66#else 67#define DPRINTF(l, s) 68#endif 69 70/* 71 * The following array is to used by locore.s to map interrupt packets 72 * to the proper IPL to send ourselves a softint. It should be filled 73 * in as the devices are probed. We should eventually change this to a 74 * vector table and call these things directly. 75 */ 76struct intrhand *intrlev[MAXINTNUM]; 77 78void strayintr(const struct trapframe64 *, int); 79int intr_list_handler(void *); 80 81extern struct evcnt intr_evcnts[]; 82 83/* 84 * Stray interrupt handler. Clear it if possible. 85 * If not, and if we get 10 interrupts in 10 seconds, panic. 86 */ 87int ignore_stray = 1; 88int straycnt[16]; 89 90void 91strayintr(const struct trapframe64 *fp, int vectored) 92{ 93 static int straytime, nstray; 94 int timesince; 95 char buf[256]; 96#if 0 97 extern int swallow_zsintrs; 98#endif 99 100 if (fp->tf_pil < 16) 101 straycnt[(int)fp->tf_pil]++; 102 103 if (ignore_stray) 104 return; 105 106 /* If we're in polled mode ignore spurious interrupts */ 107 if ((fp->tf_pil == PIL_SER) /* && swallow_zsintrs */) return; 108 109 snprintb(buf, sizeof(buf), PSTATE_BITS, 110 (fp->tf_tstate>>TSTATE_PSTATE_SHIFT)); 111 printf("stray interrupt ipl %u pc=%llx npc=%llx pstate=%s vectored=%d\n", 112 fp->tf_pil, (unsigned long long)fp->tf_pc, 113 (unsigned long long)fp->tf_npc, buf, vectored); 114 115 timesince = time_second - straytime; 116 if (timesince <= 10) { 117 if (++nstray > 500) 118 panic("crazy interrupts"); 119 } else { 120 straytime = time_second; 121 nstray = 1; 122 } 123#ifdef DDB 124 Debugger(); 125#endif 126} 127 128/* 129 * PCI devices can share interrupts so we need to have 130 * a handler to hand out interrupts. 131 */ 132int 133intr_list_handler(void *arg) 134{ 135 int claimed = 0; 136 struct intrhand *ih = (struct intrhand *)arg; 137 138 if (!arg) panic("intr_list_handler: no handlers!"); 139 while (ih && !claimed) { 140 claimed = (*ih->ih_fun)(ih->ih_arg); 141#ifdef DEBUG 142 { 143 extern int intrdebug; 144 if (intrdebug & 1) 145 printf("intr %p %x arg %p %s\n", 146 ih, ih->ih_number, ih->ih_arg, 147 claimed ? "claimed" : ""); 148 } 149#endif 150 ih = ih->ih_next; 151 } 152 return (claimed); 153} 154 155#ifdef MULTIPROCESSOR 156static int intr_biglock_wrapper(void *); 157 158static int 159intr_biglock_wrapper(void *vp) 160{ 161 struct intrhand *ih = vp; 162 int ret; 163 164 KERNEL_LOCK(1, NULL); 165 ret = (*ih->ih_realfun)(ih->ih_realarg); 166 KERNEL_UNLOCK_ONE(NULL); 167 168 return ret; 169} 170#endif 171 172/* 173 * Allocate memory for interrupt handler. 174 * The allocated memory is initialized with zeros so 175 * e.g. pointers in the intrhand structure are properly initialized. 176 * A valid pointer is always returned by the function. 177 */ 178struct intrhand* 179intrhand_alloc(void) 180{ 181 struct intrhand *ih = kmem_zalloc(sizeof(struct intrhand), KM_NOSLEEP); 182 if (ih == NULL) 183 panic("%s: failed to allocate intrhand", __func__); 184 return ih; 185} 186 187/* 188 * Attach an interrupt handler to the vector chain for the given level. 189 * This is not possible if it has been taken away as a fast vector. 190 */ 191void 192intr_establish(int level, bool mpsafe, struct intrhand *ih) 193{ 194 struct intrhand *q = NULL; 195 int s; 196#ifdef DEBUG 197 int opil = ih->ih_pil; 198#endif 199 200 /* 201 * This is O(N^2) for long chains, but chains are never long 202 * and we do want to preserve order. 203 */ 204#ifdef DIAGNOSTIC 205 if (ih->ih_pil != level) 206 printf("%s: caller %p did not pre-set ih_pil\n", 207 __func__, __builtin_return_address(0)); 208 if (ih->ih_pending != 0) 209 printf("%s: caller %p did not pre-set ih_pending to zero\n", 210 __func__, __builtin_return_address(0)); 211#endif 212 ih->ih_pil = level; /* XXXX caller should have done this before */ 213 ih->ih_pending = 0; /* XXXX caller should have done this before */ 214 ih->ih_next = NULL; 215 216 /* 217 * no need for a separate counter if ivec == 0, in that case there's 218 * either only one device using the interrupt level and there's already 219 * a counter for it or it's something special like psycho's error 220 * interrupts 221 */ 222 if (ih->ih_ivec != 0 && intrlev[ih->ih_number] == NULL) { 223 snprintf(ih->ih_name, sizeof(ih->ih_name), "%x", ih->ih_ivec); 224 evcnt_attach_dynamic(&ih->ih_cnt, EVCNT_TYPE_INTR, 225 &intr_evcnts[level], "ivec", ih->ih_name); 226 } 227 228 /* opil because we overwrote it above with level */ 229 DPRINTF(INTRDB_ESTABLISH, 230 ("%s: level %x ivec %x inumber %x pil %x\n", 231 __func__, level, ih->ih_ivec, ih->ih_number, opil)); 232 233#ifdef MULTIPROCESSOR 234 if (!mpsafe) { 235 ih->ih_realarg = ih->ih_arg; 236 ih->ih_realfun = ih->ih_fun; 237 ih->ih_arg = ih; 238 ih->ih_fun = intr_biglock_wrapper; 239 } 240#endif 241 242 /* XXXSMP */ 243 s = splhigh(); 244 /* 245 * Store in fast lookup table 246 */ 247#ifdef NOT_DEBUG 248 if (!ih->ih_number) { 249 printf("\nintr_establish: NULL vector fun %p arg %p pil %p\n", 250 ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil); 251 Debugger(); 252 } 253#endif 254 if (ih->ih_number < MAXINTNUM && ih->ih_number >= 0) { 255 if ((q = intrlev[ih->ih_number])) { 256 struct intrhand *nih; 257 /* 258 * Interrupt is already there. We need to create a 259 * new interrupt handler and interpose it. 260 */ 261 DPRINTF(INTRDB_REUSE, 262 ("intr_establish: intr reused %x\n", 263 ih->ih_number)); 264 if (q->ih_fun != intr_list_handler) { 265 nih = intrhand_alloc(); 266 /* Point the old IH at the new handler */ 267 *nih = *q; 268 nih->ih_next = NULL; 269 q->ih_arg = (void *)nih; 270 q->ih_fun = intr_list_handler; 271 } 272 /* Add the ih to the head of the list */ 273 ih->ih_next = (struct intrhand *)q->ih_arg; 274 q->ih_arg = (void *)ih; 275 } else { 276 intrlev[ih->ih_number] = ih; 277 } 278#ifdef NOT_DEBUG 279 printf("\nintr_establish: vector %x pil %x mapintr %p " 280 "clrintr %p fun %p arg %p\n", 281 ih->ih_number, ih->ih_pil, (void *)ih->ih_map, 282 (void *)ih->ih_clr, (void *)ih->ih_fun, 283 (void *)ih->ih_arg); 284 /*Debugger();*/ 285#endif 286 } else 287 panic("intr_establish: bad intr number %x", ih->ih_number); 288 289 splx(s); 290} 291 292/* 293 * Prepare an interrupt handler used for send_softint. 294 */ 295void * 296sparc_softintr_establish(int pil, int (*fun)(void *), void *arg) 297{ 298 struct intrhand *ih; 299 300 ih = intrhand_alloc(); 301 ih->ih_fun = fun; 302 ih->ih_pil = pil; 303 ih->ih_arg = arg; 304 return ih; 305} 306 307void 308sparc_softintr_disestablish(void *cookie) 309{ 310 311 kmem_free(cookie, sizeof(struct intrhand)); 312} 313 314void 315sparc_softintr_schedule(void *cookie) 316{ 317 struct intrhand *ih = (struct intrhand *)cookie; 318 319 send_softint(-1, ih->ih_pil, ih); 320} 321 322#ifdef __HAVE_FAST_SOFTINTS 323/* 324 * MD implementation of FAST software interrupt framework 325 */ 326 327int softint_fastintr(void *); 328 329void 330softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep) 331{ 332 struct intrhand *ih; 333 int pil; 334 335 switch (level) { 336 case SOFTINT_BIO: 337 pil = IPL_SOFTBIO; 338 break; 339 case SOFTINT_NET: 340 pil = IPL_SOFTNET; 341 break; 342 case SOFTINT_SERIAL: 343 pil = IPL_SOFTSERIAL; 344 break; 345 case SOFTINT_CLOCK: 346 pil = IPL_SOFTCLOCK; 347 break; 348 default: 349 panic("softint_init_md"); 350 } 351 352 ih = sparc_softintr_establish(pil, softint_fastintr, l); 353 *machdep = (uintptr_t)ih; 354} 355 356void 357softint_trigger(uintptr_t machdep) 358{ 359 struct intrhand *ih = (struct intrhand *)machdep; 360 361 send_softint(-1, ih->ih_pil, ih); 362} 363#endif /* __HAVE_FAST_SOFTINTS */ 364 365#ifdef SUN4V 366 367#include <machine/hypervisor.h> 368 369uint64_t sun4v_group_interrupt_major; 370 371int64_t 372sun4v_intr_devino_to_sysino(uint64_t devhandle, uint64_t devino, uint64_t *ino) 373{ 374 if (sun4v_group_interrupt_major < 3) 375 return hv_intr_devino_to_sysino(devhandle, devino, ino); 376 377 *ino = devino; 378 return H_EOK; 379} 380 381int64_t 382sun4v_intr_setcookie(uint64_t devhandle, uint64_t ino, uint64_t cookie_value) 383{ 384 if (sun4v_group_interrupt_major < 3) 385 return H_EOK; 386 387 return hv_vintr_setcookie(devhandle, ino, cookie_value); 388} 389 390int64_t 391sun4v_intr_setenabled(uint64_t devhandle, uint64_t ino, uint64_t intr_enabled) 392{ 393 if (sun4v_group_interrupt_major < 3) 394 return hv_intr_setenabled(ino, intr_enabled); 395 396 return hv_vintr_setenabled(devhandle, ino, intr_enabled); 397} 398 399int64_t 400sun4v_intr_setstate(uint64_t devhandle, uint64_t ino, uint64_t intr_state) 401{ 402 if (sun4v_group_interrupt_major < 3) 403 return hv_intr_setstate(ino, intr_state); 404 405 return hv_vintr_setstate(devhandle, ino, intr_state); 406} 407 408int64_t 409sun4v_intr_settarget(uint64_t devhandle, uint64_t ino, uint64_t cpuid) 410{ 411 if (sun4v_group_interrupt_major < 3) 412 return hv_intr_settarget(ino, cpuid); 413 414 return hv_vintr_settarget(devhandle, ino, cpuid); 415} 416 417#endif 418