Annotation of sys/arch/alpha/pci/sio_pic.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sio_pic.c,v 1.26 2006/06/15 20:08:29 brad Exp $ */
2: /* $NetBSD: sio_pic.c,v 1.28 2000/06/06 03:10:13 thorpej Exp $ */
3:
4: /*-
5: * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center.
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. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * Copyright (c) 1995, 1996 Carnegie-Mellon University.
43: * All rights reserved.
44: *
45: * Author: Chris G. Demetriou
46: *
47: * Permission to use, copy, modify and distribute this software and
48: * its documentation is hereby granted, provided that both the copyright
49: * notice and this permission notice appear in all copies of the
50: * software, derivative works or modified versions, and any portions
51: * thereof, and that both notices appear in supporting documentation.
52: *
53: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
54: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
55: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
56: *
57: * Carnegie Mellon requests users of this software to return to
58: *
59: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
60: * School of Computer Science
61: * Carnegie Mellon University
62: * Pittsburgh PA 15213-3890
63: *
64: * any improvements or extensions that they make and grant Carnegie the
65: * rights to redistribute these changes.
66: */
67:
68: #include <sys/param.h>
69: #include <sys/systm.h>
70:
71: #include <sys/device.h>
72: #include <sys/malloc.h>
73: #include <sys/syslog.h>
74:
75: #include <machine/intr.h>
76: #include <machine/bus.h>
77:
78: #include <dev/pci/pcireg.h>
79: #include <dev/pci/pcivar.h>
80: #include <dev/pci/pcidevs.h>
81:
82: #include <dev/pci/cy82c693reg.h>
83: #include <dev/pci/cy82c693var.h>
84:
85: #include <dev/isa/isareg.h>
86: #include <dev/isa/isavar.h>
87: #include <alpha/pci/siovar.h>
88:
89: #include "sio.h"
90:
91: /*
92: * To add to the long history of wonderful PROM console traits,
93: * AlphaStation PROMs don't reset themselves completely on boot!
94: * Therefore, if an interrupt was turned on when the kernel was
95: * started, we're not going to EVER turn it off... I don't know
96: * what will happen if new interrupts (that the PROM console doesn't
97: * want) are turned on. I'll burn that bridge when I come to it.
98: */
99: #define BROKEN_PROM_CONSOLE
100:
101: /*
102: * Private functions and variables.
103: */
104:
105: bus_space_tag_t sio_iot;
106: pci_chipset_tag_t sio_pc;
107: bus_space_handle_t sio_ioh_icu1, sio_ioh_icu2;
108:
109: #define ICU_LEN 16 /* number of ISA IRQs */
110:
111: static struct alpha_shared_intr *sio_intr;
112:
113: #ifndef STRAY_MAX
114: #define STRAY_MAX 5
115: #endif
116:
117: #ifdef BROKEN_PROM_CONSOLE
118: /*
119: * If prom console is broken, must remember the initial interrupt
120: * settings and enforce them. WHEE!
121: */
122: u_int8_t initial_ocw1[2];
123: u_int8_t initial_elcr[2];
124: #endif
125:
126: void sio_setirqstat(int, int, int);
127: int sio_intr_alloc(void *, int, int, int *);
128:
129: u_int8_t (*sio_read_elcr)(int);
130: void (*sio_write_elcr)(int, u_int8_t);
131: static void specific_eoi(int);
132: #ifdef BROKEN_PROM_CONSOLE
133: void sio_intr_shutdown(void *);
134: #endif
135:
136: /******************** i82378 SIO ELCR functions ********************/
137:
138: int i82378_setup_elcr(void);
139: u_int8_t i82378_read_elcr(int);
140: void i82378_write_elcr(int, u_int8_t);
141:
142: bus_space_handle_t sio_ioh_elcr;
143:
144: int
145: i82378_setup_elcr()
146: {
147: int rv;
148:
149: /*
150: * We could probe configuration space to see that there's
151: * actually an SIO present, but we are using this as a
152: * fall-back in case nothing else matches.
153: */
154:
155: rv = bus_space_map(sio_iot, 0x4d0, 2, 0, &sio_ioh_elcr);
156:
157: if (rv == 0) {
158: sio_read_elcr = i82378_read_elcr;
159: sio_write_elcr = i82378_write_elcr;
160: }
161:
162: return (rv);
163: }
164:
165: u_int8_t
166: i82378_read_elcr(elcr)
167: int elcr;
168: {
169:
170: return (bus_space_read_1(sio_iot, sio_ioh_elcr, elcr));
171: }
172:
173: void
174: i82378_write_elcr(elcr, val)
175: int elcr;
176: u_int8_t val;
177: {
178:
179: bus_space_write_1(sio_iot, sio_ioh_elcr, elcr, val);
180: }
181:
182: /******************** Cypress CY82C693 ELCR functions ********************/
183:
184: int cy82c693_setup_elcr(void);
185: u_int8_t cy82c693_read_elcr(int);
186: void cy82c693_write_elcr(int, u_int8_t);
187:
188: const struct cy82c693_handle *sio_cy82c693_handle;
189:
190: int
191: cy82c693_setup_elcr()
192: {
193: int device, maxndevs;
194: pcitag_t tag;
195: pcireg_t id;
196:
197: /*
198: * Search PCI configuration space for a Cypress CY82C693.
199: *
200: * Note we can make some assumptions about our bus number
201: * here, because:
202: *
203: * (1) there can be at most one ISA/EISA bridge per PCI bus, and
204: *
205: * (2) any ISA/EISA bridges must be attached to primary PCI
206: * busses (i.e. bus zero).
207: */
208:
209: maxndevs = pci_bus_maxdevs(sio_pc, 0);
210:
211: for (device = 0; device < maxndevs; device++) {
212: tag = pci_make_tag(sio_pc, 0, device, 0);
213: id = pci_conf_read(sio_pc, tag, PCI_ID_REG);
214:
215: /* Invalid vendor ID value? */
216: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
217: continue;
218: /* XXX Not invalid, but we've done this ~forever. */
219: if (PCI_VENDOR(id) == 0)
220: continue;
221:
222: if (PCI_VENDOR(id) != PCI_VENDOR_CONTAQ ||
223: PCI_PRODUCT(id) != PCI_PRODUCT_CONTAQ_82C693)
224: continue;
225:
226: /*
227: * Found one!
228: */
229:
230: #if 0
231: printf("cy82c693_setup_elcr: found 82C693 at device %d\n",
232: device);
233: #endif
234:
235: sio_cy82c693_handle = cy82c693_init(sio_iot);
236: sio_read_elcr = cy82c693_read_elcr;
237: sio_write_elcr = cy82c693_write_elcr;
238:
239: return (0);
240: }
241:
242: /*
243: * Didn't find a CY82C693.
244: */
245: return (ENODEV);
246: }
247:
248: u_int8_t
249: cy82c693_read_elcr(elcr)
250: int elcr;
251: {
252:
253: return (cy82c693_read(sio_cy82c693_handle, CONFIG_ELCR1 + elcr));
254: }
255:
256: void
257: cy82c693_write_elcr(elcr, val)
258: int elcr;
259: u_int8_t val;
260: {
261:
262: cy82c693_write(sio_cy82c693_handle, CONFIG_ELCR1 + elcr, val);
263: }
264:
265: /******************** ELCR access function configuration ********************/
266:
267: /*
268: * Put the Intel SIO at the end, so we fall back on it if we don't
269: * find anything else. If any of the non-Intel functions find a
270: * matching device, but are unable to map it for whatever reason,
271: * they should panic.
272: */
273:
274: int (*sio_elcr_setup_funcs[])(void) = {
275: cy82c693_setup_elcr,
276: i82378_setup_elcr,
277: NULL,
278: };
279:
280: /******************** Shared SIO/Cypress functions ********************/
281:
282: void
283: sio_setirqstat(irq, enabled, type)
284: int irq, enabled;
285: int type;
286: {
287: u_int8_t ocw1[2], elcr[2];
288: int icu, bit;
289:
290: #if 0
291: printf("sio_setirqstat: irq %d: %s, %s\n", irq,
292: enabled ? "enabled" : "disabled", isa_intr_typename(type));
293: #endif
294:
295: icu = irq / 8;
296: bit = irq % 8;
297:
298: ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
299: ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
300: elcr[0] = (*sio_read_elcr)(0); /* XXX */
301: elcr[1] = (*sio_read_elcr)(1); /* XXX */
302:
303: /*
304: * interrupt enable: set bit to mask (disable) interrupt.
305: */
306: if (enabled)
307: ocw1[icu] &= ~(1 << bit);
308: else
309: ocw1[icu] |= 1 << bit;
310:
311: /*
312: * interrupt type select: set bit to get level-triggered.
313: */
314: if (type == IST_LEVEL)
315: elcr[icu] |= 1 << bit;
316: else
317: elcr[icu] &= ~(1 << bit);
318:
319: #ifdef not_here
320: /* see the init function... */
321: ocw1[0] &= ~0x04; /* always enable IRQ2 on first PIC */
322: elcr[0] &= ~0x07; /* IRQ[0-2] must be edge-triggered */
323: elcr[1] &= ~0x21; /* IRQ[13,8] must be edge-triggered */
324: #endif
325:
326: bus_space_write_1(sio_iot, sio_ioh_icu1, 1, ocw1[0]);
327: bus_space_write_1(sio_iot, sio_ioh_icu2, 1, ocw1[1]);
328: (*sio_write_elcr)(0, elcr[0]); /* XXX */
329: (*sio_write_elcr)(1, elcr[1]); /* XXX */
330: }
331:
332: void
333: sio_intr_setup(pc, iot)
334: pci_chipset_tag_t pc;
335: bus_space_tag_t iot;
336: {
337: #ifdef notyet
338: char *cp;
339: #endif
340: int i;
341:
342: sio_iot = iot;
343: sio_pc = pc;
344:
345: if (bus_space_map(sio_iot, IO_ICU1, 2, 0, &sio_ioh_icu1) ||
346: bus_space_map(sio_iot, IO_ICU2, 2, 0, &sio_ioh_icu2))
347: panic("sio_intr_setup: can't map ICU I/O ports");
348:
349: for (i = 0; sio_elcr_setup_funcs[i] != NULL; i++)
350: if ((*sio_elcr_setup_funcs[i])() == 0)
351: break;
352: if (sio_elcr_setup_funcs[i] == NULL)
353: panic("sio_intr_setup: can't map ELCR");
354:
355: #ifdef BROKEN_PROM_CONSOLE
356: /*
357: * Remember the initial values, so we can restore them later.
358: */
359: initial_ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
360: initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
361: initial_elcr[0] = (*sio_read_elcr)(0); /* XXX */
362: initial_elcr[1] = (*sio_read_elcr)(1); /* XXX */
363: shutdownhook_establish(sio_intr_shutdown, 0);
364: #endif
365:
366: sio_intr = alpha_shared_intr_alloc(ICU_LEN);
367:
368: /*
369: * set up initial values for interrupt enables.
370: */
371: for (i = 0; i < ICU_LEN; i++) {
372: alpha_shared_intr_set_maxstrays(sio_intr, i, STRAY_MAX);
373:
374: switch (i) {
375: case 0:
376: case 1:
377: case 8:
378: case 13:
379: /*
380: * IRQs 0, 1, 8, and 13 must always be
381: * edge-triggered.
382: */
383: sio_setirqstat(i, 0, IST_EDGE);
384: alpha_shared_intr_set_dfltsharetype(sio_intr, i,
385: IST_EDGE);
386: specific_eoi(i);
387: break;
388:
389: case 2:
390: /*
391: * IRQ 2 must be edge-triggered, and should be
392: * enabled (otherwise IRQs 8-15 are ignored).
393: */
394: sio_setirqstat(i, 1, IST_EDGE);
395: alpha_shared_intr_set_dfltsharetype(sio_intr, i,
396: IST_UNUSABLE);
397: break;
398:
399: default:
400: /*
401: * Otherwise, disable the IRQ and set its
402: * type to (effectively) "unknown."
403: */
404: sio_setirqstat(i, 0, IST_NONE);
405: alpha_shared_intr_set_dfltsharetype(sio_intr, i,
406: IST_NONE);
407: specific_eoi(i);
408: break;
409: }
410: }
411: }
412:
413: #ifdef BROKEN_PROM_CONSOLE
414: void
415: sio_intr_shutdown(arg)
416: void *arg;
417: {
418: /*
419: * Restore the initial values, to make the PROM happy.
420: */
421: bus_space_write_1(sio_iot, sio_ioh_icu1, 1, initial_ocw1[0]);
422: bus_space_write_1(sio_iot, sio_ioh_icu2, 1, initial_ocw1[1]);
423: (*sio_write_elcr)(0, initial_elcr[0]); /* XXX */
424: (*sio_write_elcr)(1, initial_elcr[1]); /* XXX */
425: }
426: #endif
427:
428: const char *
429: sio_intr_string(v, irq)
430: void *v;
431: int irq;
432: {
433: static char irqstr[12]; /* 8 + 2 + NULL + sanity */
434:
435: if (irq == 0 || irq >= ICU_LEN || irq == 2)
436: panic("sio_intr_string: bogus isa irq 0x%x", irq);
437:
438: snprintf(irqstr, sizeof irqstr, "isa irq %d", irq);
439: return (irqstr);
440: }
441:
442: int
443: sio_intr_line(v, irq)
444: void *v;
445: int irq;
446: {
447: return (irq);
448: }
449:
450: void *
451: sio_intr_establish(v, irq, type, level, fn, arg, name)
452: void *v, *arg;
453: int irq;
454: int type;
455: int level;
456: int (*fn)(void *);
457: char *name;
458: {
459: void *cookie;
460:
461: if (irq > ICU_LEN || type == IST_NONE)
462: panic("sio_intr_establish: bogus irq or type");
463:
464: cookie = alpha_shared_intr_establish(sio_intr, irq, type, level, fn,
465: arg, name);
466:
467: if (cookie != NULL &&
468: alpha_shared_intr_firstactive(sio_intr, irq)) {
469: scb_set(0x800 + SCB_IDXTOVEC(irq), sio_iointr, NULL);
470: sio_setirqstat(irq, 1,
471: alpha_shared_intr_get_sharetype(sio_intr, irq));
472: }
473:
474: return (cookie);
475: }
476:
477: void
478: sio_intr_disestablish(v, cookie)
479: void *v;
480: void *cookie;
481: {
482: struct alpha_shared_intrhand *ih = cookie;
483: int s, ist, irq = ih->ih_num;
484:
485: s = splhigh();
486:
487: /* Remove it from the link. */
488: alpha_shared_intr_disestablish(sio_intr, cookie, "isa irq");
489:
490: /*
491: * Decide if we should disable the interrupt. We must ensure
492: * that:
493: *
494: * - An initially-enabled interrupt is never disabled.
495: * - An initially-LT interrupt is never untyped.
496: */
497: if (alpha_shared_intr_isactive(sio_intr, irq) == 0) {
498: /*
499: * IRQs 0, 1, 8, and 13 must always be edge-triggered
500: * (see setup).
501: */
502: switch (irq) {
503: case 0:
504: case 1:
505: case 8:
506: case 13:
507: /*
508: * If the interrupt was initially level-triggered
509: * a warning was printed in setup.
510: */
511: ist = IST_EDGE;
512: break;
513:
514: default:
515: ist = IST_NONE;
516: break;
517: }
518: sio_setirqstat(irq, 0, ist);
519: alpha_shared_intr_set_dfltsharetype(sio_intr, irq, ist);
520:
521: /* Release our SCB vector. */
522: scb_free(0x800 + SCB_IDXTOVEC(irq));
523: }
524:
525: splx(s);
526: }
527:
528: void
529: sio_iointr(arg, vec)
530: void *arg;
531: unsigned long vec;
532: {
533: int irq;
534:
535: irq = SCB_VECTOIDX(vec - 0x800);
536:
537: #ifdef DIAGNOSTIC
538: if (irq >= ICU_LEN || irq < 0)
539: panic("sio_iointr: irq out of range (%d)", irq);
540: #endif
541:
542: if (!alpha_shared_intr_dispatch(sio_intr, irq))
543: alpha_shared_intr_stray(sio_intr, irq, "isa irq");
544: else
545: alpha_shared_intr_reset_strays(sio_intr, irq);
546:
547: /*
548: * Some versions of the machines which use the SIO
549: * (or is it some PALcode revisions on those machines?)
550: * require the non-specific EOI to be fed to the PIC(s)
551: * by the interrupt handler.
552: */
553: specific_eoi(irq);
554: }
555:
556: #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
557:
558: int
559: sio_intr_alloc(v, mask, type, irq)
560: void *v;
561: int mask;
562: int type;
563: int *irq;
564: {
565: int i, tmp, bestirq, count;
566: struct alpha_shared_intrhand **p, *q;
567:
568: if (type == IST_NONE)
569: panic("intr_alloc: bogus type");
570:
571: bestirq = -1;
572: count = -1;
573:
574: /* some interrupts should never be dynamically allocated */
575: mask &= 0xdef8;
576:
577: /*
578: * XXX some interrupts will be used later (6 for fdc, 12 for pms).
579: * the right answer is to do "breadth-first" searching of devices.
580: */
581: mask &= 0xefbf;
582:
583: for (i = 0; i < ICU_LEN; i++) {
584: if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
585: continue;
586:
587: switch(sio_intr[i].intr_sharetype) {
588: case IST_NONE:
589: /*
590: * if nothing's using the irq, just return it
591: */
592: *irq = i;
593: return (0);
594:
595: case IST_EDGE:
596: case IST_LEVEL:
597: if (type != sio_intr[i].intr_sharetype)
598: continue;
599: /*
600: * if the irq is shareable, count the number of other
601: * handlers, and if it's smaller than the last irq like
602: * this, remember it
603: *
604: * XXX We should probably also consider the
605: * interrupt level and stick IPL_TTY with other
606: * IPL_TTY, etc.
607: */
608: for (p = &TAILQ_FIRST(&sio_intr[i].intr_q), tmp = 0;
609: (q = *p) != NULL; p = &TAILQ_NEXT(q, ih_q), tmp++)
610: ;
611: if ((bestirq == -1) || (count > tmp)) {
612: bestirq = i;
613: count = tmp;
614: }
615: break;
616:
617: case IST_PULSE:
618: /* this just isn't shareable */
619: continue;
620: }
621: }
622:
623: if (bestirq == -1)
624: return (1);
625:
626: *irq = bestirq;
627:
628: return (0);
629: }
630:
631: static void
632: specific_eoi(irq)
633: int irq;
634: {
635: if (irq > 7)
636: bus_space_write_1(sio_iot,
637: sio_ioh_icu2, 0, 0x20 | (irq & 0x07)); /* XXX */
638: bus_space_write_1(sio_iot, sio_ioh_icu1, 0, 0x20 | (irq > 7 ? 2 : irq));
639: }
CVSweb