1292915Sdim/* $OpenBSD: isr.c,v 1.12 2020/11/24 13:52:40 mpi Exp $ */ 2292915Sdim/* $NetBSD: isr.c,v 1.5 2000/07/09 08:08:20 nisimura Exp $ */ 3292915Sdim 4292915Sdim/*- 5292915Sdim * Copyright (c) 1996 The NetBSD Foundation, Inc. 6292915Sdim * All rights reserved. 7292915Sdim * 8292915Sdim * This code is derived from software contributed to The NetBSD Foundation 9292915Sdim * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe. 10292915Sdim * 11292915Sdim * Redistribution and use in source and binary forms, with or without 12292915Sdim * modification, are permitted provided that the following conditions 13292915Sdim * are met: 14292915Sdim * 1. Redistributions of source code must retain the above copyright 15292915Sdim * notice, this list of conditions and the following disclaimer. 16292915Sdim * 2. Redistributions in binary form must reproduce the above copyright 17292915Sdim * notice, this list of conditions and the following disclaimer in the 18309124Sdim * documentation and/or other materials provided with the distribution. 19292915Sdim * 20309124Sdim * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21292915Sdim * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22292915Sdim * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23309124Sdim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24292915Sdim * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25292915Sdim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26292915Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27292915Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28292915Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29292915Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30292915Sdim * POSSIBILITY OF SUCH DAMAGE. 31292915Sdim */ 32292915Sdim 33292915Sdim/* 34292915Sdim * Link and dispatch interrupts. 35292915Sdim */ 36292915Sdim 37292915Sdim#include <sys/param.h> 38292915Sdim#include <sys/systm.h> 39292915Sdim#include <sys/malloc.h> 40292915Sdim#include <sys/vmmeter.h> 41292915Sdim#include <sys/evcount.h> 42292915Sdim 43292915Sdim#include <uvm/uvm_extern.h> 44309124Sdim 45309124Sdim#include <machine/cpu.h> 46309124Sdim 47292915Sdim#include <luna88k/luna88k/isr.h> 48292915Sdim 49292915Sdimisr_autovec_list_t isr_autovec[NISRAUTOVEC]; 50292915Sdim 51292915Sdimvoid 52292915Sdimisrinit() 53292915Sdim{ 54292915Sdim int i; 55292915Sdim 56292915Sdim /* Initialize the autovector lists. */ 57292915Sdim for (i = 0; i < NISRAUTOVEC; ++i) { 58292915Sdim LIST_INIT(&isr_autovec[i]); 59292915Sdim } 60292915Sdim} 61292915Sdim 62292915Sdim/* 63292915Sdim * Establish an autovectored interrupt handler. 64292915Sdim * Called by driver attach functions. 65292915Sdim */ 66309124Sdimvoid 67309124Sdimisrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority, 68309124Sdim const char *name) 69309124Sdim{ 70309124Sdim struct isr_autovec *newisr, *curisr; 71309124Sdim isr_autovec_list_t *list; 72309124Sdim 73309124Sdim#ifdef DIAGNOSTIC 74309124Sdim if (ipl < 0 || ipl >= NISRAUTOVEC) 75309124Sdim panic("isrlink_autovec: bad ipl %d", ipl); 76292915Sdim#endif 77292915Sdim 78292915Sdim newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec), 79292915Sdim M_DEVBUF, M_NOWAIT); 80292915Sdim if (newisr == NULL) 81309124Sdim panic("isrlink_autovec: can't allocate space for isr"); 82292915Sdim 83292915Sdim /* Fill in the new entry. */ 84292915Sdim newisr->isr_func = func; 85292915Sdim newisr->isr_arg = arg; 86292915Sdim 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 */ 141void 142isrdispatch_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