Annotation of sys/arch/mvmeppc/dev/openpic.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: openpic.c,v 1.22 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_extern.h>
47:
48: #include <ddb/db_var.h>
49:
50: #include <machine/atomic.h>
51: #include <machine/autoconf.h>
52: #include <machine/intr.h>
53: #include <machine/psl.h>
54: #include <machine/pio.h>
55:
56: #include <mvmeppc/dev/openpicreg.h>
57: #include <mvmeppc/dev/ravenvar.h>
58: #include <mvmeppc/dev/ravenreg.h>
59:
60: #define ICU_LEN 32
61: #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
62: #define IO_ICU1 (isaspace_va + 0x20)
63: #define IO_ICU2 (isaspace_va + 0xa0)
64: #define IO_ELCR1 (isaspace_va + 0x4d0)
65: #define IO_ELCR2 (isaspace_va + 0x4d1)
66: #define IRQ_SLAVE 2
67: #define ICU_OFFSET 0
68: #define PIC_OFFSET 16
69:
70: #define PIC_SPURIOUS 0xff
71:
72: unsigned char icu1_val = 0xff;
73: unsigned char icu2_val = 0xff;
74: unsigned char elcr1_val = 0x00;
75: unsigned char elcr2_val = 0x00;
76:
77: int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
78: struct intrhand *intrhand[ICU_LEN];
79: int hwirq[ICU_LEN], virq[ICU_LEN];
80: unsigned int imen = 0xffffffff;
81: int virq_max;
82:
83: int fakeintr(void *);
84: const char *intr_typename(int type);
85: void intr_calculatemasks(void);
86: static __inline int cntlzw(int x);
87: int mapirq(int irq);
88: void openpic_enable_irq_mask(int irq_mask);
89:
90: #define HWIRQ_MAX 27
91: #define HWIRQ_MASK 0x0fffffff
92:
93: static __inline u_int openpic_read(int);
94: static __inline void openpic_write(int, u_int);
95: void openpic_enable_irq(int, int);
96: void openpic_disable_irq(int);
97: void openpic_init(void);
98: void openpic_set_priority(int, int);
99: static __inline int openpic_iack(int);
100: static __inline void openpic_eoi(int);
101: void openpic_initirq(int, int, int);
102:
103: void i8259_init(void);
104: int i8259_intr(void);
105: void i8259_enable_irq(int, int);
106: void i8259_disable_irq(int);
107: void i8259_eoi(int);
108: void *i8259_intr_establish(void *, int, int, int, int (*)(void *), void *,
109: char *);
110: void i8259_set_irq_mask(void);
111:
112: struct openpic_softc {
113: struct device sc_dev;
114: };
115:
116: int openpic_match(struct device *parent, void *cf, void *aux);
117: void openpic_attach(struct device *, struct device *, void *);
118: void openpic_do_pending_int(void);
119: void ext_intr_openpic(void);
120:
121: struct cfattach openpic_ca = {
122: sizeof(struct openpic_softc), openpic_match, openpic_attach
123: };
124:
125: struct cfdriver openpic_cd = {
126: NULL, "openpic", DV_DULL
127: };
128:
129: /*
130: * ISA IRQ for PCI IRQ to MPIC IRQ routing.
131: * From MVME2600APG tables 5.2 and 5.3
132: */
133: const struct pci_route {
134: int pci;
135: int openpic;
136: } pci_routes[] = {
137: { 10, 2 },
138: { 11, 5 },
139: { 14, 3 },
140: { 15, 4 },
141: { 0, 0 }
142: };
143:
144: int
145: openpic_match(parent, cf, aux)
146: struct device *parent;
147: void *cf;
148: void *aux;
149: {
150: /* We must be a child of the raven device */
151: if (strcmp(parent->dv_cfdata->cf_driver->cd_name, "raven") != 0)
152: return (0);
153: /* If there is a raven, then there is a mpic! */
154: return 1;
155: }
156:
157: u_int8_t *interrupt_reg;
158: typedef void (void_f) (void);
159: extern void_f *pending_int_f;
160: int abort_switch (void *arg);
161: int i8259_dummy(void *arg);
162:
163: typedef int mac_intr_handle_t;
164:
165: typedef void *(intr_establish_t)(void *, int, int, int, int (*)(void *),
166: void *, char *);
167: typedef void (intr_disestablish_t)(void *, void *);
168:
169: vaddr_t openpic_base;
170: extern vaddr_t isaspace_va;
171:
172: void * openpic_intr_establish(void *, int, int, int, int (*)(void *), void *,
173: char *);
174: void openpic_intr_disestablish(void *, void *);
175: void openpic_collect_preconf_intr(void);
176:
177: void
178: openpic_attach(parent, self, aux)
179: struct device *parent, *self;
180: void *aux;
181: {
182: extern intr_establish_t *intr_establish_func;
183: extern intr_disestablish_t *intr_disestablish_func;
184:
185: if ((openpic_base = (vaddr_t)mapiodev(MPCIC_BASE, MPCIC_SIZE)) == NULL) {
186: printf(": can't map MPCIC!\n");
187: return;
188: }
189:
190: /* the ICU area in isa space already mapped */
191:
192: printf(": version 0x%x", openpic_read(OPENPIC_FEATURE) & 0xFF);
193:
194: i8259_init();
195: openpic_init();
196:
197: pending_int_f = openpic_do_pending_int;
198: intr_establish_func = i8259_intr_establish;
199: intr_disestablish_func = openpic_intr_disestablish;
200:
201: openpic_collect_preconf_intr();
202:
203: /*
204: * i8259 interrupts are chained to openpic interrupt #0
205: */
206: openpic_intr_establish(parent, 0x00, IST_LEVEL, IPL_HIGH,
207: i8259_dummy, NULL, "8259 Interrupt");
208:
209: i8259_intr_establish(parent, 0x08, IST_EDGE, IPL_HIGH,
210: abort_switch, NULL, "abort button");
211:
212: printf("\n");
213: }
214:
215: void
216: openpic_collect_preconf_intr()
217: {
218: int i;
219:
220: for (i = 0; i < ppc_configed_intr_cnt; i++) {
221: #ifdef DEBUG
222: printf("\n\t%s irq %d level %d fun %x arg %x",
223: ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
224: ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
225: ppc_configed_intr[i].ih_arg);
226: #endif
227: openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
228: IST_LEVEL, ppc_configed_intr[i].ih_level,
229: ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
230: ppc_configed_intr[i].ih_what);
231: }
232: }
233:
234: int
235: abort_switch(void *arg)
236: {
237: #ifdef DDB
238: if (db_console)
239: Debugger();
240: #else
241: printf("Abort button pressed, debugger not available.\n");
242: #endif
243: return 1;
244: }
245:
246: int
247: i8259_dummy(void *arg)
248: {
249: /* All the 8259 handling happens in ext_intr_openpic(), actually. */
250: return 1;
251: }
252:
253: int
254: fakeintr(arg)
255: void *arg;
256: {
257: return 0;
258: }
259:
260: /*
261: * Register an ISA interrupt handler.
262: */
263: void *
264: i8259_intr_establish(lcv, irq, type, level, ih_fun, ih_arg, what)
265: void * lcv;
266: int irq;
267: int type;
268: int level;
269: int (*ih_fun)(void *);
270: void *ih_arg;
271: char *what;
272: {
273: struct intrhand **p, *q, *ih;
274: static struct intrhand fakehand;
275:
276: fakehand.ih_next = NULL;
277: fakehand.ih_fun = fakeintr;
278:
279: #if 0
280: printf("i8259_intr_establish, %d, %s", irq, (type == IST_EDGE) ? "EDGE":"LEVEL"));
281: #endif
282: irq = mapirq(irq + ICU_OFFSET);
283:
284: /* no point in sleeping unless someone can free memory. */
285: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
286: if (ih == NULL)
287: panic("i8259_intr_establish: can't malloc handler info");
288:
289: if (!LEGAL_IRQ(irq) || type == IST_NONE)
290: panic("i8259_intr_establish: bogus irq or type");
291:
292: switch (intrtype[irq]) {
293: case IST_EDGE:
294: case IST_LEVEL:
295: if (type == intrtype[irq])
296: break;
297: case IST_PULSE:
298: if (type != IST_NONE)
299: panic("intr_establish: can't share %s with %s",
300: intr_typename(intrtype[irq]),
301: intr_typename(type));
302: break;
303: }
304:
305: /*
306: * Figure out where to put the handler.
307: * This is O(N^2), but we want to preserve the order, and N is
308: * generally small.
309: */
310: for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
311: ;
312:
313: /*
314: * Actually install a fake handler momentarily, since we might be doing
315: * this with interrupts enabled and don't want the real routine called
316: * until masking is set up.
317: */
318: fakehand.ih_level = level;
319: *p = &fakehand;
320:
321: intr_calculatemasks();
322:
323: /*
324: * Poke the real handler in now.
325: */
326: ih->ih_fun = ih_fun;
327: ih->ih_arg = ih_arg;
328: ih->ih_next = NULL;
329: ih->ih_level = level;
330: ih->ih_irq = irq;
331: ih->ih_what = what;
332: evcount_attach(&ih->ih_count, what, (void *)&ih->ih_irq, &evcount_intr);
333: *p = ih;
334:
335: return (ih);
336: }
337:
338:
339: /*
340: * Register a PCI interrupt handler.
341: */
342: void *
343: openpic_intr_establish(lcv, irq, type, level, ih_fun, ih_arg, what)
344: void * lcv;
345: int irq;
346: int type;
347: int level;
348: int (*ih_fun)(void *);
349: void *ih_arg;
350: char *what;
351: {
352: struct intrhand **p, *q, *ih;
353: static struct intrhand fakehand;
354: const struct pci_route *pr;
355:
356: fakehand.ih_next = NULL;
357: fakehand.ih_fun = fakeintr;
358:
359: for (pr = pci_routes; pr->pci != 0; pr++)
360: if (pr->pci == irq) {
361: irq = pr->openpic;
362: break;
363: }
364:
365: irq = mapirq(irq + PIC_OFFSET);
366:
367: /* no point in sleeping unless someone can free memory. */
368: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
369: if (ih == NULL)
370: panic("intr_establish: can't malloc handler info");
371:
372: if (!LEGAL_IRQ(irq) || type == IST_NONE)
373: panic("intr_establish: bogus irq or type");
374:
375: switch (intrtype[irq]) {
376: case IST_EDGE:
377: case IST_LEVEL:
378: if (type == intrtype[irq])
379: break;
380: case IST_PULSE:
381: if (type != IST_NONE)
382: panic("intr_establish: can't share %s with %s",
383: intr_typename(intrtype[irq]),
384: intr_typename(type));
385: break;
386: }
387:
388: /*
389: * Figure out where to put the handler.
390: * This is O(N^2), but we want to preserve the order, and N is
391: * generally small.
392: */
393: for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
394: ;
395:
396: /*
397: * Actually install a fake handler momentarily, since we might be doing
398: * this with interrupts enabled and don't want the real routine called
399: * until masking is set up.
400: */
401: fakehand.ih_level = level;
402: *p = &fakehand;
403:
404: intr_calculatemasks();
405:
406: /*
407: * Poke the real handler in now.
408: */
409: ih->ih_fun = ih_fun;
410: ih->ih_arg = ih_arg;
411: ih->ih_next = NULL;
412: ih->ih_level = level;
413: ih->ih_irq = irq;
414: ih->ih_what = what;
415: evcount_attach(&ih->ih_count, what, (void *)&ih->ih_irq, &evcount_intr);
416: *p = ih;
417:
418: return (ih);
419: }
420:
421: /*
422: * Deregister an interrupt handler.
423: */
424: void
425: openpic_intr_disestablish(lcp, arg)
426: void *lcp;
427: void *arg;
428: {
429: struct intrhand *ih = arg;
430: int irq = ih->ih_irq;
431: struct intrhand **p, *q;
432:
433: if (!LEGAL_IRQ(irq))
434: panic("intr_disestablish: bogus irq");
435:
436: /*
437: * Remove the handler from the chain.
438: * This is O(n^2), too.
439: */
440: for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
441: ;
442: if (q)
443: *p = q->ih_next;
444: else
445: panic("intr_disestablish: handler not registered");
446:
447: evcount_detach(&ih->ih_count);
448: free((void *)ih, M_DEVBUF);
449:
450: intr_calculatemasks();
451:
452: if (intrhand[irq] == NULL)
453: intrtype[irq] = IST_NONE;
454: }
455:
456: const char *
457: intr_typename(type)
458: int type;
459: {
460:
461: switch (type) {
462: case IST_NONE :
463: return ("none");
464: case IST_PULSE:
465: return ("pulsed");
466: case IST_EDGE:
467: return ("edge-triggered");
468: case IST_LEVEL:
469: return ("level-triggered");
470: #ifdef DIAGNOSTIC
471: default:
472: panic("intr_typename: invalid type %d", type);
473: #endif
474: }
475: }
476:
477: /*
478: * Recalculate the interrupt masks from scratch.
479: * We could code special registry and deregistry versions of this function that
480: * would be faster, but the code would be nastier, and we don't expect this to
481: * happen very much anyway.
482: */
483: void
484: intr_calculatemasks()
485: {
486: int irq, hirq, level, levels;
487: struct intrhand *q;
488: int irqs;
489:
490: /* First, figure out which levels each IRQ uses. */
491: for (irq = 0; irq < ICU_LEN; irq++) {
492: levels = 0;
493: for (q = intrhand[irq]; q; q = q->ih_next)
494: levels |= 1 << q->ih_level;
495: intrlevel[irq] = levels;
496: }
497:
498: /* Then figure out which IRQs use each level. */
499: for (level = IPL_NONE; level < IPL_NUM; level++) {
500: irqs = 0;
501: for (irq = 0; irq < ICU_LEN; irq++)
502: if (intrlevel[irq] & (1 << level))
503: irqs |= 1 << irq;
504: imask[level] = irqs | SINT_MASK;
505: }
506:
507: /*
508: * There are tty, network and disk drivers that use free() at interrupt
509: * time, so vm > (tty | net | bio).
510: *
511: * Enforce a hierarchy that gives slow devices a better chance at not
512: * dropping data.
513: */
514: imask[IPL_NET] |= imask[IPL_BIO];
515: imask[IPL_TTY] |= imask[IPL_NET];
516: imask[IPL_VM] |= imask[IPL_TTY];
517: imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK;
518:
519: /*
520: * These are pseudo-levels.
521: */
522: imask[IPL_NONE] = 0x00000000;
523: imask[IPL_HIGH] = 0xffffffff;
524:
525: /* And eventually calculate the complete masks. */
526: for (irq = 0; irq < ICU_LEN; irq++) {
527: irqs = 1 << irq;
528: for (q = intrhand[irq]; q; q = q->ih_next)
529: irqs |= imask[q->ih_level];
530: intrmask[irq] = irqs | SINT_MASK;
531: }
532:
533: /* Lastly, determine which IRQs are actually in use. */
534: irqs = 0;
535: for (irq = 0; irq < ICU_LEN; irq++) {
536: hirq = hwirq[irq];
537: if (hirq < 0)
538: continue;
539:
540: if (intrhand[irq]) {
541: irqs |= 1 << irq;
542:
543: if (hirq >= PIC_OFFSET)
544: openpic_enable_irq(hirq, intrtype[irq]);
545: else
546: i8259_enable_irq(hirq, intrtype[irq]);
547: } else {
548: if (hirq >= PIC_OFFSET)
549: openpic_disable_irq(hirq);
550: else
551: i8259_disable_irq(hirq);
552: }
553: }
554:
555: /* always enable the chained 8259 interrupt */
556: i8259_enable_irq(IRQ_SLAVE, IST_EDGE);
557:
558: imen = ~irqs;
559: i8259_set_irq_mask();
560: }
561:
562: /*
563: * Map 64 irqs into 32 (bits).
564: */
565: int
566: mapirq(irq)
567: int irq;
568: {
569: int v;
570:
571: #ifdef DIAGNOSTIC
572: if (irq < 0 || irq >= ICU_LEN)
573: panic("invalid irq");
574: #endif
575:
576: virq_max++;
577: v = virq_max;
578: if (v > HWIRQ_MAX)
579: panic("virq overflow");
580:
581: hwirq[v] = irq;
582: virq[irq] = v;
583: #ifdef DEBUG
584: printf("mapirq %x to %x\n", irq, v);
585: #endif
586:
587: return v;
588: }
589:
590: /*
591: * Count leading zeros.
592: */
593: static __inline int
594: cntlzw(x)
595: int x;
596: {
597: int a;
598:
599: __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
600: return a;
601: }
602:
603: void
604: openpic_do_pending_int()
605: {
606: struct intrhand *ih;
607: int irq;
608: int pcpl;
609: int hwpend;
610: int s;
611: static int processing;
612:
613: if (processing)
614: return;
615:
616: processing = 1;
617: pcpl = splhigh(); /* Turn off all */
618: s = ppc_intr_disable();
619:
620: hwpend = ipending & ~pcpl; /* Do now unmasked pendings */
621: imen &= ~hwpend;
622: openpic_enable_irq_mask(~imen);
623:
624: hwpend &= HWIRQ_MASK;
625: while (hwpend) {
626: irq = 31 - cntlzw(hwpend);
627: hwpend &= ~(1L << irq);
628: ih = intrhand[irq];
629: while (ih) {
630: if ((*ih->ih_fun)(ih->ih_arg))
631: ih->ih_count.ec_count++;
632: ih = ih->ih_next;
633: }
634: }
635:
636: do {
637: if ((ipending & SINT_CLOCK) & ~pcpl) {
638: ipending &= ~SINT_CLOCK;
639: softclock();
640: }
641: if ((ipending & SINT_NET) & ~pcpl) {
642: extern int netisr;
643: int pisr;
644:
645: ipending &= ~SINT_NET;
646: while ((pisr = netisr) != 0) {
647: atomic_clearbits_int(&netisr, pisr);
648: softnet(pisr);
649: }
650: }
651: #if 0
652: if ((ipending & SINT_TTY) & ~pcpl) {
653: ipending &= ~SINT_TTY;
654: softtty();
655: }
656: #endif
657: } while (ipending & (SINT_NET|SINT_CLOCK/*|SINT_TTY*/) & ~cpl);
658: ipending &= pcpl;
659: cpl = pcpl; /* Don't use splx... we are here already! */
660:
661: #if 0
662: i8259_set_irq_mask();
663: #endif
664:
665: ppc_intr_enable(s);
666: processing = 0;
667: }
668:
669: u_int
670: openpic_read(reg)
671: int reg;
672: {
673: char *addr = (void *)(openpic_base + reg);
674:
675: return in32rb(addr);
676: }
677:
678: void
679: openpic_write(reg, val)
680: int reg;
681: u_int val;
682: {
683: char *addr = (void *)(openpic_base + reg);
684:
685: out32rb(addr, val);
686: }
687:
688: void
689: openpic_enable_irq_mask(irq_mask)
690: int irq_mask;
691: {
692: int irq, hirq;
693:
694: for (irq = 0; irq <= virq_max; irq++) {
695: hirq = hwirq[irq];
696: if (hirq < 0)
697: continue;
698:
699: if (irq_mask & (1 << irq)) {
700: if (hirq >= PIC_OFFSET)
701: openpic_enable_irq(hirq, intrtype[irq]);
702: else
703: i8259_enable_irq(hirq, intrtype[irq]);
704: } else {
705: if (hirq >= PIC_OFFSET)
706: openpic_disable_irq(hirq);
707: else
708: i8259_disable_irq(hirq);
709: }
710: }
711:
712: i8259_set_irq_mask();
713: }
714:
715: void
716: openpic_enable_irq(irq, type)
717: int irq;
718: int type;
719: {
720: u_int x, isrc;
721:
722: #ifdef DIAGNOSTIC
723: /* skip invalid irqs */
724: if (irq < PIC_OFFSET)
725: panic("openpic_enable_irq: invalid irq %x", irq);
726: #endif
727: irq -= PIC_OFFSET;
728:
729: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
730:
731: isrc = x & ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL |
732: OPENPIC_POLARITY_POSITIVE | OPENPIC_ACTIVITY);
733: if (irq == 0)
734: isrc |= OPENPIC_POLARITY_POSITIVE;
735: if (type == IST_LEVEL)
736: isrc |= OPENPIC_SENSE_LEVEL;
737: else
738: isrc |= OPENPIC_SENSE_EDGE;
739:
740: /* Ack all pending interrupts if this one is pending. */
741: while (x & OPENPIC_ACTIVITY) {
742: (void)openpic_iack(0);
743: openpic_eoi(0);
744: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
745: }
746:
747: if (x != isrc)
748: openpic_write(OPENPIC_SRC_VECTOR(irq), isrc);
749: }
750:
751: void
752: openpic_disable_irq(irq)
753: int irq;
754: {
755: u_int x;
756:
757: /* skip invalid irqs */
758: if (irq >= PIC_OFFSET)
759: irq -= PIC_OFFSET;
760:
761: x = openpic_read(OPENPIC_SRC_VECTOR(irq));
762: x |= OPENPIC_IMASK;
763: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
764: }
765:
766: void
767: i8259_set_irq_mask(void)
768: {
769: if (icu2_val != 0xff) {
770: /* Turn on the second IC */
771: icu1_val &= ~(1 << IRQ_SLAVE);
772: } else {
773: icu1_val |= (1 << IRQ_SLAVE);
774: }
775:
776: outb(IO_ICU1 + 1, icu1_val);
777: outb(IO_ICU2 + 1, icu2_val);
778: outb(IO_ELCR1, elcr1_val);
779: outb(IO_ELCR2, elcr2_val);
780: }
781:
782: void
783: i8259_disable_irq(irq)
784: int irq;
785: {
786: #ifdef DIAGNOSTIC
787: /* skip invalid irqs */
788: if (irq < 0 || irq >= PIC_OFFSET)
789: panic("i8259_disable_irq: invalid irq %x", irq);
790: #endif
791:
792: if (irq < 8) {
793: icu1_val |= 1 << irq;
794: elcr1_val &= ~(1 << irq);
795: } else {
796: irq -= 8;
797: icu2_val |= 1 << irq;
798: elcr2_val &= ~(1 << irq);
799: }
800: }
801:
802: void
803: i8259_enable_irq(irq, type)
804: int irq, type;
805: {
806: #ifdef DIAGNOSTIC
807: /* skip invalid irqs */
808: if (irq < 0 || irq >= PIC_OFFSET)
809: panic("i8259_enable_irq: invalid irq %x", irq);
810: #endif
811:
812: if (irq < 8) {
813: icu1_val &= ~(1 << irq);
814: if (type == IST_LEVEL)
815: elcr1_val |= (1 << irq);
816: else
817: elcr1_val &= ~(1 << irq);
818: } else {
819: irq -= 8;
820: icu2_val &= ~(1 << irq);
821: if (type == IST_LEVEL)
822: elcr2_val |= (1 << irq);
823: else
824: elcr2_val &= ~(1 << irq);
825: }
826: }
827:
828: void
829: i8259_eoi(int irq)
830: {
831: #ifdef DIAGNOSTIC
832: /* skip invalid irqs */
833: if (irq < 0 || irq >= PIC_OFFSET)
834: panic("i8259_eoi: invalid irq %x", irq);
835: #endif
836:
837: if (irq < 8)
838: outb(IO_ICU1, 0x60 | irq);
839: else {
840: outb(IO_ICU2, 0x60 | (irq - 8));
841: /*
842: * Do not ack on the master unless there are no
843: * other interrupts pending on the slave
844: * controller!
845: */
846: outb(IO_ICU2, 0x0b);
847: if (inb(IO_ICU2) == 0)
848: outb(IO_ICU1, 0x60 | IRQ_SLAVE);
849: }
850: }
851:
852: void
853: openpic_set_priority(cpu, pri)
854: int cpu, pri;
855: {
856: u_int x;
857:
858: x = openpic_read(OPENPIC_CPU_PRIORITY(cpu));
859: x &= ~OPENPIC_CPU_PRIORITY_MASK;
860: x |= pri;
861: openpic_write(OPENPIC_CPU_PRIORITY(cpu), x);
862: }
863:
864: int
865: openpic_iack(cpu)
866: int cpu;
867: {
868: return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
869: }
870:
871: void
872: openpic_eoi(cpu)
873: int cpu;
874: {
875: openpic_write(OPENPIC_EOI(cpu), 0);
876: openpic_read(OPENPIC_EOI(cpu));
877: }
878:
879: void
880: i8259_init(void)
881: {
882: /* initialize 8259's */
883: outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
884: outb(IO_ICU1+1, ICU_OFFSET); /* starting at this vector index */
885: outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
886: outb(IO_ICU1+1, 1); /* 8086 mode */
887: outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
888: /* init interrupt controller 2 */
889: outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
890: outb(IO_ICU2+1, ICU_OFFSET+8); /* staring at this vector index */
891: outb(IO_ICU2+1, IRQ_SLAVE);
892: outb(IO_ICU2+1, 1); /* 8086 mode */
893: outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
894: }
895:
896: int
897: i8259_intr(void)
898: {
899: int irq;
900:
901: /*
902: * Perform an interrupt acknowledge cycle on controller 1
903: */
904: outb(IO_ICU1, 0x0c);
905: irq = inb(IO_ICU1) & 7;
906:
907: if (irq == IRQ_SLAVE) {
908: /*
909: * Interrupt is cascaded so perform interrupt
910: * acknowledge on controller 2
911: */
912: outb(IO_ICU2, 0x0c);
913: irq = (inb(IO_ICU2) & 7) + 8;
914: if (irq == 15) {
915: outb(IO_ICU2, 0x0b);
916: if ((inb(IO_ICU2) & 0x80) == 0) {
917: #ifdef DIAGNOSTIC
918: printf("spurious interrupt on ICU2\n");
919: #endif
920: return PIC_SPURIOUS;
921: }
922: }
923: } else if (irq == 7) {
924: /*
925: * This may be a spurious interrupt
926: *
927: * Read the interrupt status register. If the most
928: * significant bit is not set then there is no valid
929: * interrupt
930: */
931: outb(IO_ICU1, 0x0b);
932: if ((inb(IO_ICU1) & 0x80) == 0) {
933: #ifdef DIAGNOSTIC
934: printf("spurious interrupt on ICU1\n");
935: #endif
936: return PIC_SPURIOUS;
937: }
938: }
939:
940: return (ICU_OFFSET + irq);
941: }
942:
943: void
944: ext_intr_openpic()
945: {
946: int irq, realirq;
947: int r_imen;
948: int pcpl, ocpl;
949: struct intrhand *ih;
950:
951: pcpl = cpl;
952:
953: realirq = openpic_iack(0);
954:
955: while (realirq != PIC_SPURIOUS) {
956: if (realirq == 0x00) {
957: /*
958: * Interrupt from the PCI/ISA bridge. PCI interrupts
959: * are shadowed on the ISA PIC for compatibility with
960: * MVME1600, so simply handle the ISA PIC.
961: */
962: realirq = i8259_intr();
963: openpic_eoi(0);
964: if (realirq == PIC_SPURIOUS)
965: break;
966: } else {
967: realirq += PIC_OFFSET;
968: }
969:
970: irq = virq[realirq];
971:
972: /* XXX check range */
973:
974: r_imen = 1 << irq;
975:
976: if ((pcpl & r_imen) != 0) {
977: ipending |= r_imen; /* Masked! Mark this as pending */
978: if (realirq >= PIC_OFFSET) {
979: openpic_disable_irq(realirq);
980: openpic_eoi(0);
981: } else {
982: i8259_disable_irq(realirq);
983: i8259_set_irq_mask();
984: i8259_eoi(realirq);
985: }
986: } else {
987: if (realirq >= PIC_OFFSET) {
988: openpic_disable_irq(realirq);
989: } else {
990: i8259_disable_irq(realirq);
991: i8259_set_irq_mask();
992: }
993:
994: ocpl = splraise(intrmask[irq]);
995:
996: ih = intrhand[irq];
997: while (ih) {
998: if ((*ih->ih_fun)(ih->ih_arg))
999: ih->ih_count.ec_count++;
1000: ih = ih->ih_next;
1001: }
1002:
1003: uvmexp.intrs++;
1004: __asm__ volatile("":::"memory");
1005: cpl = ocpl;
1006: __asm__ volatile("":::"memory");
1007:
1008: if (realirq >= PIC_OFFSET) {
1009: openpic_eoi(0);
1010: openpic_enable_irq(realirq, intrtype[irq]);
1011: } else {
1012: i8259_eoi(realirq);
1013: i8259_enable_irq(realirq, intrtype[irq]);
1014: i8259_set_irq_mask();
1015: }
1016: }
1017:
1018: realirq = openpic_iack(0);
1019: }
1020: ppc_intr_enable(1);
1021:
1022: splx(pcpl); /* Process pendings. */
1023: }
1024:
1025: void
1026: openpic_initirq(int irq, int pol, int sense)
1027: {
1028: u_int x;
1029:
1030: x = (irq & OPENPIC_VECTOR_MASK);
1031: x |= OPENPIC_IMASK;
1032: x |= (pol ? OPENPIC_POLARITY_POSITIVE : OPENPIC_POLARITY_NEGATIVE);
1033: x |= (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE);
1034: x |= 8 << OPENPIC_PRIORITY_SHIFT;
1035: openpic_write(OPENPIC_SRC_VECTOR(irq), x);
1036: }
1037:
1038: void
1039: openpic_init()
1040: {
1041: int irq;
1042: u_int x;
1043:
1044: /* disable all interrupts and init hwirq[] */
1045: for (irq = 0; irq < ICU_LEN; irq++) {
1046: hwirq[irq] = -1;
1047: intrtype[irq] = IST_NONE;
1048: intrmask[irq] = 0;
1049: intrlevel[irq] = 0;
1050: intrhand[irq] = NULL;
1051: openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
1052: }
1053: openpic_set_priority(0, 15);
1054:
1055: /* we don't need 8259 pass through mode */
1056: x = openpic_read(OPENPIC_CONFIG);
1057: x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
1058: openpic_write(OPENPIC_CONFIG, x);
1059:
1060: /* send all interrupts to cpu 0 */
1061: for (irq = 0; irq < ICU_LEN; irq++)
1062: openpic_write(OPENPIC_SRC_DEST(irq), CPU(0));
1063:
1064: /* special case for intr src 0 */
1065: openpic_initirq(0, 1, 0);
1066: for (irq = 1; irq < ICU_LEN; irq++) {
1067: openpic_initirq(irq, 0, 1);
1068: }
1069:
1070: /* XXX set spurious intr vector */
1071: #if 0
1072: openpic_write(OPENPIC_SPURIOUS_VECTOR, 0xFF);
1073: #endif
1074:
1075: /* unmask interrupts for cpu 0 */
1076: openpic_set_priority(0, 0);
1077:
1078: /* clear all pending interrunts */ /* < ICU_LEN ? */
1079: for (irq = 0; irq < PIC_OFFSET; irq++) {
1080: openpic_iack(0);
1081: openpic_eoi(0);
1082: }
1083:
1084: for (irq = 0; irq < PIC_OFFSET; irq++) { /* < ICU_LEN ? */
1085: i8259_disable_irq(irq);
1086: openpic_disable_irq(irq);
1087: }
1088:
1089: i8259_set_irq_mask();
1090:
1091: install_extint(ext_intr_openpic);
1092: }
CVSweb