xref: /netbsd-src/sys/arch/alpha/pci/sio_pic.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /* $NetBSD: sio_pic.c,v 1.46 2020/09/29 01:19:52 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@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.46 2020/09/29 01:19:52 thorpej Exp $");
63 
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/device.h>
67 #include <sys/malloc.h>
68 #include <sys/cpu.h>
69 #include <sys/syslog.h>
70 
71 #include <machine/alpha.h>
72 #include <machine/intr.h>
73 #include <sys/bus.h>
74 
75 #include <dev/pci/pcireg.h>
76 #include <dev/pci/pcivar.h>
77 #include <dev/pci/pcidevs.h>
78 
79 #include <dev/pci/pciidereg.h>
80 #include <dev/pci/pciidevar.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 uint8_t initial_ocw1[2];
123 uint8_t initial_elcr[2];
124 #endif
125 
126 void		sio_setirqstat(int, int, int);
127 
128 uint8_t	(*sio_read_elcr)(int);
129 void		(*sio_write_elcr)(int, uint8_t);
130 static void	specific_eoi(int);
131 #ifdef BROKEN_PROM_CONSOLE
132 void		sio_intr_shutdown(void *);
133 #endif
134 
135 /******************** i82378 SIO ELCR functions ********************/
136 
137 int		i82378_setup_elcr(void);
138 uint8_t	i82378_read_elcr(int);
139 void		i82378_write_elcr(int, uint8_t);
140 
141 bus_space_handle_t sio_ioh_elcr;
142 
143 int
144 i82378_setup_elcr(void)
145 {
146 	int rv;
147 
148 	/*
149 	 * We could probe configuration space to see that there's
150 	 * actually an SIO present, but we are using this as a
151 	 * fall-back in case nothing else matches.
152 	 */
153 
154 	rv = bus_space_map(sio_iot, 0x4d0, 2, 0, &sio_ioh_elcr);
155 
156 	if (rv == 0) {
157 		sio_read_elcr = i82378_read_elcr;
158 		sio_write_elcr = i82378_write_elcr;
159 	}
160 
161 	return (rv);
162 }
163 
164 uint8_t
165 i82378_read_elcr(int elcr)
166 {
167 
168 	return (bus_space_read_1(sio_iot, sio_ioh_elcr, elcr));
169 }
170 
171 void
172 i82378_write_elcr(int elcr, uint8_t val)
173 {
174 
175 	bus_space_write_1(sio_iot, sio_ioh_elcr, elcr, val);
176 }
177 
178 /******************** Cypress CY82C693 ELCR functions ********************/
179 
180 int		cy82c693_setup_elcr(void);
181 uint8_t	cy82c693_read_elcr(int);
182 void		cy82c693_write_elcr(int, uint8_t);
183 
184 const struct cy82c693_handle *sio_cy82c693_handle;
185 
186 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 		sio_read_elcr = cy82c693_read_elcr;
233 		sio_write_elcr = cy82c693_write_elcr;
234 
235 		return (0);
236 	}
237 
238 	/*
239 	 * Didn't find a CY82C693.
240 	 */
241 	return (ENODEV);
242 }
243 
244 uint8_t
245 cy82c693_read_elcr(int elcr)
246 {
247 
248 	return (cy82c693_read(sio_cy82c693_handle, CONFIG_ELCR1 + elcr));
249 }
250 
251 void
252 cy82c693_write_elcr(int elcr, uint8_t val)
253 {
254 
255 	cy82c693_write(sio_cy82c693_handle, CONFIG_ELCR1 + elcr, val);
256 }
257 
258 /******************** ELCR access function configuration ********************/
259 
260 /*
261  * Put the Intel SIO at the end, so we fall back on it if we don't
262  * find anything else.  If any of the non-Intel functions find a
263  * matching device, but are unable to map it for whatever reason,
264  * they should panic.
265  */
266 
267 int (*const sio_elcr_setup_funcs[])(void) = {
268 	cy82c693_setup_elcr,
269 	i82378_setup_elcr,
270 	NULL,
271 };
272 
273 /******************** Shared SIO/Cypress functions ********************/
274 
275 void
276 sio_setirqstat(int irq, int enabled, int type)
277 {
278 	uint8_t ocw1[2], elcr[2];
279 	int icu, bit;
280 
281 #if 0
282 	printf("sio_setirqstat: irq %d: %s, %s\n", irq,
283 	    enabled ? "enabled" : "disabled", isa_intr_typename(type));
284 #endif
285 
286 	icu = irq / 8;
287 	bit = irq % 8;
288 
289 	ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
290 	ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
291 	elcr[0] = (*sio_read_elcr)(0);				/* XXX */
292 	elcr[1] = (*sio_read_elcr)(1);				/* XXX */
293 
294 	/*
295 	 * interrupt enable: set bit to mask (disable) interrupt.
296 	 */
297 	if (enabled)
298 		ocw1[icu] &= ~(1 << bit);
299 	else
300 		ocw1[icu] |= 1 << bit;
301 
302 	/*
303 	 * interrupt type select: set bit to get level-triggered.
304 	 */
305 	if (type == IST_LEVEL)
306 		elcr[icu] |= 1 << bit;
307 	else
308 		elcr[icu] &= ~(1 << bit);
309 
310 #ifdef not_here
311 	/* see the init function... */
312 	ocw1[0] &= ~0x04;		/* always enable IRQ2 on first PIC */
313 	elcr[0] &= ~0x07;		/* IRQ[0-2] must be edge-triggered */
314 	elcr[1] &= ~0x21;		/* IRQ[13,8] must be edge-triggered */
315 #endif
316 
317 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, ocw1[0]);
318 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, ocw1[1]);
319 	(*sio_write_elcr)(0, elcr[0]);				/* XXX */
320 	(*sio_write_elcr)(1, elcr[1]);				/* XXX */
321 }
322 
323 void
324 sio_intr_setup(pci_chipset_tag_t pc, bus_space_tag_t iot)
325 {
326 	char *cp;
327 	int i;
328 
329 	sio_iot = iot;
330 	sio_pc = pc;
331 
332 	if (bus_space_map(sio_iot, IO_ICU1, 2, 0, &sio_ioh_icu1) ||
333 	    bus_space_map(sio_iot, IO_ICU2, 2, 0, &sio_ioh_icu2))
334 		panic("sio_intr_setup: can't map ICU I/O ports");
335 
336 	for (i = 0; sio_elcr_setup_funcs[i] != NULL; i++)
337 		if ((*sio_elcr_setup_funcs[i])() == 0)
338 			break;
339 	if (sio_elcr_setup_funcs[i] == NULL)
340 		panic("sio_intr_setup: can't map ELCR");
341 
342 #ifdef BROKEN_PROM_CONSOLE
343 	/*
344 	 * Remember the initial values, so we can restore them later.
345 	 */
346 	initial_ocw1[0] = bus_space_read_1(sio_iot, sio_ioh_icu1, 1);
347 	initial_ocw1[1] = bus_space_read_1(sio_iot, sio_ioh_icu2, 1);
348 	initial_elcr[0] = (*sio_read_elcr)(0);			/* XXX */
349 	initial_elcr[1] = (*sio_read_elcr)(1);			/* XXX */
350 	shutdownhook_establish(sio_intr_shutdown, 0);
351 #endif
352 
353 #define PCI_SIO_IRQ_STR	8
354 	sio_intr = alpha_shared_intr_alloc(ICU_LEN, PCI_SIO_IRQ_STR);
355 
356 	/*
357 	 * set up initial values for interrupt enables.
358 	 */
359 	for (i = 0; i < ICU_LEN; i++) {
360 		alpha_shared_intr_set_maxstrays(sio_intr, i, STRAY_MAX);
361 
362 		cp = alpha_shared_intr_string(sio_intr, i);
363 		snprintf(cp, PCI_SIO_IRQ_STR, "irq %d", i);
364 		evcnt_attach_dynamic(alpha_shared_intr_evcnt(sio_intr, i),
365 		    EVCNT_TYPE_INTR, NULL, "isa", cp);
366 
367 		switch (i) {
368 		case 0:
369 		case 1:
370 		case 8:
371 		case 13:
372 			/*
373 			 * IRQs 0, 1, 8, and 13 must always be
374 			 * edge-triggered.
375 			 */
376 			sio_setirqstat(i, 0, IST_EDGE);
377 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
378 			    IST_EDGE);
379 			specific_eoi(i);
380 			break;
381 
382 		case 2:
383 			/*
384 			 * IRQ 2 must be edge-triggered, and should be
385 			 * enabled (otherwise IRQs 8-15 are ignored).
386 			 */
387 			sio_setirqstat(i, 1, IST_EDGE);
388 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
389 			    IST_UNUSABLE);
390 			break;
391 
392 		default:
393 			/*
394 			 * Otherwise, disable the IRQ and set its
395 			 * type to (effectively) "unknown."
396 			 */
397 			sio_setirqstat(i, 0, IST_NONE);
398 			alpha_shared_intr_set_dfltsharetype(sio_intr, i,
399 			    IST_NONE);
400 			specific_eoi(i);
401 			break;
402 		}
403 	}
404 }
405 
406 #ifdef BROKEN_PROM_CONSOLE
407 void
408 sio_intr_shutdown(void *arg)
409 {
410 	/*
411 	 * Restore the initial values, to make the PROM happy.
412 	 */
413 	bus_space_write_1(sio_iot, sio_ioh_icu1, 1, initial_ocw1[0]);
414 	bus_space_write_1(sio_iot, sio_ioh_icu2, 1, initial_ocw1[1]);
415 	(*sio_write_elcr)(0, initial_elcr[0]);			/* XXX */
416 	(*sio_write_elcr)(1, initial_elcr[1]);			/* XXX */
417 }
418 #endif
419 
420 const char *
421 sio_intr_string(void *v, int irq, char *buf, size_t len)
422 {
423 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
424 		panic("%s: bogus isa irq 0x%x", __func__, irq);
425 
426 	snprintf(buf, len, "isa irq %d", irq);
427 	return buf;
428 }
429 
430 const struct evcnt *
431 sio_intr_evcnt(void *v, int irq)
432 {
433 
434 	if (irq == 0 || irq >= ICU_LEN || irq == 2)
435 		panic("%s: bogus isa irq 0x%x", __func__, irq);
436 
437 	return (alpha_shared_intr_evcnt(sio_intr, irq));
438 }
439 
440 void *
441 sio_intr_establish(void *v, int irq, int type, int level, int flags,
442     int (*fn)(void *), void *arg)
443 {
444 	void *cookie;
445 
446 	if (irq > ICU_LEN || type == IST_NONE)
447 		panic("sio_intr_establish: bogus irq or type");
448 
449 	cookie = alpha_shared_intr_alloc_intrhand(sio_intr, irq, type, level,
450 	    flags, fn, arg, "isa irq");
451 
452 	if (cookie == NULL)
453 		return NULL;
454 
455 	mutex_enter(&cpu_lock);
456 
457 	if (! alpha_shared_intr_link(sio_intr, cookie, "isa irq")) {
458 		mutex_exit(&cpu_lock);
459 		alpha_shared_intr_free_intrhand(cookie);
460 		return NULL;
461 	}
462 
463 	if (alpha_shared_intr_firstactive(sio_intr, irq)) {
464 		scb_set(0x800 + SCB_IDXTOVEC(irq), sio_iointr, NULL);
465 		sio_setirqstat(irq, 1,
466 		    alpha_shared_intr_get_sharetype(sio_intr, irq));
467 
468 		/*
469 		 * I've obsesrved stray ISA interrupts when interacting
470 		 * with the serial console under Qemu.  Work around that
471 		 * for now by suppressing stray interrupt reporting for
472 		 * edge-triggered interrupts.
473 		 */
474 		if (alpha_is_qemu && type == IST_EDGE) {
475 			alpha_shared_intr_set_maxstrays(sio_intr, irq, 0);
476 		}
477 	}
478 
479 	mutex_exit(&cpu_lock);
480 
481 	return cookie;
482 }
483 
484 void
485 sio_intr_disestablish(void *v, void *cookie)
486 {
487 	struct alpha_shared_intrhand *ih = cookie;
488 	int ist, irq = ih->ih_num;
489 
490 	mutex_enter(&cpu_lock);
491 
492 	/*
493 	 * Decide if we should disable the interrupt.  We must ensure
494 	 * that:
495 	 *
496 	 *	- An initially-enabled interrupt is never disabled.
497 	 *	- An initially-LT interrupt is never untyped.
498 	 */
499 	if (alpha_shared_intr_firstactive(sio_intr, irq)) {
500 		/*
501 		 * IRQs 0, 1, 8, and 13 must always be edge-triggered
502 		 * (see setup).
503 		 */
504 		switch (irq) {
505 		case 0:
506 		case 1:
507 		case 8:
508 		case 13:
509 			/*
510 			 * If the interrupt was initially level-triggered
511 			 * a warning was printed in setup.
512 			 */
513 			ist = IST_EDGE;
514 			break;
515 
516 		default:
517 			ist = IST_NONE;
518 			break;
519 		}
520 		sio_setirqstat(irq, 0, ist);
521 		alpha_shared_intr_set_dfltsharetype(sio_intr, irq, ist);
522 		alpha_shared_intr_set_maxstrays(sio_intr, irq, STRAY_MAX);
523 
524 		/* Release our SCB vector. */
525 		scb_free(0x800 + SCB_IDXTOVEC(irq));
526 	}
527 
528 	/* Remove it from the link. */
529 	alpha_shared_intr_unlink(sio_intr, cookie, "isa irq");
530 
531 	mutex_exit(&cpu_lock);
532 
533 	alpha_shared_intr_free_intrhand(cookie);
534 }
535 
536 const char *
537 sio_pci_intr_string(pci_chipset_tag_t const pc, pci_intr_handle_t const ih,
538     char * const buf, size_t const len)
539 {
540 	const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
541 
542 	return sio_intr_string(NULL /*XXX*/, irq, buf, len);
543 }
544 
545 const struct evcnt *
546 sio_pci_intr_evcnt(pci_chipset_tag_t const pc, pci_intr_handle_t const ih)
547 {
548 	const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
549 
550 	return sio_intr_evcnt(NULL /*XXX*/, irq);
551 }
552 
553 void *
554 sio_pci_intr_establish(pci_chipset_tag_t const pc, pci_intr_handle_t ih,
555     int const level, int (*func)(void *), void *arg)
556 {
557 	const u_int irq = alpha_pci_intr_handle_get_irq(&ih);
558 	const u_int flags = alpha_pci_intr_handle_get_flags(&ih);
559 
560 	return sio_intr_establish(NULL /*XXX*/, irq, IST_LEVEL, level, flags,
561 	    func, arg);
562 }
563 
564 void
565 sio_pci_intr_disestablish(pci_chipset_tag_t const pc, void *cookie)
566 {
567 	sio_intr_disestablish(NULL /*XXX*/, cookie);
568 }
569 
570 void *
571 sio_pciide_compat_intr_establish(device_t const dev,
572     const struct pci_attach_args * const pa,
573     int const chan, int (*func)(void *), void *arg)
574 {
575 	pci_chipset_tag_t const pc = pa->pa_pc;
576 	void *cookie;
577 	int bus, irq;
578 	char buf[64];
579 	int flags = 0;	/* XXX How to pass MPSAFE? */
580 
581 	pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
582 
583 	/*
584 	 * If this isn't PCI bus #0, all bets are off.
585 	 */
586 	if (bus != 0)
587 		return NULL;
588 
589 	irq = PCIIDE_COMPAT_IRQ(chan);
590 	cookie = sio_intr_establish(NULL /*XXX*/, irq, IST_EDGE, IPL_BIO,
591 	    flags, func, arg);
592 	if (cookie == NULL)
593 		return NULL;
594 
595 	aprint_normal_dev(dev, "%s channel interrupting at %s\n",
596 	    PCIIDE_CHANNEL_NAME(chan),
597 	    sio_intr_string(NULL /*XXX*/, irq, buf, sizeof(buf)));
598 
599 	return cookie;
600 }
601 
602 void *
603 sio_isa_intr_establish(void *v, int irq, int type, int level,
604     int (*fn)(void *), void *arg)
605 {
606 	return sio_intr_establish(v, irq, type, level, 0, fn, arg);
607 }
608 
609 void
610 sio_iointr(void *arg, unsigned long vec)
611 {
612 	int irq;
613 
614 	irq = SCB_VECTOIDX(vec - 0x800);
615 
616 #ifdef DIAGNOSTIC
617 	if (irq > ICU_LEN || irq < 0)
618 		panic("sio_iointr: irq out of range (%d)", irq);
619 #endif
620 
621 	if (!alpha_shared_intr_dispatch(sio_intr, irq))
622 		alpha_shared_intr_stray(sio_intr, irq, "isa irq");
623 	else
624 		alpha_shared_intr_reset_strays(sio_intr, irq);
625 
626 	/*
627 	 * Some versions of the machines which use the SIO
628 	 * (or is it some PALcode revisions on those machines?)
629 	 * require the non-specific EOI to be fed to the PIC(s)
630 	 * by the interrupt handler.
631 	 */
632 	specific_eoi(irq);
633 }
634 
635 #define	LEGAL_IRQ(x)	((x) >= 0 && (x) < ICU_LEN && (x) != 2)
636 
637 int
638 sio_intr_alloc(void *v, int mask, int type, int *irq)
639 {
640 	int i, tmp, bestirq, count;
641 	struct alpha_shared_intrhand **p, *q;
642 
643 	if (type == IST_NONE)
644 		panic("intr_alloc: bogus type");
645 
646 	bestirq = -1;
647 	count = -1;
648 
649 	/* some interrupts should never be dynamically allocated */
650 	mask &= 0xdef8;
651 
652 	/*
653 	 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
654 	 * the right answer is to do "breadth-first" searching of devices.
655 	 */
656 	mask &= 0xefbf;
657 
658 	for (i = 0; i < ICU_LEN; i++) {
659 		if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
660 			continue;
661 
662 		switch(sio_intr[i].intr_sharetype) {
663 		case IST_NONE:
664 			/*
665 			 * if nothing's using the irq, just return it
666 			 */
667 			*irq = i;
668 			return (0);
669 
670 		case IST_EDGE:
671 		case IST_LEVEL:
672 			if (type != sio_intr[i].intr_sharetype)
673 				continue;
674 			/*
675 			 * if the irq is shareable, count the number of other
676 			 * handlers, and if it's smaller than the last irq like
677 			 * this, remember it
678 			 *
679 			 * XXX We should probably also consider the
680 			 * interrupt level and stick IPL_TTY with other
681 			 * IPL_TTY, etc.
682 			 */
683 			for (p = &TAILQ_FIRST(&sio_intr[i].intr_q), tmp = 0;
684 			     (q = *p) != NULL; p = &TAILQ_NEXT(q, ih_q), tmp++)
685 				;
686 			if ((bestirq == -1) || (count > tmp)) {
687 				bestirq = i;
688 				count = tmp;
689 			}
690 			break;
691 
692 		case IST_PULSE:
693 			/* this just isn't shareable */
694 			continue;
695 		}
696 	}
697 
698 	if (bestirq == -1)
699 		return (1);
700 
701 	*irq = bestirq;
702 
703 	return (0);
704 }
705 
706 static void
707 specific_eoi(int irq)
708 {
709 	if (irq > 7)
710 		bus_space_write_1(sio_iot,
711 		    sio_ioh_icu2, 0, 0x60 | (irq & 0x07));	/* XXX */
712 	bus_space_write_1(sio_iot, sio_ioh_icu1, 0, 0x60 | (irq > 7 ? 2 : irq));
713 }
714