Home | History | Annotate | Line # | Download | only in mac68k
      1 /*	$NetBSD: intr.c,v 1.37 2026/03/18 04:08:38 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Adam Glass, Gordon W. Ross, and 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  * Link and dispatch interrupts.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.37 2026/03/18 04:08:38 thorpej Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/vmmeter.h>
     42 #include <sys/cpu.h>
     43 #include <sys/intr.h>
     44 
     45 #include <m68k/vectors.h>
     46 
     47 #include <machine/psc.h>
     48 #include <machine/viareg.h>
     49 
     50 #define	NISR	8
     51 #define	ISRLOC	0x18
     52 
     53 static int intr_noint(void *);
     54 
     55 static int ((*intr_func[NISR])(void *)) = {
     56 	intr_noint,
     57 	intr_noint,
     58 	intr_noint,
     59 	intr_noint,
     60 	intr_noint,
     61 	intr_noint,
     62 	intr_noint,
     63 	intr_noint
     64 };
     65 static void *intr_arg[NISR] = {
     66 	NULL,
     67 	NULL,
     68 	NULL,
     69 	NULL,
     70 	NULL,
     71 	NULL,
     72 	NULL,
     73 	NULL
     74 };
     75 
     76 #ifdef DEBUG
     77 int	intr_debug = 0;
     78 #endif
     79 
     80 /*
     81  * Some of the below are not used yet, but might be used someday on the
     82  * IIfx/Q700/900/950/etc. where the interrupt controller may be reprogrammed
     83  * to interrupt on different levels as listed in locore.s
     84  */
     85 uint16_t ipl2psl_table[NIPL];
     86 volatile unsigned int intr_depth;
     87 
     88 extern	u_int intrcnt[];	/* from locore.s */
     89 
     90 void	intr_computeipl(void);
     91 
     92 #define MAX_INAME_LENGTH 53
     93 #define STD_INAMES \
     94 	"spur\0via1\0via2\0unused1\0scc\0unused2\0unused3\0nmi\0clock\0"
     95 #define AUX_INAMES \
     96 	"spur\0soft\0via2\0ethernet\0scc\0sound\0via1\0nmi\0clock\0    "
     97 #define AV_INAMES \
     98 	"spur\0via1\0via2\0ethernet\0scc\0dsp\0unused1\0nmi\0clock\0   "
     99 
    100 void
    101 intr_init(void)
    102 {
    103 	extern char	intrnames[MAX_INAME_LENGTH];
    104 	extern char	eintrnames[] __diagused;
    105 	const char	*inames;
    106 
    107 	ipl2psl_table[IPL_NONE]       = 0;
    108 	ipl2psl_table[IPL_SOFTCLOCK]  = PSL_S|PSL_IPL1;
    109 	ipl2psl_table[IPL_SOFTNET]    = PSL_S|PSL_IPL1;
    110 	ipl2psl_table[IPL_SOFTSERIAL] = PSL_S|PSL_IPL1;
    111 	ipl2psl_table[IPL_SOFTBIO]    = PSL_S|PSL_IPL1;
    112 	ipl2psl_table[IPL_HIGH]       = PSL_S|PSL_IPL7;
    113 
    114 	if (mac68k_machine.aux_interrupts) {
    115 		inames = AUX_INAMES;
    116 
    117 		/* Standard spl(9) interrupt priorities */
    118 		ipl2psl_table[IPL_VM]        = (PSL_S | PSL_IPL6);
    119 		ipl2psl_table[IPL_SCHED]     = (PSL_S | PSL_IPL6);
    120 	} else {
    121 		inames = STD_INAMES;
    122 
    123 		/* Standard spl(9) interrupt priorities */
    124 		ipl2psl_table[IPL_VM]        = (PSL_S | PSL_IPL2);
    125 		ipl2psl_table[IPL_SCHED]     = (PSL_S | PSL_IPL3);
    126 
    127 		if (current_mac_model->class == MACH_CLASSAV) {
    128 			inames = AV_INAMES;
    129 			ipl2psl_table[IPL_VM]    = (PSL_S | PSL_IPL4);
    130 			ipl2psl_table[IPL_SCHED] = (PSL_S | PSL_IPL4);
    131 		}
    132 	}
    133 
    134 	KASSERT(MAX_INAME_LENGTH <=
    135 		((uintptr_t)eintrnames - (uintptr_t)intrnames));
    136 	memcpy(intrnames, inames, MAX_INAME_LENGTH);
    137 
    138 	intr_computeipl();
    139 
    140 	/* Initialize the VIAs */
    141 	via_init();
    142 
    143 	/* Initialize the PSC (if present) */
    144 	psc_init();
    145 }
    146 
    147 
    148 /*
    149  * Compute the interrupt levels for the spl*()
    150  * calls.  This doesn't have to be fast.
    151  */
    152 void
    153 intr_computeipl(void)
    154 {
    155 	/*
    156 	 * Enforce the following relationship, as defined in spl(9):
    157 	 * `bio <= net <= tty <= vm <= statclock <= clock <= sched <= serial'
    158 	 */
    159 	if (ipl2psl_table[IPL_VM] > ipl2psl_table[IPL_SCHED])
    160 		ipl2psl_table[IPL_SCHED] = ipl2psl_table[IPL_VM];
    161 
    162 	if (ipl2psl_table[IPL_SCHED] > ipl2psl_table[IPL_HIGH])
    163 		ipl2psl_table[IPL_HIGH] = ipl2psl_table[IPL_SCHED];
    164 }
    165 
    166 /*
    167  * Establish an autovectored interrupt handler.
    168  * Called by driver attach functions.
    169  *
    170  * XXX Warning!  DO NOT use Macintosh ROM traps from an interrupt handler
    171  * established by this routine, either directly or indirectly, without
    172  * properly saving and restoring all registers.  If not, chaos _will_
    173  * ensue!  (sar 19980806)
    174  */
    175 void
    176 intr_establish(int (*func)(void *), void *arg, int ipl)
    177 {
    178 	if ((ipl < 0) || (ipl >= NISR))
    179 		panic("intr_establish: bad ipl %d", ipl);
    180 
    181 #ifdef DIAGNOSTIC
    182 	if (intr_func[ipl] != intr_noint)
    183 		printf("intr_establish: attempt to share ipl %d\n", ipl);
    184 #endif
    185 
    186 	intr_func[ipl] = func;
    187 	intr_arg[ipl] = arg;
    188 }
    189 
    190 /*
    191  * Disestablish an interrupt handler.
    192  */
    193 void
    194 intr_disestablish(int ipl)
    195 {
    196 	if ((ipl < 0) || (ipl >= NISR))
    197 		panic("intr_disestablish: bad ipl %d", ipl);
    198 
    199 	intr_func[ipl] = intr_noint;
    200 	intr_arg[ipl] = NULL;
    201 }
    202 
    203 /*
    204  * This is the dispatcher called by the low-level
    205  * assembly language interrupt routine.
    206  *
    207  * XXX Note: see the warning in intr_establish()
    208  */
    209 void
    210 intr_dispatch(struct clockframe frame)
    211 {
    212 	const int ipl = VECO_TO_VECI(frame.cf_vo) - VECI_INTRAV0;
    213 
    214 	intr_depth++;
    215 
    216 	intrcnt[ipl]++;
    217 	curcpu()->ci_data.cpu_nintr++;
    218 
    219 	(void)(*intr_func[ipl])(intr_arg[ipl] ? intr_arg[ipl] : &frame);
    220 	intr_depth--;
    221 }
    222 
    223 /*
    224  * Default interrupt handler:  do nothing.
    225  */
    226 static int
    227 intr_noint(void *arg)
    228 {
    229 #ifdef DEBUG
    230 	intr_depth++;
    231 	if (intr_debug) {
    232 		const struct clockframe *frame = arg;
    233 		const int ipl = VECO_TO_VECI(frame->cf_vo) - VECI_INTRAV0;
    234 		printf("intr_noint: ipl %d\n", ipl);
    235 	}
    236 	intr_depth--;
    237 #endif
    238 	return 0;
    239 }
    240 
    241 bool
    242 cpu_intr_p(void)
    243 {
    244 
    245 	return intr_depth != 0;
    246 }
    247