// SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) "APIC: " fmt #include <asm/apic.h> #include "local.h" /* * Use DEFINE_STATIC_CALL_NULL() to avoid having to provide stub functions * for each callback. The callbacks are setup during boot and all except * wait_icr_idle() must be initialized before usage. The IPI wrappers * use static_call() and not static_call_cond() to catch any fails. */ #define DEFINE_APIC_CALL(__cb) \ DEFINE_STATIC_CALL_NULL(apic_call_##__cb, *apic->__cb) DEFINE_APIC_CALL(eoi); DEFINE_APIC_CALL(native_eoi); DEFINE_APIC_CALL(icr_read); DEFINE_APIC_CALL(icr_write); DEFINE_APIC_CALL(read); DEFINE_APIC_CALL(send_IPI); DEFINE_APIC_CALL(send_IPI_mask); DEFINE_APIC_CALL(send_IPI_mask_allbutself); DEFINE_APIC_CALL(send_IPI_allbutself); DEFINE_APIC_CALL(send_IPI_all); DEFINE_APIC_CALL(send_IPI_self); DEFINE_APIC_CALL(wait_icr_idle); DEFINE_APIC_CALL(wakeup_secondary_cpu); DEFINE_APIC_CALL(wakeup_secondary_cpu_64); DEFINE_APIC_CALL(write); EXPORT_STATIC_CALL_TRAMP_GPL(apic_call_send_IPI_mask); EXPORT_STATIC_CALL_TRAMP_GPL(apic_call_send_IPI_self); /* 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); } #define update_call(__cb) \ static_call_update(apic_call_##__cb, *apic->__cb) static __init void update_static_calls(void) { update_call(eoi); update_call(native_eoi); update_call(write); update_call(read); update_call(send_IPI); update_call(send_IPI_mask); update_call(send_IPI_mask_allbutself); update_call(send_IPI_allbutself); update_call(send_IPI_all); update_call(send_IPI_self); update_call(icr_read); update_call(icr_write); update_call(wait_icr_idle); update_call(wakeup_secondary_cpu); update_call(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; update_static_calls(); pr_info("Static calls initialized\n"); } void __init apic_install_driver(struct apic *driver) { if (apic == driver) return; 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(); update_static_calls(); pr_info("Switched APIC routing to: %s\n", driver->name); }