xref: /haiku/src/system/kernel/arch/x86/ioapic.cpp (revision fb5a1727f46e21307d58922debc859731156e652)
1dc14d97bSMichael Lotz /*
2dc14d97bSMichael Lotz  * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch.
3dc14d97bSMichael Lotz  * Distributed under the terms of the MIT License.
4dc14d97bSMichael Lotz  */
5dc14d97bSMichael Lotz 
6dc14d97bSMichael Lotz #include <arch/x86/ioapic.h>
7dc14d97bSMichael Lotz 
8dc14d97bSMichael Lotz #include <int.h>
9dc14d97bSMichael Lotz #include <vm/vm.h>
10dc14d97bSMichael Lotz 
11dc14d97bSMichael Lotz #include "irq_routing_table.h"
12dc14d97bSMichael Lotz 
13dc14d97bSMichael Lotz #include <ACPI.h>
14dc14d97bSMichael Lotz #include <AutoDeleter.h>
15dc14d97bSMichael Lotz #include <safemode.h>
16dc14d97bSMichael Lotz #include <string.h>
17dc14d97bSMichael Lotz #include <stdio.h>
18dc14d97bSMichael Lotz 
19dc14d97bSMichael Lotz #include <arch/x86/apic.h>
20dc14d97bSMichael Lotz #include <arch/x86/arch_int.h>
21dc14d97bSMichael Lotz #include <arch/x86/pic.h>
22dc14d97bSMichael Lotz 
23d11e32a8SMichael Lotz // to gain access to the ACPICA types
24d11e32a8SMichael Lotz #include "acpi.h"
25d11e32a8SMichael Lotz 
26dc14d97bSMichael Lotz 
27dc14d97bSMichael Lotz //#define TRACE_IOAPIC
28dc14d97bSMichael Lotz #ifdef TRACE_IOAPIC
29dc14d97bSMichael Lotz #	define TRACE(x) dprintf x
30dc14d97bSMichael Lotz #else
31dc14d97bSMichael Lotz #	define TRACE(x) ;
32dc14d97bSMichael Lotz #endif
33dc14d97bSMichael Lotz 
34dc14d97bSMichael Lotz 
35dc14d97bSMichael Lotz // ACPI interrupt models
36dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_PIC	0
37dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_APIC	1
38dc14d97bSMichael Lotz #define ACPI_INTERRUPT_MODEL_SAPIC	2
39dc14d97bSMichael Lotz 
40dc14d97bSMichael Lotz 
41dc14d97bSMichael Lotz // Definitions for a 82093AA IO APIC controller
420f91697fSMichael Lotz #define IO_APIC_ID							0x00
43dc14d97bSMichael Lotz #define IO_APIC_VERSION						0x01
44dc14d97bSMichael Lotz #define IO_APIC_ARBITRATION					0x02
45dc14d97bSMichael Lotz #define IO_APIC_REDIRECTION_TABLE			0x10 // entry = base + 2 * index
46dc14d97bSMichael Lotz 
470f91697fSMichael Lotz // Fields for the id register
480f91697fSMichael Lotz #define IO_APIC_ID_SHIFT					24
4963475256SMichael Lotz #define IO_APIC_ID_MASK						0xff
500f91697fSMichael Lotz 
51dc14d97bSMichael Lotz // Fields for the version register
52dc14d97bSMichael Lotz #define IO_APIC_VERSION_SHIFT				0
53dc14d97bSMichael Lotz #define IO_APIC_VERSION_MASK				0xff
54dc14d97bSMichael Lotz #define IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT	16
55dc14d97bSMichael Lotz #define IO_APIC_MAX_REDIRECTION_ENTRY_MASK	0xff
56dc14d97bSMichael Lotz 
57dc14d97bSMichael Lotz // Fields of each redirection table entry
58dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_FIELD_SHIFT		56
59f91cbddeSMichael Lotz #define IO_APIC_DESTINATION_FIELD_MASK		0xff
60dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_MASK_SHIFT		16
61dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_MASKED			1
62dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_UNMASKED			0
63dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_SHIFT			15
64dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_EDGE			0
65dc14d97bSMichael Lotz #define IO_APIC_TRIGGER_MODE_LEVEL			1
66dc14d97bSMichael Lotz #define IO_APIC_REMOTE_IRR_SHIFT			14
67dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_SHIFT			13
68dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_HIGH_ACTIVE	0
69dc14d97bSMichael Lotz #define IO_APIC_PIN_POLARITY_LOW_ACTIVE		1
70dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_SHIFT		12
71dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_IDLE		0
72dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_STATUS_PENDING		1
73dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_SHIFT		11
74dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_PHYSICAL	0
75dc14d97bSMichael Lotz #define IO_APIC_DESTINATION_MODE_LOGICAL	1
76dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_SHIFT			8
77dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_MASK			0x07
78dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_FIXED			0
79dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_LOWEST_PRIO	1
80dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_SMI			2
81dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_NMI			4
82dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_INIT			5
83dc14d97bSMichael Lotz #define IO_APIC_DELIVERY_MODE_EXT_INT		7
84dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_VECTOR_SHIFT		0
85dc14d97bSMichael Lotz #define IO_APIC_INTERRUPT_VECTOR_MASK		0xff
86dc14d97bSMichael Lotz 
87*fb5a1727SMichael Lotz #define ISA_INTERRUPT_COUNT					16
88*fb5a1727SMichael Lotz 
89dc14d97bSMichael Lotz 
905d01e61aSMichael Lotz struct ioapic_registers {
91dc14d97bSMichael Lotz 	volatile uint32	io_register_select;
92dc14d97bSMichael Lotz 	uint32			reserved[3];
93dc14d97bSMichael Lotz 	volatile uint32	io_window_register;
945d01e61aSMichael Lotz };
95dc14d97bSMichael Lotz 
96dc14d97bSMichael Lotz 
975d01e61aSMichael Lotz struct ioapic {
985d01e61aSMichael Lotz 	uint8				number;
9963475256SMichael Lotz 	uint8				apic_id;
10063475256SMichael Lotz 	uint32				version;
1015d01e61aSMichael Lotz 	uint8				max_redirection_entry;
1025d01e61aSMichael Lotz 	uint8				global_interrupt_base;
1035d01e61aSMichael Lotz 	uint8				global_interrupt_last;
1045d01e61aSMichael Lotz 	uint64				level_triggered_mask;
1055d01e61aSMichael Lotz 
1065d01e61aSMichael Lotz 	area_id				register_area;
1075d01e61aSMichael Lotz 	ioapic_registers*	registers;
1085d01e61aSMichael Lotz 
1095d01e61aSMichael Lotz 	ioapic*				next;
1105d01e61aSMichael Lotz };
1115d01e61aSMichael Lotz 
1125d01e61aSMichael Lotz 
1138908aef9SMichael Lotz static ioapic* sIOAPICs = NULL;
114*fb5a1727SMichael Lotz static int32 sSourceOverrides[ISA_INTERRUPT_COUNT];
115dc14d97bSMichael Lotz 
116dc14d97bSMichael Lotz 
117dc14d97bSMichael Lotz // #pragma mark - I/O APIC
118dc14d97bSMichael Lotz 
119dc14d97bSMichael Lotz 
12063475256SMichael Lotz static void
12163475256SMichael Lotz print_ioapic(struct ioapic& ioapic)
12263475256SMichael Lotz {
12363475256SMichael Lotz 	dprintf("io-apic %u has range %u-%u, %u entries, version 0x%08lx, "
12463475256SMichael Lotz 		"apic-id %u\n", ioapic.number, ioapic.global_interrupt_base,
12563475256SMichael Lotz 		ioapic.global_interrupt_last, ioapic.max_redirection_entry + 1,
12663475256SMichael Lotz 		ioapic.version, ioapic.apic_id);
12763475256SMichael Lotz }
12863475256SMichael Lotz 
12963475256SMichael Lotz 
1305d01e61aSMichael Lotz static inline struct ioapic*
1315d01e61aSMichael Lotz find_ioapic(int32 gsi)
132dc14d97bSMichael Lotz {
1335d01e61aSMichael Lotz 	if (gsi < 0)
1345d01e61aSMichael Lotz 		return NULL;
1355d01e61aSMichael Lotz 
1368908aef9SMichael Lotz 	struct ioapic* current = sIOAPICs;
1375d01e61aSMichael Lotz 	while (current != NULL) {
1385d01e61aSMichael Lotz 		if (gsi >= current->global_interrupt_base
1395d01e61aSMichael Lotz 			&& gsi <= current->global_interrupt_last) {
1405d01e61aSMichael Lotz 			return current;
1415d01e61aSMichael Lotz 		}
1425d01e61aSMichael Lotz 
1435d01e61aSMichael Lotz 		current = current->next;
1445d01e61aSMichael Lotz 	}
1455d01e61aSMichael Lotz 
1465d01e61aSMichael Lotz 	return NULL;
1475d01e61aSMichael Lotz }
1485d01e61aSMichael Lotz 
1495d01e61aSMichael Lotz 
1505d01e61aSMichael Lotz static inline uint32
1515d01e61aSMichael Lotz ioapic_read_32(struct ioapic& ioapic, uint8 registerSelect)
1525d01e61aSMichael Lotz {
1535d01e61aSMichael Lotz 	ioapic.registers->io_register_select = registerSelect;
1545d01e61aSMichael Lotz 	return ioapic.registers->io_window_register;
155dc14d97bSMichael Lotz }
156dc14d97bSMichael Lotz 
157dc14d97bSMichael Lotz 
158dc14d97bSMichael Lotz static inline void
1595d01e61aSMichael Lotz ioapic_write_32(struct ioapic& ioapic, uint8 registerSelect, uint32 value)
160dc14d97bSMichael Lotz {
1615d01e61aSMichael Lotz 	ioapic.registers->io_register_select = registerSelect;
1625d01e61aSMichael Lotz 	ioapic.registers->io_window_register = value;
163dc14d97bSMichael Lotz }
164dc14d97bSMichael Lotz 
165dc14d97bSMichael Lotz 
166dc14d97bSMichael Lotz static inline uint64
1675d01e61aSMichael Lotz ioapic_read_64(struct ioapic& ioapic, uint8 registerSelect)
168dc14d97bSMichael Lotz {
1695d01e61aSMichael Lotz 	ioapic.registers->io_register_select = registerSelect + 1;
1705d01e61aSMichael Lotz 	uint64 result = ioapic.registers->io_window_register;
171dc14d97bSMichael Lotz 	result <<= 32;
1725d01e61aSMichael Lotz 	ioapic.registers->io_register_select = registerSelect;
1735d01e61aSMichael Lotz 	result |= ioapic.registers->io_window_register;
174dc14d97bSMichael Lotz 	return result;
175dc14d97bSMichael Lotz }
176dc14d97bSMichael Lotz 
177dc14d97bSMichael Lotz 
178dc14d97bSMichael Lotz static inline void
1790798779aSMichael Lotz ioapic_write_64(struct ioapic& ioapic, uint8 registerSelect, uint64 value,
1800798779aSMichael Lotz 	bool maskFirst)
181dc14d97bSMichael Lotz {
1820798779aSMichael Lotz 	ioapic.registers->io_register_select
1830798779aSMichael Lotz 		= registerSelect + (maskFirst ? 0 : 1);
1840798779aSMichael Lotz 	ioapic.registers->io_window_register
1850798779aSMichael Lotz 		= (uint32)(value >> (maskFirst ? 0 : 32));
1860798779aSMichael Lotz 	ioapic.registers->io_register_select
1870798779aSMichael Lotz 		= registerSelect + (maskFirst ? 1 : 0);
1880798779aSMichael Lotz 	ioapic.registers->io_window_register
1890798779aSMichael Lotz 		= (uint32)(value >> (maskFirst ? 32 : 0));
190dc14d97bSMichael Lotz }
191dc14d97bSMichael Lotz 
192dc14d97bSMichael Lotz 
193dc14d97bSMichael Lotz static bool
194eda74390SMichael Lotz ioapic_is_spurious_interrupt(int32 gsi)
195dc14d97bSMichael Lotz {
196dc14d97bSMichael Lotz 	// the spurious interrupt vector is initialized to the max value in smp
197eda74390SMichael Lotz 	return gsi == 0xff - ARCH_INTERRUPT_BASE;
198dc14d97bSMichael Lotz }
199dc14d97bSMichael Lotz 
200dc14d97bSMichael Lotz 
201dc14d97bSMichael Lotz static bool
2025d01e61aSMichael Lotz ioapic_is_level_triggered_interrupt(int32 gsi)
203dc14d97bSMichael Lotz {
2045d01e61aSMichael Lotz 	struct ioapic* ioapic = find_ioapic(gsi);
2055d01e61aSMichael Lotz 	if (ioapic == NULL)
206dc14d97bSMichael Lotz 		return false;
207dc14d97bSMichael Lotz 
2085d01e61aSMichael Lotz 	uint8 pin = gsi - ioapic->global_interrupt_base;
209f91cbddeSMichael Lotz 	return (ioapic->level_triggered_mask & ((uint64)1 << pin)) != 0;
210dc14d97bSMichael Lotz }
211dc14d97bSMichael Lotz 
212dc14d97bSMichael Lotz 
213dc14d97bSMichael Lotz static bool
214dc14d97bSMichael Lotz ioapic_end_of_interrupt(int32 num)
215dc14d97bSMichael Lotz {
216dc14d97bSMichael Lotz 	apic_end_of_interrupt();
217dc14d97bSMichael Lotz 	return true;
218dc14d97bSMichael Lotz }
219dc14d97bSMichael Lotz 
220dc14d97bSMichael Lotz 
221dc14d97bSMichael Lotz static void
2225d01e61aSMichael Lotz ioapic_enable_io_interrupt(int32 gsi)
223dc14d97bSMichael Lotz {
224*fb5a1727SMichael Lotz 	// If enabling an overriden source is attempted, enable the override entry
225*fb5a1727SMichael Lotz 	// instead. An interrupt handler was installed at the override GSI to rely
226*fb5a1727SMichael Lotz 	// interrupts to the overriden source.
227*fb5a1727SMichael Lotz 	if (gsi < ISA_INTERRUPT_COUNT && sSourceOverrides[gsi] != 0)
228*fb5a1727SMichael Lotz 		gsi = sSourceOverrides[gsi];
229*fb5a1727SMichael Lotz 
2305d01e61aSMichael Lotz 	struct ioapic* ioapic = find_ioapic(gsi);
2315d01e61aSMichael Lotz 	if (ioapic == NULL)
232dc14d97bSMichael Lotz 		return;
233dc14d97bSMichael Lotz 
2345d01e61aSMichael Lotz 	uint8 pin = gsi - ioapic->global_interrupt_base;
2355d01e61aSMichael Lotz 	TRACE(("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
2365d01e61aSMichael Lotz 		gsi, ioapic->number, pin));
237dc14d97bSMichael Lotz 
2385d01e61aSMichael Lotz 	uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2);
239dc14d97bSMichael Lotz 	entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
240dc14d97bSMichael Lotz 	entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
2410798779aSMichael Lotz 	ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, false);
242dc14d97bSMichael Lotz }
243dc14d97bSMichael Lotz 
244dc14d97bSMichael Lotz 
245dc14d97bSMichael Lotz static void
2465d01e61aSMichael Lotz ioapic_disable_io_interrupt(int32 gsi)
247dc14d97bSMichael Lotz {
2485d01e61aSMichael Lotz 	struct ioapic* ioapic = find_ioapic(gsi);
2495d01e61aSMichael Lotz 	if (ioapic == NULL)
250dc14d97bSMichael Lotz 		return;
251dc14d97bSMichael Lotz 
2525d01e61aSMichael Lotz 	uint8 pin = gsi - ioapic->global_interrupt_base;
2535d01e61aSMichael Lotz 	TRACE(("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
2545d01e61aSMichael Lotz 		gsi, ioapic->number, pin));
255dc14d97bSMichael Lotz 
2565d01e61aSMichael Lotz 	uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2);
257dc14d97bSMichael Lotz 	entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
258dc14d97bSMichael Lotz 	entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
2590798779aSMichael Lotz 	ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, true);
260dc14d97bSMichael Lotz }
261dc14d97bSMichael Lotz 
262dc14d97bSMichael Lotz 
263dc14d97bSMichael Lotz static void
2645d01e61aSMichael Lotz ioapic_configure_io_interrupt(int32 gsi, uint32 config)
265dc14d97bSMichael Lotz {
2665d01e61aSMichael Lotz 	struct ioapic* ioapic = find_ioapic(gsi);
2675d01e61aSMichael Lotz 	if (ioapic == NULL)
268dc14d97bSMichael Lotz 		return;
269dc14d97bSMichael Lotz 
2705d01e61aSMichael Lotz 	uint8 pin = gsi - ioapic->global_interrupt_base;
2715d01e61aSMichael Lotz 	TRACE(("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; "
2725d01e61aSMichael Lotz 		"config 0x%08lx\n", gsi, ioapic->number, pin, config));
273dc14d97bSMichael Lotz 
2745d01e61aSMichael Lotz 	uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2);
275dc14d97bSMichael Lotz 	entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT)
276dc14d97bSMichael Lotz 		| (1 << IO_APIC_PIN_POLARITY_SHIFT)
277dc14d97bSMichael Lotz 		| (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT));
278dc14d97bSMichael Lotz 
279dc14d97bSMichael Lotz 	if (config & B_LEVEL_TRIGGERED) {
280dc14d97bSMichael Lotz 		entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT);
281f91cbddeSMichael Lotz 		ioapic->level_triggered_mask |= ((uint64)1 << pin);
282dc14d97bSMichael Lotz 	} else {
283dc14d97bSMichael Lotz 		entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT);
284f91cbddeSMichael Lotz 		ioapic->level_triggered_mask &= ~((uint64)1 << pin);
285dc14d97bSMichael Lotz 	}
286dc14d97bSMichael Lotz 
287dc14d97bSMichael Lotz 	if (config & B_LOW_ACTIVE_POLARITY)
288dc14d97bSMichael Lotz 		entry |= (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT);
289dc14d97bSMichael Lotz 	else
290dc14d97bSMichael Lotz 		entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT);
291dc14d97bSMichael Lotz 
292ca00b28eSMichael Lotz 	entry |= (gsi + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT;
2930798779aSMichael Lotz 	ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry, true);
2945d01e61aSMichael Lotz }
2955d01e61aSMichael Lotz 
2965d01e61aSMichael Lotz 
2975d01e61aSMichael Lotz static status_t
2985d01e61aSMichael Lotz ioapic_map_ioapic(struct ioapic& ioapic, phys_addr_t physicalAddress)
2995d01e61aSMichael Lotz {
3005d01e61aSMichael Lotz 	ioapic.register_area = vm_map_physical_memory(B_SYSTEM_TEAM, "io-apic",
3015d01e61aSMichael Lotz 		(void**)&ioapic.registers, ioapic.registers != NULL ? B_EXACT_ADDRESS
3025d01e61aSMichael Lotz 		: B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA
303d11e32a8SMichael Lotz 		| B_KERNEL_WRITE_AREA, physicalAddress, ioapic.registers != NULL);
3045d01e61aSMichael Lotz 	if (ioapic.register_area < 0) {
3055d01e61aSMichael Lotz 		panic("mapping io-apic %u failed", ioapic.number);
3065d01e61aSMichael Lotz 		return ioapic.register_area;
3075d01e61aSMichael Lotz 	}
3085d01e61aSMichael Lotz 
309d11e32a8SMichael Lotz 	dprintf("mapped io-apic %u to %p\n", ioapic.number, ioapic.registers);
310d11e32a8SMichael Lotz 
31163475256SMichael Lotz 	ioapic.version = ioapic_read_32(ioapic, IO_APIC_VERSION);
31263475256SMichael Lotz 	if (ioapic.version == 0xffffffff) {
3135d01e61aSMichael Lotz 		dprintf("io-apic %u seems inaccessible, not using it\n",
3145d01e61aSMichael Lotz 			ioapic.number);
3155d01e61aSMichael Lotz 		vm_delete_area(B_SYSTEM_TEAM, ioapic.register_area, true);
3165d01e61aSMichael Lotz 		ioapic.register_area = -1;
3175d01e61aSMichael Lotz 		ioapic.registers = NULL;
3185d01e61aSMichael Lotz 		return B_ERROR;
3195d01e61aSMichael Lotz 	}
3205d01e61aSMichael Lotz 
3215d01e61aSMichael Lotz 	ioapic.max_redirection_entry
32263475256SMichael Lotz 		= ((ioapic.version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT)
3235d01e61aSMichael Lotz 			& IO_APIC_MAX_REDIRECTION_ENTRY_MASK);
3245d01e61aSMichael Lotz 
3255d01e61aSMichael Lotz 	ioapic.global_interrupt_last
3265d01e61aSMichael Lotz 		= ioapic.global_interrupt_base + ioapic.max_redirection_entry;
3275d01e61aSMichael Lotz 
3285d01e61aSMichael Lotz 	return B_OK;
3295d01e61aSMichael Lotz }
3305d01e61aSMichael Lotz 
3315d01e61aSMichael Lotz 
3325d01e61aSMichael Lotz static status_t
33363475256SMichael Lotz ioapic_initialize_ioapic(struct ioapic& ioapic, uint8 targetAPIC)
3345d01e61aSMichael Lotz {
33563475256SMichael Lotz 	// program the APIC ID
33663475256SMichael Lotz 	ioapic_write_32(ioapic, IO_APIC_ID, ioapic.apic_id << IO_APIC_ID_SHIFT);
33763475256SMichael Lotz 
3385d01e61aSMichael Lotz 	// program the interrupt vectors of the io-apic
3395d01e61aSMichael Lotz 	ioapic.level_triggered_mask = 0;
340e9d55697SMichael Lotz 	uint8 gsi = ioapic.global_interrupt_base;
341e9d55697SMichael Lotz 	for (uint8 i = 0; i <= ioapic.max_redirection_entry; i++, gsi++) {
3425d01e61aSMichael Lotz 		// initialize everything to deliver to the boot CPU in physical mode
3435d01e61aSMichael Lotz 		// and masked until explicitly enabled through enable_io_interrupt()
34463475256SMichael Lotz 		uint64 entry = ((uint64)targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT)
3455d01e61aSMichael Lotz 			| (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT)
3465d01e61aSMichael Lotz 			| (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT)
3477a8ce431SMichael Lotz 			| ((gsi + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT);
3485d01e61aSMichael Lotz 
349e9d55697SMichael Lotz 		if (gsi == 0) {
350e9d55697SMichael Lotz 			// make GSI 0 into an external interrupt
3515d01e61aSMichael Lotz 			entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
3525d01e61aSMichael Lotz 				| (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
3535d01e61aSMichael Lotz 				| (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT);
354*fb5a1727SMichael Lotz 		} else if (gsi < ISA_INTERRUPT_COUNT) {
355*fb5a1727SMichael Lotz 			// identity map the legacy ISA interrupts
3565d01e61aSMichael Lotz 			entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
3575d01e61aSMichael Lotz 				| (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
3585d01e61aSMichael Lotz 				| (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
3595d01e61aSMichael Lotz 		} else {
3605d01e61aSMichael Lotz 			// and the rest are PCI interrupts
3615d01e61aSMichael Lotz 			entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT)
3625d01e61aSMichael Lotz 				| (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
3635d01e61aSMichael Lotz 				| (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
364f91cbddeSMichael Lotz 			ioapic.level_triggered_mask |= ((uint64)1 << i);
3655d01e61aSMichael Lotz 		}
3665d01e61aSMichael Lotz 
3670798779aSMichael Lotz 		ioapic_write_64(ioapic, IO_APIC_REDIRECTION_TABLE + 2 * i, entry, true);
3685d01e61aSMichael Lotz 	}
3695d01e61aSMichael Lotz 
3705d01e61aSMichael Lotz 	return B_OK;
371dc14d97bSMichael Lotz }
372dc14d97bSMichael Lotz 
373dc14d97bSMichael Lotz 
374*fb5a1727SMichael Lotz static int32
375*fb5a1727SMichael Lotz ioapic_source_override_handler(void* data)
376d11e32a8SMichael Lotz {
377*fb5a1727SMichael Lotz 	int32 vector = (int32)data;
378*fb5a1727SMichael Lotz 	bool levelTriggered = ioapic_is_level_triggered_interrupt(vector);
379*fb5a1727SMichael Lotz 	return int_io_interrupt_handler(vector, levelTriggered);
380d11e32a8SMichael Lotz }
381d11e32a8SMichael Lotz 
382*fb5a1727SMichael Lotz 
383*fb5a1727SMichael Lotz static status_t
384*fb5a1727SMichael Lotz acpi_enumerate_ioapics(acpi_table_madt* madt)
385*fb5a1727SMichael Lotz {
3868908aef9SMichael Lotz 	struct ioapic* lastIOAPIC = sIOAPICs;
387d11e32a8SMichael Lotz 
388d11e32a8SMichael Lotz 	acpi_subtable_header* apicEntry
389d11e32a8SMichael Lotz 		= (acpi_subtable_header*)((uint8*)madt + sizeof(acpi_table_madt));
390d11e32a8SMichael Lotz 	void* end = ((uint8*)madt + madt->Header.Length);
391d11e32a8SMichael Lotz 	while (apicEntry < end) {
392d11e32a8SMichael Lotz 		switch (apicEntry->Type) {
393d11e32a8SMichael Lotz 			case ACPI_MADT_TYPE_IO_APIC:
394d11e32a8SMichael Lotz 			{
395d11e32a8SMichael Lotz 				acpi_madt_io_apic* info = (acpi_madt_io_apic*)apicEntry;
39663475256SMichael Lotz 				dprintf("found io-apic with address 0x%08lx, global "
39763475256SMichael Lotz 					"interrupt base %lu, apic-id %u\n", (uint32)info->Address,
39863475256SMichael Lotz 					(uint32)info->GlobalIrqBase, info->Id);
399d11e32a8SMichael Lotz 
400d11e32a8SMichael Lotz 				struct ioapic* ioapic
401d11e32a8SMichael Lotz 					= (struct ioapic*)malloc(sizeof(struct ioapic));
402d11e32a8SMichael Lotz 				if (ioapic == NULL) {
403d11e32a8SMichael Lotz 					dprintf("ran out of memory while allocating io-apic "
404d11e32a8SMichael Lotz 						"structure\n");
405d11e32a8SMichael Lotz 					return B_NO_MEMORY;
406d11e32a8SMichael Lotz 				}
407d11e32a8SMichael Lotz 
4088908aef9SMichael Lotz 				ioapic->number
4098908aef9SMichael Lotz 					= lastIOAPIC != NULL ? lastIOAPIC->number + 1 : 0;
41063475256SMichael Lotz 				ioapic->apic_id = info->Id;
411d11e32a8SMichael Lotz 				ioapic->global_interrupt_base = info->GlobalIrqBase;
412d11e32a8SMichael Lotz 				ioapic->registers = NULL;
413d11e32a8SMichael Lotz 				ioapic->next = NULL;
414d11e32a8SMichael Lotz 
415d11e32a8SMichael Lotz 				dprintf("mapping io-apic %u at physical address %p\n",
416d11e32a8SMichael Lotz 					ioapic->number, (void*)info->Address);
417d11e32a8SMichael Lotz 				status_t status = ioapic_map_ioapic(*ioapic, info->Address);
41863475256SMichael Lotz 				if (status != B_OK) {
41963475256SMichael Lotz 					free(ioapic);
42063475256SMichael Lotz 					break;
42163475256SMichael Lotz 				}
42263475256SMichael Lotz 
42363475256SMichael Lotz 				print_ioapic(*ioapic);
4248908aef9SMichael Lotz 
4258908aef9SMichael Lotz 				if (lastIOAPIC == NULL)
4268908aef9SMichael Lotz 					sIOAPICs = ioapic;
4278908aef9SMichael Lotz 				else
428d11e32a8SMichael Lotz 					lastIOAPIC->next = ioapic;
4298908aef9SMichael Lotz 
430d11e32a8SMichael Lotz 				lastIOAPIC = ioapic;
431d11e32a8SMichael Lotz 				break;
432d11e32a8SMichael Lotz 			}
433*fb5a1727SMichael Lotz 		}
434*fb5a1727SMichael Lotz 
435*fb5a1727SMichael Lotz 		apicEntry
436*fb5a1727SMichael Lotz 			= (acpi_subtable_header*)((uint8*)apicEntry + apicEntry->Length);
437*fb5a1727SMichael Lotz 	}
438*fb5a1727SMichael Lotz 
439*fb5a1727SMichael Lotz 	return B_OK;
440*fb5a1727SMichael Lotz }
441*fb5a1727SMichael Lotz 
442*fb5a1727SMichael Lotz 
443*fb5a1727SMichael Lotz static void
444*fb5a1727SMichael Lotz acpi_configure_source_overrides(acpi_table_madt* madt)
445*fb5a1727SMichael Lotz {
446*fb5a1727SMichael Lotz 	acpi_subtable_header* apicEntry
447*fb5a1727SMichael Lotz 		= (acpi_subtable_header*)((uint8*)madt + sizeof(acpi_table_madt));
448*fb5a1727SMichael Lotz 	void* end = ((uint8*)madt + madt->Header.Length);
449*fb5a1727SMichael Lotz 	while (apicEntry < end) {
450*fb5a1727SMichael Lotz 		switch (apicEntry->Type) {
451*fb5a1727SMichael Lotz 			case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
452*fb5a1727SMichael Lotz 			{
453*fb5a1727SMichael Lotz 				acpi_madt_interrupt_override* info
454*fb5a1727SMichael Lotz 					= (acpi_madt_interrupt_override*)apicEntry;
455*fb5a1727SMichael Lotz 				dprintf("found interrupt override for bus %u, source irq %u, "
456*fb5a1727SMichael Lotz 					"global irq %lu, flags 0x%08lx\n", info->Bus,
457*fb5a1727SMichael Lotz 					info->SourceIrq, (uint32)info->GlobalIrq,
458*fb5a1727SMichael Lotz 					(uint32)info->IntiFlags);
459*fb5a1727SMichael Lotz 
460*fb5a1727SMichael Lotz 				if (info->SourceIrq >= ISA_INTERRUPT_COUNT) {
461*fb5a1727SMichael Lotz 					dprintf("source override exceeds isa interrupt count\n");
462*fb5a1727SMichael Lotz 					break;
463*fb5a1727SMichael Lotz 				}
464*fb5a1727SMichael Lotz 
465*fb5a1727SMichael Lotz 				if (info->SourceIrq != info->GlobalIrq) {
466*fb5a1727SMichael Lotz 					// we need a vector mapping
467*fb5a1727SMichael Lotz 					install_io_interrupt_handler(info->GlobalIrq,
468*fb5a1727SMichael Lotz 						&ioapic_source_override_handler, (void*)info->SourceIrq,
469*fb5a1727SMichael Lotz 						B_NO_ENABLE_COUNTER);
470*fb5a1727SMichael Lotz 
471*fb5a1727SMichael Lotz 					sSourceOverrides[info->SourceIrq] = info->GlobalIrq;
472*fb5a1727SMichael Lotz 				}
473*fb5a1727SMichael Lotz 
474*fb5a1727SMichael Lotz 				// configure non-standard polarity/trigger modes
475*fb5a1727SMichael Lotz 				uint32 config = 0;
476*fb5a1727SMichael Lotz 				switch (info->IntiFlags & ACPI_MADT_POLARITY_MASK) {
477*fb5a1727SMichael Lotz 					case ACPI_MADT_POLARITY_ACTIVE_LOW:
478*fb5a1727SMichael Lotz 						config = B_LOW_ACTIVE_POLARITY;
479*fb5a1727SMichael Lotz 						break;
480*fb5a1727SMichael Lotz 					default:
481*fb5a1727SMichael Lotz 						dprintf("invalid polarity in source override\n");
482*fb5a1727SMichael Lotz 						// fall through and assume active high
483*fb5a1727SMichael Lotz 					case ACPI_MADT_POLARITY_ACTIVE_HIGH:
484*fb5a1727SMichael Lotz 					case ACPI_MADT_POLARITY_CONFORMS:
485*fb5a1727SMichael Lotz 						config = B_HIGH_ACTIVE_POLARITY;
486*fb5a1727SMichael Lotz 						break;
487*fb5a1727SMichael Lotz 				}
488*fb5a1727SMichael Lotz 
489*fb5a1727SMichael Lotz 				switch (info->IntiFlags & ACPI_MADT_TRIGGER_MASK) {
490*fb5a1727SMichael Lotz 					case ACPI_MADT_TRIGGER_LEVEL:
491*fb5a1727SMichael Lotz 						config |= B_LEVEL_TRIGGERED;
492*fb5a1727SMichael Lotz 						break;
493*fb5a1727SMichael Lotz 					default:
494*fb5a1727SMichael Lotz 						dprintf("invalid trigger mode in source override\n");
495*fb5a1727SMichael Lotz 						// fall through and assume edge triggered
496*fb5a1727SMichael Lotz 					case ACPI_MADT_TRIGGER_CONFORMS:
497*fb5a1727SMichael Lotz 					case ACPI_MADT_TRIGGER_EDGE:
498*fb5a1727SMichael Lotz 						config |= B_EDGE_TRIGGERED;
499*fb5a1727SMichael Lotz 						break;
500*fb5a1727SMichael Lotz 				}
501*fb5a1727SMichael Lotz 
502*fb5a1727SMichael Lotz 				ioapic_configure_io_interrupt(info->GlobalIrq, config);
503*fb5a1727SMichael Lotz 				break;
504*fb5a1727SMichael Lotz 			}
5050414a203SMichael Lotz 
5060414a203SMichael Lotz #ifdef TRACE_IOAPIC
5070414a203SMichael Lotz 			case ACPI_MADT_TYPE_LOCAL_APIC:
5080414a203SMichael Lotz 			{
5090414a203SMichael Lotz 				// purely informational
5100414a203SMichael Lotz 				acpi_madt_local_apic* info = (acpi_madt_local_apic*)apicEntry;
5110414a203SMichael Lotz 				dprintf("found local apic with id %u, processor id %u, "
5120414a203SMichael Lotz 					"flags 0x%08lx\n", info->Id, info->ProcessorId,
5130414a203SMichael Lotz 					(uint32)info->LapicFlags);
5140414a203SMichael Lotz 				break;
5150414a203SMichael Lotz 			}
5160414a203SMichael Lotz 
5170414a203SMichael Lotz 			case ACPI_MADT_TYPE_NMI_SOURCE:
5180414a203SMichael Lotz 			{
5190414a203SMichael Lotz 				// TODO: take these into account
5200414a203SMichael Lotz 				acpi_madt_nmi_source* info
5210414a203SMichael Lotz 					= (acpi_madt_nmi_source*)apicEntry;
5220414a203SMichael Lotz 				dprintf("found nmi source global irq %lu, flags 0x%04x\n",
5230414a203SMichael Lotz 					(uint32)info->GlobalIrq, (uint16)info->IntiFlags);
5240414a203SMichael Lotz 				break;
5250414a203SMichael Lotz 			}
5260414a203SMichael Lotz 
5270414a203SMichael Lotz 			case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
5280414a203SMichael Lotz 			{
5290414a203SMichael Lotz 				// TODO: take these into account, but at apic.cpp
5300414a203SMichael Lotz 				acpi_madt_local_apic_nmi* info
5310414a203SMichael Lotz 					= (acpi_madt_local_apic_nmi*)apicEntry;
5320414a203SMichael Lotz 				dprintf("found local apic nmi source for processor %u, "
5330414a203SMichael Lotz 					"flags 0x%04x, local int %u\n", info->ProcessorId,
5340414a203SMichael Lotz 					(uint16)info->IntiFlags, info->Lint);
5350414a203SMichael Lotz 				break;
5360414a203SMichael Lotz 			}
5370414a203SMichael Lotz 
5380414a203SMichael Lotz 			case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
5390414a203SMichael Lotz 			{
5400414a203SMichael Lotz 				// TODO: take these into account, but at apic.cpp
5410414a203SMichael Lotz 				acpi_madt_local_apic_override* info
5420414a203SMichael Lotz 					= (acpi_madt_local_apic_override*)apicEntry;
5430414a203SMichael Lotz 				dprintf("found local apic override with address 0x%016llx\n",
5440414a203SMichael Lotz 					(uint64)info->Address);
5450414a203SMichael Lotz 				break;
5460414a203SMichael Lotz 			}
5470414a203SMichael Lotz 
5480414a203SMichael Lotz 			default:
5490414a203SMichael Lotz 				dprintf("found unhandled subtable of type %u length %u\n",
5500414a203SMichael Lotz 					apicEntry->Type, apicEntry->Length);
5510414a203SMichael Lotz 				break;
5520414a203SMichael Lotz #endif
553d11e32a8SMichael Lotz 		}
554d11e32a8SMichael Lotz 
555d11e32a8SMichael Lotz 		apicEntry
556d11e32a8SMichael Lotz 			= (acpi_subtable_header*)((uint8*)apicEntry + apicEntry->Length);
557d11e32a8SMichael Lotz 	}
558d11e32a8SMichael Lotz }
559d11e32a8SMichael Lotz 
560d11e32a8SMichael Lotz 
561d11e32a8SMichael Lotz static status_t
562dc14d97bSMichael Lotz acpi_set_interrupt_model(acpi_module_info* acpiModule, uint32 interruptModel)
563dc14d97bSMichael Lotz {
564dc14d97bSMichael Lotz 	acpi_object_type model;
565dc14d97bSMichael Lotz 	model.object_type = ACPI_TYPE_INTEGER;
566dc14d97bSMichael Lotz 	model.data.integer = interruptModel;
567dc14d97bSMichael Lotz 
568dc14d97bSMichael Lotz 	acpi_objects parameter;
569dc14d97bSMichael Lotz 	parameter.count = 1;
570dc14d97bSMichael Lotz 	parameter.pointer = &model;
571dc14d97bSMichael Lotz 
572dc14d97bSMichael Lotz 	dprintf("setting ACPI interrupt model to %s\n",
573dc14d97bSMichael Lotz 		interruptModel == 0 ? "PIC"
574dc14d97bSMichael Lotz 		: (interruptModel == 1 ? "APIC"
575dc14d97bSMichael Lotz 		: (interruptModel == 2 ? "SAPIC"
576dc14d97bSMichael Lotz 		: "unknown")));
577dc14d97bSMichael Lotz 
578dc14d97bSMichael Lotz 	return acpiModule->evaluate_method(NULL, "\\_PIC", &parameter, NULL);
579dc14d97bSMichael Lotz }
580dc14d97bSMichael Lotz 
581dc14d97bSMichael Lotz 
582a56cbb2aSMichael Lotz bool
583a56cbb2aSMichael Lotz ioapic_is_interrupt_available(int32 gsi)
584a56cbb2aSMichael Lotz {
585a56cbb2aSMichael Lotz 	return find_ioapic(gsi) != NULL;
586a56cbb2aSMichael Lotz }
587a56cbb2aSMichael Lotz 
588a56cbb2aSMichael Lotz 
589dc14d97bSMichael Lotz void
590dc14d97bSMichael Lotz ioapic_init(kernel_args* args)
591dc14d97bSMichael Lotz {
592dc14d97bSMichael Lotz 	static const interrupt_controller ioapicController = {
593dc14d97bSMichael Lotz 		"82093AA IOAPIC",
594dc14d97bSMichael Lotz 		&ioapic_enable_io_interrupt,
595dc14d97bSMichael Lotz 		&ioapic_disable_io_interrupt,
596dc14d97bSMichael Lotz 		&ioapic_configure_io_interrupt,
597dc14d97bSMichael Lotz 		&ioapic_is_spurious_interrupt,
598dc14d97bSMichael Lotz 		&ioapic_is_level_triggered_interrupt,
599dc14d97bSMichael Lotz 		&ioapic_end_of_interrupt
600dc14d97bSMichael Lotz 	};
601dc14d97bSMichael Lotz 
6028908aef9SMichael Lotz 	if (args->arch_args.apic == NULL)
603dc14d97bSMichael Lotz 		return;
604dc14d97bSMichael Lotz 
6058908aef9SMichael Lotz 	if (args->arch_args.ioapic_phys == 0) {
6068908aef9SMichael Lotz 		dprintf("no io-apics available, not using io-apics for interrupt "
6078908aef9SMichael Lotz 			"routing\n");
6088908aef9SMichael Lotz 		return;
6098908aef9SMichael Lotz 	}
6108908aef9SMichael Lotz 
611dc14d97bSMichael Lotz 	if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) {
6125d01e61aSMichael Lotz 		dprintf("io-apics explicitly disabled, not using io-apics for "
6135d01e61aSMichael Lotz 			"interrupt routing\n");
614dc14d97bSMichael Lotz 		return;
615dc14d97bSMichael Lotz 	}
616dc14d97bSMichael Lotz 
617dc14d97bSMichael Lotz 	// load acpi module
618dc14d97bSMichael Lotz 	status_t status;
619dc14d97bSMichael Lotz 	acpi_module_info* acpiModule;
620dc14d97bSMichael Lotz 	status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
621dc14d97bSMichael Lotz 	if (status != B_OK) {
6225d01e61aSMichael Lotz 		dprintf("acpi module not available, not configuring io-apics\n");
623dc14d97bSMichael Lotz 		return;
624dc14d97bSMichael Lotz 	}
625dc14d97bSMichael Lotz 	BPrivate::CObjectDeleter<const char, status_t>
626dc14d97bSMichael Lotz 		acpiModulePutter(B_ACPI_MODULE_NAME, put_module);
627dc14d97bSMichael Lotz 
628*fb5a1727SMichael Lotz 	acpi_table_madt* madt = NULL;
629*fb5a1727SMichael Lotz 	if (acpiModule->get_table(ACPI_SIG_MADT, 0, (void**)&madt) != B_OK) {
630*fb5a1727SMichael Lotz 		dprintf("failed to get MADT from ACPI, not configuring io-apics\n");
631*fb5a1727SMichael Lotz 		return;
632*fb5a1727SMichael Lotz 	}
633*fb5a1727SMichael Lotz 
634*fb5a1727SMichael Lotz 	status = acpi_enumerate_ioapics(madt);
635d11e32a8SMichael Lotz 	if (status != B_OK) {
636ca67ddb3SMichael Lotz 		// We don't treat this case as fatal just yet. If we are able to
637ca67ddb3SMichael Lotz 		// route everything with the available IO-APICs we're fine, if not
638ca67ddb3SMichael Lotz 		// we will fail at the routing preparation stage further down.
639ca67ddb3SMichael Lotz 		dprintf("failed to enumerate all io-apics, working with what we got\n");
640d11e32a8SMichael Lotz 	}
641d11e32a8SMichael Lotz 
642d11e32a8SMichael Lotz 	// switch to the APIC interrupt model before retrieving the IRQ routing
643dc14d97bSMichael Lotz 	// table as it will return different settings depending on the model
644dc14d97bSMichael Lotz 	status = acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_APIC);
645dc14d97bSMichael Lotz 	if (status != B_OK) {
646dc14d97bSMichael Lotz 		dprintf("failed to put ACPI into APIC interrupt model, ignoring\n");
647dc14d97bSMichael Lotz 		// don't abort, as the _PIC method is optional and as long as there
648dc14d97bSMichael Lotz 		// aren't different routings based on it this is non-fatal
649dc14d97bSMichael Lotz 	}
650dc14d97bSMichael Lotz 
651dc14d97bSMichael Lotz 	IRQRoutingTable table;
652dc14d97bSMichael Lotz 	status = prepare_irq_routing(acpiModule, table,
653eda74390SMichael Lotz 		&ioapic_is_interrupt_available);
654dc14d97bSMichael Lotz 	if (status != B_OK) {
6555d01e61aSMichael Lotz 		dprintf("IRQ routing preparation failed, not configuring io-apics\n");
656dc14d97bSMichael Lotz 		acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
657dc14d97bSMichael Lotz 			// revert to PIC interrupt model just in case
658dc14d97bSMichael Lotz 		return;
659dc14d97bSMichael Lotz 	}
660dc14d97bSMichael Lotz 
661dc14d97bSMichael Lotz 	print_irq_routing_table(table);
662dc14d97bSMichael Lotz 
6635d01e61aSMichael Lotz 	// use the boot CPU as the target for all interrupts
66463475256SMichael Lotz 	uint8 targetAPIC = args->arch_args.cpu_apic_id[0];
6655d01e61aSMichael Lotz 
6668908aef9SMichael Lotz 	struct ioapic* current = sIOAPICs;
6675d01e61aSMichael Lotz 	while (current != NULL) {
6685d01e61aSMichael Lotz 		status = ioapic_initialize_ioapic(*current, targetAPIC);
6695d01e61aSMichael Lotz 		if (status != B_OK) {
6705d01e61aSMichael Lotz 			panic("failed to initialize io-apic %u", current->number);
6715d01e61aSMichael Lotz 			acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
6725d01e61aSMichael Lotz 			return;
6735d01e61aSMichael Lotz 		}
6745d01e61aSMichael Lotz 
6755d01e61aSMichael Lotz 		current = current->next;
6765d01e61aSMichael Lotz 	}
6775d01e61aSMichael Lotz 
678dc14d97bSMichael Lotz 	status = enable_irq_routing(acpiModule, table);
679dc14d97bSMichael Lotz 	if (status != B_OK) {
680dc14d97bSMichael Lotz 		panic("failed to enable IRQ routing");
681dc14d97bSMichael Lotz 		// if it failed early on it might still work in PIC mode
682dc14d97bSMichael Lotz 		acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
683dc14d97bSMichael Lotz 		return;
684dc14d97bSMichael Lotz 	}
685dc14d97bSMichael Lotz 
686*fb5a1727SMichael Lotz 	// configure the source overrides, but let the PCI config below override it
687*fb5a1727SMichael Lotz 	acpi_configure_source_overrides(madt);
688*fb5a1727SMichael Lotz 
6895d01e61aSMichael Lotz 	// configure IO-APIC interrupts from PCI routing table
690dc14d97bSMichael Lotz 	for (int i = 0; i < table.Count(); i++) {
691dc14d97bSMichael Lotz 		irq_routing_entry& entry = table.ElementAt(i);
692dc14d97bSMichael Lotz 		ioapic_configure_io_interrupt(entry.irq,
693dc14d97bSMichael Lotz 			entry.polarity | entry.trigger_mode);
694dc14d97bSMichael Lotz 	}
695dc14d97bSMichael Lotz 
696a56cbb2aSMichael Lotz 	// kill the local ints on the local APIC
697a56cbb2aSMichael Lotz 	apic_disable_local_ints();
698a56cbb2aSMichael Lotz 		// TODO: This uses the assumption that our init is running on the
699a56cbb2aSMichael Lotz 		// boot CPU and only the boot CPU has the local ints configured
700a56cbb2aSMichael Lotz 		// because it was running in legacy PIC mode. Possibly the other
701a56cbb2aSMichael Lotz 		// local APICs of the other CPUs have them configured as well. It
702a56cbb2aSMichael Lotz 		// shouldn't really harm, but should eventually be corrected.
703a56cbb2aSMichael Lotz 
704dc14d97bSMichael Lotz 	// disable the legacy PIC
705*fb5a1727SMichael Lotz 	uint16 legacyInterrupts;
706*fb5a1727SMichael Lotz 	pic_disable(legacyInterrupts);
707*fb5a1727SMichael Lotz 
708*fb5a1727SMichael Lotz 	// enable previsouly enabled legacy interrupts
709*fb5a1727SMichael Lotz 	for (uint8 i = 0; i < 16; i++) {
710*fb5a1727SMichael Lotz 		if ((legacyInterrupts & (1 << i)) != 0)
711*fb5a1727SMichael Lotz 			ioapic_enable_io_interrupt(i);
712*fb5a1727SMichael Lotz 	}
713dc14d97bSMichael Lotz 
714dc14d97bSMichael Lotz 	// prefer the ioapic over the normal pic
7155d01e61aSMichael Lotz 	dprintf("using io-apics for interrupt routing\n");
716dc14d97bSMichael Lotz 	arch_int_set_interrupt_controller(ioapicController);
717dc14d97bSMichael Lotz }
718