1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1997, Stefan Esser <[email protected]>
5 * Copyright (c) 2000, Michael Smith <[email protected]>
6 * Copyright (c) 2000, BSDi
7 * All rights reserved.
8 * Copyright (c) 2004, John Baldwin <[email protected]>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice unmodified, this list of conditions, and the following
15 * 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 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/sysctl.h>
40 #include <vm/vm.h>
41 #include <vm/pmap.h>
42 #include <vm/vm_param.h>
43 #include <machine/md_var.h>
44 #include <dev/pci/pcivar.h>
45 #include <dev/pci/pcireg.h>
46 #include <machine/pci_cfgreg.h>
47 #include <machine/segments.h>
48 #include <machine/pc/bios.h>
49
50 #define NUM_ISA_INTERRUPTS 16
51
52 /*
53 * A link device. Loosely based on the ACPI PCI link device. This doesn't
54 * try to support priorities for different ISA interrupts.
55 */
56 struct pci_link {
57 TAILQ_ENTRY(pci_link) pl_links;
58 uint8_t pl_id;
59 uint8_t pl_irq;
60 uint16_t pl_irqmask;
61 int pl_references;
62 int pl_routed;
63 };
64
65 struct pci_link_lookup {
66 struct pci_link **pci_link_ptr;
67 int bus;
68 int device;
69 int pin;
70 };
71
72 struct pci_dev_lookup {
73 uint8_t link;
74 int bus;
75 int device;
76 int pin;
77 };
78
79 typedef void pir_entry_handler(struct PIR_entry *entry,
80 struct PIR_intpin* intpin, void *arg);
81
82 static void pci_print_irqmask(u_int16_t irqs);
83 static int pci_pir_biosroute(int bus, int device, int func, int pin,
84 int irq);
85 static int pci_pir_choose_irq(struct pci_link *pci_link, int irqmask);
86 static void pci_pir_create_links(struct PIR_entry *entry,
87 struct PIR_intpin *intpin, void *arg);
88 static void pci_pir_dump_links(void);
89 static struct pci_link *pci_pir_find_link(uint8_t link_id);
90 static void pci_pir_find_link_handler(struct PIR_entry *entry,
91 struct PIR_intpin *intpin, void *arg);
92 static void pci_pir_initial_irqs(struct PIR_entry *entry,
93 struct PIR_intpin *intpin, void *arg);
94 static void pci_pir_parse(void);
95 static uint8_t pci_pir_search_irq(int bus, int device, int pin);
96 static int pci_pir_valid_irq(struct pci_link *pci_link, int irq);
97 static void pci_pir_walk_table(pir_entry_handler *handler, void *arg);
98
99 static MALLOC_DEFINE(M_PIR, "$PIR", "$PIR structures");
100
101 static struct PIR_table *pci_route_table;
102 static device_t pir_device;
103 static int pci_route_count, pir_bios_irqs, pir_parsed;
104 static TAILQ_HEAD(, pci_link) pci_links;
105 static int pir_interrupt_weight[NUM_ISA_INTERRUPTS];
106
107 /* sysctl vars */
108 SYSCTL_DECL(_hw_pci);
109
110 /* XXX this likely should live in a header file */
111 /* IRQs 3, 4, 5, 6, 7, 9, 10, 11, 12, 14, 15 */
112 #define PCI_IRQ_OVERRIDE_MASK 0xdef8
113
114 static uint32_t pci_irq_override_mask = PCI_IRQ_OVERRIDE_MASK;
115 SYSCTL_INT(_hw_pci, OID_AUTO, irq_override_mask, CTLFLAG_RDTUN,
116 &pci_irq_override_mask, PCI_IRQ_OVERRIDE_MASK,
117 "Mask of allowed irqs to try to route when it has no good clue about\n"
118 "which irqs it should use.");
119
120 /*
121 * Look for the interrupt routing table.
122 *
123 * We use PCI BIOS's PIR table if it's available. $PIR is the standard way
124 * to do this. Sadly, some machines are not standards conforming and have
125 * _PIR instead. We shrug and cope by looking for both.
126 */
127 void
pci_pir_open(void)128 pci_pir_open(void)
129 {
130 struct PIR_table *pt;
131 uint32_t sigaddr;
132 int i;
133 uint8_t ck, *cv;
134
135 /* Don't try if we've already found a table. */
136 if (pci_route_table != NULL)
137 return;
138
139 /* Look for $PIR and then _PIR. */
140 sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
141 if (sigaddr == 0)
142 sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
143 if (sigaddr == 0)
144 return;
145
146 /* If we found something, check the checksum and length. */
147 /* XXX - Use pmap_mapdev()? */
148 pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
149 if (pt->pt_header.ph_length <= sizeof(struct PIR_header))
150 return;
151 for (cv = (u_int8_t *)pt, ck = 0, i = 0;
152 i < (pt->pt_header.ph_length); i++)
153 ck += cv[i];
154 if (ck != 0)
155 return;
156
157 /* Ok, we've got a valid table. */
158 pci_route_table = pt;
159 pci_route_count = (pt->pt_header.ph_length -
160 sizeof(struct PIR_header)) /
161 sizeof(struct PIR_entry);
162 }
163
164 /*
165 * Find the pci_link structure for a given link ID.
166 */
167 static struct pci_link *
pci_pir_find_link(uint8_t link_id)168 pci_pir_find_link(uint8_t link_id)
169 {
170 struct pci_link *pci_link;
171
172 TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
173 if (pci_link->pl_id == link_id)
174 return (pci_link);
175 }
176 return (NULL);
177 }
178
179 /*
180 * Find the link device associated with a PCI device in the table.
181 */
182 static void
pci_pir_find_link_handler(struct PIR_entry * entry,struct PIR_intpin * intpin,void * arg)183 pci_pir_find_link_handler(struct PIR_entry *entry, struct PIR_intpin *intpin,
184 void *arg)
185 {
186 struct pci_link_lookup *lookup;
187
188 lookup = (struct pci_link_lookup *)arg;
189 if (entry->pe_bus == lookup->bus &&
190 entry->pe_device == lookup->device &&
191 intpin - entry->pe_intpin == lookup->pin)
192 *lookup->pci_link_ptr = pci_pir_find_link(intpin->link);
193 }
194
195 /*
196 * Check to see if a possible IRQ setting is valid.
197 */
198 static int
pci_pir_valid_irq(struct pci_link * pci_link,int irq)199 pci_pir_valid_irq(struct pci_link *pci_link, int irq)
200 {
201
202 if (!PCI_INTERRUPT_VALID(irq))
203 return (0);
204 return (pci_link->pl_irqmask & (1 << irq));
205 }
206
207 /*
208 * Walk the $PIR executing the worker function for each valid intpin entry
209 * in the table. The handler is passed a pointer to both the entry and
210 * the intpin in the entry.
211 */
212 static void
pci_pir_walk_table(pir_entry_handler * handler,void * arg)213 pci_pir_walk_table(pir_entry_handler *handler, void *arg)
214 {
215 struct PIR_entry *entry;
216 struct PIR_intpin *intpin;
217 int i, pin;
218
219 entry = &pci_route_table->pt_entry[0];
220 for (i = 0; i < pci_route_count; i++, entry++) {
221 intpin = &entry->pe_intpin[0];
222 for (pin = 0; pin < 4; pin++, intpin++)
223 if (intpin->link != 0)
224 handler(entry, intpin, arg);
225 }
226 }
227
228 static void
pci_pir_create_links(struct PIR_entry * entry,struct PIR_intpin * intpin,void * arg)229 pci_pir_create_links(struct PIR_entry *entry, struct PIR_intpin *intpin,
230 void *arg)
231 {
232 struct pci_link *pci_link;
233
234 pci_link = pci_pir_find_link(intpin->link);
235 if (pci_link != NULL) {
236 pci_link->pl_references++;
237 if (intpin->irqs != pci_link->pl_irqmask) {
238 if (bootverbose)
239 printf(
240 "$PIR: Entry %d.%d.INT%c has different mask for link %#x, merging\n",
241 entry->pe_bus, entry->pe_device,
242 (intpin - entry->pe_intpin) + 'A',
243 pci_link->pl_id);
244 pci_link->pl_irqmask &= intpin->irqs;
245 }
246 } else {
247 pci_link = malloc(sizeof(struct pci_link), M_PIR, M_WAITOK);
248 pci_link->pl_id = intpin->link;
249 pci_link->pl_irqmask = intpin->irqs;
250 pci_link->pl_irq = PCI_INVALID_IRQ;
251 pci_link->pl_references = 1;
252 pci_link->pl_routed = 0;
253 TAILQ_INSERT_TAIL(&pci_links, pci_link, pl_links);
254 }
255 }
256
257 /*
258 * Look to see if any of the functions on the PCI device at bus/device
259 * have an interrupt routed to intpin 'pin' by the BIOS.
260 */
261 static uint8_t
pci_pir_search_irq(int bus,int device,int pin)262 pci_pir_search_irq(int bus, int device, int pin)
263 {
264 uint32_t value;
265 uint8_t func, maxfunc;
266
267 /* See if we have a valid device at function 0. */
268 value = pci_cfgregread(0, bus, device, 0, PCIR_VENDOR, 2);
269 if (value == PCIV_INVALID)
270 return (PCI_INVALID_IRQ);
271 value = pci_cfgregread(0, bus, device, 0, PCIR_HDRTYPE, 1);
272 if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
273 return (PCI_INVALID_IRQ);
274 if (value & PCIM_MFDEV)
275 maxfunc = PCI_FUNCMAX;
276 else
277 maxfunc = 0;
278
279 /* Scan all possible functions at this device. */
280 for (func = 0; func <= maxfunc; func++) {
281 value = pci_cfgregread(0, bus, device, func, PCIR_VENDOR, 2);
282 if (value == PCIV_INVALID)
283 continue;
284 value = pci_cfgregread(0, bus, device, func, PCIR_INTPIN, 1);
285
286 /*
287 * See if it uses the pin in question. Note that the passed
288 * in pin uses 0 for A, .. 3 for D whereas the intpin
289 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
290 */
291 if (value != pin + 1)
292 continue;
293 value = pci_cfgregread(0, bus, device, func, PCIR_INTLINE, 1);
294 if (bootverbose)
295 printf(
296 "$PIR: Found matching pin for %d.%d.INT%c at func %d: %d\n",
297 bus, device, pin + 'A', func, value);
298 if (value != PCI_INVALID_IRQ)
299 return (value);
300 }
301 return (PCI_INVALID_IRQ);
302 }
303
304 /*
305 * Try to initialize IRQ based on this device's IRQ.
306 */
307 static void
pci_pir_initial_irqs(struct PIR_entry * entry,struct PIR_intpin * intpin,void * arg)308 pci_pir_initial_irqs(struct PIR_entry *entry, struct PIR_intpin *intpin,
309 void *arg)
310 {
311 struct pci_link *pci_link;
312 uint8_t irq, pin;
313
314 pin = intpin - entry->pe_intpin;
315 pci_link = pci_pir_find_link(intpin->link);
316 irq = pci_pir_search_irq(entry->pe_bus, entry->pe_device, pin);
317 if (irq == PCI_INVALID_IRQ || irq == pci_link->pl_irq)
318 return;
319
320 /* Don't trust any BIOS IRQs greater than 15. */
321 if (irq >= NUM_ISA_INTERRUPTS) {
322 printf(
323 "$PIR: Ignoring invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n",
324 irq, entry->pe_bus, entry->pe_device, pin + 'A',
325 pci_link->pl_id);
326 return;
327 }
328
329 /*
330 * If we don't have an IRQ for this link yet, then we trust the
331 * BIOS, even if it seems invalid from the $PIR entries.
332 */
333 if (pci_link->pl_irq == PCI_INVALID_IRQ) {
334 if (!pci_pir_valid_irq(pci_link, irq))
335 printf(
336 "$PIR: Using invalid BIOS IRQ %d from %d.%d.INT%c for link %#x\n",
337 irq, entry->pe_bus, entry->pe_device, pin + 'A',
338 pci_link->pl_id);
339 pci_link->pl_irq = irq;
340 pci_link->pl_routed = 1;
341 return;
342 }
343
344 /*
345 * We have an IRQ and it doesn't match the current IRQ for this
346 * link. If the new IRQ is invalid, then warn about it and ignore
347 * it. If the old IRQ is invalid and the new IRQ is valid, then
348 * prefer the new IRQ instead. If both IRQs are valid, then just
349 * use the first one. Note that if we ever get into this situation
350 * we are having to guess which setting the BIOS actually routed.
351 * Perhaps we should just give up instead.
352 */
353 if (!pci_pir_valid_irq(pci_link, irq)) {
354 printf(
355 "$PIR: BIOS IRQ %d for %d.%d.INT%c is not valid for link %#x\n",
356 irq, entry->pe_bus, entry->pe_device, pin + 'A',
357 pci_link->pl_id);
358 } else if (!pci_pir_valid_irq(pci_link, pci_link->pl_irq)) {
359 printf(
360 "$PIR: Preferring valid BIOS IRQ %d from %d.%d.INT%c for link %#x to IRQ %d\n",
361 irq, entry->pe_bus, entry->pe_device, pin + 'A',
362 pci_link->pl_id, pci_link->pl_irq);
363 pci_link->pl_irq = irq;
364 pci_link->pl_routed = 1;
365 } else
366 printf(
367 "$PIR: BIOS IRQ %d for %d.%d.INT%c does not match link %#x irq %d\n",
368 irq, entry->pe_bus, entry->pe_device, pin + 'A',
369 pci_link->pl_id, pci_link->pl_irq);
370 }
371
372 /*
373 * Parse $PIR to enumerate link devices and attempt to determine their
374 * initial state. This could perhaps be cleaner if we had drivers for the
375 * various interrupt routers as they could read the initial IRQ for each
376 * link.
377 */
378 static void
pci_pir_parse(void)379 pci_pir_parse(void)
380 {
381 char tunable_buffer[64];
382 struct pci_link *pci_link;
383 int i, irq;
384
385 /* Only parse once. */
386 if (pir_parsed)
387 return;
388 pir_parsed = 1;
389
390 /* Enumerate link devices. */
391 TAILQ_INIT(&pci_links);
392 pci_pir_walk_table(pci_pir_create_links, NULL);
393 if (bootverbose) {
394 printf("$PIR: Links after initial probe:\n");
395 pci_pir_dump_links();
396 }
397
398 /*
399 * Check to see if the BIOS has already routed any of the links by
400 * checking each device connected to each link to see if it has a
401 * valid IRQ.
402 */
403 pci_pir_walk_table(pci_pir_initial_irqs, NULL);
404 if (bootverbose) {
405 printf("$PIR: Links after initial IRQ discovery:\n");
406 pci_pir_dump_links();
407 }
408
409 /*
410 * Allow the user to override the IRQ for a given link device. We
411 * allow invalid IRQs to be specified but warn about them. An IRQ
412 * of 255 or 0 clears any preset IRQ.
413 */
414 i = 0;
415 TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
416 snprintf(tunable_buffer, sizeof(tunable_buffer),
417 "hw.pci.link.%#x.irq", pci_link->pl_id);
418 if (getenv_int(tunable_buffer, &irq) == 0)
419 continue;
420 if (irq == 0)
421 irq = PCI_INVALID_IRQ;
422 if (irq != PCI_INVALID_IRQ &&
423 !pci_pir_valid_irq(pci_link, irq) && bootverbose)
424 printf(
425 "$PIR: Warning, IRQ %d for link %#x is not listed as valid\n",
426 irq, pci_link->pl_id);
427 pci_link->pl_routed = 0;
428 pci_link->pl_irq = irq;
429 i = 1;
430 }
431 if (bootverbose && i) {
432 printf("$PIR: Links after tunable overrides:\n");
433 pci_pir_dump_links();
434 }
435
436 /*
437 * Build initial interrupt weights as well as bitmap of "known-good"
438 * IRQs that the BIOS has already used for PCI link devices.
439 */
440 TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
441 if (!PCI_INTERRUPT_VALID(pci_link->pl_irq))
442 continue;
443 pir_bios_irqs |= 1 << pci_link->pl_irq;
444 pir_interrupt_weight[pci_link->pl_irq] +=
445 pci_link->pl_references;
446 }
447 if (bootverbose) {
448 printf("$PIR: IRQs used by BIOS: ");
449 pci_print_irqmask(pir_bios_irqs);
450 printf("\n");
451 printf("$PIR: Interrupt Weights:\n[ ");
452 for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
453 printf(" %3d", i);
454 printf(" ]\n[ ");
455 for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
456 printf(" %3d", pir_interrupt_weight[i]);
457 printf(" ]\n");
458 }
459 }
460
461 /*
462 * Use the PCI BIOS to route an interrupt for a given device.
463 *
464 * Input:
465 * AX = PCIBIOS_ROUTE_INTERRUPT
466 * BH = bus
467 * BL = device [7:3] / function [2:0]
468 * CH = IRQ
469 * CL = Interrupt Pin (0x0A = A, ... 0x0D = D)
470 */
471 static int
pci_pir_biosroute(int bus,int device,int func,int pin,int irq)472 pci_pir_biosroute(int bus, int device, int func, int pin, int irq)
473 {
474 struct bios_regs args;
475
476 args.eax = PCIBIOS_ROUTE_INTERRUPT;
477 args.ebx = (bus << 8) | (device << 3) | func;
478 args.ecx = (irq << 8) | (0xa + pin);
479 return (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)));
480 }
481
482 /*
483 * Route a PCI interrupt using a link device from the $PIR.
484 */
485 int
pci_pir_route_interrupt(int bus,int device,int func,int pin)486 pci_pir_route_interrupt(int bus, int device, int func, int pin)
487 {
488 struct pci_link_lookup lookup;
489 struct pci_link *pci_link;
490 int error, irq;
491
492 if (pci_route_table == NULL)
493 return (PCI_INVALID_IRQ);
494
495 /* Lookup link device for this PCI device/pin. */
496 pci_link = NULL;
497 lookup.bus = bus;
498 lookup.device = device;
499 lookup.pin = pin - 1;
500 lookup.pci_link_ptr = &pci_link;
501 pci_pir_walk_table(pci_pir_find_link_handler, &lookup);
502 if (pci_link == NULL) {
503 printf("$PIR: No matching entry for %d.%d.INT%c\n", bus,
504 device, pin - 1 + 'A');
505 return (PCI_INVALID_IRQ);
506 }
507
508 /*
509 * Pick a new interrupt if we don't have one already. We look
510 * for an interrupt from several different sets. First, if
511 * this link only has one valid IRQ, use that. Second, we
512 * check the set of PCI only interrupts from the $PIR. Third,
513 * we check the set of known-good interrupts that the BIOS has
514 * already used. Lastly, we check the "all possible valid
515 * IRQs" set.
516 */
517 if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) {
518 if (pci_link->pl_irqmask != 0 && powerof2(pci_link->pl_irqmask))
519 irq = ffs(pci_link->pl_irqmask) - 1;
520 else
521 irq = pci_pir_choose_irq(pci_link,
522 pci_route_table->pt_header.ph_pci_irqs);
523 if (!PCI_INTERRUPT_VALID(irq))
524 irq = pci_pir_choose_irq(pci_link, pir_bios_irqs);
525 if (!PCI_INTERRUPT_VALID(irq))
526 irq = pci_pir_choose_irq(pci_link,
527 pci_irq_override_mask);
528 if (!PCI_INTERRUPT_VALID(irq)) {
529 if (bootverbose)
530 printf(
531 "$PIR: Failed to route interrupt for %d:%d INT%c\n",
532 bus, device, pin - 1 + 'A');
533 return (PCI_INVALID_IRQ);
534 }
535 pci_link->pl_irq = irq;
536 }
537
538 /* Ask the BIOS to route this IRQ if we haven't done so already. */
539 if (!pci_link->pl_routed) {
540 error = pci_pir_biosroute(bus, device, func, pin - 1,
541 pci_link->pl_irq);
542
543 /* Ignore errors when routing a unique interrupt. */
544 if (error && !powerof2(pci_link->pl_irqmask)) {
545 printf("$PIR: ROUTE_INTERRUPT failed.\n");
546 return (PCI_INVALID_IRQ);
547 }
548 pci_link->pl_routed = 1;
549
550 /* Ensure the interrupt is set to level/low trigger. */
551 KASSERT(pir_device != NULL, ("missing pir device"));
552 BUS_CONFIG_INTR(pir_device, pci_link->pl_irq,
553 INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
554 }
555 if (bootverbose)
556 printf("$PIR: %d:%d INT%c routed to irq %d\n", bus, device,
557 pin - 1 + 'A', pci_link->pl_irq);
558 return (pci_link->pl_irq);
559 }
560
561 /*
562 * Try to pick an interrupt for the specified link from the interrupts
563 * set in the mask.
564 */
565 static int
pci_pir_choose_irq(struct pci_link * pci_link,int irqmask)566 pci_pir_choose_irq(struct pci_link *pci_link, int irqmask)
567 {
568 int i, irq, realmask;
569
570 /* XXX: Need to have a #define of known bad IRQs to also mask out? */
571 realmask = pci_link->pl_irqmask & irqmask;
572 if (realmask == 0)
573 return (PCI_INVALID_IRQ);
574
575 /* Find IRQ with lowest weight. */
576 irq = PCI_INVALID_IRQ;
577 for (i = 0; i < NUM_ISA_INTERRUPTS; i++) {
578 if (!(realmask & 1 << i))
579 continue;
580 if (irq == PCI_INVALID_IRQ ||
581 pir_interrupt_weight[i] < pir_interrupt_weight[irq])
582 irq = i;
583 }
584 if (bootverbose && PCI_INTERRUPT_VALID(irq)) {
585 printf("$PIR: Found IRQ %d for link %#x from ", irq,
586 pci_link->pl_id);
587 pci_print_irqmask(realmask);
588 printf("\n");
589 }
590 return (irq);
591 }
592
593 static void
pci_print_irqmask(u_int16_t irqs)594 pci_print_irqmask(u_int16_t irqs)
595 {
596 int i, first;
597
598 if (irqs == 0) {
599 printf("none");
600 return;
601 }
602 first = 1;
603 for (i = 0; i < 16; i++, irqs >>= 1)
604 if (irqs & 1) {
605 if (!first)
606 printf(" ");
607 else
608 first = 0;
609 printf("%d", i);
610 }
611 }
612
613 /*
614 * Display link devices.
615 */
616 static void
pci_pir_dump_links(void)617 pci_pir_dump_links(void)
618 {
619 struct pci_link *pci_link;
620
621 printf("Link IRQ Rtd Ref IRQs\n");
622 TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
623 printf("%#4x %3d %c %3d ", pci_link->pl_id,
624 pci_link->pl_irq, pci_link->pl_routed ? 'Y' : 'N',
625 pci_link->pl_references);
626 pci_print_irqmask(pci_link->pl_irqmask);
627 printf("\n");
628 }
629 }
630
631 /*
632 * See if any interrupts for a given PCI bus are routed in the PIR. Don't
633 * even bother looking if the BIOS doesn't support routing anyways. If we
634 * are probing a PCI-PCI bridge, then require_parse will be true and we should
635 * only succeed if a host-PCI bridge has already attached and parsed the PIR.
636 */
637 int
pci_pir_probe(int bus,int require_parse)638 pci_pir_probe(int bus, int require_parse)
639 {
640 int i;
641
642 if (pci_route_table == NULL || (require_parse && !pir_parsed))
643 return (0);
644 for (i = 0; i < pci_route_count; i++)
645 if (pci_route_table->pt_entry[i].pe_bus == bus)
646 return (1);
647 return (0);
648 }
649
650 /*
651 * The driver for the new-bus pseudo device pir0 for the $PIR table.
652 */
653
654 static int
pir_probe(device_t dev)655 pir_probe(device_t dev)
656 {
657 device_set_descf(dev, "PCI Interrupt Routing Table: %d Entries",
658 pci_route_count);
659 return (0);
660 }
661
662 static int
pir_attach(device_t dev)663 pir_attach(device_t dev)
664 {
665
666 pci_pir_parse();
667 KASSERT(pir_device == NULL, ("Multiple pir devices"));
668 pir_device = dev;
669 return (0);
670 }
671
672 static void
pir_resume_find_device(struct PIR_entry * entry,struct PIR_intpin * intpin,void * arg)673 pir_resume_find_device(struct PIR_entry *entry, struct PIR_intpin *intpin,
674 void *arg)
675 {
676 struct pci_dev_lookup *pd;
677
678 pd = (struct pci_dev_lookup *)arg;
679 if (intpin->link != pd->link || pd->bus != -1)
680 return;
681 pd->bus = entry->pe_bus;
682 pd->device = entry->pe_device;
683 pd->pin = intpin - entry->pe_intpin;
684 }
685
686 static int
pir_resume(device_t dev)687 pir_resume(device_t dev)
688 {
689 struct pci_dev_lookup pd;
690 struct pci_link *pci_link;
691 int error;
692
693 /* Ask the BIOS to re-route each link that was already routed. */
694 TAILQ_FOREACH(pci_link, &pci_links, pl_links) {
695 if (!PCI_INTERRUPT_VALID(pci_link->pl_irq)) {
696 KASSERT(!pci_link->pl_routed,
697 ("link %#x is routed but has invalid PCI IRQ",
698 pci_link->pl_id));
699 continue;
700 }
701 if (pci_link->pl_routed) {
702 pd.bus = -1;
703 pd.link = pci_link->pl_id;
704 pci_pir_walk_table(pir_resume_find_device, &pd);
705 KASSERT(pd.bus != -1,
706 ("did not find matching entry for link %#x in the $PIR table",
707 pci_link->pl_id));
708 if (bootverbose)
709 device_printf(dev,
710 "Using %d.%d.INT%c to route link %#x to IRQ %d\n",
711 pd.bus, pd.device, pd.pin + 'A',
712 pci_link->pl_id, pci_link->pl_irq);
713 error = pci_pir_biosroute(pd.bus, pd.device, 0, pd.pin,
714 pci_link->pl_irq);
715 if (error)
716 device_printf(dev,
717 "ROUTE_INTERRUPT on resume for link %#x failed.\n",
718 pci_link->pl_id);
719 }
720 }
721 return (0);
722 }
723
724 static device_method_t pir_methods[] = {
725 /* Device interface */
726 DEVMETHOD(device_probe, pir_probe),
727 DEVMETHOD(device_attach, pir_attach),
728 DEVMETHOD(device_resume, pir_resume),
729 { 0, 0 }
730 };
731
732 static driver_t pir_driver = {
733 "pir",
734 pir_methods,
735 1,
736 };
737
738 DRIVER_MODULE(pir, legacy, pir_driver, 0, 0);
739