[57/58] x86/apic: Provide static call infrastructure for APIC callbacks

Message ID 20230717223226.476875329@linutronix.de
State New
Headers
Series x86/apic: Decrapification and static calls |

Commit Message

Thomas Gleixner July 17, 2023, 11:16 p.m. UTC
  Declare and define the static calls for the hotpath APIC callbacks. Note
this deliberately uses STATIC_CALL_NULL() because otherwise it would be
required to have the definitions in the 32bit and the 64bit default APIC
implementations and it's hard to keep the calls in sync. The other option
would be to have stub functions for each callback type. Not pretty either

So the NULL capable calls are used and filled in during early boot after
the static key infrastructure has been initialized. The calls will be
static_call() except for the wait_irc_idle() callback which is valid to be
NULL for X2APIC systems.

Update the calls when a new APIC driver is installed and when a callback
override is invoked.

Export the trampolines for the two calls which are used in KVM and MCE
error inject modules.

Test the setup and let the next step convert the inline wrappers to make it
effective.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/include/asm/apic.h |   21 +++++++++++++++++++
 arch/x86/kernel/apic/init.c |   47 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)
  

Comments

Peter Zijlstra July 18, 2023, 9:19 a.m. UTC | #1
On Tue, Jul 18, 2023 at 01:16:03AM +0200, Thomas Gleixner wrote:
> Declare and define the static calls for the hotpath APIC callbacks. Note
> this deliberately uses STATIC_CALL_NULL() because otherwise it would be
> required to have the definitions in the 32bit and the 64bit default APIC
> implementations and it's hard to keep the calls in sync. The other option
> would be to have stub functions for each callback type. Not pretty either
> 
> So the NULL capable calls are used and filled in during early boot after
> the static key infrastructure has been initialized. The calls will be
> static_call() except for the wait_irc_idle() callback which is valid to be
> NULL for X2APIC systems.
> 
> Update the calls when a new APIC driver is installed and when a callback
> override is invoked.
> 
> Export the trampolines for the two calls which are used in KVM and MCE
> error inject modules.
> 
> Test the setup and let the next step convert the inline wrappers to make it
> effective.

Perhaps preserve some of that in a comment?


> --- a/arch/x86/kernel/apic/init.c
> +++ b/arch/x86/kernel/apic/init.c
> @@ -5,6 +5,28 @@
>  
>  #include "local.h"
>  

/*
 * Uses DEFINE_STATIC_CALL_NULL() to avoid having to provide a (stub)
 * function at this time.
 *
 * All except wait_icr_idle *MUST* be set before usage.
 */

> +#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);
  

Patch

--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -3,6 +3,7 @@ 
 #define _ASM_X86_APIC_H
 
 #include <linux/cpumask.h>
+#include <linux/static_call.h>
 
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
@@ -368,9 +369,29 @@  void __init apic_install_driver(struct a
 #define apic_update_callback(_callback, _fn) {					\
 		__x86_apic_override._callback = _fn;				\
 		apic->_callback = _fn;						\
+		static_call_update(apic_call_##_callback, _fn);		\
 		pr_info("APIC::%s() replaced with %ps()\n", #_callback, _fn);	\
 }
 
+#define DECLARE_APIC_CALL(__cb)						\
+	DECLARE_STATIC_CALL(apic_call_##__cb, *apic->__cb)
+
+DECLARE_APIC_CALL(eoi);
+DECLARE_APIC_CALL(native_eoi);
+DECLARE_APIC_CALL(icr_read);
+DECLARE_APIC_CALL(icr_write);
+DECLARE_APIC_CALL(read);
+DECLARE_APIC_CALL(send_IPI);
+DECLARE_APIC_CALL(send_IPI_mask);
+DECLARE_APIC_CALL(send_IPI_mask_allbutself);
+DECLARE_APIC_CALL(send_IPI_allbutself);
+DECLARE_APIC_CALL(send_IPI_all);
+DECLARE_APIC_CALL(send_IPI_self);
+DECLARE_APIC_CALL(wait_icr_idle);
+DECLARE_APIC_CALL(wakeup_secondary_cpu);
+DECLARE_APIC_CALL(wakeup_secondary_cpu_64);
+DECLARE_APIC_CALL(write);
+
 static __always_inline u32 apic_read(u32 reg)
 {
 	return apic->read(reg);
--- a/arch/x86/kernel/apic/init.c
+++ b/arch/x86/kernel/apic/init.c
@@ -5,6 +5,28 @@ 
 
 #include "local.h"
 
+#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;
 
@@ -30,10 +52,34 @@  static __init void restore_override_call
 	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)
@@ -52,6 +98,7 @@  void __init apic_install_driver(struct a
 
 	/* Apply any already installed callback overrides */
 	restore_override_callbacks();
+	update_static_calls();
 
 	pr_info("Switched APIC routing to: %s\n", driver->name);
 }