diff options
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 4333a75..826f44f 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3861,7 +3861,13 @@ static int bad_ioapic_register(int idx) static int find_free_ioapic_entry(void) { - return nr_ioapics; + int idx; + + for (idx = 0; idx < MAX_IO_APICS; idx++) + if (ioapics[idx].nr_registers == 0) + return idx; + + return MAX_IO_APICS; } /** @@ -3874,6 +3880,7 @@ static int find_free_ioapic_entry(void) int mp_register_ioapic(int id, u32 address, u32 gsi_base, struct ioapic_domain_cfg *cfg) { + bool hotplug = !!ioapic_initialized; struct mp_ioapic_gsi *gsi_cfg; int idx, ioapic, entries; u32 gsi_end; @@ -3935,6 +3942,19 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base, ioapics[idx].irqdomain = NULL; ioapics[idx].irqdomain_cfg = *cfg; + /* + * If mp_register_ioapic() is called during early boot stage when + * walking ACPI/SFI/DT tables, it's too early to create irqdomain, + * we are still using bootmem allocator. So delay it to setup_IO_APIC(). + */ + if (hotplug) { + if (mp_irqdomain_create(idx)) { + clear_fixmap(FIX_IO_APIC_BASE_0 + idx); + return -ENOMEM; + } + alloc_ioapic_saved_registers(idx); + } + if (gsi_cfg->gsi_end >= gsi_top) gsi_top = gsi_cfg->gsi_end + 1; if (nr_ioapics <= idx) |