2 * Copyright 2011, Michael Lotz mmlr@mlotz.ch.
3 * Copyright 2009, Clemens Zeidler haiku@clemens-zeidler.de.
6 * Distributed under the terms of the MIT License.
10 #include "irq_routing_table.h"
21 # define TRACE(x...) dprintf("IRQRoutingTable: " x)
27 const char* kACPIPciRootName
= "PNP0A03";
28 const char* kACPIPciExpressRootName
= "PNP0A08";
29 // Note that some configurations will still return the PCI express root
30 // when querying for the standard PCI root. This is due to the compatible ID
31 // fields in ACPI. TODO: Query both/the correct root device.
33 // TODO: as per PCI 3.0, the PCI module hardcodes it in various places as well.
34 static const uint8 kMaxPCIFunctionCount
= 8;
35 static const uint8 kMaxPCIDeviceCount
= 32;
36 // TODO: actually this is mechanism dependent
37 static const uint8 kMaxISAInterrupts
= 16;
39 irq_descriptor::irq_descriptor()
43 polarity(B_HIGH_ACTIVE_POLARITY
),
44 trigger_mode(B_EDGE_TRIGGERED
)
50 print_irq_descriptor(const irq_descriptor
& descriptor
)
52 const char* activeHighString
= "active high";
53 const char* activeLowString
= " active low";
54 const char* levelTriggeredString
= "level triggered";
55 const char* edgeTriggeredString
= "edge triggered";
57 dprintf("irq: %u, shareable: %u, polarity: %s, trigger_mode: %s\n",
58 descriptor
.irq
, descriptor
.shareable
,
59 descriptor
.polarity
== B_HIGH_ACTIVE_POLARITY
? activeHighString
61 descriptor
.trigger_mode
== B_LEVEL_TRIGGERED
? levelTriggeredString
62 : edgeTriggeredString
);
67 print_irq_routing_entry(const irq_routing_entry
& entry
)
69 dprintf("address 0x%04" B_PRIx64
"; pin %u;", entry
.device_address
,
72 if (entry
.source_index
!= 0)
73 dprintf(" GSI %" B_PRIu32
";", entry
.source_index
);
75 dprintf(" source %p %" B_PRIu32
";", entry
.source
, entry
.source_index
);
77 dprintf(" pci %u:%u pin %u func mask %" B_PRIx32
"; bios irq: %u; gsi %u;"
78 " config 0x%02x\n", entry
.pci_bus
, entry
.pci_device
, entry
.pin
+ 1,
79 entry
.pci_function_mask
, entry
.bios_irq
, entry
.irq
,
80 entry
.polarity
| entry
.trigger_mode
);
85 print_irq_routing_table(const IRQRoutingTable
& table
)
87 dprintf("IRQ routing table with %i entries\n", (int)table
.Count());
88 for (int i
= 0; i
< table
.Count(); i
++)
89 print_irq_routing_entry(table
.ElementAt(i
));
94 update_pci_info_for_entry(pci_module_info
* pci
, const irq_routing_entry
& entry
)
96 uint32 updateCount
= 0;
97 for (uint8 function
= 0; function
< kMaxPCIFunctionCount
; function
++) {
98 if ((entry
.pci_function_mask
& (1 << function
)) == 0)
101 if (pci
->update_interrupt_line(entry
.pci_bus
, entry
.pci_device
,
102 function
, entry
.irq
) == B_OK
) {
107 return updateCount
> 0 ? B_OK
: B_ENTRY_NOT_FOUND
;
112 fill_pci_info_for_entry(pci_module_info
* pci
, irq_routing_entry
& entry
)
114 // check the base device at function 0
115 uint8 headerType
= pci
->read_pci_config(entry
.pci_bus
, entry
.pci_device
, 0,
117 if (headerType
== 0xff) {
118 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
" entry not found\n",
119 entry
.pci_bus
, entry
.pci_device
);
120 // the device is not present
121 return B_ENTRY_NOT_FOUND
;
124 // we have a device, check how many functions we need to iterate
125 uint8 functionCount
= 1;
126 if ((headerType
& PCI_multifunction
) != 0)
127 functionCount
= kMaxPCIFunctionCount
;
129 for (uint8 function
= 0; function
< functionCount
; function
++) {
130 // check for device presence by looking for a valid vendor
131 uint16 vendorId
= pci
->read_pci_config(entry
.pci_bus
, entry
.pci_device
,
132 function
, PCI_vendor_id
, 2);
133 if (vendorId
== 0xffff) {
134 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" vendor 0xffff\n",
135 entry
.pci_bus
, entry
.pci_device
, function
);
139 uint8 interruptPin
= pci
->read_pci_config(entry
.pci_bus
,
140 entry
.pci_device
, function
, PCI_interrupt_pin
, 1);
142 // Finally match the pin with the entry, note that PCI pins are 1 based
143 // while ACPI ones are 0 based.
144 if (interruptPin
!= entry
.pin
+ 1) {
145 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" IRQ Pin %" B_PRIu8
146 " != %" B_PRIu8
"\n", entry
.pci_bus
, entry
.pci_device
, function
,
147 interruptPin
, entry
.pin
+ 1);
151 if (entry
.bios_irq
== 0) {
152 // Keep the originally assigned IRQ around so we can use it for
153 // white listing PCI IRQs in the ISA space as those are basically
154 // guaranteed not to overlap with ISA devices. Those white listed
155 // entries can then be used if we only have a 16 pin IO-APIC or if
156 // there are only legacy IRQ resources available for configuration
157 // (with bitmasks of 16 bits, limiting their range to ISA IRQs).
158 entry
.bios_irq
= pci
->read_pci_config(entry
.pci_bus
,
159 entry
.pci_device
, function
, PCI_interrupt_line
, 1);
162 entry
.pci_function_mask
|= 1 << function
;
165 return entry
.pci_function_mask
!= 0 ? B_OK
: B_ENTRY_NOT_FOUND
;
170 choose_link_device_configurations(acpi_module_info
* acpi
,
171 IRQRoutingTable
& routingTable
,
172 interrupt_available_check_function checkFunction
)
175 Before configuring the link devices we have to take a few things into
177 * Multiple PCI devices / functions may link to the same PCI link
178 device, so we must ensure that we don't try to configure different
179 IRQs for each device, overwriting the previous config of the
180 respective link device.
181 * If we can't use non-ISA IRQs then we must ensure that we don't
182 configure any IRQs that overlaps with ISA devices (as they use
183 different triggering modes and polarity they aren't compatible).
184 Since the ISA bus isn't enumerable we don't have any clues as to
185 where an ISA device might be connected. The only safe assumption
186 therefore is to only use IRQs that are known to be usable for PCI
187 devices. In our case we can use all the previously assigned PCI
188 interrupt_line IRQs as stored in the bios_irq field.
191 uint16 validForPCI
= 0; // only applies to the ISA IRQs
192 uint16 irqUsage
[256];
193 memset(irqUsage
, 0, sizeof(irqUsage
));
195 // find all unique link devices and resolve their possible IRQs
196 Vector
<link_device
*> links
;
197 for (int i
= 0; i
< routingTable
.Count(); i
++) {
198 irq_routing_entry
& irqEntry
= routingTable
.ElementAt(i
);
200 if (irqEntry
.bios_irq
!= 0 && irqEntry
.bios_irq
!= 255) {
201 if (irqEntry
.bios_irq
< kMaxISAInterrupts
)
202 validForPCI
|= (1 << irqEntry
.bios_irq
);
205 if (irqEntry
.source
== NULL
) {
206 // populate all hardwired GSI entries into our map
207 irqUsage
[irqEntry
.irq
]++;
208 if (irqEntry
.irq
< kMaxISAInterrupts
)
209 validForPCI
|= (1 << irqEntry
.irq
);
213 link_device
* link
= NULL
;
214 for (int j
= 0; j
< links
.Count(); j
++) {
215 link_device
* existing
= links
.ElementAt(j
);
216 if (existing
->handle
== irqEntry
.source
) {
223 link
->used_by
.PushBack(&irqEntry
);
227 // A new link device, read possible IRQs and fill them in.
228 link
= new(std::nothrow
) link_device
;
230 panic("ran out of memory while configuring irq link devices");
234 link
->handle
= irqEntry
.source
;
235 status_t status
= read_possible_irqs(acpi
, link
->handle
,
236 link
->possible_irqs
);
237 if (status
!= B_OK
) {
238 panic("failed to read possible irqs of link device");
242 status
= read_current_irq(acpi
, link
->handle
, link
->current_irq
);
243 if (status
!= B_OK
) {
244 panic("failed to read current irq of link device");
248 if (link
->current_irq
.irq
< kMaxISAInterrupts
)
249 validForPCI
|= (1 << link
->current_irq
.irq
);
251 link
->used_by
.PushBack(&irqEntry
);
252 links
.PushBack(link
);
255 for (int i
= 0; i
< links
.Count(); i
++) {
256 link_device
* link
= links
.ElementAt(i
);
258 int bestIRQIndex
= 0;
259 uint16 bestIRQUsage
= UINT16_MAX
;
260 for (int j
= 0; j
< link
->possible_irqs
.Count(); j
++) {
261 irq_descriptor
& possibleIRQ
= link
->possible_irqs
.ElementAt(j
);
262 if (!checkFunction(possibleIRQ
.irq
)) {
263 // we can't address this pin
267 if (possibleIRQ
.irq
< kMaxISAInterrupts
268 && (validForPCI
& (1 << possibleIRQ
.irq
)) == 0) {
269 // better avoid that if possible
273 if (irqUsage
[possibleIRQ
.irq
] < bestIRQUsage
) {
275 bestIRQUsage
= irqUsage
[possibleIRQ
.irq
];
279 // pick that one and update the counts
280 irq_descriptor
& chosenDescriptor
281 = link
->possible_irqs
.ElementAt(bestIRQIndex
);
282 if (!checkFunction(chosenDescriptor
.irq
)) {
283 dprintf("chosen irq %u is not addressable\n", chosenDescriptor
.irq
);
287 irqUsage
[chosenDescriptor
.irq
] += link
->used_by
.Count();
289 for (int j
= 0; j
< link
->used_by
.Count(); j
++) {
290 irq_routing_entry
* irqEntry
= link
->used_by
.ElementAt(j
);
291 irqEntry
->needs_configuration
= j
== 0; // only configure once
292 irqEntry
->irq
= chosenDescriptor
.irq
;
293 irqEntry
->polarity
= chosenDescriptor
.polarity
;
294 irqEntry
->trigger_mode
= chosenDescriptor
.trigger_mode
;
305 configure_link_devices(acpi_module_info
* acpi
, IRQRoutingTable
& routingTable
)
307 for (int i
= 0; i
< routingTable
.Count(); i
++) {
308 irq_routing_entry
& irqEntry
= routingTable
.ElementAt(i
);
309 if (!irqEntry
.needs_configuration
)
312 irq_descriptor configuration
;
313 configuration
.irq
= irqEntry
.irq
;
314 configuration
.polarity
= irqEntry
.polarity
;
315 configuration
.trigger_mode
= irqEntry
.trigger_mode
;
317 status_t status
= set_current_irq(acpi
, irqEntry
.source
, configuration
);
318 if (status
!= B_OK
) {
319 dprintf("failed to set irq on link device, keeping current\n");
320 print_irq_descriptor(configuration
);
322 // we failed to set the resource, fall back to current
323 read_current_irq(acpi
, irqEntry
.source
, configuration
);
324 for (int j
= i
; j
< routingTable
.Count(); j
++) {
325 irq_routing_entry
& other
= routingTable
.ElementAt(j
);
326 if (other
.source
== irqEntry
.source
) {
327 other
.irq
= configuration
.irq
;
328 other
.polarity
= configuration
.polarity
;
329 other
.trigger_mode
= configuration
.trigger_mode
;
334 irqEntry
.needs_configuration
= false;
342 evaluate_integer(acpi_module_info
* acpi
, acpi_handle handle
,
343 const char* method
, uint64
& value
)
345 acpi_object_type result
;
346 acpi_data resultBuffer
;
347 resultBuffer
.pointer
= &result
;
348 resultBuffer
.length
= sizeof(result
);
350 status_t status
= acpi
->evaluate_method(handle
, method
, NULL
,
355 if (result
.object_type
!= ACPI_TYPE_INTEGER
)
358 value
= result
.integer
.integer
;
364 handle_routing_table_entry(acpi_module_info
* acpi
, pci_module_info
* pci
,
365 const acpi_pci_routing_table
* acpiTable
, uint8 currentBus
,
366 irq_routing_entry
& irqEntry
)
368 bool noSource
= acpiTable
->Source
[0] == '\0';
369 // The above line would be correct according to specs...
370 noSource
= acpiTable
->SourceIndex
!= 0;
371 // ... but we use this one as there seem to be quirks where
372 // a source is indicated but not actually present. With a source
373 // index != 0 a GSI is generally indicated.
378 status
= acpi
->get_handle(NULL
, acpiTable
->Source
, &source
);
379 if (status
!= B_OK
) {
380 dprintf("failed to get handle to link device\n");
385 memset(&irqEntry
, 0, sizeof(irq_routing_entry
));
386 irqEntry
.device_address
= acpiTable
->Address
;
387 irqEntry
.pin
= acpiTable
->Pin
;
388 irqEntry
.source
= noSource
? NULL
: source
;
389 irqEntry
.source_index
= acpiTable
->SourceIndex
;
390 irqEntry
.pci_bus
= currentBus
;
391 irqEntry
.pci_device
= (uint8
)(acpiTable
->Address
>> 16);
393 status
= fill_pci_info_for_entry(pci
, irqEntry
);
394 if (status
!= B_OK
) {
395 // Note: This isn't necesarily fatal, as there can be many entries in
396 // the table pointing to disabled/optional devices. Also they can be
397 // used to describe the full actual wireing regardless of the presence
398 // of devices, in which case many entries won't have a match.
400 dprintf("no matching PCI device for irq entry: ");
401 print_irq_routing_entry(irqEntry
);
405 dprintf("found matching PCI device for irq entry: ");
406 print_irq_routing_entry(irqEntry
);
411 // fill in the GSI and config
412 irqEntry
.needs_configuration
= false;
413 irqEntry
.irq
= irqEntry
.source_index
;
414 irqEntry
.polarity
= B_LOW_ACTIVE_POLARITY
;
415 irqEntry
.trigger_mode
= B_LEVEL_TRIGGERED
;
423 find_routing_table_entry(IRQRoutingTable
& table
, uint8 bus
, uint8 device
,
426 for (int i
= 0; i
< table
.Count(); i
++) {
427 irq_routing_entry
& irqEntry
= table
.ElementAt(i
);
428 if (irqEntry
.pci_bus
!= bus
|| irqEntry
.pci_device
!= device
)
431 if (irqEntry
.pin
+ 1 == pin
)
440 ensure_all_functions_matched(pci_module_info
* pci
, uint8 bus
,
441 IRQRoutingTable
& matchedTable
, IRQRoutingTable
& unmatchedTable
,
442 Vector
<pci_address
>& parents
)
444 for (uint8 device
= 0; device
< kMaxPCIDeviceCount
; device
++) {
445 if (pci
->read_pci_config(bus
, device
, 0, PCI_vendor_id
, 2) == 0xffff) {
446 TRACE("PCI bus %" B_PRIu8
":%" B_PRIu8
" not present.\n",
452 uint8 headerType
= pci
->read_pci_config(bus
, device
, 0,
455 uint8 functionCount
= 1;
456 if ((headerType
& PCI_multifunction
) != 0)
457 functionCount
= kMaxPCIFunctionCount
;
459 for (uint8 function
= 0; function
< functionCount
; function
++) {
460 // check for device presence by looking for a valid vendor
461 if (pci
->read_pci_config(bus
, device
, function
, PCI_vendor_id
, 2)
464 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" "
465 "not present.\n", bus
, device
, function
);
470 headerType
= pci
->read_pci_config(bus
, device
, function
,
474 // if this is a bridge, recurse down
475 if ((headerType
& PCI_header_type_mask
)
476 == PCI_header_type_PCI_to_PCI_bridge
) {
478 pci_address pciAddress
;
479 pciAddress
.segment
= 0;
480 pciAddress
.bus
= bus
;
481 pciAddress
.device
= device
;
482 pciAddress
.function
= function
;
484 parents
.PushBack(pciAddress
);
486 uint8 secondaryBus
= pci
->read_pci_config(bus
, device
, function
,
487 PCI_secondary_bus
, 1);
488 if (secondaryBus
!= 0xff) {
489 ensure_all_functions_matched(pci
, secondaryBus
,
490 matchedTable
, unmatchedTable
, parents
);
496 uint8 interruptPin
= pci
->read_pci_config(bus
, device
, function
,
497 PCI_interrupt_pin
, 1);
498 if (interruptPin
== 0 || interruptPin
> 4) {
499 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" "
500 "not routed.\n", bus
, device
, function
);
505 irq_routing_entry
* irqEntry
= find_routing_table_entry(matchedTable
,
506 bus
, device
, interruptPin
);
507 if (irqEntry
!= NULL
) {
508 // we already have a matching entry for that device/pin, make
509 // sure the function mask includes us
510 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" "
511 "already matched. Will mask.\n", bus
, device
, function
);
512 irqEntry
->pci_function_mask
|= 1 << function
;
516 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" has %" B_PRIu8
" "
517 "parents, searching them...\n", bus
, device
, function
,
520 // This function has no matching routing table entry yet. Try to
521 // figure one out in the parent, based on the device number and
523 bool matched
= false;
524 uint8 parentPin
= ((device
+ interruptPin
- 1) % 4) + 1;
525 for (int i
= parents
.Count() - 1; i
>= 0; i
--) {
526 pci_address
& parent
= parents
.ElementAt(i
);
527 irqEntry
= find_routing_table_entry(matchedTable
, parent
.bus
,
528 parent
.device
, parentPin
);
529 if (irqEntry
== NULL
) {
530 // try the unmatched table as well
531 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" "
532 "no matchedTable entry.\n", bus
, device
, function
);
533 irqEntry
= find_routing_table_entry(unmatchedTable
,
534 parent
.bus
, parent
.device
, parentPin
);
537 if (irqEntry
== NULL
) {
538 // no match in that parent, go further up
539 parentPin
= ((parent
.device
+ parentPin
- 1) % 4) + 1;
541 TRACE("PCI %" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
" "
542 "no unmatchedTable entry, looking at parent pin %"
543 B_PRIu8
"...\n", bus
, device
, function
, parentPin
);
547 // found a match, make a copy and add it to the table
548 irq_routing_entry newEntry
= *irqEntry
;
549 newEntry
.device_address
= (device
<< 16) | 0xffff;
550 newEntry
.pin
= interruptPin
- 1;
551 newEntry
.pci_bus
= bus
;
552 newEntry
.pci_device
= device
;
553 newEntry
.pci_function_mask
= 1 << function
;
555 uint8 biosIRQ
= pci
->read_pci_config(bus
, device
, function
,
556 PCI_interrupt_line
, 1);
557 if (biosIRQ
!= 0 && biosIRQ
!= 255) {
558 if (newEntry
.bios_irq
!= 0 && newEntry
.bios_irq
!= 255
559 && newEntry
.bios_irq
!= biosIRQ
) {
560 // If the function was actually routed to that pin,
561 // the two bios irqs should match. If they don't
562 // that means we're not correct in our routing
564 panic("calculated irq routing doesn't match bios for "
565 "PCI %u:%u:%u", bus
, device
, function
);
569 newEntry
.bios_irq
= biosIRQ
;
572 dprintf("calculated irq routing entry: ");
573 print_irq_routing_entry(newEntry
);
575 matchedTable
.PushBack(newEntry
);
581 if (pci
->read_pci_config(bus
, device
, function
,
582 PCI_interrupt_line
, 1) == 0) {
583 dprintf("assuming no interrupt use on PCI device"
584 " %u:%u:%u (bios irq 0, no routing information)\n",
585 bus
, device
, function
);
589 dprintf("WARNING: unable to find irq routing for PCI "
590 "%" B_PRIu8
":%" B_PRIu8
":%" B_PRIu8
". Device may be "
591 "unstable / broken.\n", bus
, device
, function
);
602 read_irq_routing_table_recursive(acpi_module_info
* acpi
, pci_module_info
* pci
,
603 acpi_handle device
, uint8 currentBus
, IRQRoutingTable
& table
,
604 IRQRoutingTable
& unmatchedTable
, bool rootBridge
,
605 interrupt_available_check_function checkFunction
)
608 // check if this actually is a bridge
610 pci_address pciAddress
;
611 pciAddress
.bus
= currentBus
;
612 if (evaluate_integer(acpi
, device
, "_ADR", value
) == B_OK
) {
613 pciAddress
.device
= (uint8
)(value
>> 16);
614 pciAddress
.function
= (uint8
)value
;
616 pciAddress
.device
= 0;
617 pciAddress
.function
= 0;
620 if (pciAddress
.device
>= kMaxPCIDeviceCount
621 || pciAddress
.function
>= kMaxPCIFunctionCount
) {
622 // we don't seem to be on the PCI bus anymore
623 // (just a different type of device)
627 // Verify that the device is really present...
628 uint16 deviceID
= pci
->read_pci_config(pciAddress
.bus
,
629 pciAddress
.device
, pciAddress
.function
, PCI_device_id
, 2);
630 if (deviceID
== 0xffff) {
631 // Not present or disabled.
632 TRACE("device not present\n");
636 // ... and that it really is a PCI bridge we support.
637 uint8 baseClass
= pci
->read_pci_config(pciAddress
.bus
,
638 pciAddress
.device
, pciAddress
.function
, PCI_class_base
, 1);
639 uint8 subClass
= pci
->read_pci_config(pciAddress
.bus
,
640 pciAddress
.device
, pciAddress
.function
, PCI_class_sub
, 1);
641 if (baseClass
!= PCI_bridge
|| subClass
!= PCI_pci
) {
642 // Not a bridge or an unsupported one.
643 TRACE("not a PCI bridge\n");
647 uint8 headerType
= pci
->read_pci_config(pciAddress
.bus
,
648 pciAddress
.device
, pciAddress
.function
, PCI_header_type
, 1);
650 switch (headerType
& PCI_header_type_mask
) {
651 case PCI_header_type_PCI_to_PCI_bridge
:
652 case PCI_header_type_cardbus
:
653 TRACE("found a PCI bridge (0x%02x)\n", headerType
);
657 // Unsupported header type.
658 TRACE("unsupported header type (0x%02x)\n", headerType
);
662 // Find the secondary bus number (the "downstream" bus number for the
663 // attached devices) in the bridge configuration.
664 uint8 secondaryBus
= pci
->read_pci_config(pciAddress
.bus
,
665 pciAddress
.device
, pciAddress
.function
, PCI_secondary_bus
, 1);
666 if (secondaryBus
== 255) {
667 // The bus below this bridge is inactive, nothing to do.
668 TRACE("secondary bus is inactive\n");
672 // The secondary bus cannot be the same as the current one.
673 if (secondaryBus
== currentBus
) {
674 dprintf("invalid secondary bus %u on primary bus %u,"
675 " can't configure irq routing of devices below\n",
676 secondaryBus
, currentBus
);
677 // TODO: Maybe we want to just return B_OK anyway so that we don't
678 // fail this step. We ensure that we matched all devices at the
679 // end of preparation, so we'd detect missing child devices anyway
680 // and it would not cause us to fail for empty misconfigured busses
681 // that we don't actually care about.
685 // Everything below is now on the secondary bus.
686 TRACE("now scanning bus %u\n", secondaryBus
);
687 currentBus
= secondaryBus
;
691 buffer
.pointer
= NULL
;
692 buffer
.length
= ACPI_ALLOCATE_BUFFER
;
693 status_t status
= acpi
->get_irq_routing_table(device
, &buffer
);
694 if (status
== B_OK
) {
695 TRACE("found irq routing table\n");
697 acpi_pci_routing_table
* acpiTable
698 = (acpi_pci_routing_table
*)buffer
.pointer
;
699 while (acpiTable
->Length
) {
700 irq_routing_entry irqEntry
;
701 status
= handle_routing_table_entry(acpi
, pci
, acpiTable
,
702 currentBus
, irqEntry
);
703 if (status
== B_OK
) {
704 if (irqEntry
.source
== NULL
&& !checkFunction(irqEntry
.irq
)) {
705 dprintf("hardwired irq %u not addressable\n", irqEntry
.irq
);
706 free(buffer
.pointer
);
710 if (irqEntry
.pci_function_mask
!= 0)
711 table
.PushBack(irqEntry
);
713 unmatchedTable
.PushBack(irqEntry
);
716 acpiTable
= (acpi_pci_routing_table
*)((uint8
*)acpiTable
717 + acpiTable
->Length
);
720 free(buffer
.pointer
);
722 TRACE("no irq routing table present\n");
725 // recurse down the ACPI child devices
726 acpi_data pathBuffer
;
727 pathBuffer
.pointer
= NULL
;
728 pathBuffer
.length
= ACPI_ALLOCATE_BUFFER
;
729 status
= acpi
->ns_handle_to_pathname(device
, &pathBuffer
);
730 if (status
!= B_OK
) {
731 dprintf("failed to resolve handle to path\n");
736 void* counter
= NULL
;
737 while (acpi
->get_next_entry(ACPI_TYPE_DEVICE
, (char*)pathBuffer
.pointer
,
738 childName
, sizeof(childName
), &counter
) == B_OK
) {
740 acpi_handle childHandle
;
741 status
= acpi
->get_handle(NULL
, childName
, &childHandle
);
742 if (status
!= B_OK
) {
743 dprintf("failed to get handle to child \"%s\"\n", childName
);
747 TRACE("recursing down to child \"%s\"\n", childName
);
748 status
= read_irq_routing_table_recursive(acpi
, pci
, childHandle
,
749 currentBus
, table
, unmatchedTable
, false, checkFunction
);
754 free(pathBuffer
.pointer
);
760 read_irq_routing_table(acpi_module_info
* acpi
, IRQRoutingTable
& table
,
761 interrupt_available_check_function checkFunction
)
763 char rootPciName
[255];
764 acpi_handle rootPciHandle
;
766 status_t status
= acpi
->get_device(kACPIPciRootName
, 0, rootPciName
, 255);
770 status
= acpi
->get_handle(NULL
, rootPciName
, &rootPciHandle
);
774 // We reset the root bus to 0 here. Any failed evaluation means default
775 // values, so we don't have to do anything in the error case.
779 if (evaluate_integer(acpi
, rootPciHandle
, "_BBN", value
) == B_OK
)
780 rootBus
= (uint8
)value
;
784 if (evaluate_integer(acpi
, rootPciHandle
, "_SEG", value
) == B_OK
)
785 rootPciAddress
.segment
= (uint8
)value
;
788 pci_module_info
* pci
;
789 status
= get_module(B_PCI_MODULE_NAME
, (module_info
**)&pci
);
790 if (status
!= B_OK
) {
791 // shouldn't happen, since the PCI module is a dependency of the
792 // ACPI module and we shouldn't be here at all if it wasn't loaded
793 dprintf("failed to get PCI module!\n");
797 IRQRoutingTable unmatchedTable
;
798 status
= read_irq_routing_table_recursive(acpi
, pci
, rootPciHandle
, rootBus
,
799 table
, unmatchedTable
, true, checkFunction
);
800 if (status
!= B_OK
) {
801 put_module(B_PCI_MODULE_NAME
);
805 if (table
.Count() == 0) {
806 put_module(B_PCI_MODULE_NAME
);
810 // Now go through all the PCI devices and verify that they have a routing
811 // table entry. For the devices without a match, we calculate their pins
812 // on the bridges and try to match these in the parent routing table. We
813 // do this recursively going up the tree until we find a match or arrive
815 Vector
<pci_address
> parents
;
816 status
= ensure_all_functions_matched(pci
, rootBus
, table
, unmatchedTable
,
819 put_module(B_PCI_MODULE_NAME
);
825 prepare_irq_routing(acpi_module_info
* acpi
, IRQRoutingTable
& routingTable
,
826 interrupt_available_check_function checkFunction
)
828 status_t status
= read_irq_routing_table(acpi
, routingTable
, checkFunction
);
832 // resolve desired configuration of link devices
833 return choose_link_device_configurations(acpi
, routingTable
, checkFunction
);
838 enable_irq_routing(acpi_module_info
* acpi
, IRQRoutingTable
& routingTable
)
840 // configure the link devices; also resolves GSIs for link based entries
841 status_t status
= configure_link_devices(acpi
, routingTable
);
842 if (status
!= B_OK
) {
843 panic("failed to configure link devices");
847 pci_module_info
* pci
;
848 status
= get_module(B_PCI_MODULE_NAME
, (module_info
**)&pci
);
849 if (status
!= B_OK
) {
850 // shouldn't happen, since the PCI module is a dependency of the
851 // ACPI module and we shouldn't be here at all if it wasn't loaded
852 dprintf("failed to get PCI module!\n");
856 // update the PCI info now that all GSIs are known
857 for (int i
= 0; i
< routingTable
.Count(); i
++) {
858 irq_routing_entry
& irqEntry
= routingTable
.ElementAt(i
);
860 status
= update_pci_info_for_entry(pci
, irqEntry
);
861 if (status
!= B_OK
) {
862 dprintf("failed to update interrupt_line for PCI %u:%u mask %"
863 B_PRIx32
"\n", irqEntry
.pci_bus
, irqEntry
.pci_device
,
864 irqEntry
.pci_function_mask
);
868 put_module(B_PCI_MODULE_NAME
);
874 read_irq_descriptor(acpi_module_info
* acpi
, acpi_handle device
,
875 bool readCurrent
, irq_descriptor
* _descriptor
,
876 irq_descriptor_list
* descriptorList
)
879 buffer
.pointer
= NULL
;
880 buffer
.length
= ACPI_ALLOCATE_BUFFER
;
884 status
= acpi
->get_current_resources(device
, &buffer
);
886 status
= acpi
->get_possible_resources(device
, &buffer
);
888 if (status
!= B_OK
) {
889 dprintf("failed to read %s resources for irq\n",
890 readCurrent
? "current" : "possible");
891 free(buffer
.pointer
);
895 irq_descriptor descriptor
;
896 descriptor
.irq
= 255;
898 acpi_resource
* resource
= (acpi_resource
*)buffer
.pointer
;
899 while (resource
->Type
!= ACPI_RESOURCE_TYPE_END_TAG
) {
900 switch (resource
->Type
) {
901 case ACPI_RESOURCE_TYPE_IRQ
:
903 acpi_resource_irq
& irq
= resource
->Data
.Irq
;
904 if (irq
.InterruptCount
< 1) {
905 dprintf("acpi irq resource with no interrupts\n");
909 descriptor
.shareable
= irq
.Sharable
!= 0;
910 descriptor
.trigger_mode
= irq
.Triggering
== 0
911 ? B_LEVEL_TRIGGERED
: B_EDGE_TRIGGERED
;
912 descriptor
.polarity
= irq
.Polarity
== 0
913 ? B_HIGH_ACTIVE_POLARITY
: B_LOW_ACTIVE_POLARITY
;
916 descriptor
.irq
= irq
.Interrupts
[0];
918 for (uint16 i
= 0; i
< irq
.InterruptCount
; i
++) {
919 descriptor
.irq
= irq
.Interrupts
[i
];
920 descriptorList
->PushBack(descriptor
);
925 dprintf("acpi irq resource (%s):\n",
926 readCurrent
? "current" : "possible");
927 dprintf("\ttriggering: %s\n",
928 irq
.Triggering
== 0 ? "level" : "edge");
929 dprintf("\tpolarity: %s active\n",
930 irq
.Polarity
== 0 ? "high" : "low");
931 dprintf("\tsharable: %s\n", irq
.Sharable
!= 0 ? "yes" : "no");
932 dprintf("\tcount: %u\n", irq
.InterruptCount
);
933 if (irq
.InterruptCount
> 0) {
934 dprintf("\tinterrupts:");
935 for (uint16 i
= 0; i
< irq
.InterruptCount
; i
++)
936 dprintf(" %u", irq
.Interrupts
[i
]);
943 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
945 acpi_resource_extended_irq
& irq
= resource
->Data
.ExtendedIrq
;
946 if (irq
.InterruptCount
< 1) {
947 dprintf("acpi extended irq resource with no interrupts\n");
951 descriptor
.shareable
= irq
.Sharable
!= 0;
952 descriptor
.trigger_mode
= irq
.Triggering
== 0
953 ? B_LEVEL_TRIGGERED
: B_EDGE_TRIGGERED
;
954 descriptor
.polarity
= irq
.Polarity
== 0
955 ? B_HIGH_ACTIVE_POLARITY
: B_LOW_ACTIVE_POLARITY
;
958 descriptor
.irq
= irq
.Interrupts
[0];
960 for (uint16 i
= 0; i
< irq
.InterruptCount
; i
++) {
961 descriptor
.irq
= irq
.Interrupts
[i
];
962 descriptorList
->PushBack(descriptor
);
967 dprintf("acpi extended irq resource (%s):\n",
968 readCurrent
? "current" : "possible");
969 dprintf("\tproducer: %s\n",
970 irq
.ProducerConsumer
? "yes" : "no");
971 dprintf("\ttriggering: %s\n",
972 irq
.Triggering
== 0 ? "level" : "edge");
973 dprintf("\tpolarity: %s active\n",
974 irq
.Polarity
== 0 ? "high" : "low");
975 dprintf("\tsharable: %s\n", irq
.Sharable
!= 0 ? "yes" : "no");
976 dprintf("\tcount: %u\n", irq
.InterruptCount
);
977 if (irq
.InterruptCount
> 0) {
978 dprintf("\tinterrupts:");
979 for (uint16 i
= 0; i
< irq
.InterruptCount
; i
++)
980 dprintf(" %u", irq
.Interrupts
[i
]);
988 if (descriptor
.irq
!= 255)
991 resource
= (acpi_resource
*)((uint8
*)resource
+ resource
->Length
);
994 free(buffer
.pointer
);
996 if (descriptor
.irq
== 255)
1000 *_descriptor
= descriptor
;
1007 read_current_irq(acpi_module_info
* acpi
, acpi_handle device
,
1008 irq_descriptor
& descriptor
)
1010 return read_irq_descriptor(acpi
, device
, true, &descriptor
, NULL
);
1015 read_possible_irqs(acpi_module_info
* acpi
, acpi_handle device
,
1016 irq_descriptor_list
& descriptorList
)
1018 return read_irq_descriptor(acpi
, device
, false, NULL
, &descriptorList
);
1023 set_current_irq(acpi_module_info
* acpi
, acpi_handle device
,
1024 const irq_descriptor
& descriptor
)
1027 buffer
.pointer
= NULL
;
1028 buffer
.length
= ACPI_ALLOCATE_BUFFER
;
1030 status_t status
= acpi
->get_current_resources(device
, &buffer
);
1031 if (status
!= B_OK
) {
1032 dprintf("failed to read current resources for irq\n");
1036 bool irqWritten
= false;
1037 acpi_resource
* resource
= (acpi_resource
*)buffer
.pointer
;
1038 while (resource
->Type
!= ACPI_RESOURCE_TYPE_END_TAG
) {
1039 switch (resource
->Type
) {
1040 case ACPI_RESOURCE_TYPE_IRQ
:
1042 acpi_resource_irq
& irq
= resource
->Data
.Irq
;
1043 if (irq
.InterruptCount
< 1) {
1044 dprintf("acpi irq resource with no interrupts\n");
1049 = descriptor
.trigger_mode
== B_LEVEL_TRIGGERED
? 0 : 1;
1051 = descriptor
.polarity
== B_HIGH_ACTIVE_POLARITY
? 0 : 1;
1052 irq
.Sharable
= descriptor
.shareable
? 0 : 1;
1053 irq
.InterruptCount
= 1;
1054 irq
.Interrupts
[0] = descriptor
.irq
;
1060 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
1062 acpi_resource_extended_irq
& irq
= resource
->Data
.ExtendedIrq
;
1063 if (irq
.InterruptCount
< 1) {
1064 dprintf("acpi extended irq resource with no interrupts\n");
1069 = descriptor
.trigger_mode
== B_LEVEL_TRIGGERED
? 0 : 1;
1071 = descriptor
.polarity
== B_HIGH_ACTIVE_POLARITY
? 0 : 1;
1072 irq
.Sharable
= descriptor
.shareable
? 0 : 1;
1073 irq
.InterruptCount
= 1;
1074 irq
.Interrupts
[0] = descriptor
.irq
;
1084 resource
= (acpi_resource
*)((uint8
*)resource
+ resource
->Length
);
1088 status
= acpi
->set_current_resources(device
, &buffer
);
1090 dprintf("failed to set irq resources\n");
1092 dprintf("failed to write requested irq into resources\n");
1096 free(buffer
.pointer
);