Home | History | Annotate | Line # | Download | only in sparc64
      1 /*	$NetBSD: intr.c,v 1.73 2026/08/21 18:21:51 palle 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.73 2026/08/21 18:21:51 palle 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
     64 #define INTRDB_SUN4V       0x04
     65 static int sparc_intr_debug = 0x0;
     66 #define DPRINTF(l, s)   do { if (sparc_intr_debug & l) printf s; } while (0)
     67 #else
     68 #define DPRINTF(l, s)
     69 #endif
     70 
     71 /*
     72  * The following array is to used by locore.s to map interrupt packets
     73  * to the proper IPL to send ourselves a softint.  It should be filled
     74  * in as the devices are probed.  We should eventually change this to a
     75  * vector table and call these things directly.
     76  */
     77 struct intrhand *intrlev[MAXINTNUM];
     78 
     79 void	strayintr(const struct trapframe64 *, int);
     80 int	intr_list_handler(void *);
     81 
     82 extern struct evcnt intr_evcnts[];
     83 
     84 /*
     85  * Stray interrupt handler.  Clear it if possible.
     86  * If not, and if we get 10 interrupts in 10 seconds, panic.
     87  */
     88 int ignore_stray = 1;
     89 int straycnt[16];
     90 
     91 void
     92 strayintr(const struct trapframe64 *fp, int vectored)
     93 {
     94 	static int straytime, nstray;
     95 	int timesince;
     96 	char buf[256];
     97 #if 0
     98 	extern int swallow_zsintrs;
     99 #endif
    100 
    101 	if (fp->tf_pil < 16)
    102 		straycnt[(int)fp->tf_pil]++;
    103 
    104 	if (ignore_stray)
    105 		return;
    106 
    107 	/* If we're in polled mode ignore spurious interrupts */
    108 	if ((fp->tf_pil == PIL_SER) /* && swallow_zsintrs */) return;
    109 
    110 	snprintb(buf, sizeof(buf), PSTATE_BITS,
    111 	    (fp->tf_tstate>>TSTATE_PSTATE_SHIFT));
    112 	printf("stray interrupt ipl %u pc=%llx npc=%llx pstate=%s vectored=%d\n",
    113 	    fp->tf_pil, (unsigned long long)fp->tf_pc,
    114 	    (unsigned long long)fp->tf_npc,  buf, vectored);
    115 
    116 	timesince = time_second - straytime;
    117 	if (timesince <= 10) {
    118 		if (++nstray > 500)
    119 			panic("crazy interrupts");
    120 	} else {
    121 		straytime = time_second;
    122 		nstray = 1;
    123 	}
    124 #ifdef DDB
    125 	Debugger();
    126 #endif
    127 }
    128 
    129 /*
    130  * PCI devices can share interrupts so we need to have
    131  * a handler to hand out interrupts.
    132  */
    133 int
    134 intr_list_handler(void *arg)
    135 {
    136 	int claimed = 0;
    137 	struct intrhand *ih = (struct intrhand *)arg;
    138 
    139 	if (!arg) panic("intr_list_handler: no handlers!");
    140 	while (ih && !claimed) {
    141 		claimed = (*ih->ih_fun)(ih->ih_arg);
    142 #ifdef DEBUG
    143 		{
    144 			extern int intrdebug;
    145 			if (intrdebug & 1)
    146 				printf("intr %p %x arg %p %s\n",
    147 					ih, ih->ih_number, ih->ih_arg,
    148 					claimed ? "claimed" : "");
    149 		}
    150 #endif
    151 		ih = ih->ih_next;
    152 	}
    153 	return (claimed);
    154 }
    155 
    156 #ifdef MULTIPROCESSOR
    157 static int intr_biglock_wrapper(void *);
    158 
    159 static int
    160 intr_biglock_wrapper(void *vp)
    161 {
    162 	struct intrhand *ih = vp;
    163 	int ret;
    164 
    165 	KERNEL_LOCK(1, NULL);
    166 	ret = (*ih->ih_realfun)(ih->ih_realarg);
    167 	KERNEL_UNLOCK_ONE(NULL);
    168 
    169 	return ret;
    170 }
    171 #endif
    172 
    173 /*
    174  * Allocate memory for interrupt handler.
    175  * The allocated memory is initialized with zeros so
    176  * e.g. pointers in the intrhand structure are properly initialized.
    177  * A valid pointer is always returned by the function.
    178  */
    179 struct intrhand*
    180 intrhand_alloc(void)
    181 {
    182 	struct intrhand *ih = kmem_zalloc(sizeof(struct intrhand), KM_NOSLEEP);
    183 	if (ih == NULL)
    184 		panic("%s: failed to allocate intrhand", __func__);
    185 	return ih;
    186 }
    187 
    188 /*
    189  * Attach an interrupt handler to the vector chain for the given level.
    190  * This is not possible if it has been taken away as a fast vector.
    191  */
    192 void
    193 intr_establish(int level, bool mpsafe, struct intrhand *ih)
    194 {
    195 	struct intrhand *q = NULL;
    196 	int s;
    197 #ifdef DEBUG
    198 	int opil = ih->ih_pil;
    199 #endif
    200 
    201 	/*
    202 	 * This is O(N^2) for long chains, but chains are never long
    203 	 * and we do want to preserve order.
    204 	 */
    205 #ifdef DIAGNOSTIC
    206 	if (ih->ih_pil != level)
    207 		printf("%s: caller %p did not pre-set ih_pil\n",
    208 		    __func__, __builtin_return_address(0));
    209 	if (ih->ih_pending != 0)
    210 		printf("%s: caller %p did not pre-set ih_pending to zero\n",
    211 		    __func__, __builtin_return_address(0));
    212 #endif
    213 	ih->ih_pil = level; /* XXXX caller should have done this before */
    214 	ih->ih_pending = 0; /* XXXX caller should have done this before */
    215 	ih->ih_next = NULL;
    216 
    217 	/*
    218 	 * no need for a separate counter if ivec == 0, in that case there's
    219 	 * either only one device using the interrupt level and there's already
    220 	 * a counter for it or it's something special like psycho's error
    221 	 * interrupts
    222 	 */
    223 	if (ih->ih_ivec != 0 && intrlev[ih->ih_number] == NULL) {
    224 		snprintf(ih->ih_name, sizeof(ih->ih_name), "%x", ih->ih_ivec);
    225 		evcnt_attach_dynamic(&ih->ih_cnt, EVCNT_TYPE_INTR,
    226 		    &intr_evcnts[level], "ivec", ih->ih_name);
    227 	}
    228 
    229 	/* opil because we overwrote it above with level */
    230 	DPRINTF(INTRDB_ESTABLISH,
    231 	    ("%s: level %x ivec %x inumber %x pil %x\n",
    232 	     __func__, level, ih->ih_ivec, ih->ih_number, opil));
    233 
    234 #ifdef MULTIPROCESSOR
    235 	if (!mpsafe) {
    236 		ih->ih_realarg = ih->ih_arg;
    237 		ih->ih_realfun = ih->ih_fun;
    238 		ih->ih_arg = ih;
    239 		ih->ih_fun = intr_biglock_wrapper;
    240 	}
    241 #endif
    242 
    243 	/* XXXSMP */
    244 	s = splhigh();
    245 	/*
    246 	 * Store in fast lookup table
    247 	 */
    248 #ifdef NOT_DEBUG
    249 	if (!ih->ih_number) {
    250 		printf("\nintr_establish: NULL vector fun %p arg %p pil %p\n",
    251 			  ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil);
    252 		Debugger();
    253 	}
    254 #endif
    255 	if (ih->ih_number < MAXINTNUM && ih->ih_number >= 0) {
    256 		if ((q = intrlev[ih->ih_number])) {
    257 			struct intrhand *nih;
    258 			/*
    259 			 * Interrupt is already there.  We need to create a
    260 			 * new interrupt handler and interpose it.
    261 			 */
    262 			DPRINTF(INTRDB_REUSE,
    263 			    ("intr_establish: intr reused %x\n",
    264 			     ih->ih_number));
    265 			if (q->ih_fun != intr_list_handler) {
    266 				nih = intrhand_alloc();
    267 				/* Point the old IH at the new handler */
    268 				*nih = *q;
    269 				nih->ih_next = NULL;
    270 				q->ih_arg = (void *)nih;
    271 				q->ih_fun = intr_list_handler;
    272 			}
    273 			/* Add the ih to the head of the list */
    274 			ih->ih_next = (struct intrhand *)q->ih_arg;
    275 			q->ih_arg = (void *)ih;
    276 		} else {
    277 			intrlev[ih->ih_number] = ih;
    278 		}
    279 #ifdef NOT_DEBUG
    280 		printf("\nintr_establish: vector %x pil %x mapintr %p "
    281 			"clrintr %p fun %p arg %p\n",
    282 			ih->ih_number, ih->ih_pil, (void *)ih->ih_map,
    283 			(void *)ih->ih_clr, (void *)ih->ih_fun,
    284 			(void *)ih->ih_arg);
    285 		/*Debugger();*/
    286 #endif
    287 	} else
    288 		panic("intr_establish: bad intr number %x", ih->ih_number);
    289 
    290 	splx(s);
    291 }
    292 
    293 /*
    294  * Prepare an interrupt handler used for send_softint.
    295  */
    296 void *
    297 sparc_softintr_establish(int pil, int (*fun)(void *), void *arg)
    298 {
    299 	struct intrhand *ih;
    300 
    301 	ih = intrhand_alloc();
    302 	ih->ih_fun = fun;
    303 	ih->ih_pil = pil;
    304 	ih->ih_arg = arg;
    305 	return ih;
    306 }
    307 
    308 void
    309 sparc_softintr_disestablish(void *cookie)
    310 {
    311 
    312 	kmem_free(cookie, sizeof(struct intrhand));
    313 }
    314 
    315 void
    316 sparc_softintr_schedule(void *cookie)
    317 {
    318 	struct intrhand *ih = (struct intrhand *)cookie;
    319 
    320 	send_softint(-1, ih->ih_pil, ih);
    321 }
    322 
    323 #ifdef __HAVE_FAST_SOFTINTS
    324 /*
    325  * MD implementation of FAST software interrupt framework
    326  */
    327 
    328 int softint_fastintr(void *);
    329 
    330 void
    331 softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep)
    332 {
    333 	struct intrhand *ih;
    334 	int pil;
    335 
    336 	switch (level) {
    337 	case SOFTINT_BIO:
    338 		pil = IPL_SOFTBIO;
    339 		break;
    340 	case SOFTINT_NET:
    341 		pil = IPL_SOFTNET;
    342 		break;
    343 	case SOFTINT_SERIAL:
    344 		pil = IPL_SOFTSERIAL;
    345 		break;
    346 	case SOFTINT_CLOCK:
    347 		pil = IPL_SOFTCLOCK;
    348 		break;
    349 	default:
    350 		panic("softint_init_md");
    351 	}
    352 
    353 	ih = sparc_softintr_establish(pil, softint_fastintr, l);
    354 	*machdep = (uintptr_t)ih;
    355 }
    356 
    357 void
    358 softint_trigger(uintptr_t machdep)
    359 {
    360 	struct intrhand *ih = (struct intrhand *)machdep;
    361 
    362 	send_softint(-1, ih->ih_pil, ih);
    363 }
    364 #endif /* __HAVE_FAST_SOFTINTS */
    365 
    366 #ifdef SUN4V
    367 
    368 #include <machine/hypervisor.h>
    369 
    370 uint64_t sun4v_group_interrupt_major;
    371 
    372 int64_t
    373 sun4v_intr_devino_to_sysino(uint64_t devhandle, uint64_t devino, uint64_t *ino)
    374 {
    375 	DPRINTF(INTRDB_SUN4V,
    376 			("%s: devhandle %#lx devino %#lx\n", __func__, devhandle, devino));
    377 
    378 	if (sun4v_group_interrupt_major < 2) {
    379 		DPRINTF(INTRDB_SUN4V, ("%s: using deprecated api\n", __func__));
    380 		return hv_intr_devino_to_sysino(devhandle, devino, ino);
    381 	}
    382 	*ino = devino;
    383 	DPRINTF(INTRDB_SUN4V,
    384 			("%s: returning devino as ino %#lx\n", __func__, *ino));
    385 
    386 	return H_EOK;
    387 }
    388 
    389 int64_t
    390 sun4v_intr_setcookie(uint64_t devhandle, uint64_t ino, uint64_t cookie_value)
    391 {
    392 	DPRINTF(INTRDB_SUN4V,
    393 			("%s: devhandle %#lx ino %#lx cookie_value %#lx\n",
    394 			 __func__, devhandle, ino, cookie_value));
    395 
    396 	if (sun4v_group_interrupt_major < 2) {
    397 		DPRINTF(INTRDB_SUN4V, ("%s: using deprecated api\n", __func__));
    398 		return H_EOK;
    399 	}
    400 
    401 	return hv_vintr_setcookie(devhandle, ino, cookie_value);
    402 }
    403 
    404 int64_t
    405 sun4v_intr_setenabled(uint64_t devhandle, uint64_t ino, uint64_t intr_enabled)
    406 {
    407 	DPRINTF(INTRDB_SUN4V,
    408 			("%s: devhandle %#lx ino %#lx intr_enabled %#lx\n",
    409 			 __func__, devhandle, ino, intr_enabled));
    410 
    411 	if (sun4v_group_interrupt_major < 2) {
    412 		DPRINTF(INTRDB_SUN4V, ("%s: using deprecated api\n", __func__));
    413 		return hv_intr_setenabled(ino, intr_enabled);
    414 	}
    415 	return hv_vintr_setenabled(devhandle, ino, intr_enabled);
    416 }
    417 
    418 int64_t
    419 sun4v_intr_setstate(uint64_t devhandle, uint64_t ino, uint64_t intr_state)
    420 {
    421 	DPRINTF(INTRDB_SUN4V,
    422 			("%s: devhandle %#lx ino %#lx intr_state %#lx\n",
    423 			 __func__, devhandle, ino, intr_state));
    424 
    425 	if (sun4v_group_interrupt_major < 2) {
    426 		DPRINTF(INTRDB_SUN4V, ("%s: using deprecated api\n", __func__));
    427 		return hv_intr_setstate(ino, intr_state);
    428 	}
    429 
    430 	return hv_vintr_setstate(devhandle, ino, intr_state);
    431 }
    432 
    433 int64_t
    434 sun4v_intr_settarget(uint64_t devhandle, uint64_t ino, uint64_t cpuid)
    435 {
    436 	DPRINTF(INTRDB_SUN4V,
    437 			("%s: devhandle %#lx ino %#lx cpuid %#lx\n",
    438 			 __func__, devhandle, ino, cpuid));
    439 
    440 	if (sun4v_group_interrupt_major < 2) {
    441 		DPRINTF(INTRDB_SUN4V, ("%s: using deprecated api\n", __func__));
    442 		return hv_intr_settarget(ino, cpuid);
    443 	}
    444 
    445 	return hv_vintr_settarget(devhandle, ino, cpuid);
    446 }
    447 
    448 #endif
    449