1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #ifndef CPU_X86_LAPIC_H
4 #define CPU_X86_LAPIC_H
5
6 #include <arch/cpu.h>
7 #include <cpu/x86/lapic_def.h>
8 #include <cpu/x86/msr.h>
9 #include <device/mmio.h>
10 #include <halt.h>
11 #include <stdint.h>
12
xapic_read(unsigned int reg)13 static __always_inline uint32_t xapic_read(unsigned int reg)
14 {
15 return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
16 }
17
xapic_write(unsigned int reg,uint32_t v)18 static __always_inline void xapic_write(unsigned int reg, uint32_t v)
19 {
20 write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
21 }
22
xapic_send_ipi(uint32_t icrlow,uint32_t icrhi)23 static __always_inline void xapic_send_ipi(uint32_t icrlow, uint32_t icrhi)
24 {
25 xapic_write(LAPIC_ICR2, icrhi);
26 xapic_write(LAPIC_ICR, icrlow);
27 }
28
xapic_busy(void)29 static __always_inline int xapic_busy(void)
30 {
31 return xapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
32 }
33
x2apic_read(unsigned int reg)34 static __always_inline uint32_t x2apic_read(unsigned int reg)
35 {
36 uint32_t value, index;
37 msr_t msr;
38
39 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
40 msr = rdmsr(index);
41 value = msr.lo;
42 return value;
43 }
44
x2apic_write(unsigned int reg,uint32_t v)45 static __always_inline void x2apic_write(unsigned int reg, uint32_t v)
46 {
47 uint32_t index;
48 msr_t msr;
49
50 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
51 msr.hi = 0x0;
52 msr.lo = v;
53 wrmsr(index, msr);
54 }
55
x2apic_send_ipi(uint32_t icrlow,uint32_t icrhi)56 static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t icrhi)
57 {
58 msr_t icr;
59 icr.hi = icrhi;
60 icr.lo = icrlow;
61 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
62 }
63
is_x2apic_mode(void)64 static __always_inline bool is_x2apic_mode(void)
65 {
66 if (CONFIG(XAPIC_ONLY))
67 return false;
68
69 if (CONFIG(X2APIC_ONLY))
70 return true;
71
72 msr_t msr;
73 msr = rdmsr(LAPIC_BASE_MSR);
74 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
75 }
76
lapic_read(unsigned int reg)77 static __always_inline uint32_t lapic_read(unsigned int reg)
78 {
79 if (is_x2apic_mode())
80 return x2apic_read(reg);
81 else
82 return xapic_read(reg);
83 }
84
lapic_write(unsigned int reg,uint32_t v)85 static __always_inline void lapic_write(unsigned int reg, uint32_t v)
86 {
87 if (is_x2apic_mode())
88 x2apic_write(reg, v);
89 else
90 xapic_write(reg, v);
91 }
92
lapic_update32(unsigned int reg,uint32_t mask,uint32_t or)93 static __always_inline void lapic_update32(unsigned int reg, uint32_t mask, uint32_t or)
94 {
95 if (is_x2apic_mode()) {
96 uint32_t index;
97 msr_t msr;
98 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
99 msr = rdmsr(index);
100 msr.lo &= mask;
101 msr.lo |= or;
102 wrmsr(index, msr);
103 } else {
104 uint32_t value;
105 value = xapic_read(reg);
106 value &= mask;
107 value |= or;
108 xapic_write(reg, value);
109 }
110 }
111
lapic_send_ipi(uint32_t icrlow,uint32_t apicid)112 static __always_inline void lapic_send_ipi(uint32_t icrlow, uint32_t apicid)
113 {
114 if (is_x2apic_mode())
115 x2apic_send_ipi(icrlow, apicid);
116 else
117 xapic_send_ipi(icrlow, SET_LAPIC_DEST_FIELD(apicid));
118 }
119
lapic_busy(void)120 static __always_inline int lapic_busy(void)
121 {
122 if (is_x2apic_mode())
123 return 0;
124 else
125 return xapic_busy();
126 }
127
initial_lapicid(void)128 static __always_inline unsigned int initial_lapicid(void)
129 {
130 uint32_t lapicid;
131 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
132 lapicid = cpuid_ext(0xb, 0).edx;
133 else
134 lapicid = cpuid_ebx(1) >> 24;
135 return lapicid;
136 }
137
lapicid(void)138 static __always_inline unsigned int lapicid(void)
139 {
140 uint32_t lapicid = lapic_read(LAPIC_ID);
141
142 /* check x2apic mode and return accordingly */
143 if (!is_x2apic_mode())
144 lapicid >>= 24;
145 return lapicid;
146 }
147
lapic_send_ipi_self(uint32_t icrlow)148 static __always_inline void lapic_send_ipi_self(uint32_t icrlow)
149 {
150 int i = 1000;
151
152 /* LAPIC_DEST_SELF does not support all delivery mode -fields. */
153 lapic_send_ipi(icrlow, lapicid());
154
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().
157 */
158 const bool x2apic = is_x2apic_mode();
159
160 while (x2apic && i--)
161 cpu_relax();
162 }
163
lapic_send_ipi_others(uint32_t icrlow)164 static __always_inline void lapic_send_ipi_others(uint32_t icrlow)
165 {
166 lapic_send_ipi(LAPIC_DEST_ALLBUT | icrlow, 0);
167 }
168
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
172 */
stop_this_cpu(void)173 static __always_inline void stop_this_cpu(void)
174 {
175 /* Called by an AP when it is ready to halt and wait for a new task */
176 halt();
177 }
178 #else
179 void stop_this_cpu(void);
180 #endif
181
182 void enable_lapic(void);
183 void enable_lapic_mode(bool try_set_x2apic);
184 void disable_lapic(void);
185 void setup_lapic_interrupts(void);
186
early_lapicid(void)187 static inline unsigned int early_lapicid(void)
188 {
189 if (!CONFIG(SMP))
190 return 0;
191
192 if (!ENV_RAMSTAGE)
193 return 0;
194
195 enable_lapic();
196 return lapicid();
197 }
198
199 #endif /* CPU_X86_LAPIC_H */
200