blob: e19458f06c9d19d688c38394639ff9b92ee8b4e3 [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
32#define lapic_read_around(x) lapic_read(x)
33#define lapic_write_around(x, y) xapic_write_atomic((x), (y))
34
35
36static __always_inline uint32_t x2apic_read(unsigned int reg)
37{
38 uint32_t value, index;
39 msr_t msr;
40
41 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
42 msr = rdmsr(index);
43 value = msr.lo;
44 return value;
45}
46
47static __always_inline void x2apic_write(unsigned int reg, uint32_t v)
48{
49 uint32_t index;
50 msr_t msr;
51
52 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
53 msr.hi = 0x0;
54 msr.lo = v;
55 wrmsr(index, msr);
56}
57
58static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
59{
60 msr_t icr;
61 icr.hi = apicid;
62 icr.lo = icrlow;
63 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
64}
65
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070066static inline bool is_x2apic_mode(void)
67{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030068 if (CONFIG(XAPIC_ONLY))
69 return false;
70
71 if (CONFIG(X2APIC_ONLY))
72 return true;
73
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070074 msr_t msr;
75 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070076 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070077}
78
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010079static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000080{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030081 if (is_x2apic_mode())
82 return x2apic_read(reg);
83 else
84 return xapic_read(reg);
Eric Biedermanc84c1902004-10-14 20:13:01 +000085}
86
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010087static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000088{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030089 if (is_x2apic_mode())
90 x2apic_write(reg, v);
91 else
92 xapic_write(reg, v);
Eric Biedermanc84c1902004-10-14 20:13:01 +000093}
94
Aaron Durbin75a62e72018-09-13 02:10:45 -060095static __always_inline void lapic_wait_icr_idle(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000096{
Lee Leahy91d1e762017-03-07 14:31:19 -080097 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
Eric Biedermanc84c1902004-10-14 20:13:01 +000098}
99
Eric Biedermanc84c1902004-10-14 20:13:01 +0000100static inline void enable_lapic(void)
101{
Eric Biedermanc84c1902004-10-14 20:13:01 +0000102 msr_t msr;
103 msr = rdmsr(LAPIC_BASE_MSR);
104 msr.hi &= 0xffffff00;
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300105 msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
106 msr.lo |= LAPIC_DEFAULT_BASE;
107 msr.lo |= LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000108 wrmsr(LAPIC_BASE_MSR, msr);
109}
110
111static inline void disable_lapic(void)
112{
113 msr_t msr;
114 msr = rdmsr(LAPIC_BASE_MSR);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300115 msr.lo &= ~LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000116 wrmsr(LAPIC_BASE_MSR, msr);
117}
118
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700119static __always_inline unsigned int initial_lapicid(void)
120{
121 uint32_t lapicid;
Wonkyu Kima04256f2021-04-27 01:52:57 -0700122 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
123 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700124 else
125 lapicid = cpuid_ebx(1) >> 24;
126 return lapicid;
127}
128
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100129static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000130{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700131 uint32_t lapicid = lapic_read(LAPIC_ID);
132
133 /* check x2apic mode and return accordingly */
134 if (!is_x2apic_mode())
135 lapicid >>= 24;
136 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000137}
138
Julius Wernercd49cce2019-03-05 16:53:33 -0800139#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200140/* If we need to go back to sipi wait, we use the long non-inlined version of
141 * this function in lapic_cpu_init.c
142 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600143static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000144{
Sven Schnelle51676b12012-07-29 19:18:03 +0200145 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100146 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000147}
Sven Schnelle51676b12012-07-29 19:18:03 +0200148#else
149void stop_this_cpu(void);
150#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000151
Felix Held215ac3b2020-10-30 15:40:54 +0100152void lapic_virtual_wire_mode_init(void);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000153
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300154/* See if I need to initialize the local APIC */
155static inline int need_lapic_init(void)
156{
Julius Wernercd49cce2019-03-05 16:53:33 -0800157 return CONFIG(SMP) || CONFIG(IOAPIC);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300158}
Eric Biedermanc84c1902004-10-14 20:13:01 +0000159
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300160static inline void setup_lapic(void)
161{
162 if (need_lapic_init())
Felix Held215ac3b2020-10-30 15:40:54 +0100163 lapic_virtual_wire_mode_init();
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300164 else
165 disable_lapic();
166}
167
Eric Biedermanc84c1902004-10-14 20:13:01 +0000168#endif /* CPU_X86_LAPIC_H */