intr_machdep.c (171785) | intr_machdep.c (171805) |
---|---|
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 --- 43 unchanged lines hidden (view full) --- 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 * | 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 --- 43 unchanged lines hidden (view full) --- 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: head/sys/powerpc/powerpc/intr_machdep.c 171785 2007-08-07 23:33:35Z marcel $ | 60 * $FreeBSD: head/sys/powerpc/powerpc/intr_machdep.c 171805 2007-08-11 19:25:32Z marcel $ |
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> | 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> |
|
74#include <sys/vmmeter.h> 75#include <sys/proc.h> 76 77#include <machine/frame.h> 78#include <machine/intr_machdep.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> |
|
79#include <machine/trap.h> 80 | 81#include <machine/trap.h> 82 |
83#include "pic_if.h" 84 |
|
81#define MAX_STRAY_LOG 5 82 83MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data"); 84 | 85#define MAX_STRAY_LOG 5 86 87MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data"); 88 |
85struct ppc_intr { | 89struct powerpc_intr { |
86 struct intr_event *event; 87 long *cntp; | 90 struct intr_event *event; 91 long *cntp; |
88 int cntidx; | 92 u_int irq; |
89}; 90 | 93}; 94 |
91static struct mtx ppc_intrs_lock; 92static struct ppc_intr **ppc_intrs; 93static u_int ppc_nintrs; | 95static struct powerpc_intr *powerpc_intrs[INTR_VECTORS]; 96static u_int nvectors; /* Allocated vectors */ 97static u_int stray_count; |
94 | 98 |
95static int intrcnt_index; | 99device_t pic; |
96 | 100 |
97static void (*irq_enable)(uintptr_t); 98 | |
99static void 100intrcnt_setname(const char *name, int index) 101{ 102 snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 103 MAXCOMLEN, name); 104} 105 | 101static void 102intrcnt_setname(const char *name, int index) 103{ 104 snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s", 105 MAXCOMLEN, name); 106} 107 |
106void 107intr_init(void (*handler)(void), int nirq, void (*irq_e)(uintptr_t), 108 void (*irq_d)(uintptr_t)) | 108#ifdef INTR_FILTER 109static void 110powerpc_intr_eoi(void *arg) |
109{ | 111{ |
110 uint32_t msr; | 112 u_int irq = (uintptr_t)arg; |
111 | 113 |
112 if (ppc_intrs != NULL) 113 panic("intr_init: interrupts initialized twice\n"); | 114 PIC_EOI(pic, irq); 115} |
114 | 116 |
115 ppc_nintrs = nirq; 116 ppc_intrs = malloc(nirq * sizeof(struct ppc_intr *), M_INTR, 117 M_NOWAIT|M_ZERO); 118 if (ppc_intrs == NULL) 119 panic("intr_init: unable to allocate interrupt handler array"); | 117static void 118powerpc_intr_mask(void *arg) 119{ 120 u_int irq = (uintptr_t)arg; |
120 | 121 |
121 mtx_init(&ppc_intrs_lock, "intr table", NULL, MTX_SPIN); | 122 PIC_MASK(pic, irq); 123} 124#endif |
122 | 125 |
123 irq_enable = irq_e; | 126static void 127powerpc_intr_unmask(void *arg) 128{ 129 u_int irq = (uintptr_t)arg; |
124 | 130 |
125 intrcnt_setname("???", 0); 126 intrcnt_index = 1; | 131 PIC_UNMASK(pic, irq); 132} |
127 | 133 |
128 msr = mfmsr(); 129 mtmsr(msr & ~PSL_EE); 130 ext_intr_install(handler); 131 mtmsr(msr); | 134void 135powerpc_register_pic(device_t dev) 136{ 137 138 pic = dev; |
132} 133 134int | 139} 140 141int |
135inthand_add(const char *name, u_int irq, driver_filter_t *filter, 136 void (*handler)(void *), void *arg, int flags, void **cookiep) | 142powerpc_enable_intr(void) |
137{ | 143{ |
138 struct ppc_intr *i, *orphan; 139 u_int idx; | 144 struct powerpc_intr *i; 145 int vector; 146 147 for (vector = 0; vector < nvectors; vector++) { 148 i = powerpc_intrs[vector]; 149 if (i == NULL) 150 continue; 151 152 PIC_ENABLE(pic, i->irq, vector); 153 } 154 155 return (0); 156} 157 158int 159powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, 160 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep) 161{ 162 struct powerpc_intr *i; 163 u_int vector; |
140 int error; 141 | 164 int error; 165 |
142 /* 143 * Work around a race where more than one CPU may be registering 144 * handlers on the same IRQ at the same time. 145 */ 146 mtx_lock_spin(&ppc_intrs_lock); 147 i = ppc_intrs[irq]; 148 mtx_unlock_spin(&ppc_intrs_lock); | 166 /* XXX lock */ |
149 | 167 |
168 i = NULL; 169 for (vector = 0; vector < nvectors; vector++) { 170 i = powerpc_intrs[vector]; 171 if (i == NULL) 172 continue; 173 if (i->irq == irq) 174 break; 175 i = NULL; 176 } 177 |
|
150 if (i == NULL) { | 178 if (i == NULL) { |
179 if (nvectors >= INTR_VECTORS) { 180 /* XXX unlock */ 181 return (ENOENT); 182 } 183 |
|
151 i = malloc(sizeof(*i), M_INTR, M_NOWAIT); | 184 i = malloc(sizeof(*i), M_INTR, M_NOWAIT); |
152 if (i == NULL) | 185 if (i == NULL) { 186 /* XXX unlock */ |
153 return (ENOMEM); | 187 return (ENOMEM); |
188 } |
|
154 error = intr_event_create(&i->event, (void *)irq, 0, | 189 error = intr_event_create(&i->event, (void *)irq, 0, |
155 (void (*)(void *))irq_enable, "irq%d:", irq); | 190 powerpc_intr_unmask, 191#ifdef INTR_FILTER 192 powerpc_intr_eoi, powerpc_intr_mask, 193#endif 194 "irq%u:", irq); |
156 if (error) { | 195 if (error) { |
196 /* XXX unlock */ |
|
157 free(i, M_INTR); 158 return (error); 159 } 160 | 197 free(i, M_INTR); 198 return (error); 199 } 200 |
161 mtx_lock_spin(&ppc_intrs_lock); 162 if (ppc_intrs[irq] != NULL) { 163 orphan = i; 164 i = ppc_intrs[irq]; 165 mtx_unlock_spin(&ppc_intrs_lock); | 201 vector = nvectors++; 202 powerpc_intrs[vector] = i; |
166 | 203 |
167 intr_event_destroy(orphan->event); 168 free(orphan, M_INTR); 169 } else { 170 ppc_intrs[irq] = i; 171 idx = intrcnt_index++; 172 mtx_unlock_spin(&ppc_intrs_lock); | 204 i->irq = irq; |
173 | 205 |
174 i->cntidx = idx; 175 i->cntp = &intrcnt[idx]; 176 intrcnt_setname(i->event->ie_fullname, idx); 177 } | 206 /* XXX unlock */ 207 208 i->cntp = &intrcnt[vector]; 209 intrcnt_setname(i->event->ie_fullname, vector); 210 211 if (!cold) 212 PIC_ENABLE(pic, i->irq, vector); 213 } else { 214 /* XXX unlock */ |
178 } 179 180 error = intr_event_add_handler(i->event, name, filter, handler, arg, 181 intr_priority(flags), flags, cookiep); 182 if (!error) | 215 } 216 217 error = intr_event_add_handler(i->event, name, filter, handler, arg, 218 intr_priority(flags), flags, cookiep); 219 if (!error) |
183 intrcnt_setname(i->event->ie_fullname, i->cntidx); | 220 intrcnt_setname(i->event->ie_fullname, vector); |
184 return (error); 185} 186 187int | 221 return (error); 222} 223 224int |
188inthand_remove(u_int irq, void *cookie) | 225powerpc_teardown_intr(void *cookie) |
189{ 190 191 return (intr_event_remove_handler(cookie)); 192} 193 194void | 226{ 227 228 return (intr_event_remove_handler(cookie)); 229} 230 231void |
195intr_handle(u_int irq) | 232powerpc_dispatch_intr(u_int vector, struct trapframe *tf) |
196{ | 233{ |
197 struct ppc_intr *i; | 234 struct powerpc_intr *i; |
198 struct intr_event *ie; | 235 struct intr_event *ie; |
236#ifndef INTR_FILTER |
|
199 struct intr_handler *ih; 200 int error, sched, ret; | 237 struct intr_handler *ih; 238 int error, sched, ret; |
239#endif |
|
201 | 240 |
202 i = ppc_intrs[irq]; | 241 i = powerpc_intrs[vector]; |
203 if (i == NULL) 204 goto stray; 205 | 242 if (i == NULL) 243 goto stray; 244 |
206 atomic_add_long(i->cntp, 1); | 245 (*i->cntp)++; |
207 208 ie = i->event; 209 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__)); 210 | 246 247 ie = i->event; 248 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__)); 249 |
250#ifdef INTR_FILTER 251 if (intr_event_handle(ie, tf) != 0) { 252 PIC_MASK(pic, i->irq); 253 log(LOG_ERR, "stray irq%u\n", i->irq); 254 } 255#else |
|
211 if (TAILQ_EMPTY(&ie->ie_handlers)) 212 goto stray; 213 214 /* 215 * Execute all fast interrupt handlers directly without Giant. Note 216 * that this means that any fast interrupt handler must be MP safe. 217 */ 218 ret = 0; --- 14 unchanged lines hidden (view full) --- 233 if (!sched) { 234 if (ret == FILTER_SCHEDULE_THREAD) 235 sched = 1; 236 } 237 } 238 critical_exit(); 239 240 if (sched) { | 256 if (TAILQ_EMPTY(&ie->ie_handlers)) 257 goto stray; 258 259 /* 260 * Execute all fast interrupt handlers directly without Giant. Note 261 * that this means that any fast interrupt handler must be MP safe. 262 */ 263 ret = 0; --- 14 unchanged lines hidden (view full) --- 278 if (!sched) { 279 if (ret == FILTER_SCHEDULE_THREAD) 280 sched = 1; 281 } 282 } 283 critical_exit(); 284 285 if (sched) { |
286 PIC_MASK(pic, i->irq); |
|
241 error = intr_event_schedule_thread(ie); 242 KASSERT(error == 0, ("%s: impossible stray interrupt", 243 __func__)); 244 } else | 287 error = intr_event_schedule_thread(ie); 288 KASSERT(error == 0, ("%s: impossible stray interrupt", 289 __func__)); 290 } else |
245 irq_enable(irq); | 291 PIC_EOI(pic, i->irq); 292#endif |
246 return; 247 248stray: | 293 return; 294 295stray: |
249 atomic_add_long(&intrcnt[0], 1); 250 if (intrcnt[0] <= MAX_STRAY_LOG) { 251 printf("stray irq %d\n", irq); 252 if (intrcnt[0] >= MAX_STRAY_LOG) { | 296 stray_count++; 297 if (stray_count <= MAX_STRAY_LOG) { 298 printf("stray irq %d\n", i->irq); 299 if (stray_count >= MAX_STRAY_LOG) { |
253 printf("got %d stray interrupts, not logging anymore\n", | 300 printf("got %d stray interrupts, not logging anymore\n", |
254 MAX_STRAY_LOG); | 301 MAX_STRAY_LOG); |
255 } 256 } | 302 } 303 } |
304 if (i != NULL) 305 PIC_MASK(pic, i->irq); |
|
257} | 306} |