pci_intr_fixup.c revision 1.35 1 /* $NetBSD: pci_intr_fixup.c,v 1.35 2005/12/26 19:24:00 perry 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 <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: pci_intr_fixup.c,v 1.35 2005/12/26 19:24:00 perry Exp $");
71
72 #include "opt_pcibios.h"
73 #include "opt_pcifixup.h"
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/kernel.h>
78 #include <sys/malloc.h>
79 #include <sys/queue.h>
80 #include <sys/device.h>
81
82 #include <machine/bus.h>
83 #include <machine/intr.h>
84
85 #include <dev/pci/pcireg.h>
86 #include <dev/pci/pcivar.h>
87 #include <dev/pci/pcidevs.h>
88
89 #include <i386/pci/pci_intr_fixup.h>
90 #include <i386/pci/pcibios.h>
91
92 struct pciintr_link_map {
93 int link;
94 int clink;
95 int irq;
96 uint16_t bitmap;
97 int fixup_stage;
98 SIMPLEQ_ENTRY(pciintr_link_map) list;
99 };
100
101 pciintr_icu_tag_t pciintr_icu_tag;
102 pciintr_icu_handle_t pciintr_icu_handle;
103
104 #ifdef PCIBIOS_IRQS_HINT
105 int pcibios_irqs_hint = PCIBIOS_IRQS_HINT;
106 #endif
107
108 struct pciintr_link_map *pciintr_link_lookup(int);
109 struct pciintr_link_map *pciintr_link_alloc(struct pcibios_intr_routing *,
110 int);
111 struct pcibios_intr_routing *pciintr_pir_lookup(int, int);
112 static int pciintr_bitmap_count_irq(int, int *);
113 static int pciintr_bitmap_find_lowest_irq(int, int *);
114 int pciintr_link_init (void);
115 #ifdef PCIBIOS_INTR_GUESS
116 int pciintr_guess_irq(void);
117 #endif
118 int pciintr_link_fixup(void);
119 int pciintr_link_route(uint16_t *);
120 int pciintr_irq_release(uint16_t *);
121 int pciintr_header_fixup(pci_chipset_tag_t);
122 void pciintr_do_header_fixup(pci_chipset_tag_t, pcitag_t, void*);
123
124 SIMPLEQ_HEAD(, pciintr_link_map) pciintr_link_map_list;
125
126 const struct pciintr_icu_table {
127 pci_vendor_id_t piit_vendor;
128 pci_product_id_t piit_product;
129 int (*piit_init)(pci_chipset_tag_t,
130 bus_space_tag_t, pcitag_t, pciintr_icu_tag_t *,
131 pciintr_icu_handle_t *);
132 } pciintr_icu_table[] = {
133 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371MX,
134 piix_init },
135 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371AB_ISA,
136 piix_init },
137 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371FB_ISA,
138 piix_init },
139 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82371SB_ISA,
140 piix_init },
141 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_LPC,
142 piix_init }, /* ICH */
143 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_LPC,
144 piix_init }, /* ICH0 */
145 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_LPC,
146 ich_init }, /* ICH2 */
147 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BAM_LPC,
148 ich_init }, /* ICH2M */
149 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_LPC,
150 ich_init }, /* ICH3S */
151 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CAM_LPC,
152 ich_init }, /* ICH3M */
153 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_LPC,
154 ich_init }, /* ICH4 */
155 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_ISA,
156 ich_init }, /* ICH4M */
157 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_LPC,
158 ich_init }, /* ICH5 */
159 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FBM_LPC,
160 ich_init }, /* ICH6M */
161
162 { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C558,
163 opti82c558_init },
164 { PCI_VENDOR_OPTI, PCI_PRODUCT_OPTI_82C700,
165 opti82c700_init },
166
167 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C586_ISA,
168 via82c586_init },
169 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596A,
170 via82c586_init },
171 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_ISA,
172 via82c586_init },
173
174 { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_85C503,
175 sis85c503_init },
176
177 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC,
178 amd756_init },
179
180 { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543,
181 ali1543_init },
182
183 { 0, 0,
184 NULL },
185 };
186
187 const struct pciintr_icu_table *pciintr_icu_lookup(pcireg_t);
188
189 const struct pciintr_icu_table *
190 pciintr_icu_lookup(pcireg_t id)
191 {
192 const struct pciintr_icu_table *piit;
193
194 for (piit = pciintr_icu_table;
195 piit->piit_init != NULL;
196 piit++) {
197 if (PCI_VENDOR(id) == piit->piit_vendor &&
198 PCI_PRODUCT(id) == piit->piit_product)
199 return (piit);
200 }
201
202 return (NULL);
203 }
204
205 struct pciintr_link_map *
206 pciintr_link_lookup(int link)
207 {
208 struct pciintr_link_map *l;
209
210 SIMPLEQ_FOREACH(l, &pciintr_link_map_list, list) {
211 if (l->link == link)
212 return (l);
213 }
214
215 return (NULL);
216 }
217
218 struct pciintr_link_map *
219 pciintr_link_alloc(struct pcibios_intr_routing *pir, int pin)
220 {
221 int link = pir->linkmap[pin].link, clink, irq;
222 struct pciintr_link_map *l, *lstart;
223
224 if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */
225 /*
226 * Get the canonical link value for this entry.
227 */
228 if (pciintr_icu_getclink(pciintr_icu_tag, pciintr_icu_handle,
229 link, &clink) != 0) {
230 /*
231 * ICU doesn't understand the link value.
232 * Just ignore this PIR entry.
233 */
234 #ifdef DIAGNOSTIC
235 printf("pciintr_link_alloc: bus %d device %d: "
236 "link 0x%02x invalid\n",
237 pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link);
238 #endif
239 return (NULL);
240 }
241
242 /*
243 * Check the link value by asking the ICU for the
244 * canonical link value.
245 * Also, determine if this PIRQ is mapped to an IRQ.
246 */
247 if (pciintr_icu_get_intr(pciintr_icu_tag, pciintr_icu_handle,
248 clink, &irq) != 0) {
249 /*
250 * ICU doesn't understand the canonical link value.
251 * Just ignore this PIR entry.
252 */
253 #ifdef DIAGNOSTIC
254 printf("pciintr_link_alloc: "
255 "bus %d device %d link 0x%02x: "
256 "PIRQ 0x%02x invalid\n",
257 pir->bus, PIR_DEVFUNC_DEVICE(pir->device), link,
258 clink);
259 #endif
260 return (NULL);
261 }
262 }
263
264 l = malloc(sizeof(*l), M_DEVBUF, M_NOWAIT);
265 if (l == NULL)
266 panic("pciintr_link_alloc");
267
268 memset(l, 0, sizeof(*l));
269
270 l->link = link;
271 l->bitmap = pir->linkmap[pin].bitmap;
272 if (pciintr_icu_tag != NULL) { /* compatible PCI ICU found */
273 l->clink = clink;
274 l->irq = irq; /* maybe X86_PCI_INTERRUPT_LINE_NO_CONNECTION */
275 } else {
276 l->clink = link; /* only for PCIBIOSVERBOSE diagnostic */
277 l->irq = X86_PCI_INTERRUPT_LINE_NO_CONNECTION;
278 }
279
280 lstart = SIMPLEQ_FIRST(&pciintr_link_map_list);
281 if (lstart == NULL || lstart->link < l->link)
282 SIMPLEQ_INSERT_TAIL(&pciintr_link_map_list, l, list);
283 else
284 SIMPLEQ_INSERT_HEAD(&pciintr_link_map_list, l, list);
285
286 return (l);
287 }
288
289 struct pcibios_intr_routing *
290 pciintr_pir_lookup(int bus, int device)
291 {
292 struct pcibios_intr_routing *pir;
293 int entry;
294
295 if (pcibios_pir_table == NULL)
296 return (NULL);
297
298 for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
299 pir = &pcibios_pir_table[entry];
300 if (pir->bus == bus &&
301 PIR_DEVFUNC_DEVICE(pir->device) == device)
302 return (pir);
303 }
304
305 return (NULL);
306 }
307
308 static int
309 pciintr_bitmap_count_irq(int irq_bitmap, int *irqp)
310 {
311 int i, bit, count = 0, irq = X86_PCI_INTERRUPT_LINE_NO_CONNECTION;
312
313 if (irq_bitmap != 0) {
314 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
315 if (irq_bitmap & bit) {
316 irq = i;
317 count++;
318 }
319 }
320 }
321 *irqp = irq;
322 return (count);
323 }
324
325 static int
326 pciintr_bitmap_find_lowest_irq(int irq_bitmap, int *irqp)
327 {
328 int i, bit;
329
330 if (irq_bitmap != 0) {
331 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
332 if (irq_bitmap & bit) {
333 *irqp = i;
334 return (1); /* found */
335 }
336 }
337 }
338 return (0); /* not found */
339 }
340
341 int
342 pciintr_link_init(void)
343 {
344 int entry, pin, link;
345 struct pcibios_intr_routing *pir;
346 struct pciintr_link_map *l;
347
348 if (pcibios_pir_table == NULL) {
349 /* No PIR table; can't do anything. */
350 printf("pciintr_link_init: no PIR table\n");
351 return (1);
352 }
353
354 SIMPLEQ_INIT(&pciintr_link_map_list);
355
356 for (entry = 0; entry < pcibios_pir_table_nentries; entry++) {
357 pir = &pcibios_pir_table[entry];
358 for (pin = 0; pin < PCI_INTERRUPT_PIN_MAX; pin++) {
359 link = pir->linkmap[pin].link;
360 if (link == 0) {
361 /* No connection for this pin. */
362 continue;
363 }
364 /*
365 * Multiple devices may be wired to the same
366 * interrupt; check to see if we've seen this
367 * one already. If not, allocate a new link
368 * map entry and stuff it in the map.
369 */
370 l = pciintr_link_lookup(link);
371 if (l == NULL) {
372 (void) pciintr_link_alloc(pir, pin);
373 } else if (pir->linkmap[pin].bitmap != l->bitmap) {
374 /*
375 * violates PCI IRQ Routing Table Specification
376 */
377 #ifdef DIAGNOSTIC
378 printf("pciintr_link_init: "
379 "bus %d device %d link 0x%02x: "
380 "bad irq bitmap 0x%04x, "
381 "should be 0x%04x\n",
382 pir->bus, PIR_DEVFUNC_DEVICE(pir->device),
383 link, pir->linkmap[pin].bitmap, l->bitmap);
384 #endif
385 /* safer value. */
386 l->bitmap &= pir->linkmap[pin].bitmap;
387 /* XXX - or, should ignore this entry? */
388 }
389 }
390 }
391
392 return (0);
393 }
394
395 #ifdef PCIBIOS_INTR_GUESS
396 /*
397 * No compatible PCI ICU found.
398 * Hopes the BIOS already setup the ICU.
399 */
400 int
401 pciintr_guess_irq(void)
402 {
403 struct pciintr_link_map *l;
404 int irq, guessed = 0;
405
406 /*
407 * Stage 1: If only one IRQ is available for the link, use it.
408 */
409 SIMPLEQ_FOREACH(l, &pciintr_link_map_list, list) {
410 if (l->irq != X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
411 continue;
412 if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) {
413 l->irq = irq;
414 l->fixup_stage = 1;
415 #ifdef PCIINTR_DEBUG
416 printf("pciintr_guess_irq (stage 1): "
417 "guessing PIRQ 0x%02x to be IRQ %d\n",
418 l->clink, l->irq);
419 #endif
420 guessed = 1;
421 }
422 }
423
424 return (guessed ? 0 : -1);
425 }
426 #endif /* PCIBIOS_INTR_GUESS */
427
428 int
429 pciintr_link_fixup(void)
430 {
431 struct pciintr_link_map *l;
432 int irq;
433 uint16_t pciirq = 0;
434
435 /*
436 * First stage: Attempt to connect PIRQs which aren't
437 * yet connected.
438 */
439 SIMPLEQ_FOREACH(l, &pciintr_link_map_list, list) {
440 if (l->irq != X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
441 /*
442 * Interrupt is already connected. Don't do
443 * anything to it.
444 * In this case, l->fixup_stage == 0.
445 */
446 pciirq |= 1 << l->irq;
447 #ifdef PCIINTR_DEBUG
448 printf("pciintr_link_fixup: PIRQ 0x%02x already "
449 "connected to IRQ %d\n", l->clink, l->irq);
450 #endif
451 continue;
452 }
453 /*
454 * Interrupt isn't connected. Attempt to assign it to an IRQ.
455 */
456 #ifdef PCIINTR_DEBUG
457 printf("pciintr_link_fixup: PIRQ 0x%02x not connected",
458 l->clink);
459 #endif
460 /*
461 * Just do the easy case now; we'll defer the harder ones
462 * to Stage 2.
463 */
464 if (pciintr_bitmap_count_irq(l->bitmap, &irq) == 1) {
465 l->irq = irq;
466 l->fixup_stage = 1;
467 pciirq |= 1 << irq;
468 #ifdef PCIINTR_DEBUG
469 printf(", assigning IRQ %d", l->irq);
470 #endif
471 }
472 #ifdef PCIINTR_DEBUG
473 printf("\n");
474 #endif
475 }
476
477 /*
478 * Stage 2: Attempt to connect PIRQs which we didn't
479 * connect in Stage 1.
480 */
481 SIMPLEQ_FOREACH(l, &pciintr_link_map_list, list) {
482 if (l->irq != X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
483 continue;
484 if (pciintr_bitmap_find_lowest_irq(l->bitmap & pciirq,
485 &l->irq)) {
486 /*
487 * This IRQ is a valid PCI IRQ already
488 * connected to another PIRQ, and also an
489 * IRQ our PIRQ can use; connect it up!
490 */
491 l->fixup_stage = 2;
492 #ifdef PCIINTR_DEBUG
493 printf("pciintr_link_fixup (stage 2): "
494 "assigning IRQ %d to PIRQ 0x%02x\n",
495 l->irq, l->clink);
496 #endif
497 }
498 }
499
500 #ifdef PCIBIOS_IRQS_HINT
501 /*
502 * Stage 3: The worst case. I need configuration hint that
503 * user supplied a mask for the PCI irqs
504 */
505 SIMPLEQ_FOREACH(l, &pciintr_link_map_list, list) {
506 if (l->irq != X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
507 continue;
508 if (pciintr_bitmap_find_lowest_irq(
509 l->bitmap & pcibios_irqs_hint, &l->irq)) {
510 l->fixup_stage = 3;
511 #ifdef PCIINTR_DEBUG
512 printf("pciintr_link_fixup (stage 3): "
513 "assigning IRQ %d to PIRQ 0x%02x\n",
514 l->irq, l->clink);
515 #endif
516 }
517 }
518 #endif /* PCIBIOS_IRQS_HINT */
519
520 return (0);
521 }
522
523 int
524 pciintr_link_route(uint16_t *pciirq)
525 {
526 struct pciintr_link_map *l;
527 int rv = 0;
528
529 *pciirq = 0;
530
531 SIMPLEQ_FOREACH(l, &pciintr_link_map_list, list) {
532 if (l->fixup_stage == 0) {
533 if (l->irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
534 /* Appropriate interrupt was not found. */
535 #ifdef DIAGNOSTIC
536 printf("pciintr_link_route: "
537 "PIRQ 0x%02x: no IRQ, try "
538 "\"options PCIBIOS_IRQS_HINT=0x%04x\"\n",
539 l->clink,
540 /* suggest irq 9/10/11, if possible */
541 (l->bitmap & 0x0e00) ? (l->bitmap & 0x0e00)
542 : l->bitmap);
543 #endif
544 } else {
545 /* BIOS setting has no problem */
546 #ifdef PCIINTR_DEBUG
547 printf("pciintr_link_route: "
548 "route of PIRQ 0x%02x -> "
549 "IRQ %d preserved BIOS setting\n",
550 l->clink, l->irq);
551 #endif
552 *pciirq |= (1 << l->irq);
553 }
554 continue; /* nothing to do. */
555 }
556
557 if (pciintr_icu_set_intr(pciintr_icu_tag, pciintr_icu_handle,
558 l->clink, l->irq) != 0 ||
559 pciintr_icu_set_trigger(pciintr_icu_tag,
560 pciintr_icu_handle,
561 l->irq, IST_LEVEL) != 0) {
562 printf("pciintr_link_route: route of PIRQ 0x%02x -> "
563 "IRQ %d failed\n", l->clink, l->irq);
564 rv = 1;
565 } else {
566 /*
567 * Succssfully routed interrupt. Mark this as
568 * a PCI interrupt.
569 */
570 *pciirq |= (1 << l->irq);
571 }
572 }
573
574 return (rv);
575 }
576
577 int
578 pciintr_irq_release(uint16_t *pciirq)
579 {
580 int i, bit;
581 uint16_t bios_pciirq;
582 int reg;
583
584 #ifdef PCIINTR_DEBUG
585 printf("pciintr_irq_release: fixup pciirq level/edge map 0x%04x\n",
586 *pciirq);
587 #endif
588
589 /* Get bios level/edge setting. */
590 bios_pciirq = 0;
591 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
592 (void)pciintr_icu_get_trigger(pciintr_icu_tag,
593 pciintr_icu_handle, i, ®);
594 if (reg == IST_LEVEL)
595 bios_pciirq |= bit;
596 }
597
598 #ifdef PCIINTR_DEBUG
599 printf("pciintr_irq_release: bios pciirq level/edge map 0x%04x\n",
600 bios_pciirq);
601 #endif /* PCIINTR_DEBUG */
602
603 /* fixup final level/edge setting. */
604 *pciirq |= bios_pciirq;
605 for (i = 0, bit = 1; i < 16; i++, bit <<= 1) {
606 if ((*pciirq & bit) == 0)
607 reg = IST_EDGE;
608 else
609 reg = IST_LEVEL;
610 (void) pciintr_icu_set_trigger(pciintr_icu_tag,
611 pciintr_icu_handle, i, reg);
612
613 }
614
615 #ifdef PCIINTR_DEBUG
616 printf("pciintr_irq_release: final pciirq level/edge map 0x%04x\n",
617 *pciirq);
618 #endif /* PCIINTR_DEBUG */
619
620 return (0);
621 }
622
623 int
624 pciintr_header_fixup(pci_chipset_tag_t pc)
625 {
626 PCIBIOS_PRINTV(("------------------------------------------\n"));
627 PCIBIOS_PRINTV((" device vendor product pin PIRQ IRQ stage\n"));
628 PCIBIOS_PRINTV(("------------------------------------------\n"));
629 pci_device_foreach(pc, pcibios_max_bus, pciintr_do_header_fixup, NULL);
630 PCIBIOS_PRINTV(("------------------------------------------\n"));
631
632 return (0);
633 }
634
635 void
636 pciintr_do_header_fixup(pci_chipset_tag_t pc, pcitag_t tag, void *context)
637 {
638 struct pcibios_intr_routing *pir;
639 struct pciintr_link_map *l;
640 int pin, irq, link;
641 int bus, device, function;
642 pcireg_t intr, id;
643
644 pci_decompose_tag(pc, tag, &bus, &device, &function);
645 id = pci_conf_read(pc, tag, PCI_ID_REG);
646
647 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
648 pin = PCI_INTERRUPT_PIN(intr);
649 irq = PCI_INTERRUPT_LINE(intr);
650
651 #if 0
652 if (pin == 0) {
653 /*
654 * No interrupt used.
655 */
656 return;
657 }
658 #endif
659
660 pir = pciintr_pir_lookup(bus, device);
661 if (pir == NULL || (link = pir->linkmap[pin - 1].link) == 0) {
662 /*
663 * Interrupt not connected; no
664 * need to change.
665 */
666 return;
667 }
668
669 l = pciintr_link_lookup(link);
670 if (l == NULL) {
671 #ifdef PCIINTR_DEBUG
672 /*
673 * No link map entry.
674 * Probably pciintr_icu_getclink() or pciintr_icu_get_intr()
675 * was failed.
676 */
677 printf("pciintr_header_fixup: no entry for link 0x%02x "
678 "(%d:%d:%d:%c)\n", link, bus, device, function,
679 '@' + pin);
680 #endif
681 return;
682 }
683
684 #ifdef PCIBIOSVERBOSE
685 if (pcibiosverbose) {
686 printf("%03d:%02d:%d 0x%04x 0x%04x %c 0x%02x",
687 bus, device, function, PCI_VENDOR(id), PCI_PRODUCT(id),
688 '@' + pin, l->clink);
689 if (l->irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
690 printf(" -");
691 else
692 printf(" %3d", l->irq);
693 printf(" %d ", l->fixup_stage);
694 }
695 #endif
696
697 /*
698 * IRQs 14 and 15 are reserved for PCI IDE interrupts; don't muck
699 * with them.
700 */
701 if (irq == 14 || irq == 15) {
702 PCIBIOS_PRINTV((" WARNING: ignored\n"));
703 return;
704 }
705
706 if (l->irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
707 /* Appropriate interrupt was not found. */
708 if (pciintr_icu_tag == NULL &&
709 irq != 0 && irq != X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
710 /*
711 * Do not print warning,
712 * if no compatible PCI ICU found,
713 * but the irq is already assigned by BIOS.
714 */
715 PCIBIOS_PRINTV(("\n"));
716 } else {
717 PCIBIOS_PRINTV((" WARNING: missing IRQ\n"));
718 }
719 return;
720 }
721
722 if (l->irq == irq) {
723 /* don't have to reconfigure */
724 PCIBIOS_PRINTV((" already assigned\n"));
725 return;
726 }
727
728 if (irq == 0 || irq == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) {
729 PCIBIOS_PRINTV((" fixed up\n"));
730 } else {
731 /* routed by BIOS, but inconsistent */
732 #ifdef PCI_INTR_FIXUP_FORCE
733 /* believe PCI IRQ Routing table */
734 PCIBIOS_PRINTV((" WARNING: overriding irq %d\n", irq));
735 #else
736 /* believe PCI Interrupt Configuration Register (default) */
737 PCIBIOS_PRINTV((" WARNING: preserving irq %d\n", irq));
738 return;
739 #endif
740 }
741
742 intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
743 intr |= (l->irq << PCI_INTERRUPT_LINE_SHIFT);
744 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr);
745 }
746
747 int
748 pci_intr_fixup(pci_chipset_tag_t pc, bus_space_tag_t iot, uint16_t *pciirq)
749 {
750 const struct pciintr_icu_table *piit = NULL;
751 pcitag_t icutag;
752 pcireg_t icuid;
753
754 /*
755 * Attempt to initialize our PCI interrupt router. If
756 * the PIR Table is present in ROM, use the location
757 * specified by the PIR Table, and use the compat ID,
758 * if present. Otherwise, we have to look for the router
759 * ourselves (the PCI-ISA bridge).
760 *
761 * A number of buggy BIOS implementations leave the router
762 * entry as 000:00:0, which is typically not the correct
763 * device/function. If the router device address is set to
764 * this value, and the compatible router entry is undefined
765 * (zero is the correct value to indicate undefined), then we
766 * work on the basis it is most likely an error, and search
767 * the entire device-space of bus 0 (but obviously starting
768 * with 000:00:0, in case that really is the right one).
769 */
770 if (pcibios_pir_header.signature != 0 &&
771 (pcibios_pir_header.router_bus != 0 ||
772 PIR_DEVFUNC_DEVICE(pcibios_pir_header.router_devfunc) != 0 ||
773 PIR_DEVFUNC_FUNCTION(pcibios_pir_header.router_devfunc) != 0 ||
774 pcibios_pir_header.compat_router != 0)) {
775 icutag = pci_make_tag(pc, pcibios_pir_header.router_bus,
776 PIR_DEVFUNC_DEVICE(pcibios_pir_header.router_devfunc),
777 PIR_DEVFUNC_FUNCTION(pcibios_pir_header.router_devfunc));
778 icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
779 if ((piit = pciintr_icu_lookup(icuid)) == NULL) {
780 /*
781 * if we fail to look up an ICU at given
782 * PCI address, try compat ID next.
783 */
784 icuid = pcibios_pir_header.compat_router;
785 piit = pciintr_icu_lookup(icuid);
786 }
787 } else {
788 int device, maxdevs = pci_bus_maxdevs(pc, 0);
789
790 /*
791 * Search configuration space for a known interrupt
792 * router.
793 */
794 for (device = 0; device < maxdevs; device++) {
795 const struct pci_quirkdata *qd;
796 int function, nfuncs;
797 pcireg_t bhlcr;
798
799 icutag = pci_make_tag(pc, 0, device, 0);
800 icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
801
802 /* Invalid vendor ID value? */
803 if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
804 continue;
805 /* XXX Not invalid, but we've done this ~forever. */
806 if (PCI_VENDOR(icuid) == 0)
807 continue;
808
809 qd = pci_lookup_quirkdata(PCI_VENDOR(icuid),
810 PCI_PRODUCT(icuid));
811
812 bhlcr = pci_conf_read(pc, icutag, PCI_BHLC_REG);
813 if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
814 (qd != NULL &&
815 (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
816 nfuncs = 8;
817 else
818 nfuncs = 1;
819
820 for (function = 0; function < nfuncs; function++) {
821 icutag = pci_make_tag(pc, 0, device, function);
822 icuid = pci_conf_read(pc, icutag, PCI_ID_REG);
823
824 /* Invalid vendor ID value? */
825 if (PCI_VENDOR(icuid) == PCI_VENDOR_INVALID)
826 continue;
827 /* Not invalid, but we've done this ~forever */
828 if (PCI_VENDOR(icuid) == 0)
829 continue;
830
831 piit = pciintr_icu_lookup(icuid);
832 if (piit != NULL)
833 goto found;
834 }
835 }
836
837 /*
838 * Invalidate the ICU ID. If we failed to find the
839 * interrupt router (piit == NULL) we don't want to
840 * display a spurious device address below containing
841 * the product information of the last device we
842 * looked at.
843 */
844 icuid = 0;
845 found:;
846 }
847
848 if (piit == NULL) {
849 printf("pci_intr_fixup: no compatible PCI ICU found");
850 if (pcibios_pir_header.signature != 0 && icuid != 0)
851 printf(": ICU vendor 0x%04x product 0x%04x",
852 PCI_VENDOR(icuid), PCI_PRODUCT(icuid));
853 printf("\n");
854 #ifdef PCIBIOS_INTR_GUESS
855 if (pciintr_link_init())
856 return (-1); /* non-fatal */
857 if (pciintr_guess_irq())
858 return (-1); /* non-fatal */
859 if (pciintr_header_fixup(pc))
860 return (1); /* fatal */
861 return (0); /* success! */
862 #else
863 return (-1); /* non-fatal */
864 #endif
865 }
866
867 /*
868 * Initialize the PCI ICU.
869 */
870 if ((*piit->piit_init)(pc, iot, icutag, &pciintr_icu_tag,
871 &pciintr_icu_handle) != 0)
872 return (-1); /* non-fatal */
873
874 /*
875 * Initialize the PCI interrupt link map.
876 */
877 if (pciintr_link_init())
878 return (-1); /* non-fatal */
879
880 /*
881 * Fix up the link->IRQ mappings.
882 */
883 if (pciintr_link_fixup() != 0)
884 return (-1); /* non-fatal */
885
886 /*
887 * Now actually program the PCI ICU with the new
888 * routing information.
889 */
890 if (pciintr_link_route(pciirq) != 0)
891 return (1); /* fatal */
892
893 /*
894 * Now that we've routed all of the PIRQs, rewrite the PCI
895 * configuration headers to reflect the new mapping.
896 */
897 if (pciintr_header_fixup(pc) != 0)
898 return (1); /* fatal */
899
900 /*
901 * Free any unused PCI IRQs for ISA devices.
902 */
903 if (pciintr_irq_release(pciirq) != 0)
904 return (-1); /* non-fatal */
905
906 /*
907 * All done!
908 */
909 return (0); /* success! */
910 }
911