pci_intr_fixup.c revision 1.7 1 /* $NetBSD: pci_intr_fixup.c,v 1.7 2000/07/18 11:22:36 soda 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;
99 pciintr_icu_handle_t pciintr_icu_handle;
100
101 struct pciintr_link_map *pciintr_link_lookup __P((int));
102 struct pciintr_link_map *pciintr_link_alloc __P((struct pcibios_intr_routing *,
103 int));
104 struct pcibios_intr_routing *pciintr_pir_lookup __P((int, int));
105 static int pciintr_bitmap_count_irq __P((int, int *));
106 static int pciintr_bitmap_find_lowest_irq __P((int, int *));
107 int pciintr_link_init __P((void));
108 int pciintr_link_fixup __P((void));
109 int pciintr_link_route __P((u_int16_t *));
110 int pciintr_irq_release __P((u_int16_t *));
111 int pciintr_header_fixup __P((pci_chipset_tag_t));
112 void pciintr_do_header_fixup __P((pci_chipset_tag_t, pcitag_t));
113
114 SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list;
115
116 const struct pciintr_icu_table {
117 pci_vendor_id_t piit_vendor;
118 pci_product_id_t piit_product;
119 int (*piit_init) __P((pci_chipset_tag_t,
120 bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *,
121 pciintr_icu_handle_t *));
122 } pciintr_icu_table[] = {
123 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX,
124 piix_init },
125 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA,
126 piix_init },
127 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA,
128 piix_init },
129 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA,
130 piix_init },
131
132 { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558,
133 opti82c558_init },
134 { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700,
135 opti82c700_init },
136
137 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA,
138 via82c586_init, },
139
140 { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503,
141 sis85c503_init },
142
143 { 0, 0,
144 NULL },
145 };
146
147 const struct pciintr_icu_table *pciintr_icu_lookup __P((pcireg_t));
148
149 const struct pciintr_icu_table *
150 pciintr_icu_lookup(id)
151 pcireg_t id;
152 {
153 const struct pciintr_icu_table *piit;
154
155 for (piit = pciintr_icu_table;
156 piit->piit_init != NULL;
157 piit++) {
158 if (PCI_VENDOR(id) == piit->piit_vendor &&
159 PCI_PRODUCT(id) == piit->piit_product)
160 return (piit);
161 }
162
163 return (NULL);
164 }
165
166 struct pciintr_link_map *
167 pciintr_link_lookup(link)
168 int link;
169 {
170 struct pciintr_link_map *l;
171
172 for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
173 l = SIMPLEQ_NEXT(l, list)) {
174 if (l->link == link)
175 return (l);
176 }
177
178 return (NULL);
179 }
180
181 struct pciintr_link_map *
182 pciintr_link_alloc(pir, pin)
183 struct pcibios_intr_routing *pir;
184 int pin;
185 {
186 int link = pir->linkmap[pin].link, clink, irq;
187 struct pciintr_link_map *l, *lstart;
188
189 /*
190 * Get the canonical link value for this entry.
191 */
192 if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle, link,
193 &clink) != 0) {
194 /*
195 * ICU doesn't understand the link value.
196 * Just ignore this PIR entry.
197 */
198 #ifdef DIAGNOSTIC
199 printf("pciintr_link_alloc: bus %d device %d: "
200 "link 0x%02x invalid\n",
201 pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link);
202 #endif
203 return (NULL);
204 }
205
206 /*
207 * Check the link value by asking the ICU for the canonical link value.
208 * Also, determine if this PIRQ is mapped to an IRQ.
209 */
210 if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle, clink,
211 &irq) != 0) {
212 /*
213 * ICU doesn't understand the canonical link value.
214 * Just ignore this PIR entry.
215 */
216 #ifdef DIAGNOSTIC
217 printf("pciintr_link_alloc: bus %d device %d link 0x%02x: "
218 "PIRQ 0x%02x invalid\n",
219 pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link, clink);
220 #endif
221 return (NULL);
222 }
223
224 l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT);
225 if (l == NULL)
226 panic("pciintr_link_alloc");
227
228 memset(l, 0, sizeof(*l));
229
230 l->link = link;
231 l->bitmap = pir->linkmap[pin].bitmap;
232 l->clink = clink;
233 l->irq = irq; /* may be I386_PCI_INTERRUPT_LINE_NO_CONNECTION */
234
235 lstart = SIMPLEQ_FIRST(&pciintr_link_map_list);
236 if (lstart == NULL || lstart->link < l->link)
237 SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list);
238 else
239 SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list);
240
241 return (l);
242 }
243
244 struct pcibios_intr_routing *
245 pciintr_pir_lookup(bus, device)
246 int bus, device;
247 {
248 struct pcibios_intr_routing *pir;
249 int entry;
250
251 if (pcibios_pir_table == NULL)
252 return (NULL);
253
254 for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
255 pir = &pcibios_pir_table[entry];
256 if (pir->bus == bus &&
257 PIR_DEVFUNC_DEVICE(pir->device) == device)
258 return (pir);
259 }
260
261 return (NULL);
262 }
263
264 static int
265 pciintr_bitmap_count_irq(irq_bitmap, irqp)
266 int irq_bitmap, *irqp;
267 {
268 int i, bit, count = 0, irq = I386_PCI_INTERRUPT_LINE_NO_CONNECTION;
269
270 if (irq_bitmap != 0) {
271 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
272 if (irq_bitmap & bit) {
273 irq = i;
274 count++;
275 }
276 }
277 }
278 *irqp = irq;
279 return (count);
280 }
281
282 static int
283 pciintr_bitmap_find_lowest_irq(irq_bitmap, irqp)
284 int irq_bitmap, *irqp;
285 {
286 int i, bit;
287
288 if (irq_bitmap != 0) {
289 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
290 if (irq_bitmap & bit) {
291 *irqp = i;
292 return (1); /* found */
293 }
294 }
295 }
296 return (0); /* not found */
297 }
298
299 int
300 pciintr_link_init()
301 {
302 int entry, pin, error, link;
303 struct pcibios_intr_routing *pir;
304 struct pciintr_link_map *l;
305
306 if (pcibios_pir_table == NULL) {
307 /* No PIR table; can't do anything. */
308 printf("pciintr_link_init: no PIR table\n");
309 return (1);
310 }
311
312 error = 0;
313 SIMPLEQ_INIT(&pciintr_link_map_list);
314
315 for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
316 pir = &pcibios_pir_table[entry];
317 for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) {
318 link = pir->linkmap[pin].link;
319 if (link == 0) {
320 /* No connection for this pin. */
321 continue;
322 }
323 /*
324 * Multiple devices may be wired to the same
325 * interrupt; check to see if we've seen this
326 * one already. If not, allocate a new link
327 * map entry and stuff it in the map.
328 */
329 l = pciintr_link_lookup(link);
330 if (l == NULL) {
331 (void) pciintr_link_alloc(pir, pin);
332 } else if (pir->linkmap[pin].bitmap != l->bitmap) {
333 /*
334 * violates PCI IRQ Routing Table Specification
335 */
336 #ifdef DIAGNOSTIC
337 printf("pciintr_link_init: "
338 "bus %d device %d link 0x%02x: "
339 "bad irq bitmap 0x%04x, "
340 "should be 0x%04x\n",
341 pir->bus, PIR_DEVFUNC_DEVICE(pir->device),
342 link, pir->linkmap[pin].bitmap, l->bitmap);
343 #endif
344 /* safer value. */
345 l->bitmap &= pir->linkmap[pin].bitmap;
346 /* XXX - or, should ignore this entry? */
347 }
348 }
349 }
350
351 return (error);
352 }
353
354 int
355 pciintr_link_fixup()
356 {
357 struct pciintr_link_map *l;
358 int irq;
359 u_int16_t pciirq = 0;
360
361 /*
362 * First stage: Attempt to connect PIRQs which aren't
363 * yet connected.
364 */
365 for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
366 l = SIMPLEQ_NEXT(l, list)) {
367 if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
368 /*
369 * Interrupt is already connected. Don't do
370 * anything to it.
371 * In this case, l->fixup_stage == 0.
372 */
373 pciirq |= 1 << l->irq;
374 #ifdef PCIINTR_DEBUG
375 printf("pciintr_link_fixup: PIRQ 0x%02x already "
376 "connected to IRQ %d\n", l->clink, l->irq);
377 #endif
378 continue;
379 }
380 /*
381 * Interrupt isn't connected. Attempt to assign it to an IRQ.
382 */
383 #ifdef PCIINTR_DEBUG
384 printf("pciintr_link_fixup: PIRQ 0x%02x not connected",
385 l->clink);
386 #endif
387 /*
388 * Just do the easy case now; we'll defer the harder ones
389 * to Stage 2.
390 */
391 if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) {
392 l->irq = irq;
393 l->fixup_stage = 1;
394 pciirq |= 1 << irq;
395 #ifdef PCIINTR_DEBUG
396 printf(", assigning IRQ %d", l->irq);
397 #endif
398 }
399 #ifdef PCIINTR_DEBUG
400 printf("\n");
401 #endif
402 }
403
404 /*
405 * Stage 2: Attempt to connect PIRQs which we didn't
406 * connect in Stage 1.
407 */
408 for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
409 l = SIMPLEQ_NEXT(l, list)) {
410 if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
411 continue;
412 if (pciintr_bitmap_find_lowest_irq(l->bitmap & pciirq,
413 &l->irq)) {
414 /*
415 * This IRQ is a valid PCI IRQ already
416 * connected to another PIRQ, and also an
417 * IRQ our PIRQ can use; connect it up!
418 */
419 l->fixup_stage = 2;
420 #ifdef PCIINTR_DEBUG
421 printf("pciintr_link_fixup (stage 2): "
422 "assigning IRQ %d to PIRQ 0x%02x\n",
423 l->irq, l->clink);
424 #endif
425 }
426 }
427
428 #ifdef PCIBIOS_IRQS_HINT
429 /*
430 * Stage 3: The worst case. I need configuration hint that
431 * user supplied a mask for the PCI irqs
432 */
433 for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
434 l = SIMPLEQ_NEXT(l, list)) {
435 if (l->irq != I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
436 continue;
437 if (pciintr_bitmap_find_lowest_irq(
438 l->bitmap & PCIBIOS_IRQS_HINT, &l->irq)) {
439 l->fixup_stage = 3;
440 #ifdef PCIINTR_DEBUG
441 printf("pciintr_link_fixup (stage 3): "
442 "assigning IRQ %d to PIRQ 0x%02x\n",
443 l->irq, l->clink);
444 #endif
445 }
446 }
447 #endif /* PCIBIOS_IRQS_HINT */
448
449 return (0);
450 }
451
452 int
453 pciintr_link_route(pciirq)
454 u_int16_t *pciirq;
455 {
456 struct pciintr_link_map *l;
457 int rv = 0;
458
459 *pciirq = 0;
460
461 for (l = SIMPLEQ_FIRST(&pciintr_link_map_list); l != NULL;
462 l = SIMPLEQ_NEXT(l, list)) {
463 if (l->fixup_stage == 0) {
464 if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
465 /* Appropriate interrupt was not found. */
466 #ifdef DIAGNOSTIC
467 printf("pciintr_link_route: "
468 "PIRQ 0x%02x: no IRQ, try "
469 "\"options PCIBIOS_IRQS_HINT=0x%04x\"\n",
470 l->clink,
471 /* suggest irq 9/10/11, if possible */
472 (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00)
473 : l->bitmap);
474 #endif
475 } else {
476 /* BIOS setting has no problem */
477 #ifdef PCIINTR_DEBUG
478 printf("pciintr_link_route: "
479 "route of PIRQ 0x%02x -> "
480 "IRQ %d preserved BIOS setting\n",
481 l->clink, l->irq);
482 #endif
483 *pciirq |= (1 << l->irq);
484 }
485 continue; /* nothing to do. */
486 }
487
488 if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle,
489 l->clink, l->irq) != 0 ||
490 pciintr_icu_set_trigger(pciintr_icu_tag,
491 pciintr_icu_handle,
492 l->irq, IST_LEVEL) != 0) {
493 printf("pciintr_link_route: route of PIRQ 0x%02x -> "
494 "IRQ %d failed\n", l->clink, l->irq);
495 rv = 1;
496 } else {
497 /*
498 * Succssfully routed interrupt. Mark this as
499 * a PCI interrupt.
500 */
501 *pciirq |= (1 << l->irq);
502 }
503 }
504
505 return (rv);
506 }
507
508 int
509 pciintr_irq_release(pciirq)
510 u_int16_t *pciirq;
511 {
512 int i, bit;
513
514 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
515 if ((*pciirq & bit) == 0)
516 (void) pciintr_icu_set_trigger(pciintr_icu_tag,
517 pciintr_icu_handle, i, IST_EDGE);
518 }
519
520 return (0);
521 }
522
523 int
524 pciintr_header_fixup(pc)
525 pci_chipset_tag_t pc;
526 {
527 PCIBIOS_PRINTV(("------------------------------------------\n"));
528 PCIBIOS_PRINTV((" device vendor product pin PIRQ IRQ stage\n"));
529 PCIBIOS_PRINTV(("------------------------------------------\n"));
530 pci_device_foreach(pc, pcibios_max_bus, pciintr_do_header_fixup);
531 PCIBIOS_PRINTV(("------------------------------------------\n"));
532
533 return (0);
534 }
535
536 void
537 pciintr_do_header_fixup(pc, tag)
538 pci_chipset_tag_t pc;
539 pcitag_t tag;
540 {
541 struct pcibios_intr_routing *pir;
542 struct pciintr_link_map *l;
543 int pin, irq, link;
544 int bus, device, function;
545 pcireg_t intr, id;
546
547 pci_decompose_tag(pc, tag, &bus, &device, &function);
548 id = pci_conf_read(pc, tag, PCI_ID_REG);
549
550 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
551 pin = PCI_INTERRUPT_PIN(intr);
552 irq = PCI_INTERRUPT_LINE(intr);
553
554 if (pin == 0) {
555 /*
556 * No interrupt used.
557 */
558 return;
559 }
560
561 pir = pciintr_pir_lookup(bus, device);
562 if (pir == NULL || (link = pir->linkmap[pin - 1].link) == 0) {
563 /*
564 * Interrupt not connected; no
565 * need to change.
566 */
567 return;
568 }
569
570 l = pciintr_link_lookup(link);
571 if (l == NULL) {
572 #ifdef PCIINTR_DEBUG
573 /*
574 * No link map entry.
575 * Probably pciintr_icu_getclink() or pciintr_icu_get_intr()
576 * was failed.
577 */
578 printf("pciintr_header_fixup: no entry for link 0x%02x "
579 "(%d:%d:%d:%c)\n", link, bus, device, function,
580 '@' + pin);
581 #endif
582 return;
583 }
584
585 #ifdef PCIBIOSVERBOSE
586 if (pcibiosverbose) {
587 printf("%03d:%02d:%d 0x%04x 0x%04x %c 0x%02x",
588 bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id),
589 '@' + pin, l->clink);
590 if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION)
591 printf(" -");
592 else
593 printf(" %3d", l->irq);
594 printf(" %d ", l->fixup_stage);
595 }
596 #endif
597
598 /*
599 * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck
600 * with them.
601 */
602 if (irq == 14 || irq == 15) {
603 PCIBIOS_PRINTV((" WARNING: ignored\n"));
604 return;
605 }
606
607 if (l->irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
608 /* Appropriate interrupt was not found. */
609 PCIBIOS_PRINTV((" WARNING: missing IRQ\n"));
610 return;
611 }
612
613 if (l->irq == irq) {
614 /* don't have to reconfigure */
615 PCIBIOS_PRINTV((" already assigned\n"));
616 return;
617 }
618
619 if (irq == 0 || irq == I386_PCI_INTERRUPT_LINE_NO_CONNECTION) {
620 PCIBIOS_PRINTV((" fixed up\n"));
621 } else {
622 /* routed by BIOS, but inconsistent */
623 #ifdef PCIBIOS_INTR_FIXUP_FORCE
624 /* believe PCI IRQ Routing table */
625 PCIBIOS_PRINTV((" WARNING: override irq %d\n", irq));
626 #else
627 /* believe PCI Interrupt Configuration Register (default) */
628 PCIBIOS_PRINTV((" WARNING: leave irq %d\n", irq));
629 return;
630 #endif
631 }
632
633 intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
634 intr |= (l->irq << PCI_INTERRUPT_LINE_SHIFT);
635 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
636 }
637
638 int
639 pci_intr_fixup(pc, iot, pciirq)
640 pci_chipset_tag_t pc;
641 bus_space_tag_t iot;
642 u_int16_t *pciirq;
643 {
644 const struct pciintr_icu_table *piit = NULL;
645 pcitag_t icutag;
646 pcireg_t icuid;
647
648 /*
649 * Attempt to initialize our PCI interrupt router. If
650 * the PIR Table is present in ROM, use the location
651 * specified by the PIR Table, and use the compat ID,
652 * if present. Otherwise, we have to look for the router
653 * ourselves (the PCI-ISA bridge).
654 */
655 if (pcibios_pir_header.signature != 0) {
656 icutag = pci_make_tag(pc, pcibios_pir_header.router_bus,
657 PIR_DEVFUNC_DEVICE(pcibios_pir_header.router_devfunc),
658 PIR_DEVFUNC_FUNCTION(pcibios_pir_header.router_devfunc));
659 icuid = pcibios_pir_header.compat_router;
660 if (icuid == 0 ||
661 (piit = pciintr_icu_lookup(icuid)) == NULL) {
662 /*
663 * No compat ID, or don't know the compat ID? Read
664 * it from the configuration header.
665 */
666 icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
667 }
668 if (piit == NULL)
669 piit = pciintr_icu_lookup(icuid);
670 } else {
671 int device, maxdevs = pci_bus_maxdevs(pc, 0);
672
673 /*
674 * Search configuration space for a known interrupt
675 * router.
676 */
677 for (device = 0; device < maxdevs; device++) {
678 icutag = pci_make_tag(pc, 0, device, 0);
679 icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
680
681 /* Invalid vendor ID value? */
682 if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
683 continue;
684 /* XXX Not invalid, but we've done this ~forever. */
685 if (PCI_VENDOR(icuid) == 0)
686 continue;
687
688 piit = pciintr_icu_lookup(icuid);
689 if (piit != NULL)
690 break;
691 }
692 }
693
694 if (piit == NULL) {
695 printf("pci_intr_fixup: no compatible PCI ICU found\n");
696 return (-1); /* non-fatal */
697 }
698
699 /*
700 * Initialize the PCI ICU.
701 */
702 if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag,
703 &pciintr_icu_handle) != 0)
704 return (-1); /* non-fatal */
705
706 /*
707 * Initialize the PCI interrupt link map.
708 */
709 if (pciintr_link_init())
710 return (-1); /* non-fatal */
711
712 /*
713 * Fix up the link->IRQ mappings.
714 */
715 if (pciintr_link_fixup() != 0)
716 return (-1); /* non-fatal */
717
718 /*
719 * Now actually program the PCI ICU with the new
720 * routing information.
721 */
722 if (pciintr_link_route(pciirq) != 0)
723 return (1); /* fatal */
724
725 /*
726 * Now that we've routed all of the PIRQs, rewrite the PCI
727 * configuration headers to reflect the new mapping.
728 */
729 if (pciintr_header_fixup(pc) != 0)
730 return (1); /* fatal */
731
732 /*
733 * Free any unused PCI IRQs for ISA devices.
734 */
735 if (pciintr_irq_release(pciirq) != 0)
736 return (-1); /* non-fatal */
737
738 /*
739 * All done!
740 */
741 return (0); /* success! */
742 }
743