summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/apic/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/apic/init.c')
-rw-r--r--arch/x86/kernel/apic/init.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/arch/x86/kernel/apic/init.c b/arch/x86/kernel/apic/init.c
index 25cf39b855db..dab3afa8a86a 100644
--- a/arch/x86/kernel/apic/init.c
+++ b/arch/x86/kernel/apic/init.c
@@ -5,6 +5,37 @@
#include "local.h"
+/* The container for function call overrides */
+struct apic_override __x86_apic_override __initdata;
+
+#define apply_override(__cb) \
+ if (__x86_apic_override.__cb) \
+ apic->__cb = __x86_apic_override.__cb
+
+static __init void restore_override_callbacks(void)
+{
+ apply_override(eoi);
+ apply_override(native_eoi);
+ apply_override(write);
+ apply_override(read);
+ apply_override(send_IPI);
+ apply_override(send_IPI_mask);
+ apply_override(send_IPI_mask_allbutself);
+ apply_override(send_IPI_allbutself);
+ apply_override(send_IPI_all);
+ apply_override(send_IPI_self);
+ apply_override(icr_read);
+ apply_override(icr_write);
+ apply_override(wakeup_secondary_cpu);
+ apply_override(wakeup_secondary_cpu_64);
+}
+
+void __init apic_setup_apic_calls(void)
+{
+ /* Ensure that the default APIC has native_eoi populated */
+ apic->native_eoi = apic->eoi;
+}
+
void __init apic_install_driver(struct apic *driver)
{
if (apic == driver)
@@ -15,6 +46,13 @@ void __init apic_install_driver(struct apic *driver)
if (IS_ENABLED(CONFIG_X86_X2APIC) && apic->x2apic_set_max_apicid)
apic->max_apic_id = x2apic_max_apicid;
+ /* Copy the original eoi() callback as KVM/HyperV might overwrite it */
+ if (!apic->native_eoi)
+ apic->native_eoi = apic->eoi;
+
+ /* Apply any already installed callback overrides */
+ restore_override_callbacks();
+
pr_info("Switched APIC routing to: %s\n", driver->name);
}
@@ -41,7 +79,6 @@ void __init apic_set_eoi_cb(void (*eoi)(void))
for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
/* Should happen once for each apic */
WARN_ON((*drv)->eoi == eoi);
- (*drv)->native_eoi = (*drv)->eoi;
(*drv)->eoi = eoi;
}
}