* Prepared everything to eventually support multiple IO-APICs.
* Added some TODOs regarding register write order that might have bad side effects. * Some cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41428 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -78,57 +78,88 @@
|
|||||||
#define IO_APIC_INTERRUPT_VECTOR_MASK 0xff
|
#define IO_APIC_INTERRUPT_VECTOR_MASK 0xff
|
||||||
|
|
||||||
|
|
||||||
typedef struct ioapic_s {
|
struct ioapic_registers {
|
||||||
volatile uint32 io_register_select;
|
volatile uint32 io_register_select;
|
||||||
uint32 reserved[3];
|
uint32 reserved[3];
|
||||||
volatile uint32 io_window_register;
|
volatile uint32 io_window_register;
|
||||||
} ioapic;
|
};
|
||||||
|
|
||||||
static ioapic *sIOAPIC = NULL;
|
|
||||||
static uint32 sIOAPICMaxRedirectionEntry = 23;
|
|
||||||
|
|
||||||
static uint64 sLevelTriggeredInterrupts = 0;
|
struct ioapic {
|
||||||
// binary mask: 1 level, 0 edge
|
uint8 number;
|
||||||
|
uint8 max_redirection_entry;
|
||||||
|
uint8 global_interrupt_base;
|
||||||
|
uint8 global_interrupt_last;
|
||||||
|
uint64 level_triggered_mask;
|
||||||
|
|
||||||
|
area_id register_area;
|
||||||
|
ioapic_registers* registers;
|
||||||
|
|
||||||
|
ioapic* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static ioapic sIOAPICs = { 0, 0, 0, 0, 0, -1, NULL, NULL };
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - I/O APIC
|
// #pragma mark - I/O APIC
|
||||||
|
|
||||||
|
|
||||||
static inline uint32
|
static inline struct ioapic*
|
||||||
ioapic_read_32(uint8 registerSelect)
|
find_ioapic(int32 gsi)
|
||||||
{
|
{
|
||||||
sIOAPIC->io_register_select = registerSelect;
|
if (gsi < 0)
|
||||||
return sIOAPIC->io_window_register;
|
return NULL;
|
||||||
|
|
||||||
|
struct ioapic* current = &sIOAPICs;
|
||||||
|
while (current != NULL) {
|
||||||
|
if (gsi >= current->global_interrupt_base
|
||||||
|
&& gsi <= current->global_interrupt_last) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint32
|
||||||
|
ioapic_read_32(struct ioapic& ioapic, uint8 registerSelect)
|
||||||
|
{
|
||||||
|
ioapic.registers->io_register_select = registerSelect;
|
||||||
|
return ioapic.registers->io_window_register;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ioapic_write_32(uint8 registerSelect, uint32 value)
|
ioapic_write_32(struct ioapic& ioapic, uint8 registerSelect, uint32 value)
|
||||||
{
|
{
|
||||||
sIOAPIC->io_register_select = registerSelect;
|
ioapic.registers->io_register_select = registerSelect;
|
||||||
sIOAPIC->io_window_register = value;
|
ioapic.registers->io_window_register = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline uint64
|
static inline uint64
|
||||||
ioapic_read_64(uint8 registerSelect)
|
ioapic_read_64(struct ioapic& ioapic, uint8 registerSelect)
|
||||||
{
|
{
|
||||||
sIOAPIC->io_register_select = registerSelect + 1;
|
ioapic.registers->io_register_select = registerSelect + 1;
|
||||||
uint64 result = sIOAPIC->io_window_register;
|
uint64 result = ioapic.registers->io_window_register;
|
||||||
result <<= 32;
|
result <<= 32;
|
||||||
sIOAPIC->io_register_select = registerSelect;
|
ioapic.registers->io_register_select = registerSelect;
|
||||||
result |= sIOAPIC->io_window_register;
|
result |= ioapic.registers->io_window_register;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ioapic_write_64(uint8 registerSelect, uint64 value)
|
ioapic_write_64(struct ioapic& ioapic, uint8 registerSelect, uint64 value)
|
||||||
{
|
{
|
||||||
sIOAPIC->io_register_select = registerSelect;
|
ioapic.registers->io_register_select = registerSelect;
|
||||||
sIOAPIC->io_window_register = (uint32)value;
|
ioapic.registers->io_window_register = (uint32)value;
|
||||||
sIOAPIC->io_register_select = registerSelect + 1;
|
ioapic.registers->io_register_select = registerSelect + 1;
|
||||||
sIOAPIC->io_window_register = (uint32)(value >> 32);
|
ioapic.registers->io_window_register = (uint32)(value >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -141,12 +172,14 @@ ioapic_is_spurious_interrupt(int32 num)
|
|||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ioapic_is_level_triggered_interrupt(int32 pin)
|
ioapic_is_level_triggered_interrupt(int32 gsi)
|
||||||
{
|
{
|
||||||
if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
|
struct ioapic* ioapic = find_ioapic(gsi);
|
||||||
|
if (ioapic == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (sLevelTriggeredInterrupts & (1 << pin)) != 0;
|
uint8 pin = gsi - ioapic->global_interrupt_base;
|
||||||
|
return (ioapic->level_triggered_mask & (1 << pin)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -159,55 +192,67 @@ ioapic_end_of_interrupt(int32 num)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ioapic_enable_io_interrupt(int32 pin)
|
ioapic_enable_io_interrupt(int32 gsi)
|
||||||
{
|
{
|
||||||
if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
|
struct ioapic* ioapic = find_ioapic(gsi);
|
||||||
|
if (ioapic == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TRACE(("ioapic_enable_io_interrupt: pin %ld\n", pin));
|
uint8 pin = gsi - ioapic->global_interrupt_base;
|
||||||
|
TRACE(("ioapic_enable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
|
||||||
|
gsi, ioapic->number, pin));
|
||||||
|
|
||||||
uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2);
|
uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2);
|
||||||
entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
|
entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
|
||||||
entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
|
entry |= IO_APIC_INTERRUPT_UNMASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
|
||||||
ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
|
ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
|
||||||
|
// TODO: Take writing order into account! We must not unmask the entry
|
||||||
|
// before the other half is valid.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ioapic_disable_io_interrupt(int32 pin)
|
ioapic_disable_io_interrupt(int32 gsi)
|
||||||
{
|
{
|
||||||
if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
|
struct ioapic* ioapic = find_ioapic(gsi);
|
||||||
|
if (ioapic == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TRACE(("ioapic_disable_io_interrupt: pin %ld\n", pin));
|
uint8 pin = gsi - ioapic->global_interrupt_base;
|
||||||
|
TRACE(("ioapic_disable_io_interrupt: gsi %ld -> io-apic %u pin %u\n",
|
||||||
|
gsi, ioapic->number, pin));
|
||||||
|
|
||||||
uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2);
|
uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2);
|
||||||
entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
|
entry &= ~(1 << IO_APIC_INTERRUPT_MASK_SHIFT);
|
||||||
entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
|
entry |= IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT;
|
||||||
ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
|
ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
|
||||||
|
// TODO: Take writing order into account! We must not modify the entry
|
||||||
|
// before it is masked.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ioapic_configure_io_interrupt(int32 pin, uint32 config)
|
ioapic_configure_io_interrupt(int32 gsi, uint32 config)
|
||||||
{
|
{
|
||||||
if (pin < 0 || pin > (int32)sIOAPICMaxRedirectionEntry)
|
struct ioapic* ioapic = find_ioapic(gsi);
|
||||||
|
if (ioapic == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TRACE(("ioapic_configure_io_interrupt: pin %ld; config 0x%08lx\n", pin,
|
uint8 pin = gsi - ioapic->global_interrupt_base;
|
||||||
config));
|
TRACE(("ioapic_configure_io_interrupt: gsi %ld -> io-apic %u pin %u; "
|
||||||
|
"config 0x%08lx\n", gsi, ioapic->number, pin, config));
|
||||||
|
|
||||||
uint64 entry = ioapic_read_64(IO_APIC_REDIRECTION_TABLE + pin * 2);
|
uint64 entry = ioapic_read_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2);
|
||||||
entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT)
|
entry &= ~((1 << IO_APIC_TRIGGER_MODE_SHIFT)
|
||||||
| (1 << IO_APIC_PIN_POLARITY_SHIFT)
|
| (1 << IO_APIC_PIN_POLARITY_SHIFT)
|
||||||
| (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT));
|
| (IO_APIC_INTERRUPT_VECTOR_MASK << IO_APIC_INTERRUPT_VECTOR_SHIFT));
|
||||||
|
|
||||||
if (config & B_LEVEL_TRIGGERED) {
|
if (config & B_LEVEL_TRIGGERED) {
|
||||||
entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT);
|
entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT);
|
||||||
sLevelTriggeredInterrupts |= (1 << pin);
|
ioapic->level_triggered_mask |= (1 << pin);
|
||||||
} else {
|
} else {
|
||||||
entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT);
|
entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT);
|
||||||
sLevelTriggeredInterrupts &= ~(1 << pin);
|
ioapic->level_triggered_mask &= ~(1 << pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config & B_LOW_ACTIVE_POLARITY)
|
if (config & B_LOW_ACTIVE_POLARITY)
|
||||||
@@ -216,7 +261,82 @@ ioapic_configure_io_interrupt(int32 pin, uint32 config)
|
|||||||
entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT);
|
entry |= (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT);
|
||||||
|
|
||||||
entry |= (pin + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT;
|
entry |= (pin + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT;
|
||||||
ioapic_write_64(IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
|
ioapic_write_64(*ioapic, IO_APIC_REDIRECTION_TABLE + pin * 2, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
ioapic_map_ioapic(struct ioapic& ioapic, phys_addr_t physicalAddress)
|
||||||
|
{
|
||||||
|
ioapic.register_area = vm_map_physical_memory(B_SYSTEM_TEAM, "io-apic",
|
||||||
|
(void**)&ioapic.registers, ioapic.registers != NULL ? B_EXACT_ADDRESS
|
||||||
|
: B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA
|
||||||
|
| B_KERNEL_WRITE_AREA, physicalAddress, true);
|
||||||
|
if (ioapic.register_area < 0) {
|
||||||
|
panic("mapping io-apic %u failed", ioapic.number);
|
||||||
|
return ioapic.register_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 version = ioapic_read_32(ioapic, IO_APIC_VERSION);
|
||||||
|
if (version == 0xffffffff) {
|
||||||
|
dprintf("io-apic %u seems inaccessible, not using it\n",
|
||||||
|
ioapic.number);
|
||||||
|
vm_delete_area(B_SYSTEM_TEAM, ioapic.register_area, true);
|
||||||
|
ioapic.register_area = -1;
|
||||||
|
ioapic.registers = NULL;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ioapic.max_redirection_entry
|
||||||
|
= ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT)
|
||||||
|
& IO_APIC_MAX_REDIRECTION_ENTRY_MASK);
|
||||||
|
|
||||||
|
ioapic.global_interrupt_last
|
||||||
|
= ioapic.global_interrupt_base + ioapic.max_redirection_entry;
|
||||||
|
|
||||||
|
dprintf("io-apic %u has range %u-%u, %u entries\n", ioapic.number,
|
||||||
|
ioapic.global_interrupt_base, ioapic.global_interrupt_last,
|
||||||
|
ioapic.max_redirection_entry + 1);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
ioapic_initialize_ioapic(struct ioapic& ioapic, uint64 targetAPIC)
|
||||||
|
{
|
||||||
|
// program the interrupt vectors of the io-apic
|
||||||
|
ioapic.level_triggered_mask = 0;
|
||||||
|
for (uint8 i = 0; i <= ioapic.max_redirection_entry; i++) {
|
||||||
|
// initialize everything to deliver to the boot CPU in physical mode
|
||||||
|
// and masked until explicitly enabled through enable_io_interrupt()
|
||||||
|
uint64 entry = (targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT)
|
||||||
|
| (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT)
|
||||||
|
| (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT)
|
||||||
|
| ((i + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
// make redirection entry 0 into an external interrupt
|
||||||
|
entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
|
||||||
|
| (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
|
||||||
|
| (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT);
|
||||||
|
} else if (i < 16) {
|
||||||
|
// make 1-15 ISA interrupts
|
||||||
|
entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
|
||||||
|
| (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
|
||||||
|
| (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
|
||||||
|
} else {
|
||||||
|
// and the rest are PCI interrupts
|
||||||
|
entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT)
|
||||||
|
| (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
|
||||||
|
| (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
|
||||||
|
ioapic.level_triggered_mask |= (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
ioapic_write_64(ioapic, IO_APIC_REDIRECTION_TABLE + 2 * i, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -250,19 +370,14 @@ ioapic_map(kernel_args* args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args->arch_args.ioapic == NULL) {
|
if (args->arch_args.ioapic == NULL) {
|
||||||
dprintf("no ioapic available, not using ioapics for interrupt routing\n");
|
dprintf("no io-apic available, not using io-apics for interrupt "
|
||||||
|
"routing\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// map in the (first) IO-APIC
|
// map in the first IO-APIC
|
||||||
sIOAPIC = (ioapic *)args->arch_args.ioapic;
|
sIOAPICs.registers = (ioapic_registers*)args->arch_args.ioapic;
|
||||||
if (vm_map_physical_memory(B_SYSTEM_TEAM, "ioapic", (void**)&sIOAPIC,
|
ioapic_map_ioapic(sIOAPICs, args->arch_args.ioapic_phys);
|
||||||
B_EXACT_ADDRESS, B_PAGE_SIZE,
|
|
||||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
|
|
||||||
args->arch_args.ioapic_phys, true) < 0) {
|
|
||||||
panic("mapping the ioapic failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -279,36 +394,30 @@ ioapic_init(kernel_args* args)
|
|||||||
&ioapic_end_of_interrupt
|
&ioapic_end_of_interrupt
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sIOAPIC == NULL)
|
if (sIOAPICs.register_area < 0 || sIOAPICs.registers == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) {
|
if (get_safemode_boolean(B_SAFEMODE_DISABLE_IOAPIC, false)) {
|
||||||
dprintf("ioapic explicitly disabled, not using ioapics for interrupt "
|
dprintf("io-apics explicitly disabled, not using io-apics for "
|
||||||
"routing\n");
|
"interrupt routing\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// TODO: This can be removed once IO-APIC code is broadly tested
|
// TODO: This can be removed once IO-APIC code is broadly tested
|
||||||
if (!get_safemode_boolean(B_SAFEMODE_ENABLE_IOAPIC, false)) {
|
if (!get_safemode_boolean(B_SAFEMODE_ENABLE_IOAPIC, false)) {
|
||||||
dprintf("ioapic not enabled, not using ioapics for interrupt "
|
dprintf("io-apics not enabled, not using io-apics for interrupt "
|
||||||
"routing\n");
|
"routing\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32 version = ioapic_read_32(IO_APIC_VERSION);
|
|
||||||
if (version == 0xffffffff) {
|
|
||||||
dprintf("ioapic seems inaccessible, not using it\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// load acpi module
|
// load acpi module
|
||||||
status_t status;
|
status_t status;
|
||||||
acpi_module_info* acpiModule;
|
acpi_module_info* acpiModule;
|
||||||
status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
|
status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
dprintf("acpi module not available, not configuring ioapic\n");
|
dprintf("acpi module not available, not configuring io-apics\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BPrivate::CObjectDeleter<const char, status_t>
|
BPrivate::CObjectDeleter<const char, status_t>
|
||||||
@@ -323,18 +432,13 @@ ioapic_init(kernel_args* args)
|
|||||||
// aren't different routings based on it this is non-fatal
|
// aren't different routings based on it this is non-fatal
|
||||||
}
|
}
|
||||||
|
|
||||||
sLevelTriggeredInterrupts = 0;
|
// TODO: read out all IO-APICs from ACPI and set them up
|
||||||
sIOAPICMaxRedirectionEntry
|
|
||||||
= ((version >> IO_APIC_MAX_REDIRECTION_ENTRY_SHIFT)
|
|
||||||
& IO_APIC_MAX_REDIRECTION_ENTRY_MASK);
|
|
||||||
|
|
||||||
TRACE(("ioapic has %lu entries\n", sIOAPICMaxRedirectionEntry + 1));
|
|
||||||
|
|
||||||
IRQRoutingTable table;
|
IRQRoutingTable table;
|
||||||
status = prepare_irq_routing(acpiModule, table,
|
status = prepare_irq_routing(acpiModule, table,
|
||||||
sIOAPICMaxRedirectionEntry + 1);
|
sIOAPICs.max_redirection_entry + 1);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
dprintf("IRQ routing preparation failed, not configuring ioapic.\n");
|
dprintf("IRQ routing preparation failed, not configuring io-apics\n");
|
||||||
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
||||||
// revert to PIC interrupt model just in case
|
// revert to PIC interrupt model just in case
|
||||||
return;
|
return;
|
||||||
@@ -342,6 +446,21 @@ ioapic_init(kernel_args* args)
|
|||||||
|
|
||||||
print_irq_routing_table(table);
|
print_irq_routing_table(table);
|
||||||
|
|
||||||
|
// use the boot CPU as the target for all interrupts
|
||||||
|
uint64 targetAPIC = args->arch_args.cpu_apic_id[0];
|
||||||
|
|
||||||
|
struct ioapic* current = &sIOAPICs;
|
||||||
|
while (current != NULL) {
|
||||||
|
status = ioapic_initialize_ioapic(*current, targetAPIC);
|
||||||
|
if (status != B_OK) {
|
||||||
|
panic("failed to initialize io-apic %u", current->number);
|
||||||
|
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
status = enable_irq_routing(acpiModule, table);
|
status = enable_irq_routing(acpiModule, table);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
panic("failed to enable IRQ routing");
|
panic("failed to enable IRQ routing");
|
||||||
@@ -350,40 +469,7 @@ ioapic_init(kernel_args* args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use the boot CPU as the target for all interrupts
|
// configure IO-APIC interrupts from PCI routing table
|
||||||
uint64 targetAPIC = args->arch_args.cpu_apic_id[0];
|
|
||||||
|
|
||||||
// program the interrupt vectors of the ioapic
|
|
||||||
for (uint32 i = 0; i <= sIOAPICMaxRedirectionEntry; i++) {
|
|
||||||
// initialize everything to deliver to the boot CPU in physical mode
|
|
||||||
// and masked until explicitly enabled through enable_io_interrupt()
|
|
||||||
uint64 entry = (targetAPIC << IO_APIC_DESTINATION_FIELD_SHIFT)
|
|
||||||
| (IO_APIC_INTERRUPT_MASKED << IO_APIC_INTERRUPT_MASK_SHIFT)
|
|
||||||
| (IO_APIC_DESTINATION_MODE_PHYSICAL << IO_APIC_DESTINATION_MODE_SHIFT)
|
|
||||||
| ((i + ARCH_INTERRUPT_BASE) << IO_APIC_INTERRUPT_VECTOR_SHIFT);
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
// make redirection entry 0 into an external interrupt
|
|
||||||
entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
|
|
||||||
| (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
|
|
||||||
| (IO_APIC_DELIVERY_MODE_EXT_INT << IO_APIC_DELIVERY_MODE_SHIFT);
|
|
||||||
} else if (i < 16) {
|
|
||||||
// make 1-15 ISA interrupts
|
|
||||||
entry |= (IO_APIC_TRIGGER_MODE_EDGE << IO_APIC_TRIGGER_MODE_SHIFT)
|
|
||||||
| (IO_APIC_PIN_POLARITY_HIGH_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
|
|
||||||
| (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
|
|
||||||
} else {
|
|
||||||
// and the rest are PCI interrupts
|
|
||||||
entry |= (IO_APIC_TRIGGER_MODE_LEVEL << IO_APIC_TRIGGER_MODE_SHIFT)
|
|
||||||
| (IO_APIC_PIN_POLARITY_LOW_ACTIVE << IO_APIC_PIN_POLARITY_SHIFT)
|
|
||||||
| (IO_APIC_DELIVERY_MODE_FIXED << IO_APIC_DELIVERY_MODE_SHIFT);
|
|
||||||
sLevelTriggeredInterrupts |= (1 << i);
|
|
||||||
}
|
|
||||||
|
|
||||||
ioapic_write_64(IO_APIC_REDIRECTION_TABLE + 2 * i, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure io apic interrupts from PCI routing table
|
|
||||||
for (int i = 0; i < table.Count(); i++) {
|
for (int i = 0; i < table.Count(); i++) {
|
||||||
irq_routing_entry& entry = table.ElementAt(i);
|
irq_routing_entry& entry = table.ElementAt(i);
|
||||||
ioapic_configure_io_interrupt(entry.irq,
|
ioapic_configure_io_interrupt(entry.irq,
|
||||||
@@ -394,6 +480,6 @@ ioapic_init(kernel_args* args)
|
|||||||
pic_disable();
|
pic_disable();
|
||||||
|
|
||||||
// prefer the ioapic over the normal pic
|
// prefer the ioapic over the normal pic
|
||||||
dprintf("using ioapic for interrupt routing\n");
|
dprintf("using io-apics for interrupt routing\n");
|
||||||
arch_int_set_interrupt_controller(ioapicController);
|
arch_int_set_interrupt_controller(ioapicController);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user