1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #ifndef CPU_X86_LAPIC_H
4 #define CPU_X86_LAPIC_H
7 #include <cpu/x86/lapic_def.h>
8 #include <cpu/x86/msr.h>
9 #include <device/mmio.h>
13 static __always_inline
uint32_t xapic_read(unsigned int reg
)
15 return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE
+ reg
));
18 static __always_inline
void xapic_write(unsigned int reg
, uint32_t v
)
20 write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE
+ reg
), v
);
23 static __always_inline
void xapic_send_ipi(uint32_t icrlow
, uint32_t icrhi
)
25 xapic_write(LAPIC_ICR2
, icrhi
);
26 xapic_write(LAPIC_ICR
, icrlow
);
29 static __always_inline
int xapic_busy(void)
31 return xapic_read(LAPIC_ICR
) & LAPIC_ICR_BUSY
;
34 static __always_inline
uint32_t x2apic_read(unsigned int reg
)
36 uint32_t value
, index
;
39 index
= X2APIC_MSR_BASE_ADDRESS
+ (uint32_t)(reg
>> 4);
45 static __always_inline
void x2apic_write(unsigned int reg
, uint32_t v
)
50 index
= X2APIC_MSR_BASE_ADDRESS
+ (uint32_t)(reg
>> 4);
56 static __always_inline
void x2apic_send_ipi(uint32_t icrlow
, uint32_t icrhi
)
61 wrmsr(X2APIC_MSR_ICR_ADDRESS
, icr
);
64 static __always_inline
bool is_x2apic_mode(void)
66 if (CONFIG(XAPIC_ONLY
))
69 if (CONFIG(X2APIC_ONLY
))
73 msr
= rdmsr(LAPIC_BASE_MSR
);
74 return ((msr
.lo
& LAPIC_BASE_X2APIC_ENABLED
) == LAPIC_BASE_X2APIC_ENABLED
);
77 static __always_inline
uint32_t lapic_read(unsigned int reg
)
80 return x2apic_read(reg
);
82 return xapic_read(reg
);
85 static __always_inline
void lapic_write(unsigned int reg
, uint32_t v
)
93 static __always_inline
void lapic_update32(unsigned int reg
, uint32_t mask
, uint32_t or)
95 if (is_x2apic_mode()) {
98 index
= X2APIC_MSR_BASE_ADDRESS
+ (uint32_t)(reg
>> 4);
105 value
= xapic_read(reg
);
108 xapic_write(reg
, value
);
112 static __always_inline
void lapic_send_ipi(uint32_t icrlow
, uint32_t apicid
)
114 if (is_x2apic_mode())
115 x2apic_send_ipi(icrlow
, apicid
);
117 xapic_send_ipi(icrlow
, SET_LAPIC_DEST_FIELD(apicid
));
120 static __always_inline
int lapic_busy(void)
122 if (is_x2apic_mode())
128 static __always_inline
unsigned int initial_lapicid(void)
131 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
132 lapicid
= cpuid_ext(0xb, 0).edx
;
134 lapicid
= cpuid_ebx(1) >> 24;
138 static __always_inline
unsigned int lapicid(void)
140 uint32_t lapicid
= lapic_read(LAPIC_ID
);
142 /* check x2apic mode and return accordingly */
143 if (!is_x2apic_mode())
148 static __always_inline
void lapic_send_ipi_self(uint32_t icrlow
)
152 /* LAPIC_DEST_SELF does not support all delivery mode -fields. */
153 lapic_send_ipi(icrlow
, lapicid());
155 /* In case of X2APIC force a short delay, to prevent deadlock in a case
156 * the immediately following code acquires some lock, like with printk().
158 const bool x2apic
= is_x2apic_mode();
160 while (x2apic
&& i
--)
164 static __always_inline
void lapic_send_ipi_others(uint32_t icrlow
)
166 lapic_send_ipi(LAPIC_DEST_ALLBUT
| icrlow
, 0);
169 #if !CONFIG(AP_IN_SIPI_WAIT)
170 /* If we need to go back to sipi wait, we use the long non-inlined version of
171 * this function in lapic_cpu_stop.c
173 static __always_inline
void stop_this_cpu(void)
175 /* Called by an AP when it is ready to halt and wait for a new task */
179 void stop_this_cpu(void);
182 void enable_lapic(void);
183 void enable_lapic_mode(bool try_set_x2apic
);
184 void setup_lapic_interrupts(void);
186 static inline unsigned int early_lapicid(void)
198 #endif /* CPU_X86_LAPIC_H */