aboutsummaryrefslogtreecommitdiff
path: root/arch/x86/kernel/apic
diff options
context:
space:
mode:
authorGravatar Thomas Gleixner <tglx@linutronix.de> 2023-08-08 15:04:19 -0700
committerGravatar Dave Hansen <dave.hansen@linux.intel.com> 2023-08-09 12:00:46 -0700
commitbef4f379e953af49a9bd81790954e78fcb264920 (patch)
tree6f12836bb19fccaba438dc686b7aa3bbf73cb156 /arch/x86/kernel/apic
parentx86/xen/apic: Use standard apic driver mechanism for Xen PV (diff)
downloadlinux-bef4f379e953af49a9bd81790954e78fcb264920.tar.gz
linux-bef4f379e953af49a9bd81790954e78fcb264920.tar.bz2
linux-bef4f379e953af49a9bd81790954e78fcb264920.zip
x86/apic: Provide apic_update_callback()
There are already two variants of update mechanism for particular callbacks and virtualization just writes into the data structure. Provide an interface and use a shadow data structure to preserve callbacks so they can be reapplied when the APIC driver is replaced. The extra data structure is intentional as any new callback needs to be also updated in the core code. This also prepares for static calls. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Michael Kelley <mikelley@microsoft.com> Tested-by: Sohil Mehta <sohil.mehta@intel.com> Tested-by: Juergen Gross <jgross@suse.com> # Xen PV (dom0 and unpriv. guest)
Diffstat (limited to 'arch/x86/kernel/apic')
-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;
}
}