kernel/x86: Fix IO-APIC initialization on non-PCI systems
Currently the IO-APIC is fully initialized after PCI initialization resulting in the IO-APIC not being initialized on systems without a PCI bus (i.e. Hyper-V Gen2 VMs). This change moves IO-APIC initialization to occur during early init, deferring PCI interrupt enumeration and routing until after PCI initialization has been completed. Change-Id: I00be0be05d2e7668c3c6bc7af3afc4ff8d04a129 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10414 Reviewed-by: waddlesplash <[email protected]> Reviewed-by: X512 X512 <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
@@ -11,7 +11,7 @@ struct kernel_args;
|
|||||||
|
|
||||||
bool ioapic_is_interrupt_available(int32 gsi);
|
bool ioapic_is_interrupt_available(int32 gsi);
|
||||||
|
|
||||||
void ioapic_preinit(kernel_args* args);
|
void ioapic_init(kernel_args* args);
|
||||||
void ioapic_init();
|
void ioapic_routing_init();
|
||||||
|
|
||||||
#endif // _KERNEL_ARCH_x86_IOAPIC_H
|
#endif // _KERNEL_ARCH_x86_IOAPIC_H
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ X86PCIController::GetRange(uint32 index, pci_resource_range* range)
|
|||||||
status_t
|
status_t
|
||||||
X86PCIController::Finalize()
|
X86PCIController::Finalize()
|
||||||
{
|
{
|
||||||
ioapic_init();
|
ioapic_routing_init();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ status_t
|
|||||||
arch_int_init_io(kernel_args* args)
|
arch_int_init_io(kernel_args* args)
|
||||||
{
|
{
|
||||||
msi_init(args);
|
msi_init(args);
|
||||||
ioapic_preinit(args);
|
ioapic_init(args);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -677,16 +677,7 @@ ioapic_is_interrupt_available(int32 gsi)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ioapic_preinit(kernel_args* args)
|
ioapic_init(kernel_args* args)
|
||||||
{
|
|
||||||
sIOAPICPhys = args->arch_args.ioapic_phys;
|
|
||||||
|
|
||||||
// The real IO-APIC initialization occurs after PCI initialization.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
ioapic_init()
|
|
||||||
{
|
{
|
||||||
static const interrupt_controller ioapicController = {
|
static const interrupt_controller ioapicController = {
|
||||||
"82093AA IOAPIC",
|
"82093AA IOAPIC",
|
||||||
@@ -702,7 +693,7 @@ ioapic_init()
|
|||||||
if (!apic_available())
|
if (!apic_available())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sIOAPICPhys == 0) {
|
if (args->arch_args.ioapic_phys == 0) {
|
||||||
dprintf("no io-apics available, not using io-apics for interrupt "
|
dprintf("no io-apics available, not using io-apics for interrupt "
|
||||||
"routing\n");
|
"routing\n");
|
||||||
return;
|
return;
|
||||||
@@ -748,16 +739,6 @@ ioapic_init()
|
|||||||
// aren't different routings based on it this is non-fatal
|
// aren't different routings based on it this is non-fatal
|
||||||
}
|
}
|
||||||
|
|
||||||
IRQRoutingTable table;
|
|
||||||
status = prepare_irq_routing(acpiModule, table,
|
|
||||||
&ioapic_is_interrupt_available);
|
|
||||||
if (status != B_OK) {
|
|
||||||
dprintf("IRQ routing preparation failed, not configuring io-apics\n");
|
|
||||||
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
|
||||||
// revert to PIC interrupt model just in case
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the boot CPU as the target for all interrupts
|
// use the boot CPU as the target for all interrupts
|
||||||
uint8 targetAPIC = x86_get_cpu_apic_id(0);
|
uint8 targetAPIC = x86_get_cpu_apic_id(0);
|
||||||
|
|
||||||
@@ -773,31 +754,9 @@ ioapic_init()
|
|||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TRACE_IOAPIC
|
// configure the source overrides, but let the PCI config later override it
|
||||||
dprintf("trying interrupt routing:\n");
|
|
||||||
print_irq_routing_table(table);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
status = enable_irq_routing(acpiModule, table);
|
|
||||||
if (status != B_OK) {
|
|
||||||
panic("failed to enable IRQ routing");
|
|
||||||
// if it failed early on it might still work in PIC mode
|
|
||||||
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_irq_routing_table(table);
|
|
||||||
|
|
||||||
// configure the source overrides, but let the PCI config below override it
|
|
||||||
acpi_configure_source_overrides(madt);
|
acpi_configure_source_overrides(madt);
|
||||||
|
|
||||||
// configure IO-APIC interrupts from PCI routing table
|
|
||||||
for (int i = 0; i < table.Count(); i++) {
|
|
||||||
irq_routing_entry& entry = table.ElementAt(i);
|
|
||||||
ioapic_configure_io_interrupt(entry.irq,
|
|
||||||
entry.polarity | entry.trigger_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// kill the local ints on the local APIC
|
// kill the local ints on the local APIC
|
||||||
apic_disable_local_ints();
|
apic_disable_local_ints();
|
||||||
// TODO: This uses the assumption that our init is running on the
|
// TODO: This uses the assumption that our init is running on the
|
||||||
@@ -810,7 +769,7 @@ ioapic_init()
|
|||||||
uint16 legacyInterrupts;
|
uint16 legacyInterrupts;
|
||||||
pic_disable(legacyInterrupts);
|
pic_disable(legacyInterrupts);
|
||||||
|
|
||||||
// enable previsouly enabled legacy interrupts
|
// enable previously enabled legacy interrupts
|
||||||
for (uint8 i = 0; i < 16; i++) {
|
for (uint8 i = 0; i < 16; i++) {
|
||||||
if ((legacyInterrupts & (1 << i)) != 0)
|
if ((legacyInterrupts & (1 << i)) != 0)
|
||||||
ioapic_enable_io_interrupt(i);
|
ioapic_enable_io_interrupt(i);
|
||||||
@@ -830,7 +789,61 @@ ioapic_init()
|
|||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IO-APIC interrupt routing occurs after PCI initialization.
|
||||||
|
sIOAPICPhys = args->arch_args.ioapic_phys;
|
||||||
|
|
||||||
// prefer the ioapic over the normal pic
|
// prefer the ioapic over the normal pic
|
||||||
dprintf("using io-apics for interrupt routing\n");
|
dprintf("using io-apics for interrupt routing\n");
|
||||||
arch_int_set_interrupt_controller(ioapicController);
|
arch_int_set_interrupt_controller(ioapicController);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ioapic_routing_init()
|
||||||
|
{
|
||||||
|
if (sIOAPICPhys == 0) {
|
||||||
|
dprintf("no io-apics available, not using io-apics for interrupt routing\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load ACPI module
|
||||||
|
status_t status;
|
||||||
|
acpi_module_info* acpiModule;
|
||||||
|
status = get_module(B_ACPI_MODULE_NAME, (module_info**)&acpiModule);
|
||||||
|
if (status != B_OK) {
|
||||||
|
dprintf("ACPI module not available, not configuring io-apics\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BPrivate::CObjectDeleter<const char, status_t, put_module>
|
||||||
|
acpiModulePutter(B_ACPI_MODULE_NAME);
|
||||||
|
|
||||||
|
IRQRoutingTable table;
|
||||||
|
status = prepare_irq_routing(acpiModule, table, &ioapic_is_interrupt_available);
|
||||||
|
if (status != B_OK) {
|
||||||
|
dprintf("IRQ routing preparation failed, not configuring io-apics\n");
|
||||||
|
// revert to PIC interrupt model just in case
|
||||||
|
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACE_IOAPIC
|
||||||
|
dprintf("trying interrupt routing:\n");
|
||||||
|
print_irq_routing_table(table);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status = enable_irq_routing(acpiModule, table);
|
||||||
|
if (status != B_OK) {
|
||||||
|
panic("failed to enable IRQ routing");
|
||||||
|
// if it failed early on it might still work in PIC mode
|
||||||
|
acpi_set_interrupt_model(acpiModule, ACPI_INTERRUPT_MODEL_PIC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_irq_routing_table(table);
|
||||||
|
|
||||||
|
// configure IO-APIC interrupts from PCI routing table
|
||||||
|
for (int i = 0; i < table.Count(); i++) {
|
||||||
|
irq_routing_entry& entry = table.ElementAt(i);
|
||||||
|
ioapic_configure_io_interrupt(entry.irq, entry.polarity | entry.trigger_mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user