vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / arch / x86 / irq_routing_table.cpp
blobc442fac45697f2515cc848a95f3d91e309ccd814
1 /*
2 * Copyright 2011, Michael Lotz mmlr@mlotz.ch.
3 * Copyright 2009, Clemens Zeidler haiku@clemens-zeidler.de.
4 * All rights reserved.
6 * Distributed under the terms of the MIT License.
7 */
10 #include "irq_routing_table.h"
12 #include "acpi.h"
14 #include <int.h>
16 #include <PCI.h>
19 //#define TRACE_PRT
20 #ifdef TRACE_PRT
21 # define TRACE(x...) dprintf("IRQRoutingTable: " x)
22 #else
23 # define TRACE(x...)
24 #endif
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()
41 irq(0),
42 shareable(false),
43 polarity(B_HIGH_ACTIVE_POLARITY),
44 trigger_mode(B_EDGE_TRIGGERED)
49 void
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
60 : activeLowString,
61 descriptor.trigger_mode == B_LEVEL_TRIGGERED ? levelTriggeredString
62 : edgeTriggeredString);
66 static void
67 print_irq_routing_entry(const irq_routing_entry& entry)
69 dprintf("address 0x%04" B_PRIx64 "; pin %u;", entry.device_address,
70 entry.pin);
72 if (entry.source_index != 0)
73 dprintf(" GSI %" B_PRIu32 ";", entry.source_index);
74 else
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);
84 void
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));
93 static status_t
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)
99 continue;
101 if (pci->update_interrupt_line(entry.pci_bus, entry.pci_device,
102 function, entry.irq) == B_OK) {
103 updateCount++;
107 return updateCount > 0 ? B_OK : B_ENTRY_NOT_FOUND;
111 static status_t
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,
116 PCI_header_type, 1);
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);
136 continue;
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);
148 continue;
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;
169 static status_t
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
176 consideration:
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);
210 continue;
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) {
217 link = existing;
218 break;
222 if (link != NULL) {
223 link->used_by.PushBack(&irqEntry);
224 continue;
227 // A new link device, read possible IRQs and fill them in.
228 link = new(std::nothrow) link_device;
229 if (link == NULL) {
230 panic("ran out of memory while configuring irq link devices");
231 return B_NO_MEMORY;
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");
239 return status;
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");
245 return status;
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
264 continue;
267 if (possibleIRQ.irq < kMaxISAInterrupts
268 && (validForPCI & (1 << possibleIRQ.irq)) == 0) {
269 // better avoid that if possible
270 continue;
273 if (irqUsage[possibleIRQ.irq] < bestIRQUsage) {
274 bestIRQIndex = j;
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);
284 return B_ERROR;
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;
297 delete link;
300 return B_OK;
304 static status_t
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)
310 continue;
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;
337 return B_OK;
341 static status_t
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,
351 &resultBuffer);
352 if (status != B_OK)
353 return status;
355 if (result.object_type != ACPI_TYPE_INTEGER)
356 return B_BAD_TYPE;
358 value = result.integer.integer;
359 return B_OK;
363 static status_t
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.
375 status_t status;
376 acpi_handle source;
377 if (!noSource) {
378 status = acpi->get_handle(NULL, acpiTable->Source, &source);
379 if (status != B_OK) {
380 dprintf("failed to get handle to link device\n");
381 return status;
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.
399 #ifdef TRACE_PRT
400 dprintf("no matching PCI device for irq entry: ");
401 print_irq_routing_entry(irqEntry);
402 #endif
403 } else {
404 #ifdef TRACE_PRT
405 dprintf("found matching PCI device for irq entry: ");
406 print_irq_routing_entry(irqEntry);
407 #endif
410 if (noSource) {
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;
418 return B_OK;
422 irq_routing_entry*
423 find_routing_table_entry(IRQRoutingTable& table, uint8 bus, uint8 device,
424 uint8 pin)
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)
429 continue;
431 if (irqEntry.pin + 1 == pin)
432 return &irqEntry;
435 return NULL;
439 static status_t
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",
447 bus, device);
448 // not present
449 continue;
452 uint8 headerType = pci->read_pci_config(bus, device, 0,
453 PCI_header_type, 1);
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)
462 == 0xffff) {
463 // not present
464 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " "
465 "not present.\n", bus, device, function);
466 continue;
469 if (function > 0) {
470 headerType = pci->read_pci_config(bus, device, function,
471 PCI_header_type, 1);
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);
493 parents.PopBack();
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);
501 // not routed
502 continue;
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;
513 continue;
516 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " has %" B_PRIu8 " "
517 "parents, searching them...\n", bus, device, function,
518 parents.Count());
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
522 // interrupt pin.
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);
544 continue;
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
563 // assumption.
564 panic("calculated irq routing doesn't match bios for "
565 "PCI %u:%u:%u", bus, device, function);
566 return B_ERROR;
569 newEntry.bios_irq = biosIRQ;
572 dprintf("calculated irq routing entry: ");
573 print_irq_routing_entry(newEntry);
575 matchedTable.PushBack(newEntry);
576 matched = true;
577 break;
580 if (!matched) {
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);
586 continue;
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);
592 return B_ERROR;
597 return B_OK;
601 static status_t
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)
607 if (!rootBridge) {
608 // check if this actually is a bridge
609 uint64 value;
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;
615 } else {
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)
624 return B_OK;
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");
633 return B_OK;
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");
644 return B_OK;
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);
654 break;
656 default:
657 // Unsupported header type.
658 TRACE("unsupported header type (0x%02x)\n", headerType);
659 return B_OK;
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");
669 return B_OK;
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.
682 return B_ERROR;
685 // Everything below is now on the secondary bus.
686 TRACE("now scanning bus %u\n", secondaryBus);
687 currentBus = secondaryBus;
690 acpi_data buffer;
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);
707 return B_ERROR;
710 if (irqEntry.pci_function_mask != 0)
711 table.PushBack(irqEntry);
712 else
713 unmatchedTable.PushBack(irqEntry);
716 acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable
717 + acpiTable->Length);
720 free(buffer.pointer);
721 } else {
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");
732 return status;
735 char childName[255];
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);
744 break;
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);
750 if (status != B_OK)
751 break;
754 free(pathBuffer.pointer);
755 return status;
759 static status_t
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;
765 rootPciName[0] = 0;
766 status_t status = acpi->get_device(kACPIPciRootName, 0, rootPciName, 255);
767 if (status != B_OK)
768 return status;
770 status = acpi->get_handle(NULL, rootPciName, &rootPciHandle);
771 if (status != B_OK)
772 return status;
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.
776 uint8 rootBus = 0;
778 uint64 value;
779 if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK)
780 rootBus = (uint8)value;
782 #if 0
783 // TODO: handle
784 if (evaluate_integer(acpi, rootPciHandle, "_SEG", value) == B_OK)
785 rootPciAddress.segment = (uint8)value;
786 #endif
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");
794 return status;
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);
802 return status;
805 if (table.Count() == 0) {
806 put_module(B_PCI_MODULE_NAME);
807 return B_ERROR;
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
814 // at the top.
815 Vector<pci_address> parents;
816 status = ensure_all_functions_matched(pci, rootBus, table, unmatchedTable,
817 parents);
819 put_module(B_PCI_MODULE_NAME);
820 return status;
824 status_t
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);
829 if (status != B_OK)
830 return status;
832 // resolve desired configuration of link devices
833 return choose_link_device_configurations(acpi, routingTable, checkFunction);
837 status_t
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");
844 return status;
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");
853 return status;
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);
869 return B_OK;
873 static status_t
874 read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
875 bool readCurrent, irq_descriptor* _descriptor,
876 irq_descriptor_list* descriptorList)
878 acpi_data buffer;
879 buffer.pointer = NULL;
880 buffer.length = ACPI_ALLOCATE_BUFFER;
882 status_t status;
883 if (readCurrent)
884 status = acpi->get_current_resources(device, &buffer);
885 else
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);
892 return status;
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");
906 break;
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;
915 if (readCurrent)
916 descriptor.irq = irq.Interrupts[0];
917 else {
918 for (uint16 i = 0; i < irq.InterruptCount; i++) {
919 descriptor.irq = irq.Interrupts[i];
920 descriptorList->PushBack(descriptor);
924 #ifdef TRACE_PRT
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]);
937 dprintf("\n");
939 #endif
940 break;
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");
948 break;
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;
957 if (readCurrent)
958 descriptor.irq = irq.Interrupts[0];
959 else {
960 for (uint16 i = 0; i < irq.InterruptCount; i++) {
961 descriptor.irq = irq.Interrupts[i];
962 descriptorList->PushBack(descriptor);
966 #ifdef TRACE_PRT
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]);
981 dprintf("\n");
983 #endif
984 break;
988 if (descriptor.irq != 255)
989 break;
991 resource = (acpi_resource*)((uint8*)resource + resource->Length);
994 free(buffer.pointer);
996 if (descriptor.irq == 255)
997 return B_ERROR;
999 if (readCurrent)
1000 *_descriptor = descriptor;
1002 return B_OK;
1006 status_t
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);
1014 status_t
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);
1022 status_t
1023 set_current_irq(acpi_module_info* acpi, acpi_handle device,
1024 const irq_descriptor& descriptor)
1026 acpi_data buffer;
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");
1033 return status;
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");
1045 break;
1048 irq.Triggering
1049 = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1;
1050 irq.Polarity
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;
1056 irqWritten = true;
1057 break;
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");
1065 break;
1068 irq.Triggering
1069 = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1;
1070 irq.Polarity
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;
1076 irqWritten = true;
1077 break;
1081 if (irqWritten)
1082 break;
1084 resource = (acpi_resource*)((uint8*)resource + resource->Length);
1087 if (irqWritten) {
1088 status = acpi->set_current_resources(device, &buffer);
1089 if (status != B_OK)
1090 dprintf("failed to set irq resources\n");
1091 } else {
1092 dprintf("failed to write requested irq into resources\n");
1093 status = B_ERROR;
1096 free(buffer.pointer);
1097 return status;