xref: /netbsd-src/sys/arch/alpha/pci/sio_pic.c (revision 14e16ba0fd82c34c8823721245dd798ede969b9f)
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@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