x86/apic: Provide common init infrastructure
authorThomas Gleixner <tglx@linutronix.de>
Tue, 8 Aug 2023 22:04:18 +0000 (15:04 -0700)
committerDave Hansen <dave.hansen@linux.intel.com>
Wed, 9 Aug 2023 18:58:34 +0000 (11:58 -0700)
In preparation for converting the hotpath APIC callbacks to static keys,
provide common initialization infrastructure.

Lift apic_install_drivers() from probe_64.c and convert all places which
switch the apic instance by storing the pointer to use apic_install_driver()
as a first step.

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)
arch/x86/include/asm/apic.h
arch/x86/kernel/apic/Makefile
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/bigsmp_32.c
arch/x86/kernel/apic/init.c [new file with mode: 0644]
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/probe_64.c
arch/x86/xen/apic.c

index 5d98c4b1a73557e00f3743ed48be39bd3f71df28..90814ec845405f69c310b0d7851c58364ec0379f 100644 (file)
@@ -344,6 +344,8 @@ extern int lapic_can_unplug_cpu(void);
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
+void __init apic_install_driver(struct apic *driver);
+
 static inline u32 apic_read(u32 reg)
 {
        return apic->read(reg);
index a6fcaf16cdbf9b26a36378bf764fb955bf6ab861..2ee867d796d971b3ab9c29b34cbbb5bb98de5baa 100644 (file)
@@ -7,7 +7,7 @@
 # In particualr, smp_apic_timer_interrupt() is called in random places.
 KCOV_INSTRUMENT                := n
 
-obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o apic_common.o apic_noop.o ipi.o vector.o
+obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o apic_common.o apic_noop.o ipi.o vector.o init.o
 obj-y                          += hw_nmi.o
 
 obj-$(CONFIG_X86_IO_APIC)      += io_apic.o
index b8b801e1f76fffbeb6ec5181231aa0802b393ac7..55f2b96674332e53a418675ca454daa6ff7fb896 100644 (file)
@@ -236,8 +236,7 @@ static int modern_apic(void)
  */
 static void __init apic_disable(void)
 {
-       pr_info("APIC: switched to apic NOOP\n");
-       apic = &apic_noop;
+       apic_install_driver(&apic_noop);
 }
 
 void native_apic_icr_write(u32 low, u32 id)
@@ -2486,34 +2485,6 @@ u32 x86_msi_msg_get_destid(struct msi_msg *msg, bool extid)
 }
 EXPORT_SYMBOL_GPL(x86_msi_msg_get_destid);
 
