xref: /netbsd-src/sys/arch/powerpc/pic/intr.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: intr.c,v 1.18 2011/09/27 01:02:36 jym Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 Michael Lorenz
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.18 2011/09/27 01:02:36 jym Exp $");
31 
32 #include "opt_interrupt.h"
33 #include "opt_multiprocessor.h"
34 #include "opt_pic.h"
35 
36 #define __INTR_PRIVATE
37 
38 #include <sys/param.h>
39 #include <sys/cpu.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 
43 #include <powerpc/psl.h>
44 #include <powerpc/pic/picvar.h>
45 
46 #if defined(PIC_I8259) || defined (PIC_PREPIVR)
47 #include <machine/isa_machdep.h>
48 #endif
49 
50 #ifdef MULTIPROCESSOR
51 #include <powerpc/pic/ipivar.h>
52 #endif
53 
54 #ifdef __HAVE_FAST_SOFTINTS
55 #include <powerpc/softint.h>
56 #endif
57 
58 #define MAX_PICS	8	/* 8 PICs ought to be enough for everyone */
59 
60 #define	PIC_VIRQ_LEGAL_P(x)	((u_int)(x) < NVIRQ)
61 
62 struct pic_ops *pics[MAX_PICS];
63 int num_pics = 0;
64 int max_base = 0;
65 uint8_t	virq_map[NIRQ];
66 imask_t virq_mask = HWIRQ_MASK;
67 imask_t	imask[NIPL];
68 int	primary_pic = 0;
69 
70 static int	fakeintr(void *);
71 static int	mapirq(int);
72 static void	intr_calculatemasks(void);
73 static struct pic_ops *find_pic_by_hwirq(int);
74 
75 static struct intr_source intrsources[NVIRQ];
76 
77 void
78 pic_init(void)
79 {
80 	/* everything is in bss, no reason to zero it. */
81 }
82 
83 int
84 pic_add(struct pic_ops *pic)
85 {
86 
87 	if (num_pics >= MAX_PICS)
88 		return -1;
89 
90 	pics[num_pics] = pic;
91 	pic->pic_intrbase = max_base;
92 	max_base += pic->pic_numintrs;
93 	num_pics++;
94 
95 	return pic->pic_intrbase;
96 }
97 
98 void
99 pic_finish_setup(void)
100 {
101 	for (size_t i = 0; i < num_pics; i++) {
102 		struct pic_ops * const pic = pics[i];
103 		if (pic->pic_finish_setup != NULL)
104 			pic->pic_finish_setup(pic);
105 	}
106 }
107 
108 static struct pic_ops *
109 find_pic_by_hwirq(int hwirq)
110 {
111 	for (u_int base = 0; base < num_pics; base++) {
112 		struct pic_ops * const pic = pics[base];
113 		if (pic->pic_intrbase <= hwirq
114 		    && hwirq < pic->pic_intrbase + pic->pic_numintrs) {
115 			return pic;
116 		}
117 	}
118 	return NULL;
119 }
120 
121 static int
122 fakeintr(void *arg)
123 {
124 
125 	return 0;
126 }
127 
128 /*
129  * Register an interrupt handler.
130  */
131 void *
132 intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
133     void *ih_arg)
134 {
135 	struct intrhand **p, *q, *ih;
136 	struct pic_ops *pic;
137 	static struct intrhand fakehand;
138 	int maxipl = ipl;
139 
140 	if (maxipl == IPL_NONE)
141 		maxipl = IPL_HIGH;
142 
143 	if (hwirq >= max_base) {
144 		panic("%s: bogus IRQ %d, max is %d", __func__, hwirq,
145 		    max_base - 1);
146 	}
147 
148 	pic = find_pic_by_hwirq(hwirq);
149 	if (pic == NULL) {
150 
151 		panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
152 	}
153 
154 	const int virq = mapirq(hwirq);
155 
156 	/* no point in sleeping unless someone can free memory. */
157 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
158 	if (ih == NULL)
159 		panic("intr_establish: can't malloc handler info");
160 
161 	if (!PIC_VIRQ_LEGAL_P(virq) || type == IST_NONE)
162 		panic("intr_establish: bogus irq (%d) or type (%d)",
163 		    hwirq, type);
164 
165 	struct intr_source * const is = &intrsources[virq];
166 
167 	switch (is->is_type) {
168 	case IST_NONE:
169 		is->is_type = type;
170 		break;
171 	case IST_EDGE:
172 	case IST_LEVEL:
173 		if (type == is->is_type)
174 			break;
175 		/* FALLTHROUGH */
176 	case IST_PULSE:
177 		if (type != IST_NONE)
178 			panic("intr_establish: can't share %s with %s",
179 			    intr_typename(is->is_type),
180 			    intr_typename(type));
181 		break;
182 	}
183 	if (is->is_hand == NULL) {
184 		snprintf(is->is_source, sizeof(is->is_source), "irq %d",
185 		    is->is_hwirq);
186 		evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL,
187 		    pic->pic_name, is->is_source);
188 	}
189 
190 	/*
191 	 * Figure out where to put the handler.
192 	 * This is O(N^2), but we want to preserve the order, and N is
193 	 * generally small.
194 	 */
195 	for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) {
196 		maxipl = max(maxipl, q->ih_ipl);
197 	}
198 
199 	/*
200 	 * Actually install a fake handler momentarily, since we might be doing
201 	 * this with interrupts enabled and don't want the real routine called
202 	 * until masking is set up.
203 	 */
204 	fakehand.ih_ipl = ipl;
205 	fakehand.ih_fun = fakeintr;
206 	*p = &fakehand;
207 
208 	/*
209 	 * Poke the real handler in now.
210 	 */
211 	ih->ih_fun = ih_fun;
212 	ih->ih_arg = ih_arg;
213 	ih->ih_next = NULL;
214 	ih->ih_ipl = ipl;
215 	ih->ih_virq = virq;
216 	*p = ih;
217 
218 	if (pic->pic_establish_irq != NULL)
219 		pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase,
220 		    is->is_type, maxipl);
221 
222 	/*
223 	 * Remember the highest IPL used by this handler.
224 	 */
225 	is->is_ipl = maxipl;
226 
227 	/*
228 	 * now that the handler is established we're actually ready to
229 	 * calculate the masks
230 	 */
231 	intr_calculatemasks();
232 
233 
234 	return ih;
235 }
236 
237 void
238 dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri)
239 {
240 }
241 
242 /*
243  * Deregister an interrupt handler.
244  */
245 void
246 intr_disestablish(void *arg)
247 {
248 	struct intrhand * const ih = arg;
249 	const int virq = ih->ih_virq;
250 	struct intr_source * const is = &intrsources[virq];
251 	struct intrhand **p, **q;
252 	int maxipl = IPL_NONE;
253 
254 	if (!PIC_VIRQ_LEGAL_P(virq))
255 		panic("intr_disestablish: bogus virq %d", virq);
256 
257 	/*
258 	 * Remove the handler from the chain.
259 	 * This is O(n^2), too.
260 	 */
261 	for (p = &is->is_hand, q = NULL; (*p) != NULL; p = &(*p)->ih_next) {
262 		struct intrhand * const tmp_ih = *p;
263 		if (tmp_ih == ih) {
264 			q = p;
265 		} else {
266 			maxipl = max(maxipl, tmp_ih->ih_ipl);
267 		}
268 	}
269 	if (q)
270 		*q = ih->ih_next;
271 	else
272 		panic("intr_disestablish: handler not registered");
273 	free((void *)ih, M_DEVBUF);
274 
275 	/*
276 	 * Reset the IPL for this source now that we've removed a handler.
277 	 */
278 	is->is_ipl = maxipl;
279 
280 	intr_calculatemasks();
281 
282 	if (is->is_hand == NULL) {
283 		is->is_type = IST_NONE;
284 		evcnt_detach(&is->is_ev);
285 		/*
286 		 * Make the virutal IRQ available again.
287 		 */
288 		virq_map[virq] = 0;
289 		virq_mask |= PIC_VIRQ_TO_MASK(virq);
290 	}
291 }
292 
293 /*
294  * Map max_base irqs into 32 (bits).
295  */
296 static int
297 mapirq(int hwirq)
298 {
299 	struct pic_ops *pic;
300 
301 	if (hwirq >= max_base)
302 		panic("invalid irq %d", hwirq);
303 
304 	if ((pic = find_pic_by_hwirq(hwirq)) == NULL)
305 		panic("%s: cannot find PIC for HWIRQ %d", __func__, hwirq);
306 
307 	if (virq_map[hwirq])
308 		return virq_map[hwirq];
309 
310 	if (virq_mask == 0)
311 		panic("virq overflow");
312 
313 	const int virq = PIC_VIRQ_MS_PENDING(virq_mask);
314 	struct intr_source * const is = intrsources + virq;
315 
316 	virq_mask &= ~PIC_VIRQ_TO_MASK(virq);
317 
318 	is->is_hwirq = hwirq;
319 	is->is_pic = pic;
320 	virq_map[hwirq] = virq;
321 #ifdef PIC_DEBUG
322 	printf("mapping hwirq %d to virq %d\n", hwirq, virq);
323 #endif
324 	return virq;
325 }
326 
327 static const char * const intr_typenames[] = {
328    [IST_NONE]  = "none",
329    [IST_PULSE] = "pulsed",
330    [IST_EDGE]  = "edge-triggered",
331    [IST_LEVEL] = "level-triggered",
332 };
333 
334 const char *
335 intr_typename(int type)
336 {
337 	KASSERT((unsigned int) type < __arraycount(intr_typenames));
338 	KASSERT(intr_typenames[type] != NULL);
339 	return intr_typenames[type];
340 }
341 
342 /*
343  * Recalculate the interrupt masks from scratch.
344  * We could code special registry and deregistry versions of this function that
345  * would be faster, but the code would be nastier, and we don't expect this to
346  * happen very much anyway.
347  */
348 static void
349 intr_calculatemasks(void)
350 {
351 	imask_t newmask[NIPL] = { [IPL_NONE...IPL_HIGH] = 0 };
352 	struct intr_source *is;
353 	int irq;
354 
355 	for (u_int ipl = IPL_NONE; ipl < NIPL; ipl++) {
356 		newmask[ipl] = 0;
357 	}
358 
359 	/* First, figure out which ipl each IRQ uses. */
360 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
361 		newmask[is->is_ipl] |= PIC_VIRQ_TO_MASK(irq);
362 	}
363 
364 	/*
365 	 * IPL_NONE is used for hardware interrupts that are never blocked,
366 	 * and do not block anything else.
367 	 */
368 	newmask[IPL_NONE] = 0;
369 
370 	/*
371 	 * strict hierarchy - all IPLs block everything blocked by any lower
372 	 * IPL
373 	 */
374 	for (u_int ipl = 1; ipl < NIPL; ipl++) {
375 		newmask[ipl] |= newmask[ipl - 1];
376 	}
377 
378 #ifdef DEBUG_IPL
379 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
380 		printf("%u: %08x -> %08x\n", ipl, imask[ipl], newmask[ipl]);
381 	}
382 #endif
383 
384 	/*
385 	 * Disable all interrupts.
386 	 */
387 	for (u_int base = 0; base < num_pics; base++) {
388 		struct pic_ops * const pic = pics[base];
389 		for (u_int i = 0; i < pic->pic_numintrs; i++) {
390 			pic->pic_disable_irq(pic, i);
391 		}
392 	}
393 
394 	/*
395 	 * Now that all interrupts are disabled, update the ipl masks.
396 	 */
397 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
398 		imask[ipl] = newmask[ipl];
399 	}
400 
401 	/*
402 	 * Lastly, enable IRQs actually in use.
403 	 */
404 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
405 		if (is->is_hand)
406 			pic_enable_irq(is->is_hwirq);
407 	}
408 }
409 
410 void
411 pic_enable_irq(int hwirq)
412 {
413 	struct pic_ops * const pic = find_pic_by_hwirq(hwirq);
414 	if (pic == NULL)
415 		panic("%s: bogus IRQ %d", __func__, hwirq);
416 	const int type = intrsources[virq_map[hwirq]].is_type;
417 	(*pic->pic_enable_irq)(pic, hwirq - pic->pic_intrbase, type);
418 }
419 
420 void
421 pic_mark_pending(int hwirq)
422 {
423 	struct cpu_info * const ci = curcpu();
424 
425 	const int virq = virq_map[hwirq];
426 	if (virq == 0)
427 		printf("IRQ %d maps to 0\n", hwirq);
428 
429 	const register_t msr = mfmsr();
430 	mtmsr(msr & ~PSL_EE);
431 	ci->ci_ipending |= PIC_VIRQ_TO_MASK(virq);
432 	mtmsr(msr);
433 }
434 
435 static void
436 intr_deliver(struct intr_source *is, int virq)
437 {
438 	bool locked = false;
439 	for (struct intrhand *ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
440 		KASSERTMSG(ih->ih_fun != NULL,
441 		    "%s: irq %d, hwirq %d, is %p ih %p: "
442 		     "NULL interrupt handler!\n", __func__,
443 		     virq, is->is_hwirq, is, ih);
444 		if (ih->ih_ipl == IPL_VM) {
445 			if (!locked) {
446 				KERNEL_LOCK(1, NULL);
447 				locked = true;
448 			}
449 		} else if (locked) {
450 			KERNEL_UNLOCK_ONE(NULL);
451 			locked = false;
452 		}
453 		(*ih->ih_fun)(ih->ih_arg);
454 	}
455 	if (locked) {
456 		KERNEL_UNLOCK_ONE(NULL);
457 	}
458 	is->is_ev.ev_count++;
459 }
460 
461 void
462 pic_do_pending_int(void)
463 {
464 	struct cpu_info * const ci = curcpu();
465 	imask_t vpend;
466 
467 	if (ci->ci_iactive)
468 		return;
469 
470 	ci->ci_iactive = 1;
471 
472 	const register_t emsr = mfmsr();
473 	const register_t dmsr = emsr & ~PSL_EE;
474 
475 	KASSERT(emsr & PSL_EE);
476 	mtmsr(dmsr);
477 
478 	const int pcpl = ci->ci_cpl;
479 #ifdef __HAVE_FAST_SOFTINTS
480 again:
481 #endif
482 
483 	/* Do now unmasked pendings */
484 	while ((vpend = (ci->ci_ipending & ~imask[pcpl])) != 0) {
485 		ci->ci_idepth++;
486 		KASSERT((PIC_VIRQ_TO_MASK(0) & ci->ci_ipending) == 0);
487 
488 		/* Get most significant pending bit */
489 		const int virq = PIC_VIRQ_MS_PENDING(vpend);
490 		ci->ci_ipending &= ~PIC_VIRQ_TO_MASK(virq);
491 
492 		struct intr_source * const is = &intrsources[virq];
493 		struct pic_ops * const pic = is->is_pic;
494 
495 		splraise(is->is_ipl);
496 		mtmsr(emsr);
497 		intr_deliver(is, virq);
498 		mtmsr(dmsr);
499 		ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
500 
501 		pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase,
502 		    is->is_type);
503 		ci->ci_idepth--;
504 	}
505 
506 #ifdef __HAVE_FAST_SOFTINTS
507 	const u_int softints = (ci->ci_data.cpu_softints << pcpl) & IPL_SOFTMASK;
508 
509 	if (__predict_false(softints != 0)) {
510 		ci->ci_cpl = IPL_HIGH;
511 		mtmsr(emsr);
512 		powerpc_softint(ci, pcpl,
513 		    (vaddr_t)__builtin_return_address(0));
514 		mtmsr(dmsr);
515 		ci->ci_cpl = pcpl;
516 		if (__predict_false(ci->ci_ipending & ~imask[pcpl]))
517 			goto again;
518 	}
519 #endif
520 
521 	ci->ci_iactive = 0;
522 	mtmsr(emsr);
523 }
524 
525 int
526 pic_handle_intr(void *cookie)
527 {
528 	struct pic_ops *pic = cookie;
529 	struct cpu_info *ci = curcpu();
530 	int picirq;
531 
532 	picirq = pic->pic_get_irq(pic, PIC_GET_IRQ);
533 	if (picirq == 255)
534 		return 0;
535 
536 	const register_t msr = mfmsr();
537 	const int pcpl = ci->ci_cpl;
538 
539 	do {
540 #ifdef MULTIPROCESSOR
541 		/* THIS IS WRONG XXX */
542 		if (picirq == ipiops.ppc_ipi_vector) {
543 			ci->ci_cpl = IPL_HIGH;
544 			ipi_intr(NULL);
545 			ci->ci_cpl = pcpl;
546 			pic->pic_ack_irq(pic, picirq);
547 			continue;
548 		}
549 #endif
550 
551 		const int virq = virq_map[picirq + pic->pic_intrbase];
552 		KASSERT(virq != 0);
553 		KASSERT(picirq < pic->pic_numintrs);
554 		imask_t v_imen = PIC_VIRQ_TO_MASK(virq);
555 		struct intr_source * const is = &intrsources[virq];
556 
557 		if ((imask[pcpl] & v_imen) != 0) {
558 			ci->ci_ipending |= v_imen; /* Masked! Mark this as pending */
559 			pic->pic_disable_irq(pic, picirq);
560 		} else {
561 			/* this interrupt is no longer pending */
562 			ci->ci_ipending &= ~v_imen;
563 			ci->ci_idepth++;
564 
565 			splraise(is->is_ipl);
566 			mtmsr(msr | PSL_EE);
567 			intr_deliver(is, virq);
568 			mtmsr(msr);
569 			ci->ci_cpl = pcpl;
570 
571 			ci->ci_data.cpu_nintr++;
572 			ci->ci_idepth--;
573 		}
574 		pic->pic_ack_irq(pic, picirq);
575 	} while ((picirq = pic->pic_get_irq(pic, PIC_GET_RECHECK)) != 255);
576 
577 	mtmsr(msr | PSL_EE);
578 	splx(pcpl);	/* Process pendings. */
579 	mtmsr(msr);
580 
581 	return 0;
582 }
583 
584 void
585 pic_ext_intr(void)
586 {
587 
588 	KASSERT(pics[primary_pic] != NULL);
589 	pic_handle_intr(pics[primary_pic]);
590 
591 	return;
592 
593 }
594 
595 int
596 splraise(int ncpl)
597 {
598 	struct cpu_info *ci = curcpu();
599 	int ocpl;
600 
601 	if (ncpl == ci->ci_cpl) return ncpl;
602 	__asm volatile("sync; eieio");	/* don't reorder.... */
603 	ocpl = ci->ci_cpl;
604 	KASSERT(ncpl < NIPL);
605 	ci->ci_cpl = max(ncpl, ocpl);
606 	__asm volatile("sync; eieio");	/* reorder protect */
607 	__insn_barrier();
608 	return ocpl;
609 }
610 
611 static inline bool
612 have_pending_intr_p(struct cpu_info *ci, int ncpl)
613 {
614 	if (ci->ci_ipending & ~imask[ncpl])
615 		return true;
616 #ifdef __HAVE_FAST_SOFTINTS
617 	if ((ci->ci_data.cpu_softints << ncpl) & IPL_SOFTMASK)
618 		return true;
619 #endif
620 	return false;
621 }
622 
623 void
624 splx(int ncpl)
625 {
626 	struct cpu_info *ci = curcpu();
627 
628 	__insn_barrier();
629 	__asm volatile("sync; eieio");	/* reorder protect */
630 	ci->ci_cpl = ncpl;
631 	if (have_pending_intr_p(ci, ncpl))
632 		pic_do_pending_int();
633 
634 	__asm volatile("sync; eieio");	/* reorder protect */
635 }
636 
637 int
638 spllower(int ncpl)
639 {
640 	struct cpu_info *ci = curcpu();
641 	int ocpl;
642 
643 	__insn_barrier();
644 	__asm volatile("sync; eieio");	/* reorder protect */
645 	ocpl = ci->ci_cpl;
646 	ci->ci_cpl = ncpl;
647 	if (have_pending_intr_p(ci, ncpl))
648 		pic_do_pending_int();
649 	__asm volatile("sync; eieio");	/* reorder protect */
650 	return ocpl;
651 }
652 
653 void
654 genppc_cpu_configure(void)
655 {
656 	aprint_normal("biomask %x netmask %x ttymask %x\n",
657 	    (u_int)imask[IPL_BIO] & 0x1fffffff,
658 	    (u_int)imask[IPL_NET] & 0x1fffffff,
659 	    (u_int)imask[IPL_TTY] & 0x1fffffff);
660 
661 	spl0();
662 }
663 
664 #if defined(PIC_PREPIVR) || defined(PIC_I8259)
665 /*
666  * isa_intr_alloc needs to be done here, because it needs direct access to
667  * the various interrupt handler structures.
668  */
669 
670 int
671 genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
672     int mask, int type, int *irq_p)
673 {
674 	int irq, vi;
675 	int maybe_irq = -1;
676 	int shared_depth = 0;
677 	struct intr_source *is;
678 
679 	if (pic == NULL)
680 		return 1;
681 
682 	for (irq = 0; (mask != 0 && irq < pic->pic_numintrs);
683 	     mask >>= 1, irq++) {
684 		if ((mask & 1) == 0)
685 			continue;
686 		vi = virq_map[irq + pic->pic_intrbase];
687 		if (!vi) {
688 			*irq_p = irq;
689 			return 0;
690 		}
691 		is = &intrsources[vi];
692 		if (is->is_type == IST_NONE) {
693 			*irq_p = irq;
694 			return 0;
695 		}
696 		/* Level interrupts can be shared */
697 		if (type == IST_LEVEL && is->is_type == IST_LEVEL) {
698 			struct intrhand *ih = is->is_hand;
699 			int depth;
700 
701 			if (maybe_irq == -1) {
702 				maybe_irq = irq;
703 				continue;
704 			}
705 			for (depth = 0; ih != NULL; ih = ih->ih_next)
706 				depth++;
707 			if (depth < shared_depth) {
708 				maybe_irq = irq;
709 				shared_depth = depth;
710 			}
711 		}
712 	}
713 	if (maybe_irq != -1) {
714 		*irq_p = maybe_irq;
715 		return 0;
716 	}
717 	return 1;
718 }
719 #endif
720