Annotation of sys/arch/macppc/dev/macintr.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: macintr.c,v 1.33 2007/05/29 18:10:42 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:
56: #include <dev/ofw/openfirm.h>
57:
58: #define ICU_LEN 64
59: #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
60:
61: int m_intrtype[ICU_LEN], m_intrmask[ICU_LEN], m_intrlevel[ICU_LEN];
62: struct intrhand *m_intrhand[ICU_LEN];
63: int m_hwirq[ICU_LEN], m_virq[64];
64: unsigned int imen_m = 0xffffffff;
65: int m_virq_max = 0;
66:
67: static int fakeintr(void *);
68: static char *intr_typename(int type);
69: static void intr_calculatemasks(void);
70: static void enable_irq(int x);
71: static __inline int cntlzw(int x);
72: static int mapirq(int irq);
73: static int read_irq(void);
74: static void mac_intr_do_pending_int(void);
75:
76: extern u_int32_t *heathrow_FCR;
77:
78: #define HWIRQ_MAX 27
79: #define HWIRQ_MASK 0x0fffffff
80:
81: #define INT_STATE_REG0 (interrupt_reg + 0x20)
82: #define INT_ENABLE_REG0 (interrupt_reg + 0x24)
83: #define INT_CLEAR_REG0 (interrupt_reg + 0x28)
84: #define INT_LEVEL_REG0 (interrupt_reg + 0x2c)
85: #define INT_STATE_REG1 (INT_STATE_REG0 - 0x10)
86: #define INT_ENABLE_REG1 (INT_ENABLE_REG0 - 0x10)
87: #define INT_CLEAR_REG1 (INT_CLEAR_REG0 - 0x10)
88: #define INT_LEVEL_REG1 (INT_LEVEL_REG0 - 0x10)
89:
90: struct macintr_softc {
91: struct device sc_dev;
92: };
93:
94: int macintr_match(struct device *parent, void *cf, void *aux);
95: void macintr_attach(struct device *, struct device *, void *);
96: void mac_do_pending_int(void);
97: void mac_ext_intr(void);
98:
99: struct cfattach macintr_ca = {
100: sizeof(struct macintr_softc),
101: macintr_match,
102: macintr_attach
103: };
104:
105: struct cfdriver macintr_cd = {
106: NULL, "macintr", DV_DULL
107: };
108:
109: int
110: macintr_match(struct device *parent, void *cf, void *aux)
111: {
112: struct confargs *ca = aux;
113: char type[40];
114:
115: /*
116: * Match entry according to "present" openfirmware entry.
117: */
118: if (strcmp(ca->ca_name, "interrupt-controller") == 0 ) {
119: OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
120: if (strcmp(type, "interrupt-controller") == 0)
121: return 1;
122: }
123:
124: /*
125: * Check name for legacy interrupt controller, this is
126: * faked to allow old firmware which does not have an entry
127: * to attach to this device.
128: */
129: if (strcmp(ca->ca_name, "legacy-interrupt-controller") == 0 )
130: return 1;
131: return 0;
132: }
133:
134: u_int8_t *interrupt_reg;
135: typedef void (void_f) (void);
136: extern void_f *pending_int_f;
137: int macintr_prog_button (void *arg);
138:
139: intr_establish_t macintr_establish;
140: intr_disestablish_t macintr_disestablish;
141: extern intr_establish_t *mac_intr_establish_func;
142: extern intr_disestablish_t *mac_intr_disestablish_func;
143: void macintr_collect_preconf_intr(void);
144:
145: void
146: macintr_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:
152: interrupt_reg = (void *)mapiodev(ca->ca_baseaddr,0x100); /* XXX */
153:
154: install_extint(mac_ext_intr);
155: pending_int_f = mac_intr_do_pending_int;
156: intr_establish_func = macintr_establish;
157: intr_disestablish_func = macintr_disestablish;
158: mac_intr_establish_func = macintr_establish;
159: mac_intr_disestablish_func = macintr_disestablish;
160:
161: macintr_collect_preconf_intr();
162:
163: mac_intr_establish(parent, 0x14, IST_LEVEL, IPL_HIGH,
164: macintr_prog_button, (void *)0x14, "progbutton");
165:
166: ppc_intr_enable(1);
167:
168: printf("\n");
169: }
170:
171: void
172: macintr_collect_preconf_intr()
173: {
174: int i;
175: for (i = 0; i < ppc_configed_intr_cnt; i++) {
176: #ifdef DEBUG
177: printf("\n\t%s irq %d level %d fun %p arg %p",
178: ppc_configed_intr[i].ih_what,
179: ppc_configed_intr[i].ih_irq,
180: ppc_configed_intr[i].ih_level,
181: ppc_configed_intr[i].ih_fun,
182: ppc_configed_intr[i].ih_arg
183: );
184: #endif
185: macintr_establish(NULL,
186: ppc_configed_intr[i].ih_irq,
187: IST_LEVEL,
188: ppc_configed_intr[i].ih_level,
189: ppc_configed_intr[i].ih_fun,
190: ppc_configed_intr[i].ih_arg,
191: ppc_configed_intr[i].ih_what);
192: }
193: }
194:
195:
196: /*
197: * programmer_button function to fix args to Debugger.
198: * deal with any enables/disables, if necessary.
199: */
200: int
201: macintr_prog_button (void *arg)
202: {
203: #ifdef DDB
204: if (db_console)
205: Debugger();
206: #else
207: printf("programmer button pressed, debugger not available\n");
208: #endif
209: return 1;
210: }
211:
212: static int
213: fakeintr(void *arg)
214: {
215:
216: return 0;
217: }
218:
219: /*
220: * Register an interrupt handler.
221: */
222: void *
223: macintr_establish(void * lcv, int irq, int type, int level,
224: int (*ih_fun)(void *), void *ih_arg, char *name)
225: {
226: struct intrhand **p, *q, *ih;
227: static struct intrhand fakehand;
228:
229: fakehand.ih_next = NULL;
230: fakehand.ih_fun = fakeintr;
231:
232: #if 0
233: printf("macintr_establish, hI %d L %d ", irq, type);
234: printf("addr reg0 %x\n", INT_STATE_REG0);
235: #endif
236: irq = mapirq(irq);
237: #if 0
238: printf("vI %d ", irq);
239: #endif
240:
241: /* no point in sleeping unless someone can free memory. */
242: ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
243: if (ih == NULL)
244: panic("intr_establish: can't malloc handler info");
245:
246: if (!LEGAL_IRQ(irq) || type == IST_NONE)
247: panic("intr_establish: bogus irq or type");
248:
249: switch (m_intrtype[irq]) {
250: case IST_NONE:
251: m_intrtype[irq] = type;
252: break;
253: case IST_EDGE:
254: case IST_LEVEL:
255: if (type == m_intrtype[irq])
256: break;
257: case IST_PULSE:
258: if (type != IST_NONE)
259: panic("intr_establish: can't share %s with %s",
260: intr_typename(m_intrtype[irq]),
261: intr_typename(type));
262: break;
263: }
264:
265: /*
266: * Figure out where to put the handler.
267: * This is O(N^2), but we want to preserve the order, and N is
268: * generally small.
269: */
270: for (p = &m_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
271: ;
272:
273: /*
274: * Actually install a fake handler momentarily, since we might be doing
275: * this with interrupts enabled and DON'T WANt the real routine called
276: * until masking is set up.
277: */
278: fakehand.ih_level = level;
279: *p = &fakehand;
280:
281: intr_calculatemasks();
282:
283: /*
284: * Poke the real handler in now.
285: */
286: ih->ih_fun = ih_fun;
287: ih->ih_arg = ih_arg;
288: ih->ih_next = NULL;
289: ih->ih_level = level;
290: ih->ih_irq = irq;
291: evcount_attach(&ih->ih_count, name, (void *)&m_hwirq[irq],
292: &evcount_intr);
293: *p = ih;
294:
295: return (ih);
296: }
297:
298: /*
299: * Deregister an interrupt handler.
300: */
301: void
302: macintr_disestablish(void *lcp, void *arg)
303: {
304: struct intrhand *ih = arg;
305: int irq = ih->ih_irq;
306: struct intrhand **p, *q;
307:
308: if (!LEGAL_IRQ(irq))
309: panic("intr_disestablish: bogus irq");
310:
311: /*
312: * Remove the handler from the chain.
313: * This is O(n^2), too.
314: */
315: for (p = &m_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
316: ;
317: if (q)
318: *p = q->ih_next;
319: else
320: panic("intr_disestablish: handler not registered");
321:
322: evcount_detach(&ih->ih_count);
323: free((void *)ih, M_DEVBUF);
324:
325: intr_calculatemasks();
326:
327: if (m_intrhand[irq] == NULL)
328: m_intrtype[irq] = IST_NONE;
329: }
330:
331:
332: static char *
333: intr_typename(int type)
334: {
335: switch (type) {
336: case IST_NONE :
337: return ("none");
338: case IST_PULSE:
339: return ("pulsed");
340: case IST_EDGE:
341: return ("edge-triggered");
342: case IST_LEVEL:
343: return ("level-triggered");
344: default:
345: panic("intr_typename: invalid type %d", type);
346: #if 1 /* XXX */
347: return ("unknown");
348: #endif
349: }
350: }
351: /*
352: * Recalculate the interrupt masks from scratch.
353: * We could code special registry and deregistry versions of this function that
354: * would be faster, but the code would be nastier, and we don't expect this to
355: * happen very much anyway.
356: */
357: static void
358: intr_calculatemasks()
359: {
360: int irq, level;
361: struct intrhand *q;
362:
363: /* First, figure out which levels each IRQ uses. */
364: for (irq = 0; irq < ICU_LEN; irq++) {
365: register int levels = 0;
366: for (q = m_intrhand[irq]; q; q = q->ih_next)
367: levels |= 1 << q->ih_level;
368: m_intrlevel[irq] = levels;
369: }
370:
371: /* Then figure out which IRQs use each level. */
372: for (level = IPL_NONE; level < IPL_NUM; level++) {
373: register int irqs = 0;
374: for (irq = 0; irq < ICU_LEN; irq++)
375: if (m_intrlevel[irq] & (1 << level))
376: irqs |= 1 << irq;
377: imask[level] = irqs | SINT_MASK;
378: }
379:
380: /*
381: * There are tty, network and disk drivers that use free() at interrupt
382: * time, so vm > (tty | net | bio).
383: *
384: * Enforce a hierarchy that gives slow devices a better chance at not
385: * dropping data.
386: */
387: imask[IPL_NET] |= imask[IPL_BIO];
388: imask[IPL_TTY] |= imask[IPL_NET];
389: imask[IPL_VM] |= imask[IPL_TTY];
390: imask[IPL_CLOCK] |= imask[IPL_VM] | SPL_CLOCK;
391:
392: /*
393: * These are pseudo-levels.
394: */
395: imask[IPL_NONE] = 0x00000000;
396: imask[IPL_HIGH] = 0xffffffff;
397:
398: /* And eventually calculate the complete masks. */
399: for (irq = 0; irq < ICU_LEN; irq++) {
400: register int irqs = 1 << irq;
401: for (q = m_intrhand[irq]; q; q = q->ih_next)
402: irqs |= imask[q->ih_level];
403: m_intrmask[irq] = irqs | SINT_MASK;
404: }
405:
406: /* Lastly, determine which IRQs are actually in use. */
407: {
408: register int irqs = 0;
409: for (irq = 0; irq < ICU_LEN; irq++) {
410: if (m_intrhand[irq])
411: irqs |= 1 << irq;
412: }
413: imen_m = ~irqs;
414: enable_irq(~imen_m);
415: }
416: }
417: static void
418: enable_irq(int x)
419: {
420: int state0, state1, v;
421: int irq;
422:
423: x &= HWIRQ_MASK; /* XXX Higher bits are software interrupts. */
424:
425: state0 = state1 = 0;
426: while (x) {
427: v = 31 - cntlzw(x);
428: irq = m_hwirq[v];
429: if (irq < 32)
430: state0 |= 1 << irq;
431: else
432: state1 |= 1 << (irq - 32);
433:
434: x &= ~(1 << v);
435: }
436:
437: if (heathrow_FCR)
438: out32rb(INT_ENABLE_REG1, state1);
439:
440: out32rb(INT_ENABLE_REG0, state0);
441: }
442:
443: int m_virq_inited = 0;
444:
445: /*
446: * Map 64 irqs into 32 (bits).
447: */
448: static int
449: mapirq(int irq)
450: {
451: int v;
452: int i;
453:
454: if (m_virq_inited == 0) {
455: m_virq_max = 0;
456: for (i = 0; i < ICU_LEN; i++) {
457: m_virq[i] = 0;
458: }
459: m_virq_inited = 1;
460: }
461:
462: /* irq in table already? */
463: if (m_virq[irq] != 0)
464: return m_virq[irq];
465:
466: if (irq < 0 || irq >= 64)
467: panic("invalid irq %d", irq);
468: m_virq_max++;
469: v = m_virq_max;
470: if (v > HWIRQ_MAX)
471: panic("virq overflow");
472:
473: m_hwirq[v] = irq;
474: m_virq[irq] = v;
475: #if 0
476: printf("\nmapirq %x to %x\n", irq, v);
477: #endif
478:
479: return v;
480: }
481:
482: /*
483: * Count leading zeros.
484: */
485: static __inline int
486: cntlzw(int x)
487: {
488: int a;
489:
490: __asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
491:
492: return a;
493: }
494:
495: /*
496: * external interrupt handler
497: */
498: void
499: mac_ext_intr()
500: {
501: int irq = 0;
502: int o_imen, r_imen;
503: int pcpl;
504: struct cpu_info *ci = curcpu();
505: struct intrhand *ih;
506: volatile unsigned long int_state;
507:
508: pcpl = ci->ci_cpl; /* Turn off all */
509:
510: int_state = read_irq();
511: if (int_state == 0)
512: goto out;
513:
514: start:
515: irq = 31 - cntlzw(int_state);
516:
517: o_imen = imen_m;
518: r_imen = 1 << irq;
519:
520: if ((ci->ci_cpl & r_imen) != 0) {
521: /* Masked! Mark this as pending. */
522: ci->ci_ipending |= r_imen;
523: imen_m |= r_imen;
524: enable_irq(~imen_m);
525: } else {
526: splraise(m_intrmask[irq]);
527:
528: ih = m_intrhand[irq];
529: while (ih) {
530: if ((*ih->ih_fun)(ih->ih_arg))
531: ih->ih_count.ec_count++;
532: ih = ih->ih_next;
533: }
534:
535: uvmexp.intrs++;
536: }
537: int_state &= ~r_imen;
538: if (int_state)
539: goto start;
540:
541: out:
542: splx(pcpl); /* Process pendings. */
543: }
544:
545: void
546: mac_intr_do_pending_int()
547: {
548: struct cpu_info *ci = curcpu();
549: struct intrhand *ih;
550: int irq;
551: int pcpl;
552: int hwpend;
553: int s;
554:
555: if (ci->ci_iactive)
556: return;
557:
558: ci->ci_iactive = 1;
559: pcpl = splhigh(); /* Turn off all */
560: s = ppc_intr_disable();
561:
562: hwpend = ci->ci_ipending & ~pcpl; /* Do now unmasked pendings */
563: imen_m &= ~hwpend;
564: enable_irq(~imen_m);
565: hwpend &= HWIRQ_MASK;
566: while (hwpend) {
567: irq = 31 - cntlzw(hwpend);
568: hwpend &= ~(1L << irq);
569: ih = m_intrhand[irq];
570: while(ih) {
571: if ((*ih->ih_fun)(ih->ih_arg))
572: ih->ih_count.ec_count++;
573: ih = ih->ih_next;
574: }
575: }
576:
577: /*out32rb(INT_ENABLE_REG, ~imen_m);*/
578:
579: do {
580: if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) {
581: ci->ci_ipending &= ~SINT_CLOCK;
582: softclock();
583: }
584: if((ci->ci_ipending & SINT_NET) & ~pcpl) {
585: extern int netisr;
586: int pisr;
587:
588: ci->ci_ipending &= ~SINT_NET;
589: while ((pisr = netisr) != 0) {
590: atomic_clearbits_int(&netisr, pisr);
591: softnet(pisr);
592: }
593: }
594: if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
595: ci->ci_ipending &= ~SINT_TTY;
596: softtty();
597: }
598: } while ((ci->ci_ipending & SINT_MASK) & ~pcpl);
599: ci->ci_ipending &= pcpl;
600: ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
601: ppc_intr_enable(s);
602: ci->ci_iactive = 0;
603: }
604:
605: static int
606: read_irq()
607: {
608: int rv = 0;
609: int state0, state1, p;
610: int state0save, state1save;
611:
612: state0 = in32rb(INT_STATE_REG0);
613: if (state0)
614: out32rb(INT_CLEAR_REG0, state0);
615: state0save = state0;
616: while (state0) {
617: p = 31 - cntlzw(state0);
618: rv |= 1 << m_virq[p];
619: state0 &= ~(1 << p);
620: }
621:
622: if (heathrow_FCR) /* has heathrow? */
623: state1 = in32rb(INT_STATE_REG1);
624: else
625: state1 = 0;
626:
627: if (state1)
628: out32rb(INT_CLEAR_REG1, state1);
629: state1save = state1;
630: while (state1) {
631: p = 31 - cntlzw(state1);
632: rv |= 1 << m_virq[p + 32];
633: state1 &= ~(1 << p);
634: }
635: #if 0
636: printf("mac_intr int_stat 0:%x 1:%x\n", state0save, state1save);
637: #endif
638:
639: /* 1 << 0 is invalid. */
640: return rv & ~1;
641: }
CVSweb