blob: 1db0ff46d122b84fa68ba9ee6ba47cba255f71c1 [file] [log] [blame]
Eric Biedermanc84c1902004-10-14 20:13:01 +00001#ifndef CPU_X86_LAPIC_H
2#define CPU_X86_LAPIC_H
3
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +01004#include <arch/mmio.h>
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -07005#include <arch/cpu.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +00006#include <cpu/x86/lapic_def.h>
7#include <cpu/x86/msr.h>
Patrick Georgibd79c5e2014-11-28 22:35:36 +01008#include <halt.h>
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +01009#include <stdint.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +000010
Kyösti Mälkki41e62162021-05-31 12:38:41 +030011static __always_inline uint32_t xapic_read(unsigned int reg)
12{
13 return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
14}
15
16static __always_inline void xapic_write(unsigned int reg, uint32_t v)
17{
18 write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
19}
20
21static inline void xapic_write_atomic(unsigned long reg, uint32_t v)
22{
23 volatile uint32_t *ptr;
24
25 ptr = (volatile uint32_t *)(LAPIC_DEFAULT_BASE + reg);
26
27 asm volatile ("xchgl %0, %1\n"
28 : "+r" (v), "+m" (*(ptr))
29 : : "memory", "cc");
30}
31
Arthur Heymans6f77ff72021-05-21 09:32:45 +020032static __always_inline void xapic_send_ipi(uint32_t icrlow, uint32_t apicid)
33{
34 xapic_write_atomic(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
35 xapic_write_atomic(LAPIC_ICR, icrlow);
36}
37
Kyösti Mälkki41e62162021-05-31 12:38:41 +030038#define lapic_read_around(x) lapic_read(x)
39#define lapic_write_around(x, y) xapic_write_atomic((x), (y))
40
Kyösti Mälkki41e62162021-05-31 12:38:41 +030041static __always_inline uint32_t x2apic_read(unsigned int reg)
42{
43 uint32_t value, index;
44 msr_t msr;
45
46 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
47 msr = rdmsr(index);
48 value = msr.lo;
49 return value;
50}
51
52static __always_inline void x2apic_write(unsigned int reg, uint32_t v)
53{
54 uint32_t index;
55 msr_t msr;
56
57 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
58 msr.hi = 0x0;
59 msr.lo = v;
60 wrmsr(index, msr);
61}
62
63static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
64{
65 msr_t icr;
66 icr.hi = apicid;
67 icr.lo = icrlow;
68 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
69}
70
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070071static inline bool is_x2apic_mode(void)
72{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030073 if (CONFIG(XAPIC_ONLY))
74 return false;
75
76 if (CONFIG(X2APIC_ONLY))
77 return true;
78
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070079 msr_t msr;
80 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070081 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070082}
83
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010084static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000085{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030086 if (is_x2apic_mode())
87 return x2apic_read(reg);
88 else
89 return xapic_read(reg);
Eric Biedermanc84c1902004-10-14 20:13:01 +000090}
91
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010092static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000093{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030094 if (is_x2apic_mode())
95 x2apic_write(reg, v);
96 else
97 xapic_write(reg, v);
Eric Biedermanc84c1902004-10-14 20:13:01 +000098}
99
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +0300100static __always_inline void lapic_update32(unsigned int reg, uint32_t mask, uint32_t or)
101{
102 if (is_x2apic_mode()) {
103 uint32_t index;
104 msr_t msr;
105 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
106 msr = rdmsr(index);
107 msr.lo &= mask;
108 msr.lo |= or;
109 wrmsr(index, msr);
110 } else {
111 uint32_t value;
112 value = xapic_read(reg);
113 value &= mask;
114 value |= or;
115 xapic_write_atomic(reg, value);
116 }
117}
118
Arthur Heymans6f77ff72021-05-21 09:32:45 +0200119static __always_inline void lapic_send_ipi(uint32_t icrlow, uint32_t apicid)
120{
121 if (is_x2apic_mode())
122 x2apic_send_ipi(icrlow, apicid);
123 else
124 xapic_send_ipi(icrlow, apicid);
125}
126
Aaron Durbin75a62e72018-09-13 02:10:45 -0600127static __always_inline void lapic_wait_icr_idle(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000128{
Lee Leahy91d1e762017-03-07 14:31:19 -0800129 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000130}
131
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700132static __always_inline unsigned int initial_lapicid(void)
133{
134 uint32_t lapicid;
Wonkyu Kima04256f2021-04-27 01:52:57 -0700135 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
136 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700137 else
138 lapicid = cpuid_ebx(1) >> 24;
139 return lapicid;
140}
141
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100142static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000143{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700144 uint32_t lapicid = lapic_read(LAPIC_ID);
145
146 /* check x2apic mode and return accordingly */
147 if (!is_x2apic_mode())
148 lapicid >>= 24;
149 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000150}
151
Julius Wernercd49cce2019-03-05 16:53:33 -0800152#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200153/* If we need to go back to sipi wait, we use the long non-inlined version of
154 * this function in lapic_cpu_init.c
155 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600156static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000157{
Sven Schnelle51676b12012-07-29 19:18:03 +0200158 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100159 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000160}
Sven Schnelle51676b12012-07-29 19:18:03 +0200161#else
162void stop_this_cpu(void);
163#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000164
Kyösti Mälkki242f1d92021-06-06 16:58:19 +0300165void enable_lapic(void);
166void disable_lapic(void);
167void setup_lapic(void);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300168
Eric Biedermanc84c1902004-10-14 20:13:01 +0000169#endif /* CPU_X86_LAPIC_H */