xref: /haiku/src/system/kernel/arch/generic/acpi_irq_routing_table.cpp (revision dd2a1e350b303b855a50fd64e6cb55618be1ae6a)
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 
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
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
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
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
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
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
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
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
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
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*
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
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
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
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
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
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
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
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
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
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