1 /* $OpenBSD: isr.c,v 1.12 2020/11/24 13:52:40 mpi Exp $ */ 2 /* $NetBSD: isr.c,v 1.5 2000/07/09 08:08:20 nisimura Exp $ */ 3 4 /*- 5 * Copyright (c) 1996 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Link and dispatch interrupts. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/vmmeter.h> 41 #include <sys/evcount.h> 42 43 #include <uvm/uvm_extern.h> 44 45 #include <machine/cpu.h> 46 47 #include <luna88k/luna88k/isr.h> 48 49 isr_autovec_list_t isr_autovec[NISRAUTOVEC]; 50 51 void 52 isrinit() 53 { 54 int i; 55 56 /* Initialize the autovector lists. */ 57 for (i = 0; i < NISRAUTOVEC; ++i) { 58 LIST_INIT(&isr_autovec[i]); 59 } 60 } 61 62 /* 63 * Establish an autovectored interrupt handler. 64 * Called by driver attach functions. 65 */ 66 void 67 isrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority, 68 const char *name) 69 { 70 struct isr_autovec *newisr, *curisr; 71 isr_autovec_list_t *list; 72 73 #ifdef DIAGNOSTIC 74 if (ipl < 0 || ipl >= NISRAUTOVEC) 75 panic("isrlink_autovec: bad ipl %d", ipl); 76 #endif 77 78 newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec), 79 M_DEVBUF, M_NOWAIT); 80 if (newisr == NULL) 81 panic("isrlink_autovec: can't allocate space for isr"); 82 83 /* Fill in the new entry. */ 84 newisr->isr_func = func; 85 newisr->isr_arg = arg; 86 newisr->isr_ipl = ipl; 87 newisr->isr_priority = priority; 88 evcount_attach(&newisr->isr_count, name, &newisr->isr_ipl); 89 90 /* 91 * Some devices are particularly sensitive to interrupt 92 * handling latency. The SCC, for example, can lose many 93 * characters if its interrupt isn't handled with reasonable 94 * speed. 95 * 96 * To work around this problem, each device can give itself a 97 * "priority". An unbuffered SCC would give itself a higher 98 * priority than a SCSI device, for example. 99 * 100 * This solution was originally developed for the hp300, which 101 * has a flat spl scheme (by necessity). Thankfully, the 102 * MVME systems don't have this problem, though this may serve 103 * a useful purpose in any case. 104 */ 105 106 /* 107 * Get the appropriate ISR list. If the list is empty, no 108 * additional work is necessary; we simply insert ourselves 109 * at the head of the list. 110 */ 111 list = &isr_autovec[ipl]; 112 if (LIST_EMPTY(list)) { 113 LIST_INSERT_HEAD(list, newisr, isr_link); 114 return; 115 } 116 117 /* 118 * A little extra work is required. We traverse the list 119 * and place ourselves after any ISRs with our current (or 120 * higher) priority. 121 */ 122 for (curisr = LIST_FIRST(list); LIST_NEXT(curisr, isr_link) != NULL; 123 curisr = LIST_NEXT(curisr, isr_link)) { 124 if (newisr->isr_priority > curisr->isr_priority) { 125 LIST_INSERT_BEFORE(curisr, newisr, isr_link); 126 return; 127 } 128 } 129 130 /* 131 * We're the least important entry, it seems. We just go 132 * on the end. 133 */ 134 LIST_INSERT_AFTER(curisr, newisr, isr_link); 135 } 136 137 /* 138 * This is the dispatcher called by the low-level 139 * assembly language autovectored interrupt routine. 140 */ 141 void 142 isrdispatch_autovec(int ipl) 143 { 144 struct isr_autovec *isr; 145 isr_autovec_list_t *list; 146 int rc, handled = 0; 147 static int straycount, unexpected; 148 149 #ifdef DIAGNOSTIC 150 if (ipl < 0 || ipl >= NISRAUTOVEC) 151 panic("isrdispatch_autovec: bad ipl %d", ipl); 152 #endif 153 154 list = &isr_autovec[ipl]; 155 if (LIST_EMPTY(list)) { 156 printf("isrdispatch_autovec: ipl %d unexpected\n", ipl); 157 if (++unexpected > 10) 158 panic("too many unexpected interrupts"); 159 return; 160 } 161 162 /* Give all the handlers a chance. */ 163 LIST_FOREACH(isr, list, isr_link) { 164 #ifdef MULTIPROCESSOR 165 if (isr->isr_ipl < IPL_CLOCK) 166 __mp_lock(&kernel_lock); 167 #endif 168 rc = (*isr->isr_func)(isr->isr_arg); 169 #ifdef MULTIPROCESSOR 170 if (isr->isr_ipl < IPL_CLOCK) 171 __mp_unlock(&kernel_lock); 172 #endif 173 if (rc != 0) 174 isr->isr_count.ec_count++; 175 handled |= rc; 176 } 177 178 if (handled) 179 straycount = 0; 180 else if (++straycount > 50) 181 panic("isr_dispatch_autovec: too many stray interrupts"); 182 else 183 printf("isrdispatch_autovec: stray level %d interrupt\n", ipl); 184 } 185