1 /*
2 * Copyright 2011, Michael Lotz mmlr@mlotz.ch.
3 * Copyright 2009, Clemens Zeidler haiku@clemens-zeidler.de.
4 * All rights reserved.
5 *
6 * Distributed under the terms of the MIT License.
7 */
8
9
10 #include "acpi_irq_routing_table.h"
11
12 #include "acpi.h"
13
14 #include <int.h>
15
16 #include <PCI.h>
17
18
19 //#define TRACE_PRT
20 #ifdef TRACE_PRT
21 # define TRACE(x...) dprintf("IRQRoutingTable: " x)
22 #else
23 # define TRACE(x...)
24 #endif
25
26
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.
32
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 #if defined(__i386__) || defined(__x86_64__)
38 static const uint8 kMaxISAInterrupts = 16;
39 #else
40 static const uint8 kMaxISAInterrupts = 0;
41 #endif
42
irq_descriptor()43 irq_descriptor::irq_descriptor()
44 :
45 irq(0),
46 shareable(false),
47 polarity(B_HIGH_ACTIVE_POLARITY),
48 trigger_mode(B_EDGE_TRIGGERED)
49 {
50 }
51
52
53 void
print_irq_descriptor(const irq_descriptor & descriptor)54 print_irq_descriptor(const irq_descriptor& descriptor)
55 {
56 const char* activeHighString = "active high";
57 const char* activeLowString = " active low";
58 const char* levelTriggeredString = "level triggered";
59 const char* edgeTriggeredString = "edge triggered";
60
61 dprintf("irq: %u, shareable: %u, polarity: %s, trigger_mode: %s\n",
62 descriptor.irq, descriptor.shareable,
63 descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? activeHighString
64 : activeLowString,
65 descriptor.trigger_mode == B_LEVEL_TRIGGERED ? levelTriggeredString
66 : edgeTriggeredString);
67 }
68
69
70 static void
print_irq_routing_entry(const irq_routing_entry & entry)71 print_irq_routing_entry(const irq_routing_entry& entry)
72 {
73 dprintf("address 0x%04" B_PRIx64 "; pin %u;", entry.device_address,
74 entry.pin);
75
76 if (entry.source_index != 0)
77 dprintf(" GSI %" B_PRIu32 ";", entry.source_index);
78 else
79 dprintf(" source %p %" B_PRIu32 ";", entry.source, entry.source_index);
80
81 dprintf(" pci %u:%u pin %u func mask %" B_PRIx32 "; bios irq: %u; gsi %u;"
82 " config 0x%02x\n", entry.pci_bus, entry.pci_device, entry.pin + 1,
83 entry.pci_function_mask, entry.bios_irq, entry.irq,
84 entry.polarity | entry.trigger_mode);
85 }
86
87
88 void
print_irq_routing_table(const IRQRoutingTable & table)89 print_irq_routing_table(const IRQRoutingTable& table)
90 {
91 dprintf("IRQ routing table with %i entries\n", (int)table.Count());
92 for (int i = 0; i < table.Count(); i++)
93 print_irq_routing_entry(table.ElementAt(i));
94 }
95
96
97 static status_t
update_pci_info_for_entry(pci_module_info * pci,const irq_routing_entry & entry)98 update_pci_info_for_entry(pci_module_info* pci, const irq_routing_entry& entry)
99 {
100 uint32 updateCount = 0;
101 for (uint8 function = 0; function < kMaxPCIFunctionCount; function++) {
102 if ((entry.pci_function_mask & (1 << function)) == 0)
103 continue;
104
105 if (pci->update_interrupt_line(entry.pci_bus, entry.pci_device,
106 function, entry.irq) == B_OK) {
107 updateCount++;
108 }
109 }
110
111 return updateCount > 0 ? B_OK : B_ENTRY_NOT_FOUND;
112 }
113
114
115 static status_t
fill_pci_info_for_entry(pci_module_info * pci,irq_routing_entry & entry)116 fill_pci_info_for_entry(pci_module_info* pci, irq_routing_entry& entry)
117 {
118 // check the base device at function 0
119 uint8 headerType = pci->read_pci_config(entry.pci_bus, entry.pci_device, 0,
120 PCI_header_type, 1);
121 if (headerType == 0xff) {
122 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 " entry not found\n",
123 entry.pci_bus, entry.pci_device);
124 // the device is not present
125 return B_ENTRY_NOT_FOUND;
126 }
127
128 // we have a device, check how many functions we need to iterate
129 uint8 functionCount = 1;
130 if ((headerType & PCI_multifunction) != 0)
131 functionCount = kMaxPCIFunctionCount;
132
133 for (uint8 function = 0; function < functionCount; function++) {
134 // check for device presence by looking for a valid vendor
135 uint16 vendorId = pci->read_pci_config(entry.pci_bus, entry.pci_device,
136 function, PCI_vendor_id, 2);
137 if (vendorId == 0xffff) {
138 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " vendor 0xffff\n",
139 entry.pci_bus, entry.pci_device, function);
140 continue;
141 }
142
143 uint8 interruptPin = pci->read_pci_config(entry.pci_bus,
144 entry.pci_device, function, PCI_interrupt_pin, 1);
145
146 // Finally match the pin with the entry, note that PCI pins are 1 based
147 // while ACPI ones are 0 based.
148 if (interruptPin != entry.pin + 1) {
149 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " IRQ Pin %" B_PRIu8
150 " != %" B_PRIu8 "\n", entry.pci_bus, entry.pci_device, function,
151 interruptPin, entry.pin + 1);
152 continue;
153 }
154
155 if (entry.bios_irq == 0) {
156 // Keep the originally assigned IRQ around so we can use it for
157 // white listing PCI IRQs in the ISA space as those are basically
158 // guaranteed not to overlap with ISA devices. Those white listed
159 // entries can then be used if we only have a 16 pin IO-APIC or if
160 // there are only legacy IRQ resources available for configuration
161 // (with bitmasks of 16 bits, limiting their range to ISA IRQs).
162 entry.bios_irq = pci->read_pci_config(entry.pci_bus,
163 entry.pci_device, function, PCI_interrupt_line, 1);
164 }
165
166 entry.pci_function_mask |= 1 << function;
167 }
168
169 return entry.pci_function_mask != 0 ? B_OK : B_ENTRY_NOT_FOUND;
170 }
171
172
173 static status_t
choose_link_device_configurations(acpi_module_info * acpi,IRQRoutingTable & routingTable,interrupt_available_check_function checkFunction)174 choose_link_device_configurations(acpi_module_info* acpi,
175 IRQRoutingTable& routingTable,
176 interrupt_available_check_function checkFunction)
177 {
178 /*
179 Before configuring the link devices we have to take a few things into
180 consideration:
181 * Multiple PCI devices / functions may link to the same PCI link
182 device, so we must ensure that we don't try to configure different
183 IRQs for each device, overwriting the previous config of the
184 respective link device.
185 * If we can't use non-ISA IRQs then we must ensure that we don't
186 configure any IRQs that overlaps with ISA devices (as they use
187 different triggering modes and polarity they aren't compatible).
188 Since the ISA bus isn't enumerable we don't have any clues as to
189 where an ISA device might be connected. The only safe assumption
190 therefore is to only use IRQs that are known to be usable for PCI
191 devices. In our case we can use all the previously assigned PCI
192 interrupt_line IRQs as stored in the bios_irq field.
193 */
194
195 uint16 validForPCI = 0; // only applies to the ISA IRQs
196 uint16 irqUsage[256];
197 memset(irqUsage, 0, sizeof(irqUsage));
198
199 // find all unique link devices and resolve their possible IRQs
200 Vector<link_device*> links;
201 for (int i = 0; i < routingTable.Count(); i++) {
202 irq_routing_entry& irqEntry = routingTable.ElementAt(i);
203
204 if (irqEntry.bios_irq != 0 && irqEntry.bios_irq != 255) {
205 if (irqEntry.bios_irq < kMaxISAInterrupts)
206 validForPCI |= (1 << irqEntry.bios_irq);
207 }
208
209 if (irqEntry.source == NULL) {
210 // populate all hardwired GSI entries into our map
211 irqUsage[irqEntry.irq]++;
212 if (irqEntry.irq < kMaxISAInterrupts)
213 validForPCI |= (1 << irqEntry.irq);
214 continue;
215 }
216
217 link_device* link = NULL;
218 for (int j = 0; j < links.Count(); j++) {
219 link_device* existing = links.ElementAt(j);
220 if (existing->handle == irqEntry.source) {
221 link = existing;
222 break;
223 }
224 }
225
226 if (link != NULL) {
227 link->used_by.PushBack(&irqEntry);
228 continue;
229 }
230
231 // A new link device, read possible IRQs and fill them in.
232 link = new(std::nothrow) link_device;
233 if (link == NULL) {
234 panic("ran out of memory while configuring irq link devices");
235 return B_NO_MEMORY;
236 }
237
238 link->handle = irqEntry.source;
239 status_t status = read_possible_irqs(acpi, link->handle,
240 link->possible_irqs);
241 if (status != B_OK) {
242 panic("failed to read possible irqs of link device");
243 delete link;
244 return status;
245 }
246
247 status = read_current_irq(acpi, link->handle, link->current_irq);
248 if (status != B_OK) {
249 panic("failed to read current irq of link device");
250 delete link;
251 return status;
252 }
253
254 if (link->current_irq.irq < kMaxISAInterrupts)
255 validForPCI |= (1 << link->current_irq.irq);
256
257 link->used_by.PushBack(&irqEntry);
258 links.PushBack(link);
259 }
260
261 for (int i = 0; i < links.Count(); i++) {
262 link_device* link = links.ElementAt(i);
263
264 int bestIRQIndex = 0;
265 uint16 bestIRQUsage = UINT16_MAX;
266 for (int j = 0; j < link->possible_irqs.Count(); j++) {
267 irq_descriptor& possibleIRQ = link->possible_irqs.ElementAt(j);
268 if (!checkFunction(possibleIRQ.irq)) {
269 // we can't address this pin
270 continue;
271 }
272
273 if (possibleIRQ.irq < kMaxISAInterrupts
274 && (validForPCI & (1 << possibleIRQ.irq)) == 0) {
275 // better avoid that if possible
276 continue;
277 }
278
279 if (irqUsage[possibleIRQ.irq] < bestIRQUsage) {
280 bestIRQIndex = j;
281 bestIRQUsage = irqUsage[possibleIRQ.irq];
282 }
283 }
284
285 // pick that one and update the counts
286 irq_descriptor& chosenDescriptor
287 = link->possible_irqs.ElementAt(bestIRQIndex);
288 if (!checkFunction(chosenDescriptor.irq)) {
289 dprintf("chosen irq %u is not addressable\n", chosenDescriptor.irq);
290 return B_ERROR;
291 }
292
293 irqUsage[chosenDescriptor.irq] += link->used_by.Count();
294
295 for (int j = 0; j < link->used_by.Count(); j++) {
296 irq_routing_entry* irqEntry = link->used_by.ElementAt(j);
297 irqEntry->needs_configuration = j == 0; // only configure once
298 irqEntry->irq = chosenDescriptor.irq;
299 irqEntry->polarity = chosenDescriptor.polarity;
300 irqEntry->trigger_mode = chosenDescriptor.trigger_mode;
301 }
302
303 delete link;
304 }
305
306 return B_OK;
307 }
308
309
310 static status_t
configure_link_devices(acpi_module_info * acpi,IRQRoutingTable & routingTable)311 configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable)
312 {
313 for (int i = 0; i < routingTable.Count(); i++) {
314 irq_routing_entry& irqEntry = routingTable.ElementAt(i);
315 if (!irqEntry.needs_configuration)
316 continue;
317
318 irq_descriptor configuration;
319 configuration.irq = irqEntry.irq;
320 configuration.polarity = irqEntry.polarity;
321 configuration.trigger_mode = irqEntry.trigger_mode;
322
323 status_t status = set_current_irq(acpi, irqEntry.source, configuration);
324 if (status != B_OK) {
325 dprintf("failed to set irq on link device, keeping current\n");
326 print_irq_descriptor(configuration);
327
328 // we failed to set the resource, fall back to current
329 read_current_irq(acpi, irqEntry.source, configuration);
330 for (int j = i; j < routingTable.Count(); j++) {
331 irq_routing_entry& other = routingTable.ElementAt(j);
332 if (other.source == irqEntry.source) {
333 other.irq = configuration.irq;
334 other.polarity = configuration.polarity;
335 other.trigger_mode = configuration.trigger_mode;
336 }
337 }
338 }
339
340 irqEntry.needs_configuration = false;
341 }
342
343 return B_OK;
344 }
345
346
347 static status_t
evaluate_integer(acpi_module_info * acpi,acpi_handle handle,const char * method,uint64 & value)348 evaluate_integer(acpi_module_info* acpi, acpi_handle handle,
349 const char* method, uint64& value)
350 {
351 acpi_object_type result;
352 acpi_data resultBuffer;
353 resultBuffer.pointer = &result;
354 resultBuffer.length = sizeof(result);
355
356 status_t status = acpi->evaluate_method(handle, method, NULL,
357 &resultBuffer);
358 if (status != B_OK)
359 return status;
360
361 if (result.object_type != ACPI_TYPE_INTEGER)
362 return B_BAD_TYPE;
363
364 value = result.integer.integer;
365 return B_OK;
366 }
367
368
369 static status_t
handle_routing_table_entry(acpi_module_info * acpi,pci_module_info * pci,acpi_handle parent,const acpi_pci_routing_table * acpiTable,uint8 currentBus,irq_routing_entry & irqEntry)370 handle_routing_table_entry(acpi_module_info* acpi, pci_module_info* pci,
371 acpi_handle parent, const acpi_pci_routing_table* acpiTable,
372 uint8 currentBus, irq_routing_entry& irqEntry)
373 {
374 bool noSource = acpiTable->Source[0] == '\0';
375 // The above line would be correct according to specs...
376 noSource = acpiTable->SourceIndex != 0;
377 // ... but we use this one as there seem to be quirks where
378 // a source is indicated but not actually present. With a source
379 // index != 0 a GSI is generally indicated.
380
381 status_t status;
382 acpi_handle source;
383 if (!noSource) {
384 status = acpi->get_handle(parent, acpiTable->Source, &source);
385 if (status != B_OK) {
386 dprintf("failed to get handle to link device\n");
387 return status;
388 }
389 }
390
391 memset(&irqEntry, 0, sizeof(irq_routing_entry));
392 irqEntry.device_address = acpiTable->Address;
393 irqEntry.pin = acpiTable->Pin;
394 irqEntry.source = noSource ? NULL : source;
395 irqEntry.source_index = acpiTable->SourceIndex;
396 irqEntry.pci_bus = currentBus;
397 irqEntry.pci_device = (uint8)(acpiTable->Address >> 16);
398
399 status = fill_pci_info_for_entry(pci, irqEntry);
400 if (status != B_OK) {
401 // Note: This isn't necesarily fatal, as there can be many entries in
402 // the table pointing to disabled/optional devices. Also they can be
403 // used to describe the full actual wireing regardless of the presence
404 // of devices, in which case many entries won't have a match.
405 #ifdef TRACE_PRT
406 dprintf("no matching PCI device for irq entry: ");
407 print_irq_routing_entry(irqEntry);
408 #endif
409 } else {
410 #ifdef TRACE_PRT
411 dprintf("found matching PCI device for irq entry: ");
412 print_irq_routing_entry(irqEntry);
413 #endif
414 }
415
416 if (noSource) {
417 // fill in the GSI and config
418 irqEntry.needs_configuration = false;
419 irqEntry.irq = irqEntry.source_index;
420 irqEntry.polarity = B_LOW_ACTIVE_POLARITY;
421 irqEntry.trigger_mode = B_LEVEL_TRIGGERED;
422 }
423
424 return B_OK;
425 }
426
427
428 irq_routing_entry*
find_routing_table_entry(IRQRoutingTable & table,uint8 bus,uint8 device,uint8 pin)429 find_routing_table_entry(IRQRoutingTable& table, uint8 bus, uint8 device,
430 uint8 pin)
431 {
432 for (int i = 0; i < table.Count(); i++) {
433 irq_routing_entry& irqEntry = table.ElementAt(i);
434 if (irqEntry.pci_bus != bus || irqEntry.pci_device != device)
435 continue;
436
437 if (irqEntry.pin + 1 == pin)
438 return &irqEntry;
439 }
440
441 return NULL;
442 }
443
444
445 static status_t
ensure_all_functions_matched(pci_module_info * pci,uint8 bus,IRQRoutingTable & matchedTable,IRQRoutingTable & unmatchedTable,Vector<pci_address> & parents)446 ensure_all_functions_matched(pci_module_info* pci, uint8 bus,
447 IRQRoutingTable& matchedTable, IRQRoutingTable& unmatchedTable,
448 Vector<pci_address>& parents)
449 {
450 for (uint8 device = 0; device < kMaxPCIDeviceCount; device++) {
451 if (pci->read_pci_config(bus, device, 0, PCI_vendor_id, 2) == 0xffff) {
452 TRACE("PCI bus %" B_PRIu8 ":%" B_PRIu8 " not present.\n",
453 bus, device);
454 // not present
455 continue;
456 }
457
458 uint8 headerType = pci->read_pci_config(bus, device, 0,
459 PCI_header_type, 1);
460
461 uint8 functionCount = 1;
462 if ((headerType & PCI_multifunction) != 0)
463 functionCount = kMaxPCIFunctionCount;
464
465 for (uint8 function = 0; function < functionCount; function++) {
466 // check for device presence by looking for a valid vendor
467 if (pci->read_pci_config(bus, device, function, PCI_vendor_id, 2)
468 == 0xffff) {
469 // not present
470 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " "
471 "not present.\n", bus, device, function);
472 continue;
473 }
474
475 if (function > 0) {
476 headerType = pci->read_pci_config(bus, device, function,
477 PCI_header_type, 1);
478 }
479
480 // if this is a bridge, recurse down
481 if ((headerType & PCI_header_type_mask)
482 == PCI_header_type_PCI_to_PCI_bridge) {
483
484 pci_address pciAddress;
485 pciAddress.segment = 0;
486 pciAddress.bus = bus;
487 pciAddress.device = device;
488 pciAddress.function = function;
489
490 parents.PushBack(pciAddress);
491
492 uint8 secondaryBus = pci->read_pci_config(bus, device, function,
493 PCI_secondary_bus, 1);
494 if (secondaryBus != 0xff) {
495 ensure_all_functions_matched(pci, secondaryBus,
496 matchedTable, unmatchedTable, parents);
497 }
498
499 parents.PopBack();
500 }
501
502 uint8 interruptPin = pci->read_pci_config(bus, device, function,
503 PCI_interrupt_pin, 1);
504 if (interruptPin == 0 || interruptPin > 4) {
505 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " "
506 "not routed.\n", bus, device, function);
507 // not routed
508 continue;
509 }
510
511 irq_routing_entry* irqEntry = find_routing_table_entry(matchedTable,
512 bus, device, interruptPin);
513 if (irqEntry != NULL) {
514 // we already have a matching entry for that device/pin, make
515 // sure the function mask includes us
516 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " "
517 "already matched. Will mask.\n", bus, device, function);
518 irqEntry->pci_function_mask |= 1 << function;
519 continue;
520 }
521
522 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " has %" B_PRIu8 " "
523 "parents, searching them...\n", bus, device, function,
524 parents.Count());
525
526 // This function has no matching routing table entry yet. Try to
527 // figure one out in the parent, based on the device number and
528 // interrupt pin.
529 bool matched = false;
530 uint8 parentPin = ((device + interruptPin - 1) % 4) + 1;
531 for (int i = parents.Count() - 1; i >= 0; i--) {
532 pci_address& parent = parents.ElementAt(i);
533 irqEntry = find_routing_table_entry(matchedTable, parent.bus,
534 parent.device, parentPin);
535 if (irqEntry == NULL) {
536 // try the unmatched table as well
537 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " "
538 "no matchedTable entry.\n", bus, device, function);
539 irqEntry = find_routing_table_entry(unmatchedTable,
540 parent.bus, parent.device, parentPin);
541 }
542
543 if (irqEntry == NULL) {
544 // no match in that parent, go further up
545 parentPin = ((parent.device + parentPin - 1) % 4) + 1;
546
547 TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " "
548 "no unmatchedTable entry, looking at parent pin %"
549 B_PRIu8 "...\n", bus, device, function, parentPin);
550 continue;
551 }
552
553 // found a match, make a copy and add it to the table
554 irq_routing_entry newEntry = *irqEntry;
555 newEntry.device_address = (device << 16) | 0xffff;
556 newEntry.pin = interruptPin - 1;
557 newEntry.pci_bus = bus;
558 newEntry.pci_device = device;
559 newEntry.pci_function_mask = 1 << function;
560
561 uint8 biosIRQ = pci->read_pci_config(bus, device, function,
562 PCI_interrupt_line, 1);
563 if (biosIRQ != 0 && biosIRQ != 255) {
564 if (newEntry.bios_irq != 0 && newEntry.bios_irq != 255
565 && newEntry.bios_irq != biosIRQ) {
566 // If the function was actually routed to that pin,
567 // the two bios irqs should match. If they don't
568 // that means we're not correct in our routing
569 // assumption.
570 panic("calculated irq routing doesn't match bios for "
571 "PCI %u:%u:%u", bus, device, function);
572 return B_ERROR;
573 }
574
575 newEntry.bios_irq = biosIRQ;
576 }
577
578 dprintf("calculated irq routing entry: ");
579 print_irq_routing_entry(newEntry);
580
581 matchedTable.PushBack(newEntry);
582 matched = true;
583 break;
584 }
585
586 if (!matched) {
587 uint32 interrupt_line = pci->read_pci_config(bus, device,
588 function, PCI_interrupt_line, 1);
589 // On x86, interrupt line 255 means "unknown" or "no connection"
590 // (PCI Local Bus spec 3.0, section 6.2.4 / page 223, footnote.)
591 if (interrupt_line == 0 || interrupt_line == 255) {
592 dprintf("assuming no interrupt use on PCI device"
593 " %u:%u:%u (bios irq 0, interrupt line %" B_PRId32 ")\n",
594 bus, device, function, interrupt_line);
595 continue;
596 }
597
598 dprintf("WARNING: unable to find irq routing for PCI "
599 "%" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 ". Device may be "
600 "unstable / broken.\n", bus, device, function);
601 return B_ERROR;
602 }
603 }
604 }
605
606 return B_OK;
607 }
608
609
610 static status_t
read_irq_routing_table_recursive(acpi_module_info * acpi,pci_module_info * pci,acpi_handle parent,acpi_handle device,uint8 currentBus,IRQRoutingTable & table,IRQRoutingTable & unmatchedTable,bool rootBridge,interrupt_available_check_function checkFunction)611 read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci,
612 acpi_handle parent, acpi_handle device, uint8 currentBus,
613 IRQRoutingTable& table, IRQRoutingTable& unmatchedTable, bool rootBridge,
614 interrupt_available_check_function checkFunction)
615 {
616 if (!rootBridge) {
617 // check if this actually is a bridge
618 uint64 value;
619 pci_address pciAddress;
620 pciAddress.bus = currentBus;
621 if (evaluate_integer(acpi, device, "_ADR", value) == B_OK) {
622 pciAddress.device = (uint8)(value >> 16);
623 pciAddress.function = (uint8)value;
624 } else {
625 pciAddress.device = 0;
626 pciAddress.function = 0;
627 }
628
629 if (pciAddress.device >= kMaxPCIDeviceCount
630 || pciAddress.function >= kMaxPCIFunctionCount) {
631 // we don't seem to be on the PCI bus anymore
632 // (just a different type of device)
633 return B_OK;
634 }
635
636 // Verify that the device is really present...
637 uint16 deviceID = pci->read_pci_config(pciAddress.bus,
638 pciAddress.device, pciAddress.function, PCI_device_id, 2);
639 if (deviceID == 0xffff) {
640 // Not present or disabled.
641 TRACE("device not present\n");
642 return B_OK;
643 }
644
645 // ... and that it really is a PCI bridge we support.
646 uint8 baseClass = pci->read_pci_config(pciAddress.bus,
647 pciAddress.device, pciAddress.function, PCI_class_base, 1);
648 uint8 subClass = pci->read_pci_config(pciAddress.bus,
649 pciAddress.device, pciAddress.function, PCI_class_sub, 1);
650 if (baseClass != PCI_bridge || subClass != PCI_pci) {
651 // Not a bridge or an unsupported one.
652 TRACE("not a PCI bridge\n");
653 return B_OK;
654 }
655
656 uint8 headerType = pci->read_pci_config(pciAddress.bus,
657 pciAddress.device, pciAddress.function, PCI_header_type, 1);
658
659 switch (headerType & PCI_header_type_mask) {
660 case PCI_header_type_PCI_to_PCI_bridge:
661 case PCI_header_type_cardbus:
662 TRACE("found a PCI bridge (0x%02x)\n", headerType);
663 break;
664
665 default:
666 // Unsupported header type.
667 TRACE("unsupported header type (0x%02x)\n", headerType);
668 return B_OK;
669 }
670
671 // Find the secondary bus number (the "downstream" bus number for the
672 // attached devices) in the bridge configuration.
673 uint8 secondaryBus = pci->read_pci_config(pciAddress.bus,
674 pciAddress.device, pciAddress.function, PCI_secondary_bus, 1);
675 if (secondaryBus == 255) {
676 // The bus below this bridge is inactive, nothing to do.
677 TRACE("secondary bus is inactive\n");
678 return B_OK;
679 }
680
681 // The secondary bus cannot be the same as the current one.
682 if (secondaryBus == currentBus) {
683 dprintf("invalid secondary bus %u on primary bus %u,"
684 " can't configure irq routing of devices below\n",
685 secondaryBus, currentBus);
686 // TODO: Maybe we want to just return B_OK anyway so that we don't
687 // fail this step. We ensure that we matched all devices at the
688 // end of preparation, so we'd detect missing child devices anyway
689 // and it would not cause us to fail for empty misconfigured busses
690 // that we don't actually care about.
691 return B_ERROR;
692 }
693
694 // Everything below is now on the secondary bus.
695 TRACE("now scanning bus %u\n", secondaryBus);
696 currentBus = secondaryBus;
697 }
698
699 acpi_data buffer;
700 buffer.pointer = NULL;
701 buffer.length = ACPI_ALLOCATE_BUFFER;
702 status_t status = acpi->get_irq_routing_table(device, &buffer);
703 if (status == B_OK) {
704 TRACE("found irq routing table\n");
705
706 acpi_pci_routing_table* acpiTable
707 = (acpi_pci_routing_table*)buffer.pointer;
708 while (acpiTable->Length) {
709 irq_routing_entry irqEntry;
710 status = handle_routing_table_entry(acpi, pci, parent, acpiTable,
711 currentBus, irqEntry);
712 if (status == B_OK) {
713 if (irqEntry.source == NULL && !checkFunction(irqEntry.irq)) {
714 dprintf("hardwired irq %u not addressable\n", irqEntry.irq);
715 free(buffer.pointer);
716 return B_ERROR;
717 }
718
719 if (irqEntry.pci_function_mask != 0)
720 table.PushBack(irqEntry);
721 else
722 unmatchedTable.PushBack(irqEntry);
723 }
724
725 acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable
726 + acpiTable->Length);
727 }
728
729 free(buffer.pointer);
730 } else {
731 TRACE("no irq routing table present\n");
732 }
733
734 // recurse down the ACPI child devices
735 acpi_data pathBuffer;
736 pathBuffer.pointer = NULL;
737 pathBuffer.length = ACPI_ALLOCATE_BUFFER;
738 status = acpi->ns_handle_to_pathname(device, &pathBuffer);
739 if (status != B_OK) {
740 dprintf("failed to resolve handle to path\n");
741 return status;
742 }
743
744 char childName[255];
745 void* counter = NULL;
746 while (acpi->get_next_entry(ACPI_TYPE_DEVICE, (char*)pathBuffer.pointer,
747 childName, sizeof(childName), &counter) == B_OK) {
748
749 acpi_handle childHandle;
750 status = acpi->get_handle(NULL, childName, &childHandle);
751 if (status != B_OK) {
752 dprintf("failed to get handle to child \"%s\"\n", childName);
753 break;
754 }
755
756 TRACE("recursing down to child \"%s\"\n", childName);
757 status = read_irq_routing_table_recursive(acpi, pci, device, childHandle,
758 currentBus, table, unmatchedTable, false, checkFunction);
759 if (status != B_OK)
760 break;
761 }
762
763 free(pathBuffer.pointer);
764 return status;
765 }
766
767
768 static status_t
read_irq_routing_table(acpi_module_info * acpi,IRQRoutingTable & table,interrupt_available_check_function checkFunction)769 read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable& table,
770 interrupt_available_check_function checkFunction)
771 {
772 char rootPciName[255];
773 acpi_handle rootPciHandle;
774 rootPciName[0] = 0;
775 status_t status = acpi->get_device(kACPIPciRootName, 0, rootPciName, 255);
776 if (status != B_OK)
777 return status;
778
779 status = acpi->get_handle(NULL, rootPciName, &rootPciHandle);
780 if (status != B_OK)
781 return status;
782
783 // We reset the root bus to 0 here. Any failed evaluation means default
784 // values, so we don't have to do anything in the error case.
785 uint8 rootBus = 0;
786
787 uint64 value;
788 if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK)
789 rootBus = (uint8)value;
790
791 #if 0
792 // TODO: handle
793 if (evaluate_integer(acpi, rootPciHandle, "_SEG", value) == B_OK)
794 rootPciAddress.segment = (uint8)value;
795 #endif
796
797 pci_module_info* pci;
798 status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
799 if (status != B_OK) {
800 // shouldn't happen, since the PCI module is a dependency of the
801 // ACPI module and we shouldn't be here at all if it wasn't loaded
802 dprintf("failed to get PCI module!\n");
803 return status;
804 }
805
806 IRQRoutingTable unmatchedTable;
807 status = read_irq_routing_table_recursive(acpi, pci, ACPI_ROOT_OBJECT,
808 rootPciHandle, rootBus, table, unmatchedTable, true, checkFunction);
809 if (status != B_OK) {
810 put_module(B_PCI_MODULE_NAME);
811 return status;
812 }
813
814 if (table.Count() == 0) {
815 put_module(B_PCI_MODULE_NAME);
816 return B_ERROR;
817 }
818
819 // Now go through all the PCI devices and verify that they have a routing
820 // table entry. For the devices without a match, we calculate their pins
821 // on the bridges and try to match these in the parent routing table. We
822 // do this recursively going up the tree until we find a match or arrive
823 // at the top.
824 Vector<pci_address> parents;
825 status = ensure_all_functions_matched(pci, rootBus, table, unmatchedTable,
826 parents);
827
828 put_module(B_PCI_MODULE_NAME);
829 return status;
830 }
831
832
833 status_t
prepare_irq_routing(acpi_module_info * acpi,IRQRoutingTable & routingTable,interrupt_available_check_function checkFunction)834 prepare_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable,
835 interrupt_available_check_function checkFunction)
836 {
837 status_t status = read_irq_routing_table(acpi, routingTable, checkFunction);
838 if (status != B_OK)
839 return status;
840
841 // resolve desired configuration of link devices
842 return choose_link_device_configurations(acpi, routingTable, checkFunction);
843 }
844
845
846 status_t
enable_irq_routing(acpi_module_info * acpi,IRQRoutingTable & routingTable)847 enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable)
848 {
849 // configure the link devices; also resolves GSIs for link based entries
850 status_t status = configure_link_devices(acpi, routingTable);
851 if (status != B_OK) {
852 panic("failed to configure link devices");
853 return status;
854 }
855
856 pci_module_info* pci;
857 status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
858 if (status != B_OK) {
859 // shouldn't happen, since the PCI module is a dependency of the
860 // ACPI module and we shouldn't be here at all if it wasn't loaded
861 dprintf("failed to get PCI module!\n");
862 return status;
863 }
864
865 // update the PCI info now that all GSIs are known
866 for (int i = 0; i < routingTable.Count(); i++) {
867 irq_routing_entry& irqEntry = routingTable.ElementAt(i);
868
869 status = update_pci_info_for_entry(pci, irqEntry);
870 if (status != B_OK) {
871 dprintf("failed to update interrupt_line for PCI %u:%u mask %"
872 B_PRIx32 "\n", irqEntry.pci_bus, irqEntry.pci_device,
873 irqEntry.pci_function_mask);
874 }
875 }
876
877 put_module(B_PCI_MODULE_NAME);
878 return B_OK;
879 }
880
881
882 static status_t
read_irq_descriptor(acpi_module_info * acpi,acpi_handle device,bool readCurrent,irq_descriptor * _descriptor,irq_descriptor_list * descriptorList)883 read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
884 bool readCurrent, irq_descriptor* _descriptor,
885 irq_descriptor_list* descriptorList)
886 {
887 acpi_data buffer;
888 buffer.pointer = NULL;
889 buffer.length = ACPI_ALLOCATE_BUFFER;
890
891 status_t status;
892 if (readCurrent)
893 status = acpi->get_current_resources(device, &buffer);
894 else
895 status = acpi->get_possible_resources(device, &buffer);
896
897 if (status != B_OK) {
898 dprintf("failed to read %s resources for irq\n",
899 readCurrent ? "current" : "possible");
900 free(buffer.pointer);
901 return status;
902 }
903
904 irq_descriptor descriptor;
905 descriptor.irq = 255;
906
907 acpi_resource* resource = (acpi_resource*)buffer.pointer;
908 while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
909 switch (resource->Type) {
910 case ACPI_RESOURCE_TYPE_IRQ:
911 {
912 acpi_resource_irq& irq = resource->Data.Irq;
913 if (irq.InterruptCount < 1) {
914 dprintf("acpi irq resource with no interrupts\n");
915 break;
916 }
917
918 descriptor.shareable = irq.Shareable != 0;
919 descriptor.trigger_mode = irq.Triggering == 0
920 ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
921 descriptor.polarity = irq.Polarity == 0
922 ? B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY;
923
924 if (readCurrent)
925 descriptor.irq = irq.Interrupts[0];
926 else {
927 for (uint16 i = 0; i < irq.InterruptCount; i++) {
928 descriptor.irq = irq.Interrupts[i];
929 descriptorList->PushBack(descriptor);
930 }
931 }
932
933 #ifdef TRACE_PRT
934 dprintf("acpi irq resource (%s):\n",
935 readCurrent ? "current" : "possible");
936 dprintf("\ttriggering: %s\n",
937 irq.Triggering == 0 ? "level" : "edge");
938 dprintf("\tpolarity: %s active\n",
939 irq.Polarity == 0 ? "high" : "low");
940 dprintf("\tshareable: %s\n", irq.Shareable != 0 ? "yes" : "no");
941 dprintf("\tcount: %u\n", irq.InterruptCount);
942 if (irq.InterruptCount > 0) {
943 dprintf("\tinterrupts:");
944 for (uint16 i = 0; i < irq.InterruptCount; i++)
945 dprintf(" %u", irq.Interrupts[i]);
946 dprintf("\n");
947 }
948 #endif
949 break;
950 }
951
952 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
953 {
954 acpi_resource_extended_irq& irq = resource->Data.ExtendedIrq;
955 if (irq.InterruptCount < 1) {
956 dprintf("acpi extended irq resource with no interrupts\n");
957 break;
958 }
959
960 descriptor.shareable = irq.Shareable != 0;
961 descriptor.trigger_mode = irq.Triggering == 0
962 ? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
963 descriptor.polarity = irq.Polarity == 0
964 ? B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY;
965
966 if (readCurrent)
967 descriptor.irq = irq.Interrupts[0];
968 else {
969 for (uint16 i = 0; i < irq.InterruptCount; i++) {
970 descriptor.irq = irq.Interrupts[i];
971 descriptorList->PushBack(descriptor);
972 }
973 }
974
975 #ifdef TRACE_PRT
976 dprintf("acpi extended irq resource (%s):\n",
977 readCurrent ? "current" : "possible");
978 dprintf("\tproducer: %s\n",
979 irq.ProducerConsumer ? "yes" : "no");
980 dprintf("\ttriggering: %s\n",
981 irq.Triggering == 0 ? "level" : "edge");
982 dprintf("\tpolarity: %s active\n",
983 irq.Polarity == 0 ? "high" : "low");
984 dprintf("\tshareable: %s\n", irq.Shareable != 0 ? "yes" : "no");
985 dprintf("\tcount: %u\n", irq.InterruptCount);
986 if (irq.InterruptCount > 0) {
987 dprintf("\tinterrupts:");
988 for (uint16 i = 0; i < irq.InterruptCount; i++)
989 dprintf(" %u", irq.Interrupts[i]);
990 dprintf("\n");
991 }
992 #endif
993 break;
994 }
995 }
996
997 if (descriptor.irq != 255)
998 break;
999
1000 resource = (acpi_resource*)((uint8*)resource + resource->Length);
1001 }
1002
1003 free(buffer.pointer);
1004
1005 if (descriptor.irq == 255)
1006 return B_ERROR;
1007
1008 if (readCurrent)
1009 *_descriptor = descriptor;
1010
1011 return B_OK;
1012 }
1013
1014
1015 status_t
read_current_irq(acpi_module_info * acpi,acpi_handle device,irq_descriptor & descriptor)1016 read_current_irq(acpi_module_info* acpi, acpi_handle device,
1017 irq_descriptor& descriptor)
1018 {
1019 return read_irq_descriptor(acpi, device, true, &descriptor, NULL);
1020 }
1021
1022
1023 status_t
read_possible_irqs(acpi_module_info * acpi,acpi_handle device,irq_descriptor_list & descriptorList)1024 read_possible_irqs(acpi_module_info* acpi, acpi_handle device,
1025 irq_descriptor_list& descriptorList)
1026 {
1027 return read_irq_descriptor(acpi, device, false, NULL, &descriptorList);
1028 }
1029
1030
1031 status_t
set_current_irq(acpi_module_info * acpi,acpi_handle device,const irq_descriptor & descriptor)1032 set_current_irq(acpi_module_info* acpi, acpi_handle device,
1033 const irq_descriptor& descriptor)
1034 {
1035 acpi_data buffer;
1036 buffer.pointer = NULL;
1037 buffer.length = ACPI_ALLOCATE_BUFFER;
1038
1039 status_t status = acpi->get_current_resources(device, &buffer);
1040 if (status != B_OK) {
1041 dprintf("failed to read current resources for irq\n");
1042 return status;
1043 }
1044
1045 bool irqWritten = false;
1046 acpi_resource* resource = (acpi_resource*)buffer.pointer;
1047 while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
1048 switch (resource->Type) {
1049 case ACPI_RESOURCE_TYPE_IRQ:
1050 {
1051 acpi_resource_irq& irq = resource->Data.Irq;
1052 if (irq.InterruptCount < 1) {
1053 dprintf("acpi irq resource with no interrupts\n");
1054 break;
1055 }
1056
1057 irq.Triggering
1058 = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1;
1059 irq.Polarity
1060 = descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1;
1061 irq.Shareable = descriptor.shareable ? 0 : 1;
1062 irq.InterruptCount = 1;
1063 irq.Interrupts[0] = descriptor.irq;
1064
1065 irqWritten = true;
1066 break;
1067 }
1068
1069 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1070 {
1071 acpi_resource_extended_irq& irq = resource->Data.ExtendedIrq;
1072 if (irq.InterruptCount < 1) {
1073 dprintf("acpi extended irq resource with no interrupts\n");
1074 break;
1075 }
1076
1077 irq.Triggering
1078 = descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1;
1079 irq.Polarity
1080 = descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1;
1081 irq.Shareable = descriptor.shareable ? 0 : 1;
1082 irq.InterruptCount = 1;
1083 irq.Interrupts[0] = descriptor.irq;
1084
1085 irqWritten = true;
1086 break;
1087 }
1088 }
1089
1090 if (irqWritten)
1091 break;
1092
1093 resource = (acpi_resource*)((uint8*)resource + resource->Length);
1094 }
1095
1096 if (irqWritten) {
1097 status = acpi->set_current_resources(device, &buffer);
1098 if (status != B_OK)
1099 dprintf("failed to set irq resources\n");
1100 } else {
1101 dprintf("failed to write requested irq into resources\n");
1102 status = B_ERROR;
1103 }
1104
1105 free(buffer.pointer);
1106 return status;
1107 }
1108