xref: /netbsd-src/sys/arch/i386/pci/pci_intr_fixup.c (revision e55cffd8e520e9b03f18a1bd98bb04223e79f69f)
1 /*	$NetBSD: pci_intr_fixup.c,v 1.12 2001/04/19 17:32:40 uch Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 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  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * Copyright (c) 1999, by UCHIYAMA Yasushi
42  * All rights reserved.
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted provided that the following conditions
46  * are met:
47  * 1. Redistributions of source code must retain the above copyright
48  *    notice, this list of conditions and the following disclaimer.
49  * 2. The name of the developer may NOT be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 
65 /*
66  * PCI Interrupt Router support.
67  */
68 
69 #include "opt_pcibios.h"
70 
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/malloc.h>
75 #include <sys/queue.h>
76 #include <sys/device.h>
77 
78 #include <machine/bus.h>
79 #include <machine/intr.h>
80 
81 #include <dev/pci/pcireg.h>
82 #include <dev/pci/pcivar.h>
83 #include <dev/pci/pcidevs.h>
84 
85 #include <i386/isa/icu.h>
86 #include <i386/pci/pci_intr_fixup.h>
87 #include <i386/pci/pcibios.h>
88 
89 struct pciintr_link_map {
90 	int link;
91 	int clink;
92 	int irq;
93 	u_int16_t bitmap;
94 	int fixup_stage;
95 	SIMPLEQ_ENTRY(pciintr_link_map) list;
96 };
97 
98 pciintr_icu_tag_t pciintr_icu_tag = NULL;
99 pciintr_icu_handle_t pciintr_icu_handle;
100 
101 #ifdef PCIBIOS_IRQS_HINT
102 int pcibios_irqs_hint = PCIBIOS_IRQS_HINT;
103 #endif
104 
105 struct pciintr_link_map *pciintr_link_lookup __P((int));
106 struct pciintr_link_map *pciintr_link_alloc __P((struct pcibios_intr_routing *,
107 	int));
108 struct pcibios_intr_routing *pciintr_pir_lookup __P((int, int));
109 static int pciintr_bitmap_count_irq __P((int, int *));
110 static int pciintr_bitmap_find_lowest_irq __P((int, int *));
111 int	pciintr_link_init __P((void));
112 #ifdef PCIBIOS_INTR_GUESS
113 int	pciintr_guess_irq __P((void));
114 #endif
115 int	pciintr_link_fixup __P((void));
116 int	pciintr_link_route __P((u_int16_t *));
117 int	pciintr_irq_release __P((u_int16_t *));
118 int	pciintr_header_fixup __P((pci_chipset_tag_t));
119 void	pciintr_do_header_fixup __P((pci_chipset_tag_t, pcitag_t));
120 
121 SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list;
122 
123 const struct pciintr_icu_table {
124 	pci_vendor_id_t	piit_vendor;
125 	pci_product_id_t piit_product;
126 	int (*piit_init) __P((pci_chipset_tag_t,
127 		bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *,
128 		pciintr_icu_handle_t *));
129 } pciintr_icu_table[] = {
130 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82371MX,
131 	  piix_init },
132 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82371AB_ISA,
133 	  piix_init },
134 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82371FB_ISA,
135 	  piix_init },
136 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82371SB_ISA,
137 	  piix_init },
138 
139 	{ PCI_VENDOR_OPTI,	PCI_PRODUCT_OPTI_82C558,
140 	  opti82c558_init },
141 	{ PCI_VENDOR_OPTI,	PCI_PRODUCT_OPTI_82C700,
142 	  opti82c700_init },
143 
144 	{ PCI_VENDOR_VIATECH,	PCI_PRODUCT_VIATECH_VT82C586_ISA,
145 	  via82c586_init },
146 	{ PCI_VENDOR_VIATECH,	PCI_PRODUCT_VIATECH_VT82C686A_ISA,
147 	  via82c586_init },
148 
149 	{ PCI_VENDOR_SIS,	PCI_PRODUCT_SIS_85C503,
150 	  sis85c503_init },
151 
152 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_PBC756_PMC,
153 	  amd756_init },
154 
155 	{ 0,			0,
156 	  NULL },
157 };
158 
159 const struct pciintr_icu_table *pciintr_icu_lookup __P((pcireg_t));
160 
161 const struct pciintr_icu_table *
162 pciintr_icu_lookup(id)
163 	pcireg_t id;
164 {
165 	const struct pciintr_icu_table *piit;
166 
167 	for (piit = pciintr_icu_table;
168 	     piit->piit_init != NULL;
169 	     piit++) {
170 		if (PCI_VENDOR(id) == piit->piit_vendor &&
171 		    PCI_PRODUCT(id) == piit->piit_product)
172 			return (piit);
173 	}
174 
175 	return (NULL);
176 }
177 
178 struct pciintr_link_map *
179 pciintr_link_lookup(link)
180 	int link;
181 {
182 	struct pciintr_link_map *l;
183 
184 	for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
185 	     l = SIMPLEQ_NEXT(l, list)) {
186 		if (l->link == link)
187 			return (l);
188 	}
189 
190 	return (NULL);
191 }
192 
193 struct pciintr_link_map *
194 pciintr_link_alloc(pir, pin)
195 	struct pcibios_intr_routing *pir;
196 	int pin;
197 {
198 	int link = pir->linkmap[pin].link, clink, irq;
199 	struct pciintr_link_map *l, *lstart;
200 
201 	if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */
202 		/*
203 		 * Get the canonical link value for this entry.
204 		 */
205 		if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle,
206 		    link, &clink) != 0) {
207 			/*
208 			 * ICU doesn't understand the link value.
209 			 * Just ignore this PIR entry.
210 			 */
211 #ifdef DIAGNOSTIC
212 			printf("pciintr_link_alloc: bus %d device %d: "
213 			    "link 0x%02x invalid\n",
214 			    pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link);
215 #endif
216 			return (NULL);
217 		}
218 
219 		/*
220 		 * Check the link value by asking the ICU for the
221 		 * canonical link value.
222 		 * Also, determine if this PIRQ is mapped to an IRQ.
223 		 */
224 		if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle,
225 		    clink, &irq) != 0) {
226 			/*
227 			 * ICU doesn't understand the canonical link value.
228 			 * Just ignore this PIR entry.
229 			 */
230 #ifdef DIAGNOSTIC
231 			printf("pciintr_link_alloc: "
232 			    "bus %d device %d link 0x%02x: "
233 			    "PIRQ 0x%02x invalid\n",
234 			    pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link,
235 			    clink);
236 #endif
237 			return (NULL);
238 		}
239 	}
240 
241 	l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT);
242 	if (l == NULL)
243 		panic("pciintr_link_alloc");
244 
245 	memset(l, 0, sizeof(*l));
246 
247 	l->link = link;
248 	l->bitmap = pir->linkmap[pin].bitmap;
249 	if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */
250 		l->clink = clink;
251 		l->irq = irq; /* maybe I386_PCI_INTERRUPT_LINE_NO_CONNECTION */
252 	} else {
253 		l->clink = link; /* only for PCIBIOSVERBOSE diagnostic */
254 		l->irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION;
255 	}
256 
257 	lstart = SIMPLEQ_FIRST(&pciintr_link_map_list);
258 	if (lstart == NULL || lstart->link < l->link)
259 		SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list);
260 	else
261 		SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list);
262 
263 	return (l);
264 }
265 
266 struct pcibios_intr_routing *
267 pciintr_pir_lookup(bus, device)
268 	int bus, device;
269 {
270 	struct pcibios_intr_routing *pir;
271 	int entry;
272 
273 	if (pcibios_pir_table == NULL)
274 		return (NULL);
275 
276 	for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
277 		pir = &pcibios_pir_table[entry];
278 		if (pir->bus == bus &&
279 		    PIR_DEVFUNC_DEVICE(pir->device) == device)
280 			return (pir);
281 	}
282 
283 	return (NULL);
284 }
285 
286 static int
287 pciintr_bitmap_count_irq(irq_bitmap, irqp)
288 	int irq_bitmap, *irqp;
289 {
290 	int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION;
291 
292 	if (irq_bitmap != 0) {
293 		for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
294 			if (irq_bitmap & bit) {
295 				irq = i;
296 				count++;
297 			}
298 		}
299 	}
300 	*irqp = irq;
301 	return (count);
302 }
303 
304 static int
305 pciintr_bitmap_find_lowest_irq(irq_bitmap, irqp)
306 	int irq_bitmap, *irqp;
307 {
308 	int i, bit;
309 
310 	if (irq_bitmap != 0) {
311 		for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
312 			if (irq_bitmap & bit) {
313 				*irqp = i;
314 				return (1); /* found */
315 			}
316 		}
317 	}
318 	return (0); /* not found */
319 }
320 
321 int
322 pciintr_link_init()
323 {
324 	int entry, pin, link;
325 	struct pcibios_intr_routing *pir;
326 	struct pciintr_link_map *l;
327 
328 	if (pcibios_pir_table == NULL) {
329 		/* No PIR table; can't do anything. */
330 		printf("pciintr_link_init: no PIR table\n");
331 		return (1);
332 	}
333 
334 	SIMPLEQ_INIT(&pciintr_link_map_list);
335 
336 	for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
337 		pir = &pcibios_pir_table[entry];
338 		for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) {
339 			link = pir->linkmap[pin].link;
340 			if (link == 0) {
341 				/* No connection for this pin. */
342 				continue;
343 			}
344 			/*
345 			 * Multiple devices may be wired to the same
346 			 * interrupt; check to see if we've seen this
347 			 * one already.  If not, allocate a new link
348 			 * map entry and stuff it in the map.
349 			 */
350 			l = pciintr_link_lookup(link);
351 			if (l == NULL) {
352 				(void) pciintr_link_alloc(pir, pin);
353 			} else if (pir->linkmap[pin].bitmap != l->bitmap) {
354 				/*
355 				 * violates PCI IRQ Routing Table Specification
356 				 */
357 #ifdef DIAGNOSTIC
358 				printf("pciintr_link_init: "
359 				    "bus %d device %d link 0x%02x: "
360 				    "bad irq bitmap 0x%04x, "
361 				    "should be 0x%04x\n",
362 				    pir->bus, PIR_DEVFUNC_DEVICE(pir->device),
363 				    link, pir->linkmap[pin].bitmap, l->bitmap);
364 #endif
365 				/* safer value. */
366 				l->bitmap &= pir->linkmap[pin].bitmap;
367 				/* XXX - or, should ignore this entry? */
368 			}
369 		}
370 	}
371 
372 	return (0);
373 }
374 
375 #ifdef PCIBIOS_INTR_GUESS
376 /*
377  * No compatible PCI ICU found.
378  * Hopes the BIOS already setup the ICU.
379  */
380 int
381 pciintr_guess_irq()
382 {
383 	struct pciintr_link_map *l;
384 	int irq, guessed = 0;
385 
386 	/*
387 	 * Stage 1: If only one IRQ is available for the link, use it.
388 	 */
389 	for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
390 	     l = SIMPLEQ_NEXT(l, list)) {
391 		if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
392 			continue;
393 		if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) {
394 			l->irq = irq;
395 			l->fixup_stage = 1;
396 #ifdef PCIINTR_DEBUG
397 			printf("pciintr_guess_irq (stage 1): "
398 			    "guessing PIRQ 0x%02x to be IRQ %d\n",
399 			    l->clink, l->irq);
400 #endif
401 			guessed = 1;
402 		}
403 	}
404 
405 	return (guessed ? 0 : -1);
406 }
407 #endif /* PCIBIOS_INTR_GUESS */
408 
409 int
410 pciintr_link_fixup()
411 {
412 	struct pciintr_link_map *l;
413 	int irq;
414 	u_int16_t pciirq = 0;
415 
416 	/*
417 	 * First stage: Attempt to connect PIRQs which aren't
418 	 * yet connected.
419 	 */
420 	for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
421 	     l = SIMPLEQ_NEXT(l, list)) {
422 		if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
423 			/*
424 			 * Interrupt is already connected.  Don't do
425 			 * anything to it.
426 			 * In this case, l->fixup_stage == 0.
427 			 */
428 			pciirq |= 1 << l->irq;
429 #ifdef PCIINTR_DEBUG
430 			printf("pciintr_link_fixup: PIRQ 0x%02x already "
431 			    "connected to IRQ %d\n", l->clink, l->irq);
432 #endif
433 			continue;
434 		}
435 		/*
436 		 * Interrupt isn't connected.  Attempt to assign it to an IRQ.
437 		 */
438 #ifdef PCIINTR_DEBUG
439 		printf("pciintr_link_fixup: PIRQ 0x%02x not connected",
440 		    l->clink);
441 #endif
442 		/*
443 		 * Just do the easy case now; we'll defer the harder ones
444 		 * to Stage 2.
445 		 */
446 		if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) {
447 			l->irq = irq;
448 			l->fixup_stage = 1;
449 			pciirq |= 1 << irq;
450 #ifdef PCIINTR_DEBUG
451 			printf(", assigning IRQ %d", l->irq);
452 #endif
453 		}
454 #ifdef PCIINTR_DEBUG
455 		printf("\n");
456 #endif
457 	}
458 
459 	/*
460 	 * Stage 2: Attempt to connect PIRQs which we didn't
461 	 * connect in Stage 1.
462 	 */
463 	for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
464 	     l = SIMPLEQ_NEXT(l, list)) {
465 		if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
466 			continue;
467 		if (pciintr_bitmap_find_lowest_irq(l->bitmap & pciirq,
468 		    &l->irq)) {
469 			/*
470 			 * This IRQ is a valid PCI IRQ already
471 			 * connected to another PIRQ, and also an
472 			 * IRQ our PIRQ can use; connect it up!
473 			 */
474 			l->fixup_stage = 2;
475 #ifdef PCIINTR_DEBUG
476 			printf("pciintr_link_fixup (stage 2): "
477 			       "assigning IRQ %d to PIRQ 0x%02x\n",
478 			       l->irq, l->clink);
479 #endif
480 		}
481 	}
482 
483 #ifdef PCIBIOS_IRQS_HINT
484 	/*
485 	 * Stage 3: The worst case. I need configuration hint that
486 	 * user supplied a mask for the PCI irqs
487 	 */
488 	for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
489 	     l = SIMPLEQ_NEXT(l, list)) {
490 		if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
491 			continue;
492 		if (pciintr_bitmap_find_lowest_irq(
493 		    l->bitmap & pcibios_irqs_hint, &l->irq)) {
494 			l->fixup_stage = 3;
495 #ifdef PCIINTR_DEBUG
496 			printf("pciintr_link_fixup (stage 3): "
497 			       "assigning IRQ %d to PIRQ 0x%02x\n",
498 			       l->irq, l->clink);
499 #endif
500 		}
501 	}
502 #endif /* PCIBIOS_IRQS_HINT */
503 
504 	return (0);
505 }
506 
507 int
508 pciintr_link_route(pciirq)
509 	u_int16_t *pciirq;
510 {
511 	struct pciintr_link_map *l;
512 	int rv = 0;
513 
514 	*pciirq = 0;
515 
516 	for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
517 	     l = SIMPLEQ_NEXT(l, list)) {
518 		if (l->fixup_stage == 0) {
519 			if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
520 				/* Appropriate interrupt was not found. */
521 #ifdef DIAGNOSTIC
522 				printf("pciintr_link_route: "
523 				    "PIRQ 0x%02x: no IRQ, try "
524 				    "\"options PCIBIOS_IRQS_HINT=0x%04x\"\n",
525 				    l->clink,
526 				    /* suggest irq 9/10/11, if possible */
527 				    (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00)
528 				    : l->bitmap);
529 #endif
530 			} else {
531 				/* BIOS setting has no problem */
532 #ifdef PCIINTR_DEBUG
533 				printf("pciintr_link_route: "
534 				    "route of PIRQ 0x%02x -> "
535 				    "IRQ %d preserved BIOS setting\n",
536 				    l->clink, l->irq);
537 #endif
538 				*pciirq |= (1 << l->irq);
539 			}
540 			continue; /* nothing to do. */
541 		}
542 
543 		if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle,
544 					 l->clink, l->irq) != 0 ||
545 		    pciintr_icu_set_trigger(pciintr_icu_tag,
546 					    pciintr_icu_handle,
547 					    l->irq, IST_LEVEL) != 0) {
548 			printf("pciintr_link_route: route of PIRQ 0x%02x -> "
549 			    "IRQ %d failed\n", l->clink, l->irq);
550 			rv = 1;
551 		} else {
552 			/*
553 			 * Succssfully routed interrupt.  Mark this as
554 			 * a PCI interrupt.
555 			 */
556 			*pciirq |= (1 << l->irq);
557 		}
558 	}
559 
560 	return (rv);
561 }
562 
563 int
564 pciintr_irq_release(pciirq)
565 	u_int16_t *pciirq;
566 {
567 	int i, bit;
568 
569 	for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
570 		if ((*pciirq & bit) == 0)
571 			(void) pciintr_icu_set_trigger(pciintr_icu_tag,
572 			    pciintr_icu_handle, i, IST_EDGE);
573 	}
574 
575 	return (0);
576 }
577 
578 int
579 pciintr_header_fixup(pc)
580 	pci_chipset_tag_t pc;
581 {
582 	PCIBIOS_PRINTV(("------------------------------------------\n"));
583 	PCIBIOS_PRINTV(("  device vendor product pin PIRQ IRQ stage\n"));
584 	PCIBIOS_PRINTV(("------------------------------------------\n"));
585 	pci_device_foreach(pc, pcibios_max_bus, pciintr_do_header_fixup);
586 	PCIBIOS_PRINTV(("------------------------------------------\n"));
587 
588 	return (0);
589 }
590 
591 void
592 pciintr_do_header_fixup(pc, tag)
593 	pci_chipset_tag_t pc;
594 	pcitag_t tag;
595 {
596 	struct pcibios_intr_routing *pir;
597 	struct pciintr_link_map *l;
598 	int pin, irq, link;
599 	int bus, device, function;
600 	pcireg_t intr, id;
601 
602 	pci_decompose_tag(pc, tag, &bus, &device, &function);
603 	id = pci_conf_read(pc, tag, PCI_ID_REG);
604 
605 	intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
606 	pin = PCI_INTERRUPT_PIN(intr);
607 	irq = PCI_INTERRUPT_LINE(intr);
608 
609 	if (pin == 0) {
610 		/*
611 		 * No interrupt used.
612 		 */
613 		return;
614 	}
615 
616 	pir = pciintr_pir_lookup(bus, device);
617 	if (pir == NULL || (link = pir->linkmap[pin - 1].link) == 0) {
618 		/*
619 		 * Interrupt not connected; no
620 		 * need to change.
621 		 */
622 		return;
623 	}
624 
625 	l = pciintr_link_lookup(link);
626 	if (l == NULL) {
627 #ifdef PCIINTR_DEBUG
628 		/*
629 		 * No link map entry.
630 		 * Probably pciintr_icu_getclink() or pciintr_icu_get_intr()
631 		 * was failed.
632 		 */
633 		printf("pciintr_header_fixup: no entry for link 0x%02x "
634 		       "(%d:%d:%d:%c)\n", link, bus, device, function,
635 		       '@' + pin);
636 #endif
637 		return;
638 	}
639 
640 #ifdef PCIBIOSVERBOSE
641 	if (pcibiosverbose) {
642 		printf("%03d:%02d:%d 0x%04x 0x%04x   %c  0x%02x",
643 		    bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id),
644 		    '@' + pin, l->clink);
645 		if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
646 			printf("   -");
647 		else
648 			printf(" %3d", l->irq);
649 		printf("  %d   ", l->fixup_stage);
650 	}
651 #endif
652 
653 	/*
654 	 * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck
655 	 * with them.
656 	 */
657 	if (irq == 14 || irq == 15) {
658 		PCIBIOS_PRINTV((" WARNING: ignored\n"));
659 		return;
660 	}
661 
662 	if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
663 		/* Appropriate interrupt was not found. */
664 		if (pciintr_icu_tag == NULL &&
665 		    irq != 0 && irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
666 			/*
667 			 * Do not print warning,
668 			 * if no compatible PCI ICU found,
669 			 * but the irq is already assigned by BIOS.
670 			 */
671 			PCIBIOS_PRINTV(("\n"));
672 		} else {
673 			PCIBIOS_PRINTV((" WARNING: missing IRQ\n"));
674 		}
675 		return;
676 	}
677 
678 	if (l->irq == irq) {
679 		/* don't have to reconfigure */
680 		PCIBIOS_PRINTV((" already assigned\n"));
681 		return;
682 	}
683 
684 	if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
685 		PCIBIOS_PRINTV((" fixed up\n"));
686 	} else {
687 		/* routed by BIOS, but inconsistent */
688 #ifdef PCIBIOS_INTR_FIXUP_FORCE
689 		/* believe PCI IRQ Routing table */
690 		PCIBIOS_PRINTV((" WARNING: overriding irq %d\n", irq));
691 #else
692 		/* believe PCI Interrupt Configuration Register (default) */
693 		PCIBIOS_PRINTV((" WARNING: preserving irq %d\n", irq));
694 		return;
695 #endif
696 	}
697 
698 	intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
699 	intr |= (l->irq << PCI_INTERRUPT_LINE_SHIFT);
700 	pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
701 }
702 
703 int
704 pci_intr_fixup(pc, iot, pciirq)
705 	pci_chipset_tag_t pc;
706 	bus_space_tag_t iot;
707 	u_int16_t *pciirq;
708 {
709 	const struct pciintr_icu_table *piit = NULL;
710 	pcitag_t icutag;
711 	pcireg_t icuid;
712 
713 	/*
714 	 * Attempt to initialize our PCI interrupt router.  If
715 	 * the PIR Table is present in ROM, use the location
716 	 * specified by the PIR Table, and use the compat ID,
717 	 * if present.  Otherwise, we have to look for the router
718 	 * ourselves (the PCI-ISA bridge).
719 	 */
720 	if (pcibios_pir_header.signature != 0) {
721 		icutag = pci_make_tag(pc, pcibios_pir_header.router_bus,
722 		    PIR_DEVFUNC_DEVICE(pcibios_pir_header.router_devfunc),
723 		    PIR_DEVFUNC_FUNCTION(pcibios_pir_header.router_devfunc));
724 		icuid = pcibios_pir_header.compat_router;
725 		if (icuid == 0 ||
726 		    (piit = pciintr_icu_lookup(icuid)) == NULL) {
727 			/*
728 			 * No compat ID, or don't know the compat ID?  Read
729 			 * it from the configuration header.
730 			 */
731 			icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
732 		}
733 		if (piit == NULL)
734 			piit = pciintr_icu_lookup(icuid);
735 	} else {
736 		int device, maxdevs = pci_bus_maxdevs(pc, 0);
737 
738 		/*
739 		 * Search configuration space for a known interrupt
740 		 * router.
741 		 */
742 		for (device = 0; device < maxdevs; device++) {
743 			icutag = pci_make_tag(pc, 0, device, 0);
744 			icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
745 
746 			/* Invalid vendor ID value? */
747 			if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
748 				continue;
749 			/* XXX Not invalid, but we've done this ~forever. */
750 			if (PCI_VENDOR(icuid) == 0)
751 				continue;
752 
753 			piit = pciintr_icu_lookup(icuid);
754 			if (piit != NULL)
755 				break;
756 		}
757 	}
758 
759 	if (piit == NULL) {
760 		printf("pci_intr_fixup: no compatible PCI ICU found");
761 		if (pcibios_pir_header.signature != 0 && icuid != 0)
762 			printf(": ICU vendor 0x%04x product 0x%04x",
763 			    PCI_VENDOR(icuid), PCI_PRODUCT(icuid));
764 		printf("\n");
765 #ifdef PCIBIOS_INTR_GUESS
766 		if (pciintr_link_init())
767 			return (-1);	/* non-fatal */
768 		if (pciintr_guess_irq())
769 			return (-1);	/* non-fatal */
770 		if (pciintr_header_fixup(pc))
771 			return (1);	/* fatal */
772 		return (0);		/* success! */
773 #else
774 		return (-1);		/* non-fatal */
775 #endif
776 	}
777 
778 	/*
779 	 * Initialize the PCI ICU.
780 	 */
781 	if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag,
782 	    &pciintr_icu_handle) != 0)
783 		return (-1);		/* non-fatal */
784 
785 	/*
786 	 * Initialize the PCI interrupt link map.
787 	 */
788 	if (pciintr_link_init())
789 		return (-1);		/* non-fatal */
790 
791 	/*
792 	 * Fix up the link->IRQ mappings.
793 	 */
794 	if (pciintr_link_fixup() != 0)
795 		return (-1);		/* non-fatal */
796 
797 	/*
798 	 * Now actually program the PCI ICU with the new
799 	 * routing information.
800 	 */
801 	if (pciintr_link_route(pciirq) != 0)
802 		return (1);		/* fatal */
803 
804 	/*
805 	 * Now that we've routed all of the PIRQs, rewrite the PCI
806 	 * configuration headers to reflect the new mapping.
807 	 */
808 	if (pciintr_header_fixup(pc) != 0)
809 		return (1);		/* fatal */
810 
811 	/*
812 	 * Free any unused PCI IRQs for ISA devices.
813 	 */
814 	if (pciintr_irq_release(pciirq) != 0)
815 		return (-1);		/* non-fatal */
816 
817 	/*
818 	 * All done!
819 	 */
820 	return (0);			/* success! */
821 }
822