]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/powerpc/powerpc/intr_machdep.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / powerpc / powerpc / intr_machdep.c
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 "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->pic = NULL;
168         i->vector = -1;
169
170         mtx_lock(&intr_table_lock);
171         for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
172             vector++) {
173                 iscan = powerpc_intrs[vector];
174                 if (iscan != NULL && iscan->irq == irq)
175                         break;
176                 if (iscan == NULL && i->vector == -1)
177                         i->vector = vector;
178                 iscan = NULL;
179         }
180
181         if (iscan == NULL && i->vector != -1) {
182                 powerpc_intrs[i->vector] = i;
183                 sprintf(intrname, "irq%u:", i->irq);
184                 intrcnt_setname(intrname, i->vector);
185                 nvectors++;
186         }
187         mtx_unlock(&intr_table_lock);
188
189         if (iscan != NULL || i->vector == -1) {
190                 free(i, M_INTR);
191                 i = iscan;
192         }
193
194         return (i);
195 }
196
197 static int
198 powerpc_map_irq(struct powerpc_intr *i)
199 {
200
201 #if ISA_IRQ_COUNT > 0
202         if (i->irq < ISA_IRQ_COUNT) {
203                 if (pic8259 == NULL) {
204                         i->pic = pic;
205                         i->intline = 0;
206                         return (ENXIO);
207                 }
208                 i->pic = pic8259;
209                 i->intline = i->irq;
210                 return (0);
211         }
212 #endif
213
214         i->pic = pic;
215         i->intline = i->irq - ISA_IRQ_COUNT;
216         return (0);
217 }
218
219 static void
220 powerpc_intr_eoi(void *arg)
221 {
222         struct powerpc_intr *i = arg;
223
224         PIC_EOI(i->pic, i->intline);
225 }
226
227 static void
228 powerpc_intr_mask(void *arg)
229 {
230         struct powerpc_intr *i = arg;
231
232         PIC_MASK(i->pic, i->intline);
233 }
234
235 static void
236 powerpc_intr_unmask(void *arg)
237 {
238         struct powerpc_intr *i = arg;
239
240         PIC_UNMASK(i->pic, i->intline);
241 }
242
243 void
244 powerpc_register_pic(device_t dev, u_int ipi)
245 {
246
247         pic = dev;
248         ipi_irq = ipi + ISA_IRQ_COUNT;
249 }
250
251 void
252 powerpc_register_8259(device_t dev)
253 {
254
255         pic8259 = dev;
256 }
257
258 int
259 powerpc_enable_intr(void)
260 {
261         struct powerpc_intr *i;
262         int error, vector;
263
264         if (pic == NULL)
265                 panic("no PIC detected\n");
266
267 #ifdef SMP
268         /* Install an IPI handler. */
269         error = powerpc_setup_intr("IPI", ipi_irq, powerpc_ipi_handler,
270             NULL, NULL, INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie);
271         if (error) {
272                 printf("unable to setup IPI handler\n");
273                 return (error);
274         }
275 #endif
276
277         for (vector = 0; vector < nvectors; vector++) {
278                 i = powerpc_intrs[vector];
279                 if (i == NULL)
280                         continue;
281
282                 error = powerpc_map_irq(i);
283                 if (error)
284                         continue;
285
286                 if (i->trig != INTR_TRIGGER_CONFORM ||
287                     i->pol != INTR_POLARITY_CONFORM)
288                         PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
289
290                 if (i->event != NULL)
291                         PIC_ENABLE(i->pic, i->intline, vector);
292         }
293
294         return (0);
295 }
296
297 int
298 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, 
299     driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
300 {
301         struct powerpc_intr *i;
302         int error, enable = 0;
303
304         i = intr_lookup(irq);
305         if (i == NULL)
306                 return (ENOMEM);
307
308         if (i->event == NULL) {
309                 error = intr_event_create(&i->event, (void *)i, 0, irq,
310                     powerpc_intr_mask, powerpc_intr_unmask, powerpc_intr_eoi,
311                     NULL, "irq%u:", irq);
312                 if (error)
313                         return (error);
314
315                 i->cntp = &intrcnt[i->vector];
316
317                 enable = 1;
318         }
319
320         error = intr_event_add_handler(i->event, name, filter, handler, arg,
321             intr_priority(flags), flags, cookiep);
322
323         mtx_lock(&intr_table_lock);
324         intrcnt_setname(i->event->ie_fullname, i->vector);
325         mtx_unlock(&intr_table_lock);
326
327         if (!cold) {
328                 error = powerpc_map_irq(i);
329
330                 if (!error && (i->trig != INTR_TRIGGER_CONFORM ||
331                     i->pol != INTR_POLARITY_CONFORM))
332                         PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
333
334                 if (!error && enable)
335                         PIC_ENABLE(i->pic, i->intline, i->vector);
336         }
337         return (error);
338 }
339
340 int
341 powerpc_teardown_intr(void *cookie)
342 {
343
344         return (intr_event_remove_handler(cookie));
345 }
346
347 int
348 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
349 {
350         struct powerpc_intr *i;
351
352         i = intr_lookup(irq);
353         if (i == NULL)
354                 return (ENOMEM);
355
356         i->trig = trig;
357         i->pol = pol;
358
359         if (!cold && i->pic != NULL)
360                 PIC_CONFIG(i->pic, i->intline, trig, pol);
361
362         return (0);
363 }
364
365 void
366 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
367 {
368         struct powerpc_intr *i;
369         struct intr_event *ie;
370
371         i = powerpc_intrs[vector];
372         if (i == NULL)
373                 goto stray;
374
375         (*i->cntp)++;
376
377         ie = i->event;
378         KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
379
380         if (intr_event_handle(ie, tf) != 0) {
381                 goto stray;
382         }
383         return;
384
385 stray:
386         stray_count++;
387         if (stray_count <= MAX_STRAY_LOG) {
388                 printf("stray irq %d\n", i ? i->irq : -1);
389                 if (stray_count >= MAX_STRAY_LOG) {
390                         printf("got %d stray interrupts, not logging anymore\n",
391                             MAX_STRAY_LOG);
392                 }
393         }
394         if (i != NULL)
395                 PIC_MASK(i->pic, i->intline);
396 }