Home | History | Annotate | Line # | Download | only in pci
      1 /* $NetBSD: sio_pic.c,v 1.54 2024/08/17 15:05:13 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1998, 2000, 2020 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
     35  * All rights reserved.
     36  *
     37  * Author: Chris G. Demetriou
     38  *
     39  * Permission to use, copy, modify and distribute this software and
     40  * its documentation is hereby granted, provided that both the copyright
     41  * notice and this permission notice appear in all copies of the
     42  * software, derivative works or modified versions, and any portions
     43  * thereof, and that both notices appear in supporting documentation.
     44  *
     45  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     46  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     47  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     48  *
     49  * Carnegie Mellon requests users of this software to return to
     50  *
     51  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     52  *  School of Computer Science
     53  *  Carnegie Mellon University
     54  *  Pittsburgh PA 15213-3890
     55  *
     56  * any improvements or extensions that they make and grant Carnegie the
     57  * rights to redistribute these changes.
     58  */
     59 
     60 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     61 
     62 __KERNEL_RCSID(0, "$NetBSD: sio_pic.c,v 1.54 2024/08/17 15:05:13 thorpej Exp $");
     63 
     64 #include <sys/param.h>
     65 #include <sys/systm.h>
     66 #include <sys/device.h>
     67 #include <sys/cpu.h>
     68 #include <sys/syslog.h>
     69 
     70 #include <machine/alpha.h>
     71 #include <machine/intr.h>
     72 #include <sys/bus.h>
     73 
     74 #include <dev/pci/pcireg.h>
     75 #include <dev/pci/pcivar.h>
     76 #include <dev/pci/pcidevs.h>
     77 
     78 #include <dev/pci/pciidereg.h>
     79 #include <dev/pci/pciidevar.h>
     80 
     81 #include <dev/ic/i8259reg.h>
     82 
     83 #include <dev/pci/cy82c693reg.h>
     84 #include <dev/pci/cy82c693var.h>
     85 
     86 #include <dev/isa/isareg.h>
     87 #include <dev/isa/isavar.h>
     88 #include <alpha/pci/sioreg.h>
     89 #include <alpha/pci/siovar.h>
     90 
     91 #include "sio.h"
     92 
     93 /*
     94  * To add to the long history of wonderful PROM console traits,
     95  * AlphaStation PROMs don't reset themselves completely on boot!
     96  * Therefore, if an interrupt was turned on when the kernel was
     97  * started, we're not going to EVER turn it off...  I don't know
     98  * what will happen if new interrupts (that the PROM console doesn't
     99  * want) are turned on.  I'll burn that bridge when I come to it.
    100  */
    101 #define	BROKEN_PROM_CONSOLE
    102 
    103 /*
    104  * Private functions and variables.
    105  */
    106 
    107 static bus_space_tag_t sio_iot;
    108 static pci_chipset_tag_t sio_pc;
    109 static bus_space_handle_t sio_ioh_icu1, sio_ioh_icu2;
    110 
    111 #define	ICU_LEN		16		/* number of ISA IRQs */
    112 
    113 static struct alpha_shared_intr *sio_intr;
    114 
    115 #ifndef STRAY_MAX
    116 #define	STRAY_MAX	5
    117 #endif
    118 
    119 #ifdef BROKEN_PROM_CONSOLE
    120 /*
    121  * If prom console is broken, must remember the initial interrupt
    122  * settings and enforce them.  WHEE!
    123  */
    124 static uint8_t initial_ocw1[2];
    125 static uint8_t initial_elcr[2];
    126 #endif
    127 
    128 static void	sio_setirqstat(int, int, int);
    129 
    130 static uint8_t	(*sio_read_elcr)(int);
    131 static void	(*sio_write_elcr)(int, uint8_t);
    132 static void	specific_eoi(int);
    133 #ifdef BROKEN_PROM_CONSOLE
    134 static void	sio_intr_shutdown(void *);
    135 #endif
    136 
    137 /******************** i82378 SIO ELCR functions ********************/
    138 
    139 static bus_space_handle_t sio_ioh_elcr;
    140 
    141 static uint8_t	i82378_read_elcr(int);
    142 static void	i82378_write_elcr(int, uint8_t);
    143 
    144 static int
    145 i82378_setup_elcr(void)
    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, SIO_REG_ICU1ELC, 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 static uint8_t
    166 i82378_read_elcr(int elcr)
    167 {
    168 
    169 	return (bus_space_read_1(sio_iot, sio_ioh_elcr, elcr));
    170 }
    171 
    172 static void
    173 i82378_write_elcr(int elcr, uint8_t val)
    174 {
    175 
    176 	bus_space_write_1(sio_iot, sio_ioh_elcr, elcr, val);
    177 }
    178 
    179 /******************** Cypress CY82C693 ELCR functions ********************/
    180 
    181 static const struct cy82c693_handle *sio_cy82c693_handle;
    182 
    183 static uint8_t	cy82c693_read_elcr(int);
    184 static void	cy82c693_write_elcr(int, uint8_t);
    185 
    186 static int
    187 cy82c693_setup_elcr(void)
    188 {
    189 	int device, maxndevs;
    190 	pcitag_t tag;
    191 	pcireg_t id;
    192 
    193 	/*
    194 	 * Search PCI configuration space for a Cypress CY82C693.
    195 	 *
    196 	 * Note we can make some assumptions about our bus number
    197 	 * here, because:
    198 	 *
    199 	 *	(1) there can be at most one ISA/EISA bridge per PCI bus, and
    200 	 *
    201 	 *	(2) any ISA/EISA bridges must be attached to primary PCI
    202 	 *	    busses (i.e. bus zero).
    203 	 */
    204 
    205 	maxndevs = pci_bus_maxdevs(sio_pc, 0);
    206 
    207 	for (device = 0; device < maxndevs; device++) {
    208 		tag = pci_make_tag(sio_pc, 0, device, 0);
    209 		id = pci_conf_read(sio_pc, tag, PCI_ID_REG);
    210 
    211 		/* Invalid vendor ID value? */
    212 		if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
    213 			continue;
    214 		/* XXX Not invalid, but we've done this ~forever. */
    215 		if (PCI_VENDOR(id) == 0)
    216 			continue;
    217 
    218 		if (PCI_VENDOR(id) != PCI_VENDOR_CONTAQ ||
    219 		    PCI_PRODUCT(id) != PCI_PRODUCT_CONTAQ_82C693)
    220 			continue;
    221 
    222 		/*
    223 		 * Found one!
    224 		 */
    225 
    226 #if 0
    227 		printf("cy82c693_setup_elcr: found 82C693 at device %d\n",
    228 		    device);
    229 #endif
    230 
    231 		sio_cy82c693_handle = cy82c693_init(sio_iot);
    232 		if (sio_cy82c693_handle == NULL) {
    233 			panic("%s: cy82c693_init() failed.", __func__);
    234 		}
    235 		sio_read_elcr = cy82c693_read_elcr;
    236 		sio_write_elcr = cy82c693_write_elcr;
    237 
    238 		return (0);
    239 	}
    240 
    241 	/*
    242 	 * Didn't find a CY82C693.
    243 	 */
    244 	return (ENODEV);
    245 }
    246 
    247 static uint8_t
    248 cy82c693_read_elcr(int elcr)
    249 {
    250 
    251 	return (cy82c693_read(sio_cy82c693_handle, CONFIG_ELCR1 + elcr));
    252 }
    253 
    254 static void
    255 cy82c693_write_elcr(int elcr, uint8_t val)
    256 {
    257 
    258 	cy82c693_write(sio_cy82c693_handle, CONFIG_ELCR1 + elcr, val);
    259 }
    260 
    261 /******************** ELCR access function configuration ********************/
    262 
    263 /*
    264  * Put the Intel SIO at the end, so we fall back on it if we don't
    265  * find anything else.  If any of the non-Intel functions find a
    266  * matching device, but are unable to map it for whatever reason,
    267  * they should panic.
    268  */
    269 
    270 static int (*const sio_elcr_setup_funcs[])(void) = {
    271 	cy82c693_setup_elcr,
    272 	i82378_setup_elcr,
    273 	NULL,
    274 };
    275 
    276 /******************** Shared SIO/Cypress functions ********************/
    277 
    278 static inline void
    279 specific_eoi(int irq)
    280 {
    281 	if (irq > 7) {
    282 		bus_space_write_1(sio_iot, sio_ioh_icu2, PIC_OCW2,
    283 		    OCW2_EOI | OCW2_SL | (irq & 0x07));	/* XXX */
    284 	}
    285 	bus_space_write_1(sio_iot, sio_ioh_icu1, PIC_OCW2,
    286 	    OCW2_EOI | OCW2_SL | (irq > 7 ? 2 : irq));
    287 }
    288 
    289 static void
    290 sio_setirqstat(int irq, int enabled, int type)
    291 {
    292 	uint8_t ocw1[2], elcr[2];
    293 	int icu, bit;
    294 
    295 #if 0
    296 	printf("sio_setirqstat: irq %d: %s, %s\n", irq,
    297 	    enabled ? "enabled" : "disabled", isa_intr_typename(type));
    298 #endif
    299 
    300 	icu = irq / 8;
    301 	bit = irq % 8;
    302 
    303 	ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, PIC_OCW1);
    304 	ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, PIC_OCW1);
    305 	elcr[0] = (*sio_read_elcr)(0);				/* XXX */
    306 	elcr[1] = (*sio_read_elcr)(1);				/* XXX */
    307 
    308 	/*
    309 	 * interrupt enable: set bit to mask (disable) interrupt.
    310 	 */
    311 	if (enabled)
    312 		ocw1[icu] &= ~(1 << bit);
    313 	else
    314 		ocw1[icu] |= 1 << bit;
    315 
    316 	/*
    317 	 * interrupt type select: set bit to get level-triggered.
    318 	 */
    319 	if (type == IST_LEVEL)
    320 		elcr[icu] |= 1 << bit;
    321 	else
    322 		elcr[icu] &= ~(1 << bit);
    323 
    324 #ifdef not_here
    325 	/* see the init function... */
    326 	ocw1[0] &= ~0x04;		/* always enable IRQ2 on first PIC */
    327 	elcr[0] &= ~0x07;		/* IRQ[0-2] must be edge-triggered */
    328 	elcr[1] &= ~0x21;		/* IRQ[13,8] must be edge-triggered */
    329 #endif
    330 
    331 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, ocw1[0]);
    332 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, ocw1[1]);
    333 	(*sio_write_elcr)(0, elcr[0]);				/* XXX */
    334 	(*sio_write_elcr)(1, elcr[1]);				/* XXX */
    335 }
    336 
    337 void
    338 sio_intr_setup(pci_chipset_tag_t pc, bus_space_tag_t iot)
    339 {
    340 	struct evcnt *ev;
    341 	const char *cp;
    342 	int i;
    343 
    344 	sio_iot = iot;
    345 	sio_pc = pc;
    346 
    347 	if (bus_space_map(sio_iot, IO_ICU1, 2, 0, &sio_ioh_icu1) ||
    348 	    bus_space_map(sio_iot, IO_ICU2, 2, 0, &sio_ioh_icu2))
    349 		panic("sio_intr_setup: can't map ICU I/O ports");
    350 
    351 	for (i = 0; sio_elcr_setup_funcs[i] != NULL; i++)
    352 		if ((*sio_elcr_setup_funcs[i])() == 0)
    353 			break;
    354 	if (sio_elcr_setup_funcs[i] == NULL)
    355 		panic("sio_intr_setup: can't map ELCR");
    356 
    357 #ifdef BROKEN_PROM_CONSOLE
    358 	/*
    359 	 * Remember the initial values, so we can restore them later.
    360 	 */
    361 	initial_ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
    362 	initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
    363 	initial_elcr[0] = (*sio_read_elcr)(0);			/* XXX */
    364 	initial_elcr[1] = (*sio_read_elcr)(1);			/* XXX */
    365 	shutdownhook_establish(sio_intr_shutdown, 0);
    366 #endif
    367 
    368 	sio_intr = alpha_shared_intr_alloc(ICU_LEN);
    369 
    370 	/*
    371 	 * set up initial values for interrupt enables.
    372 	 */
    373 	for (i = 0; i < ICU_LEN; i++) {
    374 		alpha_shared_intr_set_maxstrays(sio_intr, i, STRAY_MAX);
    375 
    376 		ev = alpha_shared_intr_evcnt(sio_intr, i);
    377 		cp = alpha_shared_intr_string(sio_intr, i);
    378 
    379 		evcnt_attach_dynamic(ev, EVCNT_TYPE_INTR, NULL, "isa", cp);
    380 
    381 		switch (i) {
    382 		case 0:
    383 		case 1:
    384 		case 8:
    385 		case 13:
    386 			/*
    387 			 * IRQs 0, 1, 8, and 13 must always be
    388 			 * edge-triggered.
    389 			 */
    390 			sio_setirqstat(i, 0, IST_EDGE);
    391 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
    392 			    IST_EDGE);
    393 			specific_eoi(i);
    394 			break;
    395 
    396 		case 2:
    397 			/*
    398 			 * IRQ 2 must be edge-triggered, and should be
    399 			 * enabled (otherwise IRQs 8-15 are ignored).
    400 			 */
    401 			sio_setirqstat(i, 1, IST_EDGE);
    402 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
    403 			    IST_UNUSABLE);
    404 			break;
    405 
    406 		default:
    407 			/*
    408 			 * Otherwise, disable the IRQ and set its
    409 			 * type to (effectively) "unknown."
    410 			 */
    411 			sio_setirqstat(i, 0, IST_NONE);
    412 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
    413 			    IST_NONE);
    414 			specific_eoi(i);
    415 			break;
    416 		}
    417 	}
    418 }
    419 
    420 #ifdef BROKEN_PROM_CONSOLE
    421 static void
    422 sio_intr_shutdown(void *arg)
    423 {
    424 	/*
    425 	 * Restore the initial values, to make the PROM happy.
    426 	 */
    427 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, initial_ocw1[0]);
    428 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, initial_ocw1[1]);
    429 	(*sio_write_elcr)(0, initial_elcr[0]);			/* XXX */
    430 	(*sio_write_elcr)(1, initial_elcr[1]);			/* XXX */
    431 }
    432 #endif
    433 
    434 const char *
    435 sio_intr_string(void *v, int irq, char *buf, size_t len)
    436 {
    437 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    438 		panic("%s: bogus isa irq 0x%x", __func__, irq);
    439 
    440 	snprintf(buf, len, "isa irq %d", irq);
    441 	return buf;
    442 }
    443 
    444 const struct evcnt *
    445 sio_intr_evcnt(void *v, int irq)
    446 {
    447 
    448 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
    449 		panic("%s: bogus isa irq 0x%x", __func__, irq);
    450 
    451 	return (alpha_shared_intr_evcnt(sio_intr, irq));
    452 }
    453 
    454 void *
    455 sio_intr_establish(void *v, int irq, int type, int level, int flags,
    456     int (*fn)(void *), void *arg)
    457 {
    458 	void *cookie;
    459 
    460 	if (irq > ICU_LEN || type == IST_NONE)
    461 		panic("sio_intr_establish: bogus irq or type");
    462 
    463 	cookie = alpha_shared_intr_alloc_intrhand(sio_intr, irq, type, level,
    464 	    flags, fn, arg, "isa");
    465 
    466 	if (cookie == NULL)
    467 		return NULL;
    468 
    469 	mutex_enter(&cpu_lock);
    470 
    471 	if (! alpha_shared_intr_link(sio_intr, cookie, "isa")) {
    472 		mutex_exit(&cpu_lock);
    473 		alpha_shared_intr_free_intrhand(cookie);
    474 		return NULL;
    475 	}
    476 
    477 	if (alpha_shared_intr_firstactive(sio_intr, irq)) {
    478 		scb_set(0x800 + SCB_IDXTOVEC(irq), sio_iointr, NULL);
    479 		sio_setirqstat(irq, 1,
    480 		    alpha_shared_intr_get_sharetype(sio_intr, irq));
    481 
    482 		/*
    483 		 * I've obsesrved stray ISA interrupts when interacting
    484 		 * with the serial console under Qemu.  Work around that
    485 		 * for now by suppressing stray interrupt reporting for
    486 		 * edge-triggered interrupts.
    487 		 */
    488 		if (alpha_is_qemu && type == IST_EDGE) {
    489 			alpha_shared_intr_set_maxstrays(sio_intr, irq, 0);
    490 		}
    491 	}
    492 
    493 	mutex_exit(&cpu_lock);
    494 
    495 	return cookie;
    496 }
    497 
    498 void
    499 sio_intr_disestablish(void *v, void *cookie)
    500 {
    501 	struct alpha_shared_intrhand *ih = cookie;
    502 	int ist, irq = ih->ih_num;
    503 
    504 	mutex_enter(&cpu_lock);
    505 
    506 	/*
    507 	 * Decide if we should disable the interrupt.  We must ensure
    508 	 * that:
    509 	 *
    510 	 *	- An initially-enabled interrupt is never disabled.
    511 	 *	- An initially-LT interrupt is never untyped.
    512 	 */
    513 	if (alpha_shared_intr_firstactive(sio_intr, irq)) {
    514 		/*
    515 		 * IRQs 0, 1, 8, and 13 must always be edge-triggered
    516 		 * (see setup).
    517 		 */
    518 		switch (irq) {
    519 		case 0:
    520 		case 1:
    521 		case 8:
    522 		case 13:
    523 			/*
    524 			 * If the interrupt was initially level-triggered
    525 			 * a warning was printed in setup.
    526 			 */
    527 			ist = IST_EDGE;
    528 			break;
    529 
    530 		default:
    531 			ist = IST_NONE;
    532 			break;
    533 		}
    534 		sio_setirqstat(irq, 0, ist);
    535 		alpha_shared_intr_set_dfltsharetype(sio_intr, irq, ist);
    536 		alpha_shared_intr_set_maxstrays(sio_intr, irq, STRAY_MAX);
    537 
    538 		/* Release our SCB vector. */
    539 		scb_free(0x800 + SCB_IDXTOVEC(irq));
    540 	}
    541 
    542 	/* Remove it from the link. */
    543 	alpha_shared_intr_unlink(sio_intr, cookie, "isa");
    544 
    545 	mutex_exit(&cpu_lock);
    546 
    547 	alpha_shared_intr_free_intrhand(cookie);
    548 }
    549 
    550 /* XXX All known Alpha systems with Intel i82378 have it at device 7. */
    551 #define	SIO_I82378_DEV		7
    552 
    553 int
    554 sio_pirq_intr_map(pci_chipset_tag_t pc, int pirq, pci_intr_handle_t *ihp)
    555 {
    556 	KASSERT(pirq >= 0 && pirq <= 3);
    557 	KASSERT(pc == sio_pc);
    558 
    559 	const pcireg_t rtctrl =
    560 	    pci_conf_read(sio_pc, pci_make_tag(sio_pc, 0, SIO_I82378_DEV, 0),
    561 			  SIO_PCIREG_PIRQ_RTCTRL);
    562 	const pcireg_t pirqreg = PIRQ_RTCTRL_PIRQx(rtctrl, pirq);
    563 
    564 	if (pirqreg & PIRQ_RTCTRL_NOT_ROUTED) {
    565 		/* not routed -> no mapping */
    566 		return 1;
    567 	}
    568 
    569 	const int irq = __SHIFTOUT(pirqreg, PIRQ_RTCTRL_IRQ);
    570 
    571 #if 0
    572 	printf("sio_pirq_intr_map: pirq %d -> ISA irq %d, rtctl = 0x%08x\n",
    573 	    pirq, irq, rtctrl);
    574 #endif
    575 
    576 	alpha_pci_intr_handle_init(ihp, irq, 0);
    577 	return 0;
    578 }
    579 
    580 const char *
    581 sio_pci_intr_string(pci_chipset_tag_t const pc, pci_intr_handle_t const ih,
    582     char * const buf, size_t const len)
    583 {
    584 	const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
    585 
    586 	return sio_intr_string(NULL /*XXX*/, irq, buf, len);
    587 }
    588 
    589 const struct evcnt *
    590 sio_pci_intr_evcnt(pci_chipset_tag_t const pc, pci_intr_handle_t const ih)
    591 {
    592 	const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
    593 
    594 	return sio_intr_evcnt(NULL /*XXX*/, irq);
    595 }
    596 
    597 void *
    598 sio_pci_intr_establish(pci_chipset_tag_t const pc, pci_intr_handle_t ih,
    599     int const level, int (*func)(void *), void *arg)
    600 {
    601 	const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
    602 	const u_int flags = alpha_pci_intr_handle_get_flags(&ih);
    603 
    604 	return sio_intr_establish(NULL /*XXX*/, irq, IST_LEVEL, level, flags,
    605 	    func, arg);
    606 }
    607 
    608 void
    609 sio_pci_intr_disestablish(pci_chipset_tag_t const pc, void *cookie)
    610 {
    611 	sio_intr_disestablish(NULL /*XXX*/, cookie);
    612 }
    613 
    614 void *
    615 sio_pciide_compat_intr_establish(device_t const dev,
    616     const struct pci_attach_args * const pa,
    617     int const chan, int (*func)(void *), void *arg)
    618 {
    619 	pci_chipset_tag_t const pc = pa->pa_pc;
    620 	void *cookie;
    621 	int bus, irq;
    622 	char buf[64];
    623 	int flags = 0;	/* XXX How to pass MPSAFE? */
    624 
    625 	pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
    626 
    627 	/*
    628 	 * If this isn't PCI bus #0, all bets are off.
    629 	 */
    630 	if (bus != 0)
    631 		return NULL;
    632 
    633 	irq = PCIIDE_COMPAT_IRQ(chan);
    634 	cookie = sio_intr_establish(NULL /*XXX*/, irq, IST_EDGE, IPL_BIO,
    635 	    flags, func, arg);
    636 	if (cookie == NULL)
    637 		return NULL;
    638 
    639 	aprint_normal_dev(dev, "%s channel interrupting at %s\n",
    640 	    PCIIDE_CHANNEL_NAME(chan),
    641 	    sio_intr_string(NULL /*XXX*/, irq, buf, sizeof(buf)));
    642 
    643 	return cookie;
    644 }
    645 
    646 void *
    647 sio_isa_intr_establish(void *v, int irq, int type, int level,
    648     int (*fn)(void *), void *arg)
    649 {
    650 	return sio_intr_establish(v, irq, type, level, 0, fn, arg);
    651 }
    652 
    653 void
    654 sio_iointr(void *arg, unsigned long vec)
    655 {
    656 	int irq;
    657 
    658 	irq = SCB_VECTOIDX(vec - 0x800);
    659 
    660 #ifdef DIAGNOSTIC
    661 	if (irq > ICU_LEN || irq < 0)
    662 		panic("sio_iointr: irq out of range (%d)", irq);
    663 #endif
    664 
    665 	if (!alpha_shared_intr_dispatch(sio_intr, irq))
    666 		alpha_shared_intr_stray(sio_intr, irq, "isa");
    667 	else
    668 		alpha_shared_intr_reset_strays(sio_intr, irq);
    669 
    670 	/*
    671 	 * Some versions of the machines which use the SIO
    672 	 * (or is it some PALcode revisions on those machines?)
    673 	 * require the non-specific EOI to be fed to the PIC(s)
    674 	 * by the interrupt handler.
    675 	 */
    676 	specific_eoi(irq);
    677 }
    678 
    679 #define	LEGAL_IRQ(x)	((x) >= 0 && (x) < ICU_LEN && (x) != 2)
    680 
    681 int
    682 sio_intr_alloc(void *v, int mask, int type, int *irq)
    683 {
    684 	int i, tmp, bestirq, count;
    685 	struct alpha_shared_intrhand **p, *q;
    686 
    687 	if (type == IST_NONE)
    688 		panic("intr_alloc: bogus type");
    689 
    690 	bestirq = -1;
    691 	count = -1;
    692 
    693 	/* some interrupts should never be dynamically allocated */
    694 	mask &= 0xdef8;
    695 
    696 	/*
    697 	 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
    698 	 * the right answer is to do "breadth-first" searching of devices.
    699 	 */
    700 	mask &= 0xefbf;
    701 
    702 	for (i = 0; i < ICU_LEN; i++) {
    703 		if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
    704 			continue;
    705 
    706 		switch(sio_intr[i].intr_sharetype) {
    707 		case IST_NONE:
    708 			/*
    709 			 * if nothing's using the irq, just return it
    710 			 */
    711 			*irq = i;
    712 			return (0);
    713 
    714 		case IST_EDGE:
    715 		case IST_LEVEL:
    716 			if (type != sio_intr[i].intr_sharetype)
    717 				continue;
    718 			/*
    719 			 * if the irq is shareable, count the number of other
    720 			 * handlers, and if it's smaller than the last irq like
    721 			 * this, remember it
    722 			 *
    723 			 * XXX We should probably also consider the
    724 			 * interrupt level and stick IPL_TTY with other
    725 			 * IPL_TTY, etc.
    726 			 */
    727 			for (p = &TAILQ_FIRST(&sio_intr[i].intr_q), tmp = 0;
    728 			     (q = *p) != NULL; p = &TAILQ_NEXT(q, ih_q), tmp++)
    729 				;
    730 			if ((bestirq == -1) || (count > tmp)) {
    731 				bestirq = i;
    732 				count = tmp;
    733 			}
    734 			break;
    735 
    736 		case IST_PULSE:
    737 			/* this just isn't shareable */
    738 			continue;
    739 		}
    740 	}
    741 
    742 	if (bestirq == -1)
    743 		return (1);
    744 
    745 	*irq = bestirq;
    746 
    747 	return (0);
    748 }
    749