Home | History | Annotate | Line # | Download | only in pci
sio_pic.c revision 1.18.4.1
      1  1.18.4.1   thorpej /* $NetBSD: sio_pic.c,v 1.18.4.1 1997/09/04 00:53:59 thorpej Exp $ */
      2       1.1       cgd 
      3       1.1       cgd /*
      4       1.6       cgd  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
      5       1.1       cgd  * All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * Author: Chris G. Demetriou
      8       1.1       cgd  *
      9       1.1       cgd  * Permission to use, copy, modify and distribute this software and
     10       1.1       cgd  * its documentation is hereby granted, provided that both the copyright
     11       1.1       cgd  * notice and this permission notice appear in all copies of the
     12       1.1       cgd  * software, derivative works or modified versions, and any portions
     13       1.1       cgd  * thereof, and that both notices appear in supporting documentation.
     14       1.1       cgd  *
     15       1.1       cgd  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     16       1.1       cgd  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     17       1.1       cgd  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     18       1.1       cgd  *
     19       1.1       cgd  * Carnegie Mellon requests users of this software to return to
     20       1.1       cgd  *
     21       1.1       cgd  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     22       1.1       cgd  *  School of Computer Science
     23       1.1       cgd  *  Carnegie Mellon University
     24       1.1       cgd  *  Pittsburgh PA 15213-3890
     25       1.1       cgd  *
     26       1.1       cgd  * any improvements or extensions that they make and grant Carnegie the
     27       1.1       cgd  * rights to redistribute these changes.
     28       1.1       cgd  */
     29      1.17       cgd 
     30      1.18       cgd #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     31      1.18       cgd 
     32  1.18.4.1   thorpej __KERNEL_RCSID(0, "$NetBSD: sio_pic.c,v 1.18.4.1 1997/09/04 00:53:59 thorpej Exp $");
     33       1.1       cgd 
     34       1.1       cgd #include <sys/param.h>
     35       1.1       cgd #include <sys/systm.h>
     36       1.1       cgd #include <sys/device.h>
     37       1.1       cgd #include <sys/malloc.h>
     38       1.1       cgd #include <sys/syslog.h>
     39       1.1       cgd 
     40       1.4       cgd #include <machine/intr.h>
     41       1.4       cgd #include <machine/bus.h>
     42       1.4       cgd 
     43       1.2       cgd #include <dev/isa/isareg.h>
     44       1.1       cgd #include <dev/isa/isavar.h>
     45       1.2       cgd #include <alpha/pci/siovar.h>
     46       1.2       cgd 
     47       1.2       cgd #ifndef EVCNT_COUNTERS
     48       1.2       cgd #include <machine/intrcnt.h>
     49       1.2       cgd #endif
     50       1.1       cgd 
     51       1.2       cgd #include "sio.h"
     52       1.1       cgd 
     53       1.1       cgd /*
     54       1.1       cgd  * To add to the long history of wonderful PROM console traits,
     55       1.1       cgd  * AlphaStation PROMs don't reset themselves completely on boot!
     56       1.1       cgd  * Therefore, if an interrupt was turned on when the kernel was
     57       1.1       cgd  * started, we're not going to EVER turn it off...  I don't know
     58       1.1       cgd  * what will happen if new interrupts (that the PROM console doesn't
     59       1.1       cgd  * want) are turned on.  I'll burn that bridge when I come to it.
     60       1.1       cgd  */
     61       1.1       cgd #define	BROKEN_PROM_CONSOLE
     62       1.1       cgd 
     63       1.2       cgd /*
     64       1.2       cgd  * Private functions and variables.
     65       1.2       cgd  */
     66       1.4       cgd 
     67      1.14       cgd bus_space_tag_t sio_iot;
     68      1.14       cgd bus_space_handle_t sio_ioh_icu1, sio_ioh_icu2, sio_ioh_elcr;
     69       1.1       cgd 
     70       1.1       cgd #define	ICU_LEN		16		/* number of ISA IRQs */
     71       1.1       cgd 
     72      1.16       cgd static struct alpha_shared_intr *sio_intr;
     73       1.2       cgd #ifdef EVCNT_COUNTERS
     74       1.2       cgd struct evcnt sio_intr_evcnt;
     75       1.2       cgd #endif
     76       1.1       cgd 
     77       1.1       cgd #ifndef STRAY_MAX
     78       1.1       cgd #ifdef BROKEN_PROM_CONSOLE
     79       1.1       cgd /*
     80       1.1       cgd  * If prom console is broken, because initial interrupt settings
     81       1.1       cgd  * must be kept, there's no way to escape stray interrupts.
     82       1.1       cgd  */
     83       1.1       cgd #define	STRAY_MAX	0
     84       1.1       cgd #else
     85       1.1       cgd #define	STRAY_MAX	5
     86       1.1       cgd #endif
     87       1.1       cgd #endif
     88       1.1       cgd 
     89       1.1       cgd #ifdef BROKEN_PROM_CONSOLE
     90       1.1       cgd /*
     91       1.1       cgd  * If prom console is broken, must remember the initial interrupt
     92       1.1       cgd  * settings and enforce them.  WHEE!
     93       1.1       cgd  */
     94       1.1       cgd u_int8_t initial_ocw1[2];
     95       1.1       cgd u_int8_t initial_elcr[2];
     96       1.1       cgd #define	INITIALLY_ENABLED(irq) \
     97       1.1       cgd 	    ((initial_ocw1[(irq) / 8] & (1 << ((irq) % 8))) == 0)
     98       1.1       cgd #define	INITIALLY_LEVEL_TRIGGERED(irq) \
     99       1.1       cgd 	    ((initial_elcr[(irq) / 8] & (1 << ((irq) % 8))) != 0)
    100       1.1       cgd #else
    101       1.1       cgd #define	INITIALLY_ENABLED(irq)		((irq) == 2 ? 1 : 0)
    102       1.1       cgd #define	INITIALLY_LEVEL_TRIGGERED(irq)	0
    103       1.1       cgd #endif
    104       1.1       cgd 
    105      1.15       cgd void	sio_setirqstat __P((int, int, int));
    106      1.15       cgd 
    107       1.1       cgd void
    108       1.1       cgd sio_setirqstat(irq, enabled, type)
    109       1.1       cgd 	int irq, enabled;
    110       1.3   mycroft 	int type;
    111       1.1       cgd {
    112       1.1       cgd 	u_int8_t ocw1[2], elcr[2];
    113       1.1       cgd 	int icu, bit;
    114       1.1       cgd 
    115       1.1       cgd #if 0
    116      1.13  christos 	printf("sio_setirqstat: irq %d: %s, %s\n", irq,
    117       1.1       cgd 	    enabled ? "enabled" : "disabled", isa_intr_typename(type));
    118       1.1       cgd #endif
    119       1.1       cgd 
    120       1.1       cgd 	icu = irq / 8;
    121       1.1       cgd 	bit = irq % 8;
    122       1.1       cgd 
    123      1.14       cgd 	ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
    124      1.14       cgd 	ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
    125      1.14       cgd 	elcr[0] = bus_space_read_1(sio_iot, sio_ioh_elcr, 0);	/* XXX */
    126      1.14       cgd 	elcr[1] = bus_space_read_1(sio_iot, sio_ioh_elcr, 1);	/* XXX */
    127       1.1       cgd 
    128       1.1       cgd 	/*
    129       1.1       cgd 	 * interrupt enable: set bit to mask (disable) interrupt.
    130       1.1       cgd 	 */
    131       1.1       cgd 	if (enabled)
    132       1.1       cgd 		ocw1[icu] &= ~(1 << bit);
    133       1.1       cgd 	else
    134       1.1       cgd 		ocw1[icu] |= 1 << bit;
    135       1.1       cgd 
    136       1.1       cgd 	/*
    137       1.1       cgd 	 * interrupt type select: set bit to get level-triggered.
    138       1.1       cgd 	 */
    139       1.3   mycroft 	if (type == IST_LEVEL)
    140       1.1       cgd 		elcr[icu] |= 1 << bit;
    141       1.1       cgd 	else
    142       1.1       cgd 		elcr[icu] &= ~(1 << bit);
    143       1.1       cgd 
    144       1.1       cgd #ifdef not_here
    145       1.1       cgd 	/* see the init function... */
    146       1.1       cgd 	ocw1[0] &= ~0x04;		/* always enable IRQ2 on first PIC */
    147       1.1       cgd 	elcr[0] &= ~0x07;		/* IRQ[0-2] must be edge-triggered */
    148       1.1       cgd 	elcr[1] &= ~0x21;		/* IRQ[13,8] must be edge-triggered */
    149       1.1       cgd #endif
    150       1.1       cgd 
    151       1.1       cgd #ifdef BROKEN_PROM_CONSOLE
    152       1.1       cgd 	/*
    153       1.1       cgd 	 * make sure that the initially clear bits (unmasked interrupts)
    154       1.1       cgd 	 * are never set, and that the initially-level-triggered
    155       1.1       cgd 	 * intrrupts always remain level-triggered, to keep the prom happy.
    156       1.1       cgd 	 */
    157       1.1       cgd 	if ((ocw1[0] & ~initial_ocw1[0]) != 0 ||
    158       1.1       cgd 	    (ocw1[1] & ~initial_ocw1[1]) != 0 ||
    159       1.1       cgd 	    (elcr[0] & initial_elcr[0]) != initial_elcr[0] ||
    160       1.1       cgd 	    (elcr[1] & initial_elcr[1]) != initial_elcr[1]) {
    161      1.13  christos 		printf("sio_sis: initial: ocw = (%2x,%2x), elcr = (%2x,%2x)\n",
    162       1.1       cgd 		    initial_ocw1[0], initial_ocw1[1],
    163       1.1       cgd 		    initial_elcr[0], initial_elcr[1]);
    164      1.13  christos 		printf("         current: ocw = (%2x,%2x), elcr = (%2x,%2x)\n",
    165       1.1       cgd 		    ocw1[0], ocw1[1], elcr[0], elcr[1]);
    166       1.1       cgd 		panic("sio_setirqstat: hosed");
    167       1.1       cgd 	}
    168       1.1       cgd #endif
    169       1.1       cgd 
    170      1.14       cgd 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, ocw1[0]);
    171      1.14       cgd 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, ocw1[1]);
    172      1.14       cgd 	bus_space_write_1(sio_iot, sio_ioh_elcr, 0, elcr[0]);	/* XXX */
    173      1.14       cgd 	bus_space_write_1(sio_iot, sio_ioh_elcr, 1, elcr[1]);	/* XXX */
    174       1.1       cgd }
    175       1.1       cgd 
    176       1.1       cgd void
    177      1.14       cgd sio_intr_setup(iot)
    178      1.14       cgd 	bus_space_tag_t iot;
    179       1.1       cgd {
    180       1.1       cgd 	int i;
    181       1.1       cgd 
    182      1.14       cgd 	sio_iot = iot;
    183       1.4       cgd 
    184      1.14       cgd 	if (bus_space_map(sio_iot, IO_ICU1, IO_ICUSIZE, 0, &sio_ioh_icu1) ||
    185      1.14       cgd 	    bus_space_map(sio_iot, IO_ICU2, IO_ICUSIZE, 0, &sio_ioh_icu2) ||
    186      1.14       cgd 	    bus_space_map(sio_iot, 0x4d0, 2, 0, &sio_ioh_elcr))
    187       1.4       cgd 		panic("sio_intr_setup: can't map I/O ports");
    188       1.2       cgd 
    189       1.1       cgd #ifdef BROKEN_PROM_CONSOLE
    190       1.1       cgd 	/*
    191       1.1       cgd 	 * Remember the initial values, because the prom is stupid.
    192       1.1       cgd 	 */
    193      1.14       cgd 	initial_ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
    194      1.14       cgd 	initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
    195      1.14       cgd 	initial_elcr[0] = bus_space_read_1(sio_iot, sio_ioh_elcr, 0); /* XXX */
    196      1.14       cgd 	initial_elcr[1] = bus_space_read_1(sio_iot, sio_ioh_elcr, 1); /* XXX */
    197       1.1       cgd #if 0
    198      1.13  christos 	printf("initial_ocw1[0] = 0x%x\n", initial_ocw1[0]);
    199      1.13  christos 	printf("initial_ocw1[1] = 0x%x\n", initial_ocw1[1]);
    200      1.13  christos 	printf("initial_elcr[0] = 0x%x\n", initial_elcr[0]);
    201      1.13  christos 	printf("initial_elcr[1] = 0x%x\n", initial_elcr[1]);
    202       1.1       cgd #endif
    203       1.1       cgd #endif
    204       1.1       cgd 
    205      1.16       cgd 	sio_intr = alpha_shared_intr_alloc(ICU_LEN);
    206      1.16       cgd 
    207       1.1       cgd 	/*
    208       1.1       cgd 	 * set up initial values for interrupt enables.
    209       1.1       cgd 	 */
    210       1.1       cgd 	for (i = 0; i < ICU_LEN; i++) {
    211      1.16       cgd 		alpha_shared_intr_set_maxstrays(sio_intr, i, STRAY_MAX);
    212      1.16       cgd 
    213       1.1       cgd 		switch (i) {
    214       1.1       cgd 		case 0:
    215       1.1       cgd 		case 1:
    216       1.1       cgd 		case 8:
    217       1.1       cgd 		case 13:
    218       1.1       cgd 			/*
    219       1.1       cgd 			 * IRQs 0, 1, 8, and 13 must always be
    220       1.1       cgd 			 * edge-triggered.
    221       1.1       cgd 			 */
    222       1.1       cgd 			if (INITIALLY_LEVEL_TRIGGERED(i))
    223      1.13  christos 				printf("sio_intr_setup: %d LT!\n", i);
    224       1.3   mycroft 			sio_setirqstat(i, INITIALLY_ENABLED(i), IST_EDGE);
    225      1.16       cgd 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
    226      1.16       cgd 			    IST_EDGE);
    227       1.1       cgd 			break;
    228       1.1       cgd 
    229       1.1       cgd 		case 2:
    230       1.1       cgd 			/*
    231       1.1       cgd 			 * IRQ 2 must be edge-triggered, and should be
    232       1.1       cgd 			 * enabled (otherwise IRQs 8-15 are ignored).
    233       1.1       cgd 			 */
    234       1.1       cgd 			if (INITIALLY_LEVEL_TRIGGERED(i))
    235      1.13  christos 				printf("sio_intr_setup: %d LT!\n", i);
    236       1.1       cgd 			if (!INITIALLY_ENABLED(i))
    237      1.13  christos 				printf("sio_intr_setup: %d not enabled!\n", i);
    238       1.3   mycroft 			sio_setirqstat(i, 1, IST_EDGE);
    239      1.16       cgd 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
    240      1.16       cgd 			    IST_UNUSABLE);
    241       1.1       cgd 			break;
    242       1.1       cgd 
    243       1.1       cgd 		default:
    244       1.1       cgd 			/*
    245       1.1       cgd 			 * Otherwise, disable the IRQ and set its
    246       1.1       cgd 			 * type to (effectively) "unknown."
    247       1.1       cgd 			 */
    248       1.1       cgd 			sio_setirqstat(i, INITIALLY_ENABLED(i),
    249       1.3   mycroft 			    INITIALLY_LEVEL_TRIGGERED(i) ? IST_LEVEL :
    250       1.3   mycroft 				IST_NONE);
    251      1.16       cgd 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
    252      1.16       cgd 			    INITIALLY_LEVEL_TRIGGERED(i) ? IST_LEVEL :
    253      1.16       cgd                                 IST_NONE);
    254       1.1       cgd 			break;
    255       1.1       cgd 		}
    256       1.1       cgd 	}
    257       1.1       cgd }
    258       1.1       cgd 
    259       1.4       cgd const char *
    260       1.4       cgd sio_intr_string(v, irq)
    261       1.4       cgd 	void *v;
    262       1.4       cgd 	int irq;
    263       1.4       cgd {
    264       1.7       cgd 	static char irqstr[12];		/* 8 + 2 + NULL + sanity */
    265       1.4       cgd 
    266       1.4       cgd 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    267      1.16       cgd 		panic("sio_intr_string: bogus isa irq 0x%x\n", irq);
    268       1.4       cgd 
    269      1.13  christos 	sprintf(irqstr, "isa irq %d", irq);
    270       1.4       cgd 	return (irqstr);
    271       1.4       cgd }
    272       1.4       cgd 
    273       1.1       cgd void *
    274      1.16       cgd sio_intr_establish(v, irq, type, level, fn, arg)
    275      1.16       cgd 	void *v, *arg;
    276       1.4       cgd         int irq;
    277       1.3   mycroft         int type;
    278       1.3   mycroft         int level;
    279      1.16       cgd         int (*fn)(void *);
    280       1.1       cgd {
    281      1.16       cgd 	void *cookie;
    282       1.1       cgd 
    283       1.3   mycroft 	if (irq > ICU_LEN || type == IST_NONE)
    284       1.1       cgd 		panic("sio_intr_establish: bogus irq or type");
    285       1.1       cgd 
    286      1.16       cgd 	cookie = alpha_shared_intr_establish(sio_intr, irq, type, level, fn,
    287      1.16       cgd 	    arg, "isa irq");
    288       1.1       cgd 
    289      1.16       cgd 	if (cookie)
    290      1.16       cgd 		sio_setirqstat(irq, alpha_shared_intr_isactive(sio_intr, irq),
    291      1.16       cgd 		    alpha_shared_intr_get_sharetype(sio_intr, irq));
    292       1.1       cgd 
    293      1.16       cgd 	return (cookie);
    294       1.1       cgd }
    295       1.1       cgd 
    296       1.1       cgd void
    297       1.4       cgd sio_intr_disestablish(v, cookie)
    298       1.4       cgd 	void *v;
    299       1.4       cgd 	void *cookie;
    300       1.1       cgd {
    301       1.1       cgd 
    302      1.15       cgd 	printf("sio_intr_disestablish(%p)\n", cookie);
    303       1.1       cgd 	/* XXX */
    304       1.1       cgd 
    305       1.1       cgd 	/* XXX NEVER ALLOW AN INITIALLY-ENABLED INTERRUPT TO BE DISABLED */
    306       1.1       cgd 	/* XXX NEVER ALLOW AN INITIALLY-LT INTERRUPT TO BECOME UNTYPED */
    307       1.1       cgd }
    308       1.1       cgd 
    309       1.1       cgd void
    310       1.1       cgd sio_iointr(framep, vec)
    311       1.1       cgd 	void *framep;
    312      1.10       cgd 	unsigned long vec;
    313       1.1       cgd {
    314      1.16       cgd 	int irq;
    315       1.1       cgd 
    316       1.1       cgd 	irq = (vec - 0x800) >> 4;
    317       1.1       cgd #ifdef DIAGNOSTIC
    318       1.1       cgd 	if (irq > ICU_LEN || irq < 0)
    319       1.1       cgd 		panic("sio_iointr: irq out of range (%d)", irq);
    320       1.1       cgd #endif
    321       1.1       cgd 
    322       1.2       cgd #ifdef EVCNT_COUNTERS
    323       1.2       cgd 	sio_intr_evcnt.ev_count++;
    324       1.2       cgd #else
    325      1.16       cgd #ifdef DEBUG
    326       1.2       cgd 	if (ICU_LEN != INTRCNT_ISA_IRQ_LEN)
    327       1.2       cgd 		panic("sio interrupt counter sizes inconsistent");
    328      1.16       cgd #endif
    329       1.2       cgd 	intrcnt[INTRCNT_ISA_IRQ + irq]++;
    330       1.2       cgd #endif
    331       1.2       cgd 
    332      1.16       cgd 	if (!alpha_shared_intr_dispatch(sio_intr, irq))
    333      1.16       cgd 		alpha_shared_intr_stray(sio_intr, irq, "isa irq");
    334       1.1       cgd 
    335       1.1       cgd 	/*
    336       1.1       cgd 	 * Some versions of the machines which use the SIO
    337       1.1       cgd 	 * (or is it some PALcode revisions on those machines?)
    338       1.1       cgd 	 * require the non-specific EOI to be fed to the PIC(s)
    339       1.1       cgd 	 * by the interrupt handler.
    340       1.1       cgd 	 */
    341       1.1       cgd 	if (irq > 7)
    342      1.14       cgd 		bus_space_write_1(sio_iot,
    343       1.4       cgd 		    sio_ioh_icu2, 0, 0x20 | (irq & 0x07));	/* XXX */
    344      1.14       cgd 	bus_space_write_1(sio_iot,
    345       1.4       cgd 	    sio_ioh_icu1, 0, 0x20 | (irq > 7 ? 2 : irq));	/* XXX */
    346       1.1       cgd }
    347