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
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
37#if defined(__i386__) || defined(__x86_64__)
38static const uint8 kMaxISAInterrupts = 16;
39#else
40static const uint8 kMaxISAInterrupts = 0;
41#endif
42
43irq_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
53void
54print_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
70static void
71print_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
88void
89print_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
97static status_t
98update_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
115static status_t
116fill_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
173static status_t
174choose_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
310static status_t
311configure_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
347static status_t
348evaluate_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
369static status_t
370handle_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
428irq_routing_entry*
429find_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
445static status_t
446ensure_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
610static status_t
611read_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
768static status_t
769read_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
833status_t
834prepare_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
846status_t
847enable_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
882static status_t
883read_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
1015status_t
1016read_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
1023status_t
1024read_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
1031status_t
1032set_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