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 "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
27const char* kACPIPciRootName = "PNP0A03";
28const 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.
34static const uint8 kMaxPCIFunctionCount = 8;
35static const uint8 kMaxPCIDeviceCount = 32;
36	// TODO: actually this is mechanism dependent
37static const uint8 kMaxISAInterrupts = 16;
38
39irq_descriptor::irq_descriptor()
40	:
41	irq(0),
42	shareable(false),
43	polarity(B_HIGH_ACTIVE_POLARITY),
44	trigger_mode(B_EDGE_TRIGGERED)
45{
46}
47
48
49void
50print_irq_descriptor(const irq_descriptor& descriptor)
51{
52	const char* activeHighString = "active high";
53	const char* activeLowString = " active low";
54	const char* levelTriggeredString = "level triggered";
55	const char* edgeTriggeredString = "edge triggered";
56
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);
63}
64
65
66static void
67print_irq_routing_entry(const irq_routing_entry& entry)
68{
69	dprintf("address 0x%04" B_PRIx64 "; pin %u;", entry.device_address,
70		entry.pin);
71
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);
76
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);
81}
82
83
84void
85print_irq_routing_table(const IRQRoutingTable& table)
86{
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));
90}
91
92
93static status_t
94update_pci_info_for_entry(pci_module_info* pci, const irq_routing_entry& entry)
95{
96	uint32 updateCount = 0;
97	for (uint8 function = 0; function < kMaxPCIFunctionCount; function++) {
98		if ((entry.pci_function_mask & (1 << function)) == 0)
99			continue;
100
101		if (pci->update_interrupt_line(entry.pci_bus, entry.pci_device,
102			function, entry.irq) == B_OK) {
103			updateCount++;
104		}
105	}
106
107	return updateCount > 0 ? B_OK : B_ENTRY_NOT_FOUND;
108}
109
110
111static status_t
112fill_pci_info_for_entry(pci_module_info* pci, irq_routing_entry& entry)
113{
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;
122	}
123
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;
128
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;
137		}
138
139		uint8 interruptPin = pci->read_pci_config(entry.pci_bus,
140			entry.pci_device, function, PCI_interrupt_pin, 1);
141
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;
149		}
150
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);
160		}
161
162		entry.pci_function_mask |= 1 << function;
163	}
164
165	return entry.pci_function_mask != 0 ? B_OK : B_ENTRY_NOT_FOUND;
166}
167
168
169static status_t
170choose_link_device_configurations(acpi_module_info* acpi,
171	IRQRoutingTable& routingTable,
172	interrupt_available_check_function checkFunction)
173{
174	/*
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.
189	*/
190
191	uint16 validForPCI = 0; // only applies to the ISA IRQs
192	uint16 irqUsage[256];
193	memset(irqUsage, 0, sizeof(irqUsage));
194
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);
199
200		if (irqEntry.bios_irq != 0 && irqEntry.bios_irq != 255) {
201			if (irqEntry.bios_irq < kMaxISAInterrupts)
202				validForPCI |= (1 << irqEntry.bios_irq);
203		}
204
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;
211		}
212
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;
219			}
220		}
221
222		if (link != NULL) {
223			link->used_by.PushBack(&irqEntry);
224			continue;
225		}
226
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;
232		}
233
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;
240		}
241
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;
246		}
247
248		if (link->current_irq.irq < kMaxISAInterrupts)
249			validForPCI |= (1 << link->current_irq.irq);
250
251		link->used_by.PushBack(&irqEntry);
252		links.PushBack(link);
253	}
254
255	for (int i = 0; i < links.Count(); i++) {
256		link_device* link = links.ElementAt(i);
257
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;
265			}
266
267			if (possibleIRQ.irq < kMaxISAInterrupts
268				&& (validForPCI & (1 << possibleIRQ.irq)) == 0) {
269				// better avoid that if possible
270				continue;
271			}
272
273			if (irqUsage[possibleIRQ.irq] < bestIRQUsage) {
274				bestIRQIndex = j;
275				bestIRQUsage = irqUsage[possibleIRQ.irq];
276			}
277		}
278
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;
285		}
286
287		irqUsage[chosenDescriptor.irq] += link->used_by.Count();
288
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;
295		}
296
297		delete link;
298	}
299
300	return B_OK;
301}
302
303
304static status_t
305configure_link_devices(acpi_module_info* acpi, IRQRoutingTable& routingTable)
306{
307	for (int i = 0; i < routingTable.Count(); i++) {
308		irq_routing_entry& irqEntry = routingTable.ElementAt(i);
309		if (!irqEntry.needs_configuration)
310			continue;
311
312		irq_descriptor configuration;
313		configuration.irq = irqEntry.irq;
314		configuration.polarity = irqEntry.polarity;
315		configuration.trigger_mode = irqEntry.trigger_mode;
316
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);
321
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;
330				}
331			}
332		}
333
334		irqEntry.needs_configuration = false;
335	}
336
337	return B_OK;
338}
339
340
341static status_t
342evaluate_integer(acpi_module_info* acpi, acpi_handle handle,
343	const char* method, uint64& value)
344{
345	acpi_object_type result;
346	acpi_data resultBuffer;
347	resultBuffer.pointer = &result;
348	resultBuffer.length = sizeof(result);
349
350	status_t status = acpi->evaluate_method(handle, method, NULL,
351		&resultBuffer);
352	if (status != B_OK)
353		return status;
354
355	if (result.object_type != ACPI_TYPE_INTEGER)
356		return B_BAD_TYPE;
357
358	value = result.integer.integer;
359	return B_OK;
360}
361
362
363static status_t
364handle_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)
367{
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.
374
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;
382		}
383	}
384
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);
392
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
408	}
409
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;
416	}
417
418	return B_OK;
419}
420
421
422irq_routing_entry*
423find_routing_table_entry(IRQRoutingTable& table, uint8 bus, uint8 device,
424	uint8 pin)
425{
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;
430
431		if (irqEntry.pin + 1 == pin)
432			return &irqEntry;
433	}
434
435	return NULL;
436}
437
438
439static status_t
440ensure_all_functions_matched(pci_module_info* pci, uint8 bus,
441	IRQRoutingTable& matchedTable, IRQRoutingTable& unmatchedTable,
442	Vector<pci_address>& parents)
443{
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;
450		}
451
452		uint8 headerType = pci->read_pci_config(bus, device, 0,
453			PCI_header_type, 1);
454
455		uint8 functionCount = 1;
456		if ((headerType & PCI_multifunction) != 0)
457			functionCount = kMaxPCIFunctionCount;
458
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;
467			}
468
469			if (function > 0) {
470				headerType = pci->read_pci_config(bus, device, function,
471					PCI_header_type, 1);
472			}
473
474			// if this is a bridge, recurse down
475			if ((headerType & PCI_header_type_mask)
476				== PCI_header_type_PCI_to_PCI_bridge) {
477
478				pci_address pciAddress;
479				pciAddress.segment = 0;
480				pciAddress.bus = bus;
481				pciAddress.device = device;
482				pciAddress.function = function;
483
484				parents.PushBack(pciAddress);
485
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);
491				}
492
493				parents.PopBack();
494			}
495
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;
503			}
504
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;
514			}
515
516			TRACE("PCI %" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 " has %" B_PRIu8 " "
517				"parents, searching them...\n", bus, device, function,
518				parents.Count());
519
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);
535				}
536
537				if (irqEntry == NULL) {
538					// no match in that parent, go further up
539					parentPin = ((parent.device + parentPin - 1) % 4) + 1;
540
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;
545				}
546
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;
554
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;
567					}
568
569					newEntry.bios_irq = biosIRQ;
570				}
571
572				dprintf("calculated irq routing entry: ");
573				print_irq_routing_entry(newEntry);
574
575				matchedTable.PushBack(newEntry);
576				matched = true;
577				break;
578			}
579
580			if (!matched) {
581				uint32 interrupt_line = pci->read_pci_config(bus, device,
582					function, PCI_interrupt_line, 1);
583				// On x86, interrupt line 255 means "unknown" or "no connection"
584				// (PCI Local Bus spec 3.0, section 6.2.4 / page 223, footnote.)
585				if (interrupt_line == 0 || interrupt_line == 255) {
586					dprintf("assuming no interrupt use on PCI device"
587						" %u:%u:%u (bios irq 0, interrupt line %" B_PRId32 ")\n",
588						bus, device, function, interrupt_line);
589					continue;
590				}
591
592				dprintf("WARNING: unable to find irq routing for PCI "
593					"%" B_PRIu8 ":%" B_PRIu8 ":%" B_PRIu8 ". Device may be "
594					"unstable / broken.\n", bus, device, function);
595				return B_ERROR;
596			}
597		}
598	}
599
600	return B_OK;
601}
602
603
604static status_t
605read_irq_routing_table_recursive(acpi_module_info* acpi, pci_module_info* pci,
606	acpi_handle device, uint8 currentBus, IRQRoutingTable& table,
607	IRQRoutingTable& unmatchedTable, bool rootBridge,
608	interrupt_available_check_function checkFunction)
609{
610	if (!rootBridge) {
611		// check if this actually is a bridge
612		uint64 value;
613		pci_address pciAddress;
614		pciAddress.bus = currentBus;
615		if (evaluate_integer(acpi, device, "_ADR", value) == B_OK) {
616			pciAddress.device = (uint8)(value >> 16);
617			pciAddress.function = (uint8)value;
618		} else {
619			pciAddress.device = 0;
620			pciAddress.function = 0;
621		}
622
623		if (pciAddress.device >= kMaxPCIDeviceCount
624			|| pciAddress.function >= kMaxPCIFunctionCount) {
625			// we don't seem to be on the PCI bus anymore
626			// (just a different type of device)
627			return B_OK;
628		}
629
630		// Verify that the device is really present...
631		uint16 deviceID = pci->read_pci_config(pciAddress.bus,
632			pciAddress.device, pciAddress.function, PCI_device_id, 2);
633		if (deviceID == 0xffff) {
634			// Not present or disabled.
635			TRACE("device not present\n");
636			return B_OK;
637		}
638
639		// ... and that it really is a PCI bridge we support.
640		uint8 baseClass = pci->read_pci_config(pciAddress.bus,
641			pciAddress.device, pciAddress.function, PCI_class_base, 1);
642		uint8 subClass = pci->read_pci_config(pciAddress.bus,
643			pciAddress.device, pciAddress.function, PCI_class_sub, 1);
644		if (baseClass != PCI_bridge || subClass != PCI_pci) {
645			// Not a bridge or an unsupported one.
646			TRACE("not a PCI bridge\n");
647			return B_OK;
648		}
649
650		uint8 headerType = pci->read_pci_config(pciAddress.bus,
651			pciAddress.device, pciAddress.function, PCI_header_type, 1);
652
653		switch (headerType & PCI_header_type_mask) {
654			case PCI_header_type_PCI_to_PCI_bridge:
655			case PCI_header_type_cardbus:
656				TRACE("found a PCI bridge (0x%02x)\n", headerType);
657				break;
658
659			default:
660				// Unsupported header type.
661				TRACE("unsupported header type (0x%02x)\n", headerType);
662				return B_OK;
663		}
664
665		// Find the secondary bus number (the "downstream" bus number for the
666		// attached devices) in the bridge configuration.
667		uint8 secondaryBus = pci->read_pci_config(pciAddress.bus,
668			pciAddress.device, pciAddress.function, PCI_secondary_bus, 1);
669		if (secondaryBus == 255) {
670			// The bus below this bridge is inactive, nothing to do.
671			TRACE("secondary bus is inactive\n");
672			return B_OK;
673		}
674
675		// The secondary bus cannot be the same as the current one.
676		if (secondaryBus == currentBus) {
677			dprintf("invalid secondary bus %u on primary bus %u,"
678				" can't configure irq routing of devices below\n",
679				secondaryBus, currentBus);
680			// TODO: Maybe we want to just return B_OK anyway so that we don't
681			// fail this step. We ensure that we matched all devices at the
682			// end of preparation, so we'd detect missing child devices anyway
683			// and it would not cause us to fail for empty misconfigured busses
684			// that we don't actually care about.
685			return B_ERROR;
686		}
687
688		// Everything below is now on the secondary bus.
689		TRACE("now scanning bus %u\n", secondaryBus);
690		currentBus = secondaryBus;
691	}
692
693	acpi_data buffer;
694	buffer.pointer = NULL;
695	buffer.length = ACPI_ALLOCATE_BUFFER;
696	status_t status = acpi->get_irq_routing_table(device, &buffer);
697	if (status == B_OK) {
698		TRACE("found irq routing table\n");
699
700		acpi_pci_routing_table* acpiTable
701			= (acpi_pci_routing_table*)buffer.pointer;
702		while (acpiTable->Length) {
703			irq_routing_entry irqEntry;
704			status = handle_routing_table_entry(acpi, pci, acpiTable,
705				currentBus, irqEntry);
706			if (status == B_OK) {
707				if (irqEntry.source == NULL && !checkFunction(irqEntry.irq)) {
708					dprintf("hardwired irq %u not addressable\n", irqEntry.irq);
709					free(buffer.pointer);
710					return B_ERROR;
711				}
712
713				if (irqEntry.pci_function_mask != 0)
714					table.PushBack(irqEntry);
715				else
716					unmatchedTable.PushBack(irqEntry);
717			}
718
719			acpiTable = (acpi_pci_routing_table*)((uint8*)acpiTable
720				+ acpiTable->Length);
721		}
722
723		free(buffer.pointer);
724	} else {
725		TRACE("no irq routing table present\n");
726	}
727
728	// recurse down the ACPI child devices
729	acpi_data pathBuffer;
730	pathBuffer.pointer = NULL;
731	pathBuffer.length = ACPI_ALLOCATE_BUFFER;
732	status = acpi->ns_handle_to_pathname(device, &pathBuffer);
733	if (status != B_OK) {
734		dprintf("failed to resolve handle to path\n");
735		return status;
736	}
737
738	char childName[255];
739	void* counter = NULL;
740	while (acpi->get_next_entry(ACPI_TYPE_DEVICE, (char*)pathBuffer.pointer,
741		childName, sizeof(childName), &counter) == B_OK) {
742
743		acpi_handle childHandle;
744		status = acpi->get_handle(NULL, childName, &childHandle);
745		if (status != B_OK) {
746			dprintf("failed to get handle to child \"%s\"\n", childName);
747			break;
748		}
749
750		TRACE("recursing down to child \"%s\"\n", childName);
751		status = read_irq_routing_table_recursive(acpi, pci, childHandle,
752			currentBus, table, unmatchedTable, false, checkFunction);
753		if (status != B_OK)
754			break;
755	}
756
757	free(pathBuffer.pointer);
758	return status;
759}
760
761
762static status_t
763read_irq_routing_table(acpi_module_info* acpi, IRQRoutingTable& table,
764	interrupt_available_check_function checkFunction)
765{
766	char rootPciName[255];
767	acpi_handle rootPciHandle;
768	rootPciName[0] = 0;
769	status_t status = acpi->get_device(kACPIPciRootName, 0, rootPciName, 255);
770	if (status != B_OK)
771		return status;
772
773	status = acpi->get_handle(NULL, rootPciName, &rootPciHandle);
774	if (status != B_OK)
775		return status;
776
777	// We reset the root bus to 0 here. Any failed evaluation means default
778	// values, so we don't have to do anything in the error case.
779	uint8 rootBus = 0;
780
781	uint64 value;
782	if (evaluate_integer(acpi, rootPciHandle, "_BBN", value) == B_OK)
783		rootBus = (uint8)value;
784
785#if 0
786	// TODO: handle
787	if (evaluate_integer(acpi, rootPciHandle, "_SEG", value) == B_OK)
788		rootPciAddress.segment = (uint8)value;
789#endif
790
791	pci_module_info* pci;
792	status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
793	if (status != B_OK) {
794		// shouldn't happen, since the PCI module is a dependency of the
795		// ACPI module and we shouldn't be here at all if it wasn't loaded
796		dprintf("failed to get PCI module!\n");
797		return status;
798	}
799
800	IRQRoutingTable unmatchedTable;
801	status = read_irq_routing_table_recursive(acpi, pci, rootPciHandle, rootBus,
802		table, unmatchedTable, true, checkFunction);
803	if (status != B_OK) {
804		put_module(B_PCI_MODULE_NAME);
805		return status;
806	}
807
808	if (table.Count() == 0) {
809		put_module(B_PCI_MODULE_NAME);
810		return B_ERROR;
811	}
812
813	// Now go through all the PCI devices and verify that they have a routing
814	// table entry. For the devices without a match, we calculate their pins
815	// on the bridges and try to match these in the parent routing table. We
816	// do this recursively going up the tree until we find a match or arrive
817	// at the top.
818	Vector<pci_address> parents;
819	status = ensure_all_functions_matched(pci, rootBus, table, unmatchedTable,
820		parents);
821
822	put_module(B_PCI_MODULE_NAME);
823	return status;
824}
825
826
827status_t
828prepare_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable,
829	interrupt_available_check_function checkFunction)
830{
831	status_t status = read_irq_routing_table(acpi, routingTable, checkFunction);
832	if (status != B_OK)
833		return status;
834
835	// resolve desired configuration of link devices
836	return choose_link_device_configurations(acpi, routingTable, checkFunction);
837}
838
839
840status_t
841enable_irq_routing(acpi_module_info* acpi, IRQRoutingTable& routingTable)
842{
843	// configure the link devices; also resolves GSIs for link based entries
844	status_t status = configure_link_devices(acpi, routingTable);
845	if (status != B_OK) {
846		panic("failed to configure link devices");
847		return status;
848	}
849
850	pci_module_info* pci;
851	status = get_module(B_PCI_MODULE_NAME, (module_info**)&pci);
852	if (status != B_OK) {
853		// shouldn't happen, since the PCI module is a dependency of the
854		// ACPI module and we shouldn't be here at all if it wasn't loaded
855		dprintf("failed to get PCI module!\n");
856		return status;
857	}
858
859	// update the PCI info now that all GSIs are known
860	for (int i = 0; i < routingTable.Count(); i++) {
861		irq_routing_entry& irqEntry = routingTable.ElementAt(i);
862
863		status = update_pci_info_for_entry(pci, irqEntry);
864		if (status != B_OK) {
865			dprintf("failed to update interrupt_line for PCI %u:%u mask %"
866				B_PRIx32 "\n", irqEntry.pci_bus, irqEntry.pci_device,
867				irqEntry.pci_function_mask);
868		}
869	}
870
871	put_module(B_PCI_MODULE_NAME);
872	return B_OK;
873}
874
875
876static status_t
877read_irq_descriptor(acpi_module_info* acpi, acpi_handle device,
878	bool readCurrent, irq_descriptor* _descriptor,
879	irq_descriptor_list* descriptorList)
880{
881	acpi_data buffer;
882	buffer.pointer = NULL;
883	buffer.length = ACPI_ALLOCATE_BUFFER;
884
885	status_t status;
886	if (readCurrent)
887		status = acpi->get_current_resources(device, &buffer);
888	else
889		status = acpi->get_possible_resources(device, &buffer);
890
891	if (status != B_OK) {
892		dprintf("failed to read %s resources for irq\n",
893			readCurrent ? "current" : "possible");
894		free(buffer.pointer);
895		return status;
896	}
897
898	irq_descriptor descriptor;
899	descriptor.irq = 255;
900
901	acpi_resource* resource = (acpi_resource*)buffer.pointer;
902	while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
903		switch (resource->Type) {
904			case ACPI_RESOURCE_TYPE_IRQ:
905			{
906				acpi_resource_irq& irq = resource->Data.Irq;
907				if (irq.InterruptCount < 1) {
908					dprintf("acpi irq resource with no interrupts\n");
909					break;
910				}
911
912				descriptor.shareable = irq.Sharable != 0;
913				descriptor.trigger_mode = irq.Triggering == 0
914					? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
915				descriptor.polarity = irq.Polarity == 0
916					? B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY;
917
918				if (readCurrent)
919					descriptor.irq = irq.Interrupts[0];
920				else {
921					for (uint16 i = 0; i < irq.InterruptCount; i++) {
922						descriptor.irq = irq.Interrupts[i];
923						descriptorList->PushBack(descriptor);
924					}
925				}
926
927#ifdef TRACE_PRT
928				dprintf("acpi irq resource (%s):\n",
929					readCurrent ? "current" : "possible");
930				dprintf("\ttriggering: %s\n",
931					irq.Triggering == 0 ? "level" : "edge");
932				dprintf("\tpolarity: %s active\n",
933					irq.Polarity == 0 ? "high" : "low");
934				dprintf("\tsharable: %s\n", irq.Sharable != 0 ? "yes" : "no");
935				dprintf("\tcount: %u\n", irq.InterruptCount);
936				if (irq.InterruptCount > 0) {
937					dprintf("\tinterrupts:");
938					for (uint16 i = 0; i < irq.InterruptCount; i++)
939						dprintf(" %u", irq.Interrupts[i]);
940					dprintf("\n");
941				}
942#endif
943				break;
944			}
945
946			case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
947			{
948				acpi_resource_extended_irq& irq = resource->Data.ExtendedIrq;
949				if (irq.InterruptCount < 1) {
950					dprintf("acpi extended irq resource with no interrupts\n");
951					break;
952				}
953
954				descriptor.shareable = irq.Sharable != 0;
955				descriptor.trigger_mode = irq.Triggering == 0
956					? B_LEVEL_TRIGGERED : B_EDGE_TRIGGERED;
957				descriptor.polarity = irq.Polarity == 0
958					? B_HIGH_ACTIVE_POLARITY : B_LOW_ACTIVE_POLARITY;
959
960				if (readCurrent)
961					descriptor.irq = irq.Interrupts[0];
962				else {
963					for (uint16 i = 0; i < irq.InterruptCount; i++) {
964						descriptor.irq = irq.Interrupts[i];
965						descriptorList->PushBack(descriptor);
966					}
967				}
968
969#ifdef TRACE_PRT
970				dprintf("acpi extended irq resource (%s):\n",
971					readCurrent ? "current" : "possible");
972				dprintf("\tproducer: %s\n",
973					irq.ProducerConsumer ? "yes" : "no");
974				dprintf("\ttriggering: %s\n",
975					irq.Triggering == 0 ? "level" : "edge");
976				dprintf("\tpolarity: %s active\n",
977					irq.Polarity == 0 ? "high" : "low");
978				dprintf("\tsharable: %s\n", irq.Sharable != 0 ? "yes" : "no");
979				dprintf("\tcount: %u\n", irq.InterruptCount);
980				if (irq.InterruptCount > 0) {
981					dprintf("\tinterrupts:");
982					for (uint16 i = 0; i < irq.InterruptCount; i++)
983						dprintf(" %u", irq.Interrupts[i]);
984					dprintf("\n");
985				}
986#endif
987				break;
988			}
989		}
990
991		if (descriptor.irq != 255)
992			break;
993
994		resource = (acpi_resource*)((uint8*)resource + resource->Length);
995	}
996
997	free(buffer.pointer);
998
999	if (descriptor.irq == 255)
1000		return B_ERROR;
1001
1002	if (readCurrent)
1003		*_descriptor = descriptor;
1004
1005	return B_OK;
1006}
1007
1008
1009status_t
1010read_current_irq(acpi_module_info* acpi, acpi_handle device,
1011	irq_descriptor& descriptor)
1012{
1013	return read_irq_descriptor(acpi, device, true, &descriptor, NULL);
1014}
1015
1016
1017status_t
1018read_possible_irqs(acpi_module_info* acpi, acpi_handle device,
1019	irq_descriptor_list& descriptorList)
1020{
1021	return read_irq_descriptor(acpi, device, false, NULL, &descriptorList);
1022}
1023
1024
1025status_t
1026set_current_irq(acpi_module_info* acpi, acpi_handle device,
1027	const irq_descriptor& descriptor)
1028{
1029	acpi_data buffer;
1030	buffer.pointer = NULL;
1031	buffer.length = ACPI_ALLOCATE_BUFFER;
1032
1033	status_t status = acpi->get_current_resources(device, &buffer);
1034	if (status != B_OK) {
1035		dprintf("failed to read current resources for irq\n");
1036		return status;
1037	}
1038
1039	bool irqWritten = false;
1040	acpi_resource* resource = (acpi_resource*)buffer.pointer;
1041	while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
1042		switch (resource->Type) {
1043			case ACPI_RESOURCE_TYPE_IRQ:
1044			{
1045				acpi_resource_irq& irq = resource->Data.Irq;
1046				if (irq.InterruptCount < 1) {
1047					dprintf("acpi irq resource with no interrupts\n");
1048					break;
1049				}
1050
1051				irq.Triggering
1052					= descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1;
1053				irq.Polarity
1054					= descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1;
1055				irq.Sharable = descriptor.shareable ? 0 : 1;
1056				irq.InterruptCount = 1;
1057				irq.Interrupts[0] = descriptor.irq;
1058
1059				irqWritten = true;
1060				break;
1061			}
1062
1063			case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1064			{
1065				acpi_resource_extended_irq& irq = resource->Data.ExtendedIrq;
1066				if (irq.InterruptCount < 1) {
1067					dprintf("acpi extended irq resource with no interrupts\n");
1068					break;
1069				}
1070
1071				irq.Triggering
1072					= descriptor.trigger_mode == B_LEVEL_TRIGGERED ? 0 : 1;
1073				irq.Polarity
1074					= descriptor.polarity == B_HIGH_ACTIVE_POLARITY ? 0 : 1;
1075				irq.Sharable = descriptor.shareable ? 0 : 1;
1076				irq.InterruptCount = 1;
1077				irq.Interrupts[0] = descriptor.irq;
1078
1079				irqWritten = true;
1080				break;
1081			}
1082		}
1083
1084		if (irqWritten)
1085			break;
1086
1087		resource = (acpi_resource*)((uint8*)resource + resource->Length);
1088	}
1089
1090	if (irqWritten) {
1091		status = acpi->set_current_resources(device, &buffer);
1092		if (status != B_OK)
1093			dprintf("failed to set irq resources\n");
1094	} else {
1095		dprintf("failed to write requested irq into resources\n");
1096		status = B_ERROR;
1097	}
1098
1099	free(buffer.pointer);
1100	return status;
1101}
1102