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