Home | History | Annotate | Line # | Download | only in mac68k
      1 /*	$NetBSD: intr.c,v 1.36 2024/02/28 13:05:40 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.36 2024/02/28 13:05:40 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 volatile int ssir;
     88 
     89 extern	u_int intrcnt[];	/* from locore.s */
     90 
     91 void	intr_computeipl(void);
     92 
     93 #define MAX_INAME_LENGTH 53
     94 #define STD_INAMES \
     95 	"spur\0via1\0via2\0unused1\0scc\0unused2\0unused3\0nmi\0clock\0"
     96 #define AUX_INAMES \
     97 	"spur\0soft\0via2\0ethernet\0scc\0sound\0via1\0nmi\0clock\0    "
     98 #define AV_INAMES \
     99 	"spur\0via1\0via2\0ethernet\0scc\0dsp\0unused1\0nmi\0clock\0   "
    100 
    101 void
    102 intr_init(void)
    103 {
    104 	extern char	intrnames[MAX_INAME_LENGTH];
    105 	extern char	eintrnames[] __diagused;
    106 	const char	*inames;
    107 
    108 	ipl2psl_table[IPL_NONE]       = 0;
    109 	ipl2psl_table[IPL_SOFTCLOCK]  = PSL_S|PSL_IPL1;
    110 	ipl2psl_table[IPL_SOFTNET]    = PSL_S|PSL_IPL1;
    111 	ipl2psl_table[IPL_SOFTSERIAL] = PSL_S|PSL_IPL1;
    112 	ipl2psl_table[IPL_SOFTBIO]    = PSL_S|PSL_IPL1;
    113 	ipl2psl_table[IPL_HIGH]       = PSL_S|PSL_IPL7;
    114 
    115 	if (mac68k_machine.aux_interrupts) {
    116 		inames = AUX_INAMES;
    117 
    118 		/* Standard spl(9) interrupt priorities */
    119 		ipl2psl_table[IPL_VM]        = (PSL_S | PSL_IPL6);
    120 		ipl2psl_table[IPL_SCHED]     = (PSL_S | PSL_IPL6);
    121 	} else {
    122 		inames = STD_INAMES;
    123 
    124 		/* Standard spl(9) interrupt priorities */
    125 		ipl2psl_table[IPL_VM]        = (PSL_S | PSL_IPL2);
    126 		ipl2psl_table[IPL_SCHED]     = (PSL_S | PSL_IPL3);
    127 
    128 		if (current_mac_model->class == MACH_CLASSAV) {
    129 			inames = AV_INAMES;
    130 			ipl2psl_table[IPL_VM]    = (PSL_S | PSL_IPL4);
    131 			ipl2psl_table[IPL_SCHED] = (PSL_S | PSL_IPL4);
    132 		}
    133 	}
    134 
    135 	KASSERT(MAX_INAME_LENGTH <=
    136 		((uintptr_t)eintrnames - (uintptr_t)intrnames));
    137 	memcpy(intrnames, inames, MAX_INAME_LENGTH);
    138 
    139 	intr_computeipl();
    140 
    141 	/* Initialize the VIAs */
    142 	via_init();
    143 
    144 	/* Initialize the PSC (if present) */
    145 	psc_init();
    146 }
    147 
    148 
    149 /*
    150  * Compute the interrupt levels for the spl*()
    151  * calls.  This doesn't have to be fast.
    152  */
    153 void
    154 intr_computeipl(void)
    155 {
    156 	/*
    157 	 * Enforce the following relationship, as defined in spl(9):
    158 	 * `bio <= net <= tty <= vm <= statclock <= clock <= sched <= serial'
    159 	 */
    160 	if (ipl2psl_table[IPL_VM] > ipl2psl_table[IPL_SCHED])
    161 		ipl2psl_table[IPL_SCHED] = ipl2psl_table[IPL_VM];
    162 
    163 	if (ipl2psl_table[IPL_SCHED] > ipl2psl_table[IPL_HIGH])
    164 		ipl2psl_table[IPL_HIGH] = ipl2psl_table[IPL_SCHED];
    165 }
    166 
    167 /*
    168  * Establish an autovectored interrupt handler.
    169  * Called by driver attach functions.
    170  *
    171  * XXX Warning!  DO NOT use Macintosh ROM traps from an interrupt handler
    172  * established by this routine, either directly or indirectly, without
    173  * properly saving and restoring all registers.  If not, chaos _will_
    174  * ensue!  (sar 19980806)
    175  */
    176 void
    177 intr_establish(int (*func)(void *), void *arg, int ipl)
    178 {
    179 	if ((ipl < 0) || (ipl >= NISR))
    180 		panic("intr_establish: bad ipl %d", ipl);
    181 
    182 #ifdef DIAGNOSTIC
    183 	if (intr_func[ipl] != intr_noint)
    184 		printf("intr_establish: attempt to share ipl %d\n", ipl);
    185 #endif
    186 
    187 	intr_func[ipl] = func;
    188 	intr_arg[ipl] = arg;
    189 }
    190 
    191 /*
    192  * Disestablish an interrupt handler.
    193  */
    194 void
    195 intr_disestablish(int ipl)
    196 {
    197 	if ((ipl < 0) || (ipl >= NISR))
    198 		panic("intr_disestablish: bad ipl %d", ipl);
    199 
    200 	intr_func[ipl] = intr_noint;
    201 	intr_arg[ipl] = NULL;
    202 }
    203 
    204 /*
    205  * This is the dispatcher called by the low-level
    206  * assembly language interrupt routine.
    207  *
    208  * XXX Note: see the warning in intr_establish()
    209  */
    210 void
    211 intr_dispatch(struct clockframe frame)
    212 {
    213 	const int ipl = VECO_TO_VECI(frame.cf_vo) - VECI_INTRAV0;
    214 
    215 	intr_depth++;
    216 
    217 	intrcnt[ipl]++;
    218 	curcpu()->ci_data.cpu_nintr++;
    219 
    220 	(void)(*intr_func[ipl])(intr_arg[ipl] ? intr_arg[ipl] : &frame);
    221 	intr_depth--;
    222 }
    223 
    224 /*
    225  * Default interrupt handler:  do nothing.
    226  */
    227 static int
    228 intr_noint(void *arg)
    229 {
    230 #ifdef DEBUG
    231 	intr_depth++;
    232 	if (intr_debug) {
    233 		const struct clockframe *frame = arg;
    234 		const int ipl = VECO_TO_VECI(frame->cf_vo) - VECI_INTRAV0;
    235 		printf("intr_noint: ipl %d\n", ipl);
    236 	}
    237 	intr_depth--;
    238 #endif
    239 	return 0;
    240 }
    241 
    242 bool
    243 cpu_intr_p(void)
    244 {
    245 
    246 	return intr_depth != 0;
    247 }
    248