Annotation of sys/arch/macppc/dev/openpic.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: openpic.c,v 1.40 2007/05/29 18:10:43 miod Exp $ */
2:
3: /*-
4: * Copyright (c) 1995 Per Fogelstrom
5: * Copyright (c) 1993, 1994 Charles M. Hannum.
6: * Copyright (c) 1990 The Regents of the University of California.
7: * All rights reserved.
8: *
9: * This code is derived from software contributed to Berkeley by
10: * William Jolitz and Don Ahn.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)isa.c 7.2 (Berkeley) 5/12/91
37: */
38:
39: #include <sys/param.h>
40: #include <sys/device.h>
41: #include <sys/ioctl.h>
42: #include <sys/mbuf.h>
43: #include <sys/socket.h>
44: #include <sys/systm.h>
45:
46: #include <uvm/uvm.h>
47: #include <ddb/db_var.h>
48:
49: #include <machine/atomic.h>
50: #include <machine/autoconf.h>
51: #include <machine/intr.h>
52: #include <machine/psl.h>
53: #include <machine/pio.h>
54: #include <machine/powerpc.h>
55: #include <macppc/dev/openpicreg.h>
56: #include <dev/ofw/openfirm.h>
57:
58: #define ICU_LEN 128
59: #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
60:
61: int o_intrtype[ICU_LEN], o_intrmask[ICU_LEN], o_intrlevel[ICU_LEN];
62: struct intrhand *o_intrhand[ICU_LEN] = { 0 };
63: int o_hwirq[ICU_LEN], o_virq[ICU_LEN];
64: unsigned int imen_o = 0xffffffff;
65: int o_virq_max;
66:
67: static int fakeintr(void *);
68: static char *intr_typename(int type);
69: static void intr_calculatemasks(void);
70: static __inline int cntlzw(int x);
71: static int mapirq(int irq);
72: int openpic_prog_button(void *arg);
73: void openpic_enable_irq_mask(int irq_mask);
74:
75: #define HWIRQ_MAX 27
76: #define HWIRQ_MASK 0x0fffffff
77:
78: static __inline u_int openpic_read(int);
79: static __inline void openpic_write(int, u_int);
80: void openpic_set_enable_irq(int, int);
81: void openpic_enable_irq(int);
82: void openpic_disable_irq(int);
83: void openpic_init(void);
84: void openpic_set_priority(int, int);
85: static __inline int openpic_read_irq(int);
86: static __inline void openpic_eoi(int);
87:
88: struct openpic_softc {
89: struct device sc_dev;
90: };
91:
92: int openpic_match(struct device *parent, void *cf, void *aux);
93: void openpic_attach(struct device *, struct device *, void *);
94: void openpic_do_pending_int(void);
95: void openpic_collect_preconf_intr(void);
96: void ext_intr_openpic(void);
97:
98: struct cfattach openpic_ca = {
99: sizeof(struct openpic_softc),
100: openpic_match,
101: openpic_attach
102: };
103:
104: struct cfdriver openpic_cd = {
105: NULL, "openpic", DV_DULL
106: };
107:
108: int
109: openpic_match(struct device *parent, void *cf, void *aux)
110: {
111: char type[40];
112: int pirq;
113: struct confargs *ca = aux;
114:
115: bzero (type, sizeof(type));
116:
117: if (OF_getprop(ca->ca_node, "interrupt-parent", &pirq, sizeof(pirq))
118: == sizeof(pirq))
119: return 0; /* XXX */
120:
121: if (strcmp(ca->ca_name, "interrupt-controller") != 0 &&
122: strcmp(ca->ca_name, "mpic") != 0)
123: return 0;
124:
125: OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
126: if (strcmp(type, "open-pic") != 0)
127: return 0;
128:
129: if (ca->ca_nreg < 8)
130: return 0;
131:
132: return 1;
133: }
134:
135: typedef void (void_f) (void);
136: extern void_f *pending_int_f;
137:
138: vaddr_t openpic_base;
139: void * openpic_intr_establish( void * lcv, int irq, int type, int level,
140: int (*ih_fun)(void *), void *ih_arg, char *name);
141: void openpic_intr_disestablish( void *lcp, void *arg);
142: void openpic_collect_preconf_intr(void);
143: int openpic_big_endian;
144:
145: void
146: openpic_attach(struct device *parent, struct device *self, void *aux)
147: {
148: struct confargs *ca = aux;
149: extern intr_establish_t *intr_establish_func;
150: extern intr_disestablish_t *intr_disestablish_func;
151: extern intr_establish_t *mac_intr_establish_func;
152: extern intr_disestablish_t *mac_intr_disestablish_func;
153: u_int32_t reg;
154:
155: reg = 0;
156: if (OF_getprop(ca->ca_node, "big-endian", ®, sizeof reg) == 0)
157: openpic_big_endian = 1;
158:
159: openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr +
160: ca->ca_reg[0], 0x40000);
161:
162: printf(": version 0x%x %s endian", openpic_read(OPENPIC_VENDOR_ID),
163: openpic_big_endian ? "big" : "little" );
164:
165: openpic_init();
166:
167: pending_int_f = openpic_do_pending_int;
168: intr_establish_func = openpic_intr_establish;
169: intr_disestablish_func = openpic_intr_disestablish;
170: mac_intr_establish_func = openpic_intr_establish;
171: mac_intr_disestablish_func = openpic_intr_disestablish;
172: install_extint(ext_intr_openpic);
173:
174: #if 1
175: openpic_collect_preconf_intr();
176: #endif
177:
178: #if 1
179: mac_intr_establish(parent, 0x37, IST_LEVEL,
180: IPL_HIGH, openpic_prog_button, (void *)0x37, "progbutton");
181: #endif
182: ppc_intr_enable(1);
183:
184: printf("\n");
185: }
186:
187: void
188: openpic_collect_preconf_intr()
189: {
190: int i;
191: for (i = 0; i < ppc_configed_intr_cnt; i++) {
192: #ifdef DEBUG
193: printf("\n\t%s irq %d level %d fun %x arg %x",
194: ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
195: ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
196: ppc_configed_intr[i].ih_arg);
197: #endif
198: openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
199: IST_LEVEL, ppc_configed_intr[i].ih_level,
200: ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
201: ppc_configed_intr[i].ih_what);
202: }
203: }
204:
205: static int
206: fakeintr(void *arg)
207: {
208:
209: return 0;
210: }
211:
212: /*
213: * Register an interrupt handler.
214: */
215: void *
216: openpic_intr_establish(void *lcv, int irq, int type, int level,
217: int (*ih_fun)(void *), void *ih_arg, char *name)
218: {
219: struct intrhand **p, *q, *ih;
220: static struct intrhand fakehand;
221:
222: fakehand.ih_next = NULL;
223: fakehand.ih_fun = fakeintr;
224:
225: #if 0
226: printf("mac_intr_establish, hI %d L %d ", irq, type);
227: #endif
228:
229: irq = mapirq(irq);
230: #if 0
231: printf("vI %d ", irq);
232: #endif
233:
234: /* no point in sleeping unless someone can free memory. */
235: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
236: if (ih == NULL)
237: panic("intr_establish: can't malloc handler info");
238:
239: if (!LEGAL_IRQ(irq) || type == IST_NONE)
240: panic("intr_establish: bogus irq or type");
241:
242: switch (o_intrtype[irq]) {
243: case IST_NONE:
244: o_intrtype[irq] = type;
245: break;
246: case IST_EDGE:
247: case IST_LEVEL:
248: if (type == o_intrtype[irq])
249: break;
250: case IST_PULSE:
251: if (type != IST_NONE)
252: panic("intr_establish: can't share %s with %s",
253: intr_typename(o_intrtype[irq]),
254: intr_typename(type));
255: break;
256: }
257:
258: /*
259: * Figure out where to put the handler.
260: * This is O(N^2), but we want to preserve the order, and N is
261: * generally small.
262: */
263: for (p = &o_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
264: ;
265:
266: /*
267: * Actually install a fake handler momentarily, since we might be doing
268: * this with interrupts enabled and DON'T WANt the real routine called
269: * until masking is set up.
270: */
271: fakehand.ih_level = level;
272: *p = &fakehand;
273:
274: intr_calculatemasks();
275:
276: /*
277: * Poke the real handler in now.
278: */
279: ih->ih_fun = ih_fun;
280: ih->ih_arg = ih_arg;
281: ih->ih_next = NULL;
282: ih->ih_level = level;
283: ih->ih_irq = irq;
284: evcount_attach(&ih->ih_count, name, (void *)&o_hwirq[irq],
285: &evcount_intr);
286: *p = ih;
287:
288: return (ih);
289: }
290:
291: /*
292: * Deregister an interrupt handler.
293: */
294: void
295: openpic_intr_disestablish(void *lcp, void *arg)
296: {
297: struct intrhand *ih = arg;
298: int irq = ih->ih_irq;
299: struct intrhand **p, *q;
300:
301: if (!LEGAL_IRQ(irq))
302: panic("intr_disestablish: bogus irq");
303:
304: /*
305: * Remove the handler from the chain.
306: * This is O(n^2), too.
307: */
308: for (p = &o_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
309: ;
310: if (q)
311: *p = q->ih_next;
312: else
313: panic("intr_disestablish: handler not registered");
314:
315: evcount_detach(&ih->ih_count);
316: free((void *)ih, M_DEVBUF);
317:
318: intr_calculatemasks();
319:
320: if (o_intrhand[irq] == NULL)
321: o_intrtype[irq] = IST_NONE;
322: }
323:
324:
325: static char *
326: intr_typename(int type)
327: {
328:
329: switch (type) {
330: case IST_NONE:
331: return ("none");
332: case IST_PULSE:
333: return ("pulsed");
334: case IST_EDGE:
335: return ("edge-triggered");
336: case IST_LEVEL:
337: return ("level-triggered");
338: default:
339: panic("intr_typename: invalid type %d", type);
340: #if 1 /* XXX */
341: return ("unknown");
342: #endif
343: }
344: }
345:
346: /*
347: * Recalculate the interrupt masks from scratch.
348: * We could code special registry and deregistry versions of this function that
349: * would be faster, but the code would be nastier, and we don't expect this to
350: * happen very much anyway.
351: */
352: static void
353: intr_calculatemasks()
354: {
355: int irq, level;
356: struct intrhand *q;
357:
358: /* First, figure out which levels each IRQ uses. */
359: for (irq = 0; irq < ICU_LEN; irq++) {
360: register int levels = 0;
361: for (q = o_intrhand[irq]; q; q = q->ih_next)
362: levels |= 1 << q->ih_level;
363: o_intrlevel[irq] = levels;
364: }
365:
366: /* Then figure out which IRQs use each level. */
367: for (level = IPL_NONE; level < IPL_NUM; level++) {
368: register int irqs = 0;
369: for (irq = 0; irq < ICU_LEN; irq++)
370: if (o_intrlevel[irq] & (1 << level))
371: irqs |= 1 << irq;
372: imask[level] = irqs | SINT_MASK;
373: }
374:
375: /*
376: * There are tty, network and disk drivers that use free() at interrupt
377: * time, so vm > (tty | net | bio).
378: *
379: * Enforce a hierarchy that gives slow devices a better chance at not
380: * dropping data.
381: */
382: imask[IPL_NET] |= imask[IPL_BIO];
383: imask[IPL_TTY] |= imask[IPL_NET];
384: imask[IPL_VM] |= imask[IPL_TTY];
385: imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK;
386:
387: /*
388: * These are pseudo-levels.
389: */
390: imask[IPL_NONE] = 0x00000000;
391: imask[IPL_HIGH] = 0xffffffff;
392:
393: /* And eventually calculate the complete masks. */
394: for (irq = 0; irq < ICU_LEN; irq++) {
395: register int irqs = 1 << irq;
396: for (q = o_intrhand[irq]; q; q = q->ih_next)
397: irqs |= imask[q->ih_level];
398: o_intrmask[irq] = irqs | SINT_MASK;
399: }
400:
401: /* Lastly, determine which IRQs are actually in use. */
402: {
403: register int irqs = 0;
404: for (irq = 0; irq < ICU_LEN; irq++) {
405: if (o_intrhand[irq]) {
406: irqs |= 1 << irq;
407: openpic_enable_irq(o_hwirq[irq]);
408: } else {
409: openpic_disable_irq(o_hwirq[irq]);
410: }
411: }
412: imen_o = ~irqs;
413: }
414: }
415:
416: /*
417: * Map 64 irqs into 32 (bits).
418: */
419: static int
420: mapirq(int irq)
421: {
422: int v;
423:
424: /* irq in table already? */
425: if (o_virq[irq] != 0)
426: return o_virq[irq];
427:
428: if (irq < 0 || irq >= ICU_LEN)
429: panic("invalid irq %d", irq);
430:
431: o_virq_max++;
432: v = o_virq_max;
433: if (v > HWIRQ_MAX)
434: panic("virq overflow");
435:
436: o_hwirq[v] = irq;
437: o_virq[irq] = v;
438: #if 0
439: printf("\nmapirq %x to %x\n", irq, v);
440: #endif
441:
442: return v;
443: }
444:
445: /*
446: * Count leading zeros.
447: */
448: static __inline int
449: cntlzw(int x)
450: {
451: int a;
452:
453: __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
454:
455: return a;
456: }
457:
458:
459: void
460: openpic_do_pending_int()
461: {
462: struct cpu_info *ci = curcpu();
463: struct intrhand *ih;
464: int irq;
465: int pcpl;
466: int hwpend;
467: int s;
468:
469: if (ci->ci_iactive)
470: return;
471:
472: ci->ci_iactive = 1;
473: pcpl = splhigh(); /* Turn off all */
474: s = ppc_intr_disable();
475:
476: hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */
477: imen_o &= ~hwpend;
478: openpic_enable_irq_mask(~imen_o);
479: hwpend &= HWIRQ_MASK;
480: while (hwpend) {
481: irq = 31 - cntlzw(hwpend);
482: hwpend &= ~(1L << irq);
483: ih = o_intrhand[irq];
484: while(ih) {
485: ppc_intr_enable(1);
486:
487: if ((*ih->ih_fun)(ih->ih_arg))
488: ih->ih_count.ec_count++;
489:
490: (void)ppc_intr_disable();
491:
492: ih = ih->ih_next;
493: }
494: }
495:
496: /*out32rb(INT_ENABLE_REG, ~imen_o);*/
497:
498: do {
499: if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) {
500: ci->ci_ipending &= ~SINT_CLOCK;
501: softclock();
502: }
503: if((ci->ci_ipending & SINT_NET) & ~pcpl) {
504: extern int netisr;
505: int pisr;
506:
507: ci->ci_ipending &= ~SINT_NET;
508: while ((pisr = netisr) != 0) {
509: atomic_clearbits_int(&netisr, pisr);
510: softnet(pisr);
511: }
512: }
513: if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
514: ci->ci_ipending &= ~SINT_TTY;
515: softtty();
516: }
517: } while ((ci->ci_ipending & SINT_MASK) & ~pcpl);
518: ci->ci_ipending &= pcpl;
519: ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
520: ppc_intr_enable(s);
521: ci->ci_iactive = 0;
522: }
523:
524: u_int
525: openpic_read(int reg)
526: {
527: char *addr = (void *)(openpic_base + reg);
528:
529: if (openpic_big_endian)
530: return in32(addr);
531: else
532: return in32rb(addr);
533: }
534:
535: void
536: openpic_write(int reg, u_int val)
537: {
538: char *addr = (void *)(openpic_base + reg);
539:
540: if (openpic_big_endian)
541: out32(addr, val);
542: else
543: out32rb(addr, val);
544: }
545:
546: void
547: openpic_enable_irq_mask(int irq_mask)
548: {
549: int irq;
550: for ( irq = 0; irq <= o_virq_max; irq++) {
551: if (irq_mask & (1 << irq))
552: openpic_enable_irq(o_hwirq[irq]);
553: else
554: openpic_disable_irq(o_hwirq[irq]);
555: }
556: }
557:
558: void
559: openpic_set_enable_irq(int irq, int type)
560: {
561: u_int x;
562:
563: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
564: x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE);
565: if (type == IST_LEVEL)
566: x |= OPENPIC_SENSE_LEVEL;
567: else
568: x |= OPENPIC_SENSE_EDGE;
569: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
570: }
571: void
572: openpic_enable_irq(int irq)
573: {
574: u_int x;
575:
576: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
577: x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE);
578: if (o_intrtype[o_virq[irq]] == IST_LEVEL)
579: x |= OPENPIC_SENSE_LEVEL;
580: else
581: x |= OPENPIC_SENSE_EDGE;
582: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
583: }
584:
585: void
586: openpic_disable_irq(int irq)
587: {
588: u_int x;
589:
590: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
591: x |= OPENPIC_IMASK;
592: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
593: }
594:
595: void
596: openpic_set_priority(int cpu, int pri)
597: {
598: u_int x;
599:
600: x = openpic_read(OPENPIC_CPU_PRIORITY(cpu));
601: x &= ~OPENPIC_CPU_PRIORITY_MASK;
602: x |= pri;
603: openpic_write(OPENPIC_CPU_PRIORITY(cpu), x);
604: }
605:
606: int
607: openpic_read_irq(int cpu)
608: {
609: return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
610: }
611:
612: void
613: openpic_eoi(int cpu)
614: {
615: openpic_write(OPENPIC_EOI(cpu), 0);
616: openpic_read(OPENPIC_EOI(cpu));
617: }
618:
619: void
620: ext_intr_openpic()
621: {
622: struct cpu_info *ci = curcpu();
623: int irq, realirq;
624: int r_imen;
625: int pcpl, ocpl;
626: struct intrhand *ih;
627:
628: pcpl = ci->ci_cpl;
629:
630: realirq = openpic_read_irq(0);
631:
632: while (realirq != 255) {
633: irq = o_virq[realirq];
634:
635: /* XXX check range */
636:
637: r_imen = 1 << irq;
638:
639: if ((pcpl & r_imen) != 0) {
640: /* Masked! Mark this as pending. */
641: ci->ci_ipending |= r_imen;
642: openpic_disable_irq(realirq);
643: openpic_eoi(0);
644: } else {
645: openpic_disable_irq(realirq);
646: openpic_eoi(0);
647: ocpl = splraise(o_intrmask[irq]);
648:
649: ih = o_intrhand[irq];
650: while (ih) {
651: ppc_intr_enable(1);
652:
653: if ((*ih->ih_fun)(ih->ih_arg))
654: ih->ih_count.ec_count++;
655:
656: (void)ppc_intr_disable();
657: ih = ih->ih_next;
658: }
659:
660: uvmexp.intrs++;
661: __asm__ volatile("":::"memory"); /* don't reorder.... */
662: ci->ci_cpl = ocpl;
663: __asm__ volatile("":::"memory"); /* don't reorder.... */
664: openpic_enable_irq(realirq);
665: }
666:
667: realirq = openpic_read_irq(0);
668: }
669: ppc_intr_enable(1);
670:
671: splx(pcpl); /* Process pendings. */
672: }
673:
674: void
675: openpic_init()
676: {
677: int irq;
678: u_int x;
679:
680: /* disable all interrupts */
681: for (irq = 0; irq < 255; irq++)
682: openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
683: openpic_set_priority(0, 15);
684:
685: /* we don't need 8259 pass through mode */
686: x = openpic_read(OPENPIC_CONFIG);
687: x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
688: openpic_write(OPENPIC_CONFIG, x);
689:
690: /* send all interrupts to cpu 0 */
691: for (irq = 0; irq < ICU_LEN; irq++)
692: openpic_write(OPENPIC_IDEST(irq), 1 << 0);
693: for (irq = 0; irq < ICU_LEN; irq++) {
694: x = irq;
695: x |= OPENPIC_IMASK;
696: x |= OPENPIC_POLARITY_POSITIVE;
697: x |= OPENPIC_SENSE_LEVEL;
698: x |= 8 << OPENPIC_PRIORITY_SHIFT;
699: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
700: }
701:
702: /* XXX set spurious intr vector */
703:
704: openpic_set_priority(0, 0);
705:
706: /* clear all pending interrunts */
707: for (irq = 0; irq < ICU_LEN; irq++) {
708: openpic_read_irq(0);
709: openpic_eoi(0);
710: }
711:
712: for (irq = 0; irq < ICU_LEN; irq++)
713: openpic_disable_irq(irq);
714:
715: install_extint(ext_intr_openpic);
716: }
717:
718: /*
719: * programmer_button function to fix args to Debugger.
720: * deal with any enables/disables, if necessary.
721: */
722: int
723: openpic_prog_button (void *arg)
724: {
725: #ifdef DDB
726: if (db_console)
727: Debugger();
728: #else
729: printf("programmer button pressed, debugger not available\n");
730: #endif
731: return 1;
732: }
CVSweb