1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 /*- 33 * Copyright (c) 2002 Benno Rice. 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 58 * form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20 59 * 60 * $FreeBSD$ 61 */ 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/kernel.h> 66 #include <sys/queue.h> 67 #include <sys/bus.h> 68 #include <sys/interrupt.h> 69 #include <sys/ktr.h> 70 #include <sys/lock.h> 71 #include <sys/malloc.h> 72 #include <sys/mutex.h> 73 #include <sys/pcpu.h> 74 #include <sys/syslog.h> 75 #include <sys/vmmeter.h> 76 #include <sys/proc.h> 77 78 #include <machine/frame.h> 79 #include <machine/intr_machdep.h> 80 #include <machine/md_var.h> 81 #include <machine/smp.h> 82 #include <machine/trap.h> 83 84 #include "pic_if.h" 85 86 #define MAX_STRAY_LOG 5 87 88 MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data"); 89 90 struct powerpc_intr { 91 struct intr_event *event; 92 long *cntp; 93 enum intr_trigger trig; 94 enum intr_polarity pol; 95 u_int irq; 96 u_int vector; 97 }; 98 99 static struct powerpc_intr *powerpc_intrs[INTR_VECTORS]; 100 static u_int nvectors; /* Allocated vectors */ 101 static u_int stray_count; 102 103 #ifdef SMP 104 static void *ipi_cookie; 105 #endif 106 107 static u_int ipi_irq; 108 109 device_t pic; 110 111 static void 112 intrcnt_setname(const char *name, int index) 113 { 114 snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 115 MAXCOMLEN, name); 116 } 117 118 static struct powerpc_intr * 119 intr_lookup(u_int irq) 120 { 121 char intrname[8]; 122 struct powerpc_intr *i, *iscan; 123 int vector; 124 125 for (vector = 0; vector < nvectors; vector++) { 126 i = powerpc_intrs[vector]; 127 if (i != NULL && i->irq == irq) 128 return (i); 129 } 130 131 i = malloc(sizeof(*i), M_INTR, M_NOWAIT); 132 if (i == NULL) 133 return (NULL); 134 135 i->event = NULL; 136 i->cntp = NULL; 137 i->trig = INTR_TRIGGER_CONFORM; 138 i->pol = INTR_POLARITY_CONFORM; 139 i->irq = irq; 140 i->vector = -1; 141 142 /* XXX LOCK */ 143 144 for (vector = 0; vector < INTR_VECTORS && vector <= nvectors; 145 vector++) { 146 iscan = powerpc_intrs[vector]; 147 if (iscan != NULL && iscan->irq == irq) 148 break; 149 if (iscan == NULL && i->vector == -1) 150 i->vector = vector; 151 iscan = NULL; 152 } 153 154 if (iscan == NULL && i->vector != -1) { 155 powerpc_intrs[i->vector] = i; 156 sprintf(intrname, "irq%u:", i->irq); 157 intrcnt_setname(intrname, i->vector); 158 nvectors++; 159 } 160 161 /* XXX UNLOCK */ 162 163 if (iscan != NULL || i->vector == -1) { 164 free(i, M_INTR); 165 i = iscan; 166 } 167 168 return (i); 169 } 170 171 static void 172 powerpc_intr_eoi(void *arg) 173 { 174 u_int irq = (uintptr_t)arg; 175 176 PIC_EOI(pic, irq); 177 } 178 179 static void 180 powerpc_intr_mask(void *arg) 181 { 182 u_int irq = (uintptr_t)arg; 183 184 PIC_MASK(pic, irq); 185 } 186 187 static void 188 powerpc_intr_unmask(void *arg) 189 { 190 u_int irq = (uintptr_t)arg; 191 192 PIC_UNMASK(pic, irq); 193 } 194 195 void 196 powerpc_register_pic(device_t dev, u_int ipi) 197 { 198 199 pic = dev; 200 ipi_irq = ipi; 201 } 202 203 int 204 powerpc_enable_intr(void) 205 { 206 struct powerpc_intr *i; 207 #ifdef SMP 208 int error; 209 #endif 210 int vector; 211 212 if (pic == NULL) 213 panic("no PIC detected\n"); 214 215 #ifdef SMP 216 /* Install an IPI handler. */ 217 error = powerpc_setup_intr("IPI", ipi_irq, powerpc_ipi_handler, 218 NULL, NULL, INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie); 219 if (error) { 220 printf("unable to setup IPI handler\n"); 221 return (error); 222 } 223 #endif 224 225 for (vector = 0; vector < nvectors; vector++) { 226 i = powerpc_intrs[vector]; 227 if (i == NULL) 228 continue; 229 230 if (i->trig != INTR_TRIGGER_CONFORM || 231 i->pol != INTR_POLARITY_CONFORM) 232 PIC_CONFIG(pic, i->irq, i->trig, i->pol); 233 234 if (i->event != NULL) 235 PIC_ENABLE(pic, i->irq, vector); 236 } 237 238 return (0); 239 } 240 241 int 242 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, 243 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) 244 { 245 struct powerpc_intr *i; 246 int error, enable = 0; 247 248 i = intr_lookup(irq); 249 if (i == NULL) 250 return (ENOMEM); 251 252 if (i->event == NULL) { 253 error = intr_event_create(&i->event, (void *)irq, 0, irq, 254 powerpc_intr_mask, powerpc_intr_unmask, powerpc_intr_eoi, 255 NULL, "irq%u:", irq); 256 if (error) 257 return (error); 258 259 i->cntp = &intrcnt[i->vector]; 260 261 enable = 1; 262 } 263 264 error = intr_event_add_handler(i->event, name, filter, handler, arg, 265 intr_priority(flags), flags, cookiep); 266 intrcnt_setname(i->event->ie_fullname, i->vector); 267 268 if (!cold && enable) 269 PIC_ENABLE(pic, i->irq, i->vector); 270 271 return (error); 272 } 273 274 int 275 powerpc_teardown_intr(void *cookie) 276 { 277 278 return (intr_event_remove_handler(cookie)); 279 } 280 281 int 282 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol) 283 { 284 struct powerpc_intr *i; 285 286 if (trig == INTR_TRIGGER_CONFORM && pol == INTR_POLARITY_CONFORM) 287 return (0); 288 289 i = intr_lookup(irq); 290 if (i == NULL) 291 return (ENOMEM); 292 293 i->trig = trig; 294 i->pol = pol; 295 296 if (!cold) 297 PIC_CONFIG(pic, irq, trig, pol); 298 299 return (0); 300 } 301 302 void 303 powerpc_dispatch_intr(u_int vector, struct trapframe *tf) 304 { 305 struct powerpc_intr *i; 306 struct intr_event *ie; 307 308 i = powerpc_intrs[vector]; 309 if (i == NULL) 310 goto stray; 311 312 (*i->cntp)++; 313 314 ie = i->event; 315 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__)); 316 317 if (intr_event_handle(ie, tf) != 0) { 318 goto stray; 319 } 320 return; 321 322 stray: 323 stray_count++; 324 if (stray_count <= MAX_STRAY_LOG) { 325 printf("stray irq %d\n", i ? i->irq : -1); 326 if (stray_count >= MAX_STRAY_LOG) { 327 printf("got %d stray interrupts, not logging anymore\n", 328 MAX_STRAY_LOG); 329 } 330 } 331 if (i != NULL) 332 PIC_MASK(pic, i->irq); 333 } 334