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: releng/8.0/sys/powerpc/powerpc/intr_machdep.c 191450 2009-04-24 03:51:11Z marcel $
61 */
62
63 #include "opt_platform.h"
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/kernel.h>
68 #include <sys/queue.h>
69 #include <sys/bus.h>
70 #include <sys/interrupt.h>
71 #include <sys/ktr.h>
72 #include <sys/lock.h>
73 #include <sys/malloc.h>
74 #include <sys/mutex.h>
75 #include <sys/pcpu.h>
76 #include <sys/syslog.h>
77 #include <sys/vmmeter.h>
78 #include <sys/proc.h>
79
80 #include <machine/frame.h>
81 #include <machine/intr_machdep.h>
82 #include <machine/md_var.h>
83 #include <machine/smp.h>
84 #include <machine/trap.h>
85
86 #include "pic_if.h"
87
88 #ifdef MPC85XX
89 #define ISA_IRQ_COUNT 16
90 #endif
91
92 #ifndef ISA_IRQ_COUNT
93 #define ISA_IRQ_COUNT 0
94 #endif
95
96 #define MAX_STRAY_LOG 5
97
98 MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
99
100 struct powerpc_intr {
101 struct intr_event *event;
102 long *cntp;
103 u_int irq;
104 device_t pic;
105 u_int intline;
106 u_int vector;
107 enum intr_trigger trig;
108 enum intr_polarity pol;
109 };
110
111 static struct mtx intr_table_lock;
112 static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
113 static u_int nvectors; /* Allocated vectors */
114 static u_int stray_count;
115
116 #ifdef SMP
117 static void *ipi_cookie;
118 #endif
119
120 static u_int ipi_irq;
121
122 device_t pic;
123 device_t pic8259;
124
125 static void
126 intr_init(void *dummy __unused)
127 {
128
129 mtx_init(&intr_table_lock, "intr sources lock", NULL, MTX_DEF);
130 }
131 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
132
133 static void
134 intrcnt_setname(const char *name, int index)
135 {
136
137 snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
138 MAXCOMLEN, name);
139 }
140
141 static struct powerpc_intr *
142 intr_lookup(u_int irq)
143 {
144 char intrname[8];
145 struct powerpc_intr *i, *iscan;
146 int vector;
147
148 mtx_lock(&intr_table_lock);
149 for (vector = 0; vector < nvectors; vector++) {
150 i = powerpc_intrs[vector];
151 if (i != NULL && i->irq == irq) {
152 mtx_unlock(&intr_table_lock);
153 return (i);
154 }
155 }
156 mtx_unlock(&intr_table_lock);
157
158 i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
159 if (i == NULL)
160 return (NULL);
161
162 i->event = NULL;
163 i->cntp = NULL;
164 i->trig = INTR_TRIGGER_CONFORM;
165 i->pol = INTR_POLARITY_CONFORM;
166 i->irq = irq;
167 i->vector = -1;
168
169 mtx_lock(&intr_table_lock);
170 for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
171 vector++) {
172 iscan = powerpc_intrs[vector];
173 if (iscan != NULL && iscan->irq == irq)
174 break;
175 if (iscan == NULL && i->vector == -1)
176 i->vector = vector;
177 iscan = NULL;
178 }
179
180 if (iscan == NULL && i->vector != -1) {
181 powerpc_intrs[i->vector] = i;
182 sprintf(intrname, "irq%u:", i->irq);
183 intrcnt_setname(intrname, i->vector);
184 nvectors++;
185 }
186 mtx_unlock(&intr_table_lock);
187
188 if (iscan != NULL || i->vector == -1) {
189 free(i, M_INTR);
190 i = iscan;
191 }
192
193 return (i);
194 }
195
196 static int
197 powerpc_map_irq(struct powerpc_intr *i)
198 {
199
200 #if ISA_IRQ_COUNT > 0
201 if (i->irq < ISA_IRQ_COUNT) {
202 if (pic8259 == NULL) {
203 i->pic = pic;
204 i->intline = 0;
205 return (ENXIO);
206 }
207 i->pic = pic8259;
208 i->intline = i->irq;
209 return (0);
210 }
211 #endif
212
213 i->pic = pic;
214 i->intline = i->irq - ISA_IRQ_COUNT;
215 return (0);
216 }
217
218 static void
219 powerpc_intr_eoi(void *arg)
220 {
221 struct powerpc_intr *i = arg;
222
223 PIC_EOI(i->pic, i->intline);
224 }
225
226 static void
227 powerpc_intr_mask(void *arg)
228 {
229 struct powerpc_intr *i = arg;
230
231 PIC_MASK(i->pic, i->intline);
232 }
233
234 static void
235 powerpc_intr_unmask(void *arg)
236 {
237 struct powerpc_intr *i = arg;
238
239 PIC_UNMASK(i->pic, i->intline);
240 }
241
242 void
243 powerpc_register_pic(device_t dev, u_int ipi)
244 {
245
246 pic = dev;
247 ipi_irq = ipi + ISA_IRQ_COUNT;
248 }
249
250 void
251 powerpc_register_8259(device_t dev)
252 {
253
254 pic8259 = dev;
255 }
256
257 int
258 powerpc_enable_intr(void)
259 {
260 struct powerpc_intr *i;
261 int error, vector;
262
263 if (pic == NULL)
264 panic("no PIC detected\n");
265
266 #ifdef SMP
267 /* Install an IPI handler. */
268 error = powerpc_setup_intr("IPI", ipi_irq, powerpc_ipi_handler,
269 NULL, NULL, INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie);
270 if (error) {
271 printf("unable to setup IPI handler\n");
272 return (error);
273 }
274 #endif
275
276 for (vector = 0; vector < nvectors; vector++) {
277 i = powerpc_intrs[vector];
278 if (i == NULL)
279 continue;
280
281 error = powerpc_map_irq(i);
282 if (error)
283 continue;
284
285 if (i->trig != INTR_TRIGGER_CONFORM ||
286 i->pol != INTR_POLARITY_CONFORM)
287 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
288
289 if (i->event != NULL)
290 PIC_ENABLE(i->pic, i->intline, vector);
291 }
292
293 return (0);
294 }
295
296 int
297 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
298 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
299 {
300 struct powerpc_intr *i;
301 int error, enable = 0;
302
303 i = intr_lookup(irq);
304 if (i == NULL)
305 return (ENOMEM);
306
307 if (i->event == NULL) {
308 error = intr_event_create(&i->event, (void *)i, 0, irq,
309 powerpc_intr_mask, powerpc_intr_unmask, powerpc_intr_eoi,
310 NULL, "irq%u:", irq);
311 if (error)
312 return (error);
313
314 i->cntp = &intrcnt[i->vector];
315
316 enable = 1;
317 }
318
319 error = intr_event_add_handler(i->event, name, filter, handler, arg,
320 intr_priority(flags), flags, cookiep);
321
322 mtx_lock(&intr_table_lock);
323 intrcnt_setname(i->event->ie_fullname, i->vector);
324 mtx_unlock(&intr_table_lock);
325
326 if (!cold) {
327 error = powerpc_map_irq(i);
328 if (!error && enable)
329 PIC_ENABLE(i->pic, i->intline, i->vector);
330 }
331 return (error);
332 }
333
334 int
335 powerpc_teardown_intr(void *cookie)
336 {
337
338 return (intr_event_remove_handler(cookie));
339 }
340
341 int
342 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
343 {
344 struct powerpc_intr *i;
345
346 i = intr_lookup(irq);
347 if (i == NULL)
348 return (ENOMEM);
349
350 i->trig = trig;
351 i->pol = pol;
352
353 if (!cold)
354 PIC_CONFIG(i->pic, i->intline, trig, pol);
355
356 return (0);
357 }
358
359 void
360 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
361 {
362 struct powerpc_intr *i;
363 struct intr_event *ie;
364
365 i = powerpc_intrs[vector];
366 if (i == NULL)
367 goto stray;
368
369 (*i->cntp)++;
370
371 ie = i->event;
372 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
373
374 if (intr_event_handle(ie, tf) != 0) {
375 goto stray;
376 }
377 return;
378
379 stray:
380 stray_count++;
381 if (stray_count <= MAX_STRAY_LOG) {
382 printf("stray irq %d\n", i ? i->irq : -1);
383 if (stray_count >= MAX_STRAY_LOG) {
384 printf("got %d stray interrupts, not logging anymore\n",
385 MAX_STRAY_LOG);
386 }
387 }
388 if (i != NULL)
389 PIC_MASK(i->pic, i->intline);
390 }
Cache object: 7ba875bd7fd9b7b975dad86f46733386
|