1 /* $NetBSD: isr.c,v 1.24 2010/12/20 00:25:45 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 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 and Gordon W. Ross. 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 * This handles multiple attach of autovectored interrupts. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: isr.c,v 1.24 2010/12/20 00:25:45 matt Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 #include <sys/malloc.h> 43 #include <sys/vmmeter.h> 44 #include <sys/cpu.h> 45 #include <sys/intr.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <net/netisr.h> 50 51 #include <machine/autoconf.h> 52 #include <machine/mon.h> 53 54 #include <sun68k/sun68k/vector.h> 55 56 extern int intrcnt[]; /* statistics */ 57 58 #define NUM_LEVELS 8 59 60 struct isr { 61 struct isr *isr_next; 62 isr_func_t isr_intr; 63 void *isr_arg; 64 int isr_ipl; 65 }; 66 67 #if 0 68 #define _IPL_NSOFT (_IPL_SOFT_LEVEL_MAX - _IPL_SOFT_LEVEL_MIN + 1) 69 #endif 70 71 int idepth; 72 73 void set_vector_entry(int, void *); 74 void *get_vector_entry(int); 75 76 /* 77 * These are called from locore. The "struct clockframe" arg 78 * is really just the normal H/W interrupt frame format. 79 * (kern_clock really wants it to be named that...) 80 */ 81 void isr_autovec (struct clockframe); 82 void isr_vectored(struct clockframe); 83 84 void 85 isr_add_custom(int level, void *handler) 86 { 87 88 set_vector_entry(AUTOVEC_BASE + level, handler); 89 } 90 91 92 static struct isr *isr_autovec_list[NUM_LEVELS]; 93 94 /* 95 * This is called by the assembly routines 96 * for handling auto-vectored interrupts. 97 */ 98 void 99 isr_autovec(struct clockframe cf) 100 { 101 struct isr *isr; 102 int n, ipl, vec; 103 104 idepth++; 105 106 vec = (cf.cf_vo & 0xFFF) >> 2; 107 #ifdef DIAGNOSTIC 108 if ((vec < AUTOVEC_BASE) || (vec >= (AUTOVEC_BASE + NUM_LEVELS))) 109 panic("isr_autovec: bad vec"); 110 #endif 111 ipl = vec - AUTOVEC_BASE; 112 113 n = intrcnt[ipl]; 114 intrcnt[ipl] = n + 1; 115 curcpu()->ci_data.cpu_nintr++; 116 117 isr = isr_autovec_list[ipl]; 118 if (isr == NULL) { 119 if (n == 0) 120 printf("isr_autovec: ipl %d unexpected\n", ipl); 121 goto out; 122 } 123 124 /* Give all the handlers a chance. */ 125 n = 0; 126 while (isr) { 127 n |= (*isr->isr_intr)(isr->isr_arg); 128 isr = isr->isr_next; 129 } 130 if (n == 0) 131 printf("isr_autovec: ipl %d not claimed\n", ipl); 132 133 out: 134 idepth--; 135 136 ATOMIC_CAS_CHECK(&cf); 137 } 138 139 /* 140 * Establish an interrupt handler. 141 * Called by driver attach functions. 142 */ 143 void 144 isr_add_autovect(isr_func_t handler, void *arg, int level) 145 { 146 struct isr *new_isr; 147 148 if ((level < 0) || (level >= NUM_LEVELS)) 149 panic("isr_add: bad level=%d", level); 150 new_isr = malloc(sizeof(struct isr), M_DEVBUF, M_NOWAIT); 151 if (new_isr == NULL) 152 panic("isr_add: malloc failed"); 153 154 new_isr->isr_intr = handler; 155 new_isr->isr_arg = arg; 156 new_isr->isr_ipl = level; 157 new_isr->isr_next = isr_autovec_list[level]; 158 isr_autovec_list[level] = new_isr; 159 } 160 161 struct vector_handler { 162 isr_func_t func; 163 void *arg; 164 }; 165 static struct vector_handler isr_vector_handlers[192]; 166 167 /* 168 * This is called by the assembly glue 169 * for handling vectored interrupts. 170 */ 171 void 172 isr_vectored(struct clockframe cf) 173 { 174 struct vector_handler *vh; 175 int ipl, vec; 176 177 idepth++; 178 179 vec = (cf.cf_vo & 0xFFF) >> 2; 180 ipl = _getsr(); 181 ipl = (ipl >> 8) & 7; 182 183 intrcnt[ipl]++; 184 curcpu()->ci_data.cpu_nintr++; 185 186 #ifdef DIAGNOSTIC 187 if (vec < 64 || vec >= 256) { 188 printf("isr_vectored: vector=0x%x (invalid)\n", vec); 189 goto out; 190 } 191 #endif 192 vh = &isr_vector_handlers[vec - 64]; 193 if (vh->func == NULL) { 194 printf("isr_vectored: vector=0x%x (nul func)\n", vec); 195 set_vector_entry(vec, (void *)badtrap); 196 goto out; 197 } 198 199 /* OK, call the isr function. */ 200 if ((*vh->func)(vh->arg) == 0) 201 printf("isr_vectored: vector=0x%x (not claimed)\n", vec); 202 203 out: 204 idepth--; 205 ATOMIC_CAS_CHECK(&cf); 206 } 207 208 /* 209 * Establish an interrupt handler. 210 * Called by driver attach functions. 211 */ 212 extern void _isr_vectored(void); 213 214 void 215 isr_add_vectored(isr_func_t func, void *arg, int level, int vec) 216 { 217 struct vector_handler *vh; 218 219 if (vec < 64 || vec >= 256) { 220 printf("isr_add_vectored: vect=0x%x (invalid)\n", vec); 221 return; 222 } 223 vh = &isr_vector_handlers[vec - 64]; 224 if (vh->func) { 225 printf("isr_add_vectored: vect=0x%x (in use)\n", vec); 226 return; 227 } 228 vh->func = func; 229 vh->arg = arg; 230 set_vector_entry(vec, (void *)_isr_vectored); 231 } 232 233 /* 234 * XXX - could just kill these... 235 */ 236 void 237 set_vector_entry(int entry, void *handler) 238 { 239 240 if ((entry < 0) || (entry >= NVECTORS)) 241 panic("set_vector_entry: setting vector too high or low"); 242 vector_table[entry] = handler; 243 } 244 245 void * 246 get_vector_entry(int entry) 247 { 248 249 if ((entry < 0) || (entry >= NVECTORS)) 250 panic("get_vector_entry: setting vector too high or low"); 251 return (void *)vector_table[entry]; 252 } 253 254 const uint16_t ipl2psl_table[NIPL] = { 255 [IPL_NONE] = PSL_S | PSL_IPL0, 256 [IPL_SOFTBIO] = PSL_S | PSL_IPL1, 257 [IPL_SOFTCLOCK] = PSL_S | PSL_IPL1, 258 [IPL_SOFTNET] = PSL_S | PSL_IPL1, 259 [IPL_SOFTSERIAL] = PSL_S | PSL_IPL3, 260 [IPL_VM] = PSL_S | PSL_IPL4, 261 [IPL_SCHED] = PSL_S | PSL_IPL6, 262 [IPL_HIGH] = PSL_S | PSL_IPL7, 263 }; 264