1 /* $NetBSD: sa11x0_irqhandler.c,v 1.2 2002/04/12 18:50:32 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to the NetBSD Foundation 8 * by IWAMOTO Toshihiro. 9 * 10 * This code is derived from software contributed to The NetBSD Foundation 11 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 12 * Simulation Facility, NASA Ames Research Center. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the NetBSD 25 * Foundation, Inc. and its contributors. 26 * 4. Neither the name of The NetBSD Foundation nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 */ 42 43 /*- 44 * Copyright (c) 1991 The Regents of the University of California. 45 * All rights reserved. 46 * 47 * This code is derived from software contributed to Berkeley by 48 * William Jolitz. 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 1. Redistributions of source code must retain the above copyright 54 * notice, this list of conditions and the following disclaimer. 55 * 2. Redistributions in binary form must reproduce the above copyright 56 * notice, this list of conditions and the following disclaimer in the 57 * documentation and/or other materials provided with the distribution. 58 * 3. All advertising materials mentioning features or use of this software 59 * must display the following acknowledgement: 60 * This product includes software developed by the University of 61 * California, Berkeley and its contributors. 62 * 4. Neither the name of the University nor the names of its contributors 63 * may be used to endorse or promote products derived from this software 64 * without specific prior written permission. 65 * 66 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 67 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 68 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 69 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 70 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 71 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 72 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 73 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 74 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 75 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 76 * SUCH DAMAGE. 77 * 78 * @(#)isa.c 7.2 (Berkeley) 5/13/91 79 */ 80 81 82 #include "opt_irqstats.h" 83 84 #include <sys/param.h> 85 #include <sys/kernel.h> 86 #include <sys/systm.h> 87 #include <sys/syslog.h> 88 #include <sys/malloc.h> 89 #include <uvm/uvm_extern.h> 90 91 #include <arm/sa11x0/sa11x0_reg.h> 92 #include <arm/sa11x0/sa11x0_var.h> 93 94 #include <machine/intr.h> 95 #include <machine/cpu.h> 96 97 irqhandler_t *irqhandlers[NIRQS]; 98 99 int current_intr_depth; 100 u_int actual_mask; 101 #ifdef hpcarm 102 #define IPL_LEVELS (NIPL+1) 103 u_int imask[NIPL]; 104 #else 105 u_int spl_mask; 106 u_int irqmasks[IPL_LEVELS]; 107 #endif 108 u_int irqblock[NIRQS]; 109 110 111 extern void set_spl_masks(); 112 static int fakeintr(void *); 113 #ifdef DEBUG 114 static int dumpirqhandlers(); 115 #endif 116 /* 117 * Recalculate the interrupt masks from scratch. 118 * We could code special registry and deregistry versions of this function that 119 * would be faster, but the code would be nastier, and we don't expect this to 120 * happen very much anyway. 121 */ 122 void 123 intr_calculatemasks() 124 { 125 int irq, level; 126 struct irqhandler *q; 127 int intrlevel[ICU_LEN]; 128 129 /* First, figure out which levels each IRQ uses. */ 130 for (irq = 0; irq < ICU_LEN; irq++) { 131 int levels = 0; 132 for (q = irqhandlers[irq]; q; q = q->ih_next) 133 levels |= 1 << q->ih_level; 134 intrlevel[irq] = levels; 135 } 136 137 /* Then figure out which IRQs use each level. */ 138 #ifdef hpcarm 139 for (level = 0; level < NIPL; level++) { 140 #else 141 for (level = 0; level <= IPL_LEVELS; level++) { 142 #endif 143 int irqs = 0; 144 for (irq = 0; irq < ICU_LEN; irq++) 145 if (intrlevel[irq] & (1 << level)) 146 irqs |= 1 << irq; 147 #ifdef hpcarm 148 imask[level] = irqs; 149 #else 150 irqmasks[level] = irqs; 151 #endif 152 } 153 154 /* 155 * Enforce a hierarchy that gives slow devices a better chance at not 156 * dropping data. 157 */ 158 #ifdef hpcarm 159 for (level = NIPL - 1; level > 0; level--) 160 imask[level - 1] |= imask[level]; 161 #else 162 for (level = IPL_LEVELS; level > 0; level--) 163 irqmasks[level - 1] |= irqmasks[level]; 164 #endif 165 /* 166 * Calculate irqblock[], which emulates hardware interrupt levels. 167 */ 168 for (irq = 0; irq < ICU_LEN; irq++) { 169 int irqs = 1 << irq; 170 for (q = irqhandlers[irq]; q; q = q->ih_next) 171 #ifdef hpcarm 172 irqs |= ~imask[q->ih_level]; 173 #else 174 irqs |= ~irqmasks[q->ih_level]; 175 #endif 176 irqblock[irq] = irqs; 177 } 178 } 179 180 181 const struct evcnt * 182 sa11x0_intr_evcnt(sa11x0_chipset_tag_t ic, int irq) 183 { 184 185 /* XXX for now, no evcnt parent reported */ 186 return NULL; 187 } 188 189 void * 190 sa11x0_intr_establish(sa11x0_chipset_tag_t ic, int irq, int type, int level, 191 int (*ih_fun)(void *), void *ih_arg) 192 { 193 int saved_cpsr; 194 struct irqhandler **p, *q, *ih; 195 static struct irqhandler fakehand = {fakeintr}; 196 197 /* no point in sleeping unless someone can free memory. */ 198 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 199 if (ih == NULL) 200 panic("sa11x0_intr_establish: can't malloc handler info"); 201 202 if (irq < 0 || irq >= ICU_LEN || type == IST_NONE) 203 panic("intr_establish: bogus irq or type"); 204 205 /* All interrupts are level intrs. */ 206 207 /* 208 * Figure out where to put the handler. 209 * This is O(N^2), but we want to preserve the order, and N is 210 * generally small. 211 */ 212 for (p = &irqhandlers[irq]; (q = *p) != NULL; p = &q->ih_next) 213 ; 214 215 /* 216 * Actually install a fake handler momentarily, since we might be doing 217 * this with interrupts enabled and don't want the real routine called 218 * until masking is set up. 219 */ 220 fakehand.ih_level = level; 221 *p = &fakehand; 222 223 intr_calculatemasks(); 224 225 /* 226 * Poke the real handler in now. 227 */ 228 ih->ih_func = ih_fun; 229 ih->ih_arg = ih_arg; 230 #ifdef hpcarm 231 ih->ih_count = 0; 232 #else 233 ih->ih_num = 0; 234 #endif 235 ih->ih_next = NULL; 236 ih->ih_level = level; 237 #ifdef hpcarm 238 ih->ih_irq = irq; 239 #endif 240 ih->ih_name = NULL; /* XXX */ 241 *p = ih; 242 243 saved_cpsr = SetCPSR(I32_bit, I32_bit); 244 set_spl_masks(); 245 246 irq_setmasks(); 247 248 SetCPSR(I32_bit, saved_cpsr & I32_bit); 249 #ifdef DEBUG 250 dumpirqhandlers(); 251 #endif 252 return (ih); 253 } 254 255 #ifdef hpcarm 256 /* 257 * Deregister an interrupt handler. 258 */ 259 void 260 sa11x0_intr_disestablish(sa11x0_chipset_tag_t ic, void *arg) 261 { 262 struct irqhandler *ih = arg; 263 int irq = ih->ih_irq; 264 int saved_cpsr; 265 struct irqhandler **p, *q; 266 267 #if DIAGNOSTIC 268 if (irq < 0 || irq >= ICU_LEN) 269 panic("intr_disestablish: bogus irq"); 270 #endif 271 272 /* 273 * Remove the handler from the chain. 274 * This is O(n^2), too. 275 */ 276 for (p = &irqhandlers[irq]; (q = *p) != NULL && q != ih; 277 p = &q->ih_next) 278 ; 279 if (q) 280 *p = q->ih_next; 281 else 282 panic("intr_disestablish: handler not registered"); 283 free(ih, M_DEVBUF); 284 285 intr_calculatemasks(); 286 saved_cpsr = SetCPSR(I32_bit, I32_bit); 287 set_spl_masks(); 288 289 irq_setmasks(); 290 SetCPSR(I32_bit, saved_cpsr & I32_bit); 291 292 } 293 #endif 294 295 void 296 stray_irqhandler(void *p) 297 { 298 299 printf("stray interrupt\n"); 300 } 301 302 int 303 fakeintr(void *p) 304 { 305 306 return 0; 307 } 308 309 #ifdef DEBUG 310 int 311 dumpirqhandlers() 312 { 313 int irq; 314 struct irqhandler *p; 315 316 for (irq = 0; irq < ICU_LEN; irq++) { 317 printf("irq %d:", irq); 318 p = irqhandlers[irq]; 319 for (; p; p = p->ih_next) 320 printf("ih_func: 0x%lx, ", (unsigned long)p->ih_func); 321 printf("\n"); 322 } 323 return 0; 324 } 325 #endif 326 /* End of irqhandler.c */ 327