diff options
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 31 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 22 |
2 files changed, 50 insertions, 3 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 2d76f022adc2..0b993511e0c5 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -780,8 +780,35 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); | |||
780 | 780 | ||
781 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) | 781 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) |
782 | { | 782 | { |
783 | /* TBD */ | 783 | int ret = -ENOSYS; |
784 | return -EINVAL; | 784 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC |
785 | int ioapic_id; | ||
786 | u64 addr; | ||
787 | struct ioapic_domain_cfg cfg = { | ||
788 | .type = IOAPIC_DOMAIN_DYNAMIC, | ||
789 | .ops = &acpi_irqdomain_ops, | ||
790 | }; | ||
791 | |||
792 | ioapic_id = acpi_get_ioapic_id(handle, gsi_base, &addr); | ||
793 | if (ioapic_id < 0) { | ||
794 | unsigned long long uid; | ||
795 | acpi_status status; | ||
796 | |||
797 | status = acpi_evaluate_integer(handle, METHOD_NAME__UID, | ||
798 | NULL, &uid); | ||
799 | if (ACPI_FAILURE(status)) { | ||
800 | acpi_handle_warn(handle, "failed to get IOAPIC ID.\n"); | ||
801 | return -EINVAL; | ||
802 | } | ||
803 | ioapic_id = (int)uid; | ||
804 | } | ||
805 | |||
806 | mutex_lock(&acpi_ioapic_lock); | ||
807 | ret = mp_register_ioapic(ioapic_id, phys_addr, gsi_base, &cfg); | ||
808 | mutex_unlock(&acpi_ioapic_lock); | ||
809 | #endif | ||
810 | |||
811 | return ret; | ||
785 | } | 812 | } |
786 | 813 | ||
787 | EXPORT_SYMBOL(acpi_register_ioapic); | 814 | EXPORT_SYMBOL(acpi_register_ioapic); |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 4333a751937d..826f44f0a2bf 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) | |||
3861 | 3861 | ||
3862 | static int find_free_ioapic_entry(void) | 3862 | static int find_free_ioapic_entry(void) |
3863 | { | 3863 | { |
3864 | return nr_ioapics; | 3864 | int idx; |
3865 | |||
3866 | for (idx = 0; idx < MAX_IO_APICS; idx++) | ||
3867 | if (ioapics[idx].nr_registers == 0) | ||
3868 | return idx; | ||
3869 | |||
3870 | return MAX_IO_APICS; | ||
3865 | } | 3871 | } |
3866 | 3872 | ||
3867 | /** | 3873 | /** |
@@ -3874,6 +3880,7 @@ static int find_free_ioapic_entry(void) | |||
3874 | int mp_register_ioapic(int id, u32 address, u32 gsi_base, | 3880 | int mp_register_ioapic(int id, u32 address, u32 gsi_base, |
3875 | struct ioapic_domain_cfg *cfg) | 3881 | struct ioapic_domain_cfg *cfg) |
3876 | { | 3882 | { |
3883 | bool hotplug = !!ioapic_initialized; | ||
3877 | struct mp_ioapic_gsi *gsi_cfg; | 3884 | struct mp_ioapic_gsi *gsi_cfg; |
3878 | int idx, ioapic, entries; | 3885 | int idx, ioapic, entries; |
3879 | u32 gsi_end; | 3886 | u32 gsi_end; |
@@ -3935,6 +3942,19 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base, | |||
3935 | ioapics[idx].irqdomain = NULL; | 3942 | ioapics[idx].irqdomain = NULL; |
3936 | ioapics[idx].irqdomain_cfg = *cfg; | 3943 | ioapics[idx].irqdomain_cfg = *cfg; |
3937 | 3944 | ||
3945 | /* | ||
3946 | * If mp_register_ioapic() is called during early boot stage when | ||
3947 | * walking ACPI/SFI/DT tables, it's too early to create irqdomain, | ||
3948 | * we are still using bootmem allocator. So delay it to setup_IO_APIC(). | ||
3949 | */ | ||
3950 | if (hotplug) { | ||
3951 | if (mp_irqdomain_create(idx)) { | ||
3952 | clear_fixmap(FIX_IO_APIC_BASE_0 + idx); | ||
3953 | return -ENOMEM; | ||
3954 | } | ||
3955 | alloc_ioapic_saved_registers(idx); | ||
3956 | } | ||
3957 | |||
3938 | if (gsi_cfg->gsi_end >= gsi_top) | 3958 | if (gsi_cfg->gsi_end >= gsi_top) |
3939 | gsi_top = gsi_cfg->gsi_end + 1; | 3959 | gsi_top = gsi_cfg->gsi_end + 1; |
3940 | if (nr_ioapics <= idx) | 3960 | if (nr_ioapics <= idx) |