xref: /openbmc/linux/arch/x86/kernel/apic/init.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
13af1e415SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23af1e415SThomas Gleixner #define pr_fmt(fmt) "APIC: " fmt
33af1e415SThomas Gleixner 
43af1e415SThomas Gleixner #include <asm/apic.h>
53af1e415SThomas Gleixner 
63af1e415SThomas Gleixner #include "local.h"
73af1e415SThomas Gleixner 
8*3b7c27e6SThomas Gleixner /*
9*3b7c27e6SThomas Gleixner  * Use DEFINE_STATIC_CALL_NULL() to avoid having to provide stub functions
10*3b7c27e6SThomas Gleixner  * for each callback. The callbacks are setup during boot and all except
11*3b7c27e6SThomas Gleixner  * wait_icr_idle() must be initialized before usage. The IPI wrappers
12*3b7c27e6SThomas Gleixner  * use static_call() and not static_call_cond() to catch any fails.
13*3b7c27e6SThomas Gleixner  */
14*3b7c27e6SThomas Gleixner #define DEFINE_APIC_CALL(__cb)						\
15*3b7c27e6SThomas Gleixner 	DEFINE_STATIC_CALL_NULL(apic_call_##__cb, *apic->__cb)
16*3b7c27e6SThomas Gleixner 
17*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(eoi);
18*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(native_eoi);
19*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(icr_read);
20*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(icr_write);
21*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(read);
22*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(send_IPI);
23*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(send_IPI_mask);
24*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(send_IPI_mask_allbutself);
25*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(send_IPI_allbutself);
26*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(send_IPI_all);
27*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(send_IPI_self);
28*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(wait_icr_idle);
29*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(wakeup_secondary_cpu);
30*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(wakeup_secondary_cpu_64);
31*3b7c27e6SThomas Gleixner DEFINE_APIC_CALL(write);
32*3b7c27e6SThomas Gleixner 
33*3b7c27e6SThomas Gleixner EXPORT_STATIC_CALL_TRAMP_GPL(apic_call_send_IPI_mask);
34*3b7c27e6SThomas Gleixner EXPORT_STATIC_CALL_TRAMP_GPL(apic_call_send_IPI_self);
35*3b7c27e6SThomas Gleixner 
36bef4f379SThomas Gleixner /* The container for function call overrides */
37bef4f379SThomas Gleixner struct apic_override __x86_apic_override __initdata;
38bef4f379SThomas Gleixner 
39bef4f379SThomas Gleixner #define apply_override(__cb)					\
40bef4f379SThomas Gleixner 	if (__x86_apic_override.__cb)				\
41bef4f379SThomas Gleixner 		apic->__cb = __x86_apic_override.__cb
42bef4f379SThomas Gleixner 
restore_override_callbacks(void)43bef4f379SThomas Gleixner static __init void restore_override_callbacks(void)
44bef4f379SThomas Gleixner {
45bef4f379SThomas Gleixner 	apply_override(eoi);
46bef4f379SThomas Gleixner 	apply_override(native_eoi);
47bef4f379SThomas Gleixner 	apply_override(write);
48bef4f379SThomas Gleixner 	apply_override(read);
49bef4f379SThomas Gleixner 	apply_override(send_IPI);
50bef4f379SThomas Gleixner 	apply_override(send_IPI_mask);
51bef4f379SThomas Gleixner 	apply_override(send_IPI_mask_allbutself);
52bef4f379SThomas Gleixner 	apply_override(send_IPI_allbutself);
53bef4f379SThomas Gleixner 	apply_override(send_IPI_all);
54bef4f379SThomas Gleixner 	apply_override(send_IPI_self);
55bef4f379SThomas Gleixner 	apply_override(icr_read);
56bef4f379SThomas Gleixner 	apply_override(icr_write);
57bef4f379SThomas Gleixner 	apply_override(wakeup_secondary_cpu);
58bef4f379SThomas Gleixner 	apply_override(wakeup_secondary_cpu_64);
59bef4f379SThomas Gleixner }
60bef4f379SThomas Gleixner 
61*3b7c27e6SThomas Gleixner #define update_call(__cb)					\
62*3b7c27e6SThomas Gleixner 	static_call_update(apic_call_##__cb, *apic->__cb)
63*3b7c27e6SThomas Gleixner 
update_static_calls(void)64*3b7c27e6SThomas Gleixner static __init void update_static_calls(void)
65*3b7c27e6SThomas Gleixner {
66*3b7c27e6SThomas Gleixner 	update_call(eoi);
67*3b7c27e6SThomas Gleixner 	update_call(native_eoi);
68*3b7c27e6SThomas Gleixner 	update_call(write);
69*3b7c27e6SThomas Gleixner 	update_call(read);
70*3b7c27e6SThomas Gleixner 	update_call(send_IPI);
71*3b7c27e6SThomas Gleixner 	update_call(send_IPI_mask);
72*3b7c27e6SThomas Gleixner 	update_call(send_IPI_mask_allbutself);
73*3b7c27e6SThomas Gleixner 	update_call(send_IPI_allbutself);
74*3b7c27e6SThomas Gleixner 	update_call(send_IPI_all);
75*3b7c27e6SThomas Gleixner 	update_call(send_IPI_self);
76*3b7c27e6SThomas Gleixner 	update_call(icr_read);
77*3b7c27e6SThomas Gleixner 	update_call(icr_write);
78*3b7c27e6SThomas Gleixner 	update_call(wait_icr_idle);
79*3b7c27e6SThomas Gleixner 	update_call(wakeup_secondary_cpu);
80*3b7c27e6SThomas Gleixner 	update_call(wakeup_secondary_cpu_64);
81*3b7c27e6SThomas Gleixner }
82*3b7c27e6SThomas Gleixner 
apic_setup_apic_calls(void)83bef4f379SThomas Gleixner void __init apic_setup_apic_calls(void)
84bef4f379SThomas Gleixner {
85bef4f379SThomas Gleixner 	/* Ensure that the default APIC has native_eoi populated */
86bef4f379SThomas Gleixner 	apic->native_eoi = apic->eoi;
87*3b7c27e6SThomas Gleixner 	update_static_calls();
88*3b7c27e6SThomas Gleixner 	pr_info("Static calls initialized\n");
89bef4f379SThomas Gleixner }
90bef4f379SThomas Gleixner 
apic_install_driver(struct apic * driver)913af1e415SThomas Gleixner void __init apic_install_driver(struct apic *driver)
923af1e415SThomas Gleixner {
933af1e415SThomas Gleixner 	if (apic == driver)
943af1e415SThomas Gleixner 		return;
953af1e415SThomas Gleixner 
963af1e415SThomas Gleixner 	apic = driver;
973af1e415SThomas Gleixner 
983af1e415SThomas Gleixner 	if (IS_ENABLED(CONFIG_X86_X2APIC) && apic->x2apic_set_max_apicid)
993af1e415SThomas Gleixner 		apic->max_apic_id = x2apic_max_apicid;
1003af1e415SThomas Gleixner 
101bef4f379SThomas Gleixner 	/* Copy the original eoi() callback as KVM/HyperV might overwrite it */
102bef4f379SThomas Gleixner 	if (!apic->native_eoi)
103bef4f379SThomas Gleixner 		apic->native_eoi = apic->eoi;
104bef4f379SThomas Gleixner 
105bef4f379SThomas Gleixner 	/* Apply any already installed callback overrides */
106bef4f379SThomas Gleixner 	restore_override_callbacks();
107*3b7c27e6SThomas Gleixner 	update_static_calls();
108bef4f379SThomas Gleixner 
1093af1e415SThomas Gleixner 	pr_info("Switched APIC routing to: %s\n", driver->name);
1103af1e415SThomas Gleixner }
111