]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powerpc/intr_machdep.c
MFV r262617: ncurses 5.9.
[FreeBSD/FreeBSD.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_isa.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/cpuset.h>
71 #include <sys/interrupt.h>
72 #include <sys/ktr.h>
73 #include <sys/lock.h>
74 #include <sys/malloc.h>
75 #include <sys/mutex.h>
76 #include <sys/pcpu.h>
77 #include <sys/smp.h>
78 #include <sys/syslog.h>
79 #include <sys/vmmeter.h>
80 #include <sys/proc.h>
81
82 #include <machine/frame.h>
83 #include <machine/intr_machdep.h>
84 #include <machine/md_var.h>
85 #include <machine/smp.h>
86 #include <machine/trap.h>
87
88 #include "pic_if.h"
89
90 #define MAX_STRAY_LOG   5
91
92 static MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
93
94 struct powerpc_intr {
95         struct intr_event *event;
96         long    *cntp;
97         u_int   irq;
98         device_t pic;
99         u_int   intline;
100         u_int   vector;
101         u_int   cntindex;
102         cpuset_t cpu;
103         enum intr_trigger trig;
104         enum intr_polarity pol;
105         int     fwcode;
106 };
107
108 struct pic {
109         device_t dev;
110         uint32_t node;
111         u_int   irqs;
112         u_int   ipis;
113         int     base;
114 };
115
116 static u_int intrcnt_index = 0;
117 static struct mtx intr_table_lock;
118 static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
119 static struct pic piclist[MAX_PICS];
120 static u_int nvectors;          /* Allocated vectors */
121 static u_int npics;             /* PICs registered */
122 #ifdef DEV_ISA
123 static u_int nirqs = 16;        /* Allocated IRQS (ISA pre-allocated). */
124 #else
125 static u_int nirqs = 0;         /* Allocated IRQs. */
126 #endif
127 static u_int stray_count;
128
129 device_t root_pic;
130
131 #ifdef SMP
132 static void *ipi_cookie;
133 #endif
134
135 static void
136 intr_init(void *dummy __unused)
137 {
138
139         mtx_init(&intr_table_lock, "intr sources lock", NULL, MTX_DEF);
140 }
141 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL);
142
143 #ifdef SMP
144 static void
145 smp_intr_init(void *dummy __unused)
146 {
147         struct powerpc_intr *i;
148         int vector;
149
150         for (vector = 0; vector < nvectors; vector++) {
151                 i = powerpc_intrs[vector];
152                 if (i != NULL && i->pic == root_pic)
153                         PIC_BIND(i->pic, i->intline, i->cpu);
154         }
155 }
156 SYSINIT(smp_intr_init, SI_SUB_SMP, SI_ORDER_ANY, smp_intr_init, NULL);
157 #endif
158
159 static void
160 intrcnt_setname(const char *name, int index)
161 {
162
163         snprintf(intrnames + (MAXCOMLEN + 1) * index, MAXCOMLEN + 1, "%-*s",
164             MAXCOMLEN, name);
165 }
166
167 void
168 intrcnt_add(const char *name, u_long **countp)
169 {
170         int idx;
171
172         idx = atomic_fetchadd_int(&intrcnt_index, 1);
173         *countp = &intrcnt[idx];
174         intrcnt_setname(name, idx);
175 }
176
177 static struct powerpc_intr *
178 intr_lookup(u_int irq)
179 {
180         char intrname[16];
181         struct powerpc_intr *i, *iscan;
182         int vector;
183
184         mtx_lock(&intr_table_lock);
185         for (vector = 0; vector < nvectors; vector++) {
186                 i = powerpc_intrs[vector];
187                 if (i != NULL && i->irq == irq) {
188                         mtx_unlock(&intr_table_lock);
189                         return (i);
190                 }
191         }
192
193         i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
194         if (i == NULL) {
195                 mtx_unlock(&intr_table_lock);
196                 return (NULL);
197         }
198
199         i->event = NULL;
200         i->cntp = NULL;
201         i->trig = INTR_TRIGGER_CONFORM;
202         i->pol = INTR_POLARITY_CONFORM;
203         i->irq = irq;
204         i->pic = NULL;
205         i->vector = -1;
206
207 #ifdef SMP
208         i->cpu = all_cpus;
209 #else
210         CPU_SETOF(0, &i->cpu);
211 #endif
212
213         for (vector = 0; vector < INTR_VECTORS && vector <= nvectors;
214             vector++) {
215                 iscan = powerpc_intrs[vector];
216                 if (iscan != NULL && iscan->irq == irq)
217                         break;
218                 if (iscan == NULL && i->vector == -1)
219                         i->vector = vector;
220                 iscan = NULL;
221         }
222
223         if (iscan == NULL && i->vector != -1) {
224                 powerpc_intrs[i->vector] = i;
225                 i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1);
226                 i->cntp = &intrcnt[i->cntindex];
227                 sprintf(intrname, "irq%u:", i->irq);
228                 intrcnt_setname(intrname, i->cntindex);
229                 nvectors++;
230         }
231         mtx_unlock(&intr_table_lock);
232
233         if (iscan != NULL || i->vector == -1) {
234                 free(i, M_INTR);
235                 i = iscan;
236         }
237
238         return (i);
239 }
240
241 static int
242 powerpc_map_irq(struct powerpc_intr *i)
243 {
244         struct pic *p;
245         u_int cnt;
246         int idx;
247
248         for (idx = 0; idx < npics; idx++) {
249                 p = &piclist[idx];
250                 cnt = p->irqs + p->ipis;
251                 if (i->irq >= p->base && i->irq < p->base + cnt)
252                         break;
253         }
254         if (idx == npics)
255                 return (EINVAL);
256
257         i->intline = i->irq - p->base;
258         i->pic = p->dev;
259
260         /* Try a best guess if that failed */
261         if (i->pic == NULL)
262                 i->pic = root_pic;
263
264         return (0);
265 }
266
267 static void
268 powerpc_intr_eoi(void *arg)
269 {
270         struct powerpc_intr *i = arg;
271
272         PIC_EOI(i->pic, i->intline);
273 }
274
275 static void
276 powerpc_intr_pre_ithread(void *arg)
277 {
278         struct powerpc_intr *i = arg;
279
280         PIC_MASK(i->pic, i->intline);
281         PIC_EOI(i->pic, i->intline);
282 }
283
284 static void
285 powerpc_intr_post_ithread(void *arg)
286 {
287         struct powerpc_intr *i = arg;
288
289         PIC_UNMASK(i->pic, i->intline);
290 }
291
292 static int
293 powerpc_assign_intr_cpu(void *arg, u_char cpu)
294 {
295 #ifdef SMP
296         struct powerpc_intr *i = arg;
297
298         if (cpu == NOCPU)
299                 i->cpu = all_cpus;
300         else
301                 CPU_SETOF(cpu, &i->cpu);
302
303         if (!cold && i->pic != NULL && i->pic == root_pic)
304                 PIC_BIND(i->pic, i->intline, i->cpu);
305
306         return (0);
307 #else
308         return (EOPNOTSUPP);
309 #endif
310 }
311
312 void
313 powerpc_register_pic(device_t dev, uint32_t node, u_int irqs, u_int ipis,
314     u_int atpic)
315 {
316         struct pic *p;
317         u_int irq;
318         int idx;
319
320         mtx_lock(&intr_table_lock);
321
322         /* XXX see powerpc_get_irq(). */
323         for (idx = 0; idx < npics; idx++) {
324                 p = &piclist[idx];
325                 if (p->node != node)
326                         continue;
327                 if (node != 0 || p->dev == dev)
328                         break;
329         }
330         p = &piclist[idx];
331
332         p->dev = dev;
333         p->node = node;
334         p->irqs = irqs;
335         p->ipis = ipis;
336         if (idx == npics) {
337 #ifdef DEV_ISA
338                 p->base = (atpic) ? 0 : nirqs;
339 #else
340                 p->base = nirqs;
341 #endif
342                 irq = p->base + irqs + ipis;
343                 nirqs = MAX(nirqs, irq);
344                 npics++;
345         }
346
347         mtx_unlock(&intr_table_lock);
348 }
349
350 u_int
351 powerpc_get_irq(uint32_t node, u_int pin)
352 {
353         int idx;
354
355         if (node == 0)
356                 return (pin);
357
358         mtx_lock(&intr_table_lock);
359         for (idx = 0; idx < npics; idx++) {
360                 if (piclist[idx].node == node) {
361                         mtx_unlock(&intr_table_lock);
362                         return (piclist[idx].base + pin);
363                 }
364         }
365
366         /*
367          * XXX we should never encounter an unregistered PIC, but that
368          * can only be done when we properly support bus enumeration
369          * using multiple passes. Until then, fake an entry and give it
370          * some adhoc maximum number of IRQs and IPIs.
371          */
372         piclist[idx].dev = NULL;
373         piclist[idx].node = node;
374         piclist[idx].irqs = 124;
375         piclist[idx].ipis = 4;
376         piclist[idx].base = nirqs;
377         nirqs += 128;
378         npics++;
379
380         mtx_unlock(&intr_table_lock);
381
382         return (piclist[idx].base + pin);
383 }
384
385 int
386 powerpc_enable_intr(void)
387 {
388         struct powerpc_intr *i;
389         int error, vector;
390 #ifdef SMP
391         int n;
392 #endif
393
394         if (npics == 0)
395                 panic("no PIC detected\n");
396
397         if (root_pic == NULL)
398                 root_pic = piclist[0].dev;
399
400 #ifdef SMP
401         /* Install an IPI handler. */
402         if (mp_ncpus > 1) {
403                 for (n = 0; n < npics; n++) {
404                         if (piclist[n].dev != root_pic)
405                                 continue;
406
407                         KASSERT(piclist[n].ipis != 0,
408                             ("%s: SMP root PIC does not supply any IPIs",
409                             __func__));
410                         error = powerpc_setup_intr("IPI",
411                             MAP_IRQ(piclist[n].node, piclist[n].irqs),
412                             powerpc_ipi_handler, NULL, NULL,
413                             INTR_TYPE_MISC | INTR_EXCL, &ipi_cookie);
414                         if (error) {
415                                 printf("unable to setup IPI handler\n");
416                                 return (error);
417                         }
418                 }
419         }
420 #endif
421
422         for (vector = 0; vector < nvectors; vector++) {
423                 i = powerpc_intrs[vector];
424                 if (i == NULL)
425                         continue;
426
427                 error = powerpc_map_irq(i);
428                 if (error)
429                         continue;
430
431                 if (i->trig == -1)
432                         PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode,
433                             &i->trig, &i->pol);
434                 if (i->trig != INTR_TRIGGER_CONFORM ||
435                     i->pol != INTR_POLARITY_CONFORM)
436                         PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
437
438                 if (i->event != NULL)
439                         PIC_ENABLE(i->pic, i->intline, vector);
440         }
441
442         return (0);
443 }
444
445 int
446 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
447     driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
448 {
449         struct powerpc_intr *i;
450         int error, enable = 0;
451
452         i = intr_lookup(irq);
453         if (i == NULL)
454                 return (ENOMEM);
455
456         if (i->event == NULL) {
457                 error = intr_event_create(&i->event, (void *)i, 0, irq,
458                     powerpc_intr_pre_ithread, powerpc_intr_post_ithread,
459                     powerpc_intr_eoi, powerpc_assign_intr_cpu, "irq%u:", irq);
460                 if (error)
461                         return (error);
462
463                 enable = 1;
464         }
465
466         error = intr_event_add_handler(i->event, name, filter, handler, arg,
467             intr_priority(flags), flags, cookiep);
468
469         mtx_lock(&intr_table_lock);
470         intrcnt_setname(i->event->ie_fullname, i->cntindex);
471         mtx_unlock(&intr_table_lock);
472
473         if (!cold) {
474                 error = powerpc_map_irq(i);
475
476                 if (!error) {
477                         if (i->trig == -1)
478                                 PIC_TRANSLATE_CODE(i->pic, i->intline,
479                                     i->fwcode, &i->trig, &i->pol);
480         
481                         if (i->trig != INTR_TRIGGER_CONFORM ||
482                             i->pol != INTR_POLARITY_CONFORM)
483                                 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
484
485                         if (i->pic == root_pic)
486                                 PIC_BIND(i->pic, i->intline, i->cpu);
487
488                         if (enable)
489                                 PIC_ENABLE(i->pic, i->intline, i->vector);
490                 }
491         }
492         return (error);
493 }
494
495 int
496 powerpc_teardown_intr(void *cookie)
497 {
498
499         return (intr_event_remove_handler(cookie));
500 }
501
502 #ifdef SMP
503 int
504 powerpc_bind_intr(u_int irq, u_char cpu)
505 {
506         struct powerpc_intr *i;
507
508         i = intr_lookup(irq);
509         if (i == NULL)
510                 return (ENOMEM);
511
512         return (intr_event_bind(i->event, cpu));
513 }
514 #endif
515
516 int
517 powerpc_fw_config_intr(int irq, int sense_code)
518 {
519         struct powerpc_intr *i;
520
521         i = intr_lookup(irq);
522         if (i == NULL)
523                 return (ENOMEM);
524
525         i->trig = -1;
526         i->pol = INTR_POLARITY_CONFORM;
527         i->fwcode = sense_code;
528
529         if (!cold && i->pic != NULL) {
530                 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, &i->trig,
531                     &i->pol);
532                 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol);
533         }
534
535         return (0);
536 }
537
538 int
539 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol)
540 {
541         struct powerpc_intr *i;
542
543         i = intr_lookup(irq);
544         if (i == NULL)
545                 return (ENOMEM);
546
547         i->trig = trig;
548         i->pol = pol;
549
550         if (!cold && i->pic != NULL)
551                 PIC_CONFIG(i->pic, i->intline, trig, pol);
552
553         return (0);
554 }
555
556 void
557 powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
558 {
559         struct powerpc_intr *i;
560         struct intr_event *ie;
561
562         i = powerpc_intrs[vector];
563         if (i == NULL)
564                 goto stray;
565
566         (*i->cntp)++;
567
568         ie = i->event;
569         KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
570
571         if (intr_event_handle(ie, tf) != 0) {
572                 goto stray;
573         }
574         return;
575
576 stray:
577         stray_count++;
578         if (stray_count <= MAX_STRAY_LOG) {
579                 printf("stray irq %d\n", i ? i->irq : -1);
580                 if (stray_count >= MAX_STRAY_LOG) {
581                         printf("got %d stray interrupts, not logging anymore\n",
582                             MAX_STRAY_LOG);
583                 }
584         }
585         if (i != NULL)
586                 PIC_MASK(i->pic, i->intline);
587 }