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