-#ifdef CONFIG_X86_64
-void __init acpi_wake_cpu_handler_update(wakeup_cpu_handler handler)
-{
-       struct apic **drv;
-
-       for (drv = __apicdrivers; drv < __apicdrivers_end; drv++)
-               (*drv)->wakeup_secondary_cpu_64 = handler;
-}
-#endif
-
-/*
- * Override the generic EOI implementation with an optimized version.
- * Only called during early boot when only one CPU is active and with
- * interrupts disabled, so we know this does not race with actual APIC driver
- * use.
- */
-void __init apic_set_eoi_cb(void (*eoi)(void))
-{
-       struct apic **drv;
-
-       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;
-       }
-}
-
 static void __init apic_bsp_up_setup(void)
 {
 #ifdef CONFIG_X86_64
index 5ce1b3740a72db9130ea50234ba8c1acb629adc3..032a84e2c3ccc7e345ed0c05193965549989510f 100644 (file)
@@ -143,11 +143,7 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 
 static int physflat_probe(void)
 {
-       if (apic == &apic_physflat || num_possible_cpus() > 8 ||
-           jailhouse_paravirt())
-               return 1;
-
-       return 0;
+       return apic == &apic_physflat || num_possible_cpus() > 8 || jailhouse_paravirt();
 }
 
 static struct apic apic_physflat __ro_after_init = {
index 23c29a0a49881f7c73a70312380bb395e338d657..0e5535add4b5f1e0e941b34a107cfc5f04b72c9b 100644 (file)
@@ -119,10 +119,8 @@ bool __init apic_bigsmp_possible(bool cmdline_override)
 
 void __init apic_bigsmp_force(void)
 {
-       if (apic != &apic_bigsmp) {
-               apic = &apic_bigsmp;
-               pr_info("Overriding APIC driver with bigsmp\n");
-       }
+       if (apic != &apic_bigsmp)
+               apic_install_driver(&apic_bigsmp);
 }
 
 apic_driver(apic_bigsmp);
diff --git a/arch/x86/kernel/apic/init.c b/arch/x86/kernel/apic/init.c
new file mode 100644 (file)
index 0000000..25cf39b
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#define pr_fmt(fmt) "APIC: " fmt
+
+#include <asm/apic.h>
+
+#include "local.h"
+
+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;
+
+       pr_info("Switched APIC routing to: %s\n", driver->name);
+}
+
+#ifdef CONFIG_X86_64
+void __init acpi_wake_cpu_handler_update(wakeup_cpu_handler handler)
+{
+       struct apic **drv;
+
+       for (drv = __apicdrivers; drv < __apicdrivers_end; drv++)
+               (*drv)->wakeup_secondary_cpu_64 = handler;
+}
+#endif
+
+/*
+ * Override the generic EOI implementation with an optimized version.
+ * Only called during early boot when only one CPU is active and with
+ * interrupts disabled, so we know this does not race with actual APIC driver
+ * use.
+ */
+void __init apic_set_eoi_cb(void (*eoi)(void))
+{
+       struct apic **drv;
+
+       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;
+       }
+}
index 3671cc1c6814a94eea56dab7252afefa19249ae0..9a06df6cdd6807412343a0af0bf328b8cf5dc466 100644 (file)
@@ -82,7 +82,7 @@ static int __init parse_apic(char *arg)
 
        for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
                if (!strcmp((*drv)->name, arg)) {
-                       apic = *drv;
+                       apic_install_driver(*drv);
                        cmdline_apic = 1;
                        return 0;
                }
@@ -129,7 +129,7 @@ void __init x86_32_probe_apic(void)
 
                for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
                        if ((*drv)->probe()) {
-                               apic = *drv;
+                               apic_install_driver(*drv);
                                break;
                        }
                }
@@ -137,5 +137,4 @@ void __init x86_32_probe_apic(void)
                if (drv == __apicdrivers_end)
                        panic("Didn't find an APIC driver");
        }
-       printk(KERN_INFO "Using APIC driver %s\n", apic->name);
 }
index a12a379280a861aaac3adb7e8450b4122b8a9886..ecdf0c4121e154da9e4a3995165f76eeb66ccbae 100644 (file)
 
 #include "local.h"
 
-static __init void 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;
-
-       pr_info("Switched APIC routing to %s:\n", apic->name);
-}
-
 /* Select the appropriate APIC driver */
 void __init x86_64_probe_apic(void)
 {
index 804a26b7c85e8036a6cafdcb80a6072d0ed3a4d2..1838aefc632fb57f12b63f68304763c0dbde7cab 100644 (file)
@@ -160,20 +160,16 @@ static struct apic xen_pv_apic = {
 
 static void __init xen_apic_check(void)
 {
-       if (apic == &xen_pv_apic)
-               return;
-
-       pr_info("Switched APIC routing from %s to %s.\n", apic->name,
-               xen_pv_apic.name);
-       apic = &xen_pv_apic;
+       apic_install_driver(&xen_pv_apic);
 }
+
 void __init xen_init_apic(void)
 {
        x86_apic_ops.io_apic_read = xen_io_apic_read;
        /* On PV guests the APIC CPUID bit is disabled so none of the
         * routines end up executing. */
        if (!xen_initial_domain())
-               apic = &xen_pv_apic;
+               apic_install_driver(&xen_pv_apic);
 
        x86_platform.apic_post_init = xen_apic_check;
 }