blob: e131d2ec46aa89d2cded029bae6759c8b2361fe1 [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
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020021static __always_inline void xapic_send_ipi(uint32_t icrlow, uint32_t icrhi)
Arthur Heymans6f77ff72021-05-21 09:32:45 +020022{
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020023 xapic_write(LAPIC_ICR2, icrhi);
Kyösti Mälkkib31b0332021-05-31 14:41:15 +030024 xapic_write(LAPIC_ICR, icrlow);
Arthur Heymans6f77ff72021-05-21 09:32:45 +020025}
26
Arthur Heymansa4ceba42021-05-21 09:32:45 +020027static __always_inline int xapic_busy(void)
28{
29 return xapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
30}
31
Kyösti Mälkki41e62162021-05-31 12:38:41 +030032static __always_inline uint32_t x2apic_read(unsigned int reg)
33{
34 uint32_t value, index;
35 msr_t msr;
36
37 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
38 msr = rdmsr(index);
39 value = msr.lo;
40 return value;
41}
42
43static __always_inline void x2apic_write(unsigned int reg, uint32_t v)
44{
45 uint32_t index;
46 msr_t msr;
47
48 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
49 msr.hi = 0x0;
50 msr.lo = v;
51 wrmsr(index, msr);
52}
53
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020054static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t icrhi)
Kyösti Mälkki41e62162021-05-31 12:38:41 +030055{
56 msr_t icr;
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020057 icr.hi = icrhi;
Kyösti Mälkki41e62162021-05-31 12:38:41 +030058 icr.lo = icrlow;
59 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
60}
61
Kyösti Mälkkic8d26c02021-06-06 17:07:25 +030062static __always_inline bool is_x2apic_mode(void)
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070063{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030064 if (CONFIG(XAPIC_ONLY))
65 return false;
66
67 if (CONFIG(X2APIC_ONLY))
68 return true;
69
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070070 msr_t msr;
71 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070072 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070073}
74
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010075static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000076{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030077 if (is_x2apic_mode())
78 return x2apic_read(reg);
79 else
80 return xapic_read(reg);
Eric Biedermanc84c1902004-10-14 20:13:01 +000081}
82
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010083static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000084{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030085 if (is_x2apic_mode())
86 x2apic_write(reg, v);
87 else
88 xapic_write(reg, v);
Eric Biedermanc84c1902004-10-14 20:13:01 +000089}
90
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +030091static __always_inline void lapic_update32(unsigned int reg, uint32_t mask, uint32_t or)
92{
93 if (is_x2apic_mode()) {
94 uint32_t index;
95 msr_t msr;
96 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
97 msr = rdmsr(index);
98 msr.lo &= mask;
99 msr.lo |= or;
100 wrmsr(index, msr);
101 } else {
102 uint32_t value;
103 value = xapic_read(reg);
104 value &= mask;
105 value |= or;
Kyösti Mälkkib31b0332021-05-31 14:41:15 +0300106 xapic_write(reg, value);
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +0300107 }
108}
109
Arthur Heymans6f77ff72021-05-21 09:32:45 +0200110static __always_inline void lapic_send_ipi(uint32_t icrlow, uint32_t apicid)
111{
112 if (is_x2apic_mode())
113 x2apic_send_ipi(icrlow, apicid);
114 else
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +0200115 xapic_send_ipi(icrlow, SET_LAPIC_DEST_FIELD(apicid));
Arthur Heymans6f77ff72021-05-21 09:32:45 +0200116}
117
Arthur Heymansa4ceba42021-05-21 09:32:45 +0200118static __always_inline int lapic_busy(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000119{
Arthur Heymansa4ceba42021-05-21 09:32:45 +0200120 if (is_x2apic_mode())
121 return 0;
122 else
123 return xapic_busy();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000124}
125
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700126static __always_inline unsigned int initial_lapicid(void)
127{
128 uint32_t lapicid;
Kyösti Mälkkiceaf9592021-10-16 18:12:53 +0300129 if (cpuid_get_max_func() >= 0xb)
Wonkyu Kima04256f2021-04-27 01:52:57 -0700130 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700131 else
132 lapicid = cpuid_ebx(1) >> 24;
133 return lapicid;
134}
135
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100136static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000137{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700138 uint32_t lapicid = lapic_read(LAPIC_ID);
139
140 /* check x2apic mode and return accordingly */
141 if (!is_x2apic_mode())
142 lapicid >>= 24;
143 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000144}
145
Kyösti Mälkki710bdc42021-10-15 17:14:20 +0300146static __always_inline void lapic_send_ipi_self(uint32_t icrlow)
147{
Kyösti Mälkki7aea15a2021-10-15 17:14:20 +0300148 int i = 1000;
149
Kyösti Mälkki710bdc42021-10-15 17:14:20 +0300150 /* LAPIC_DEST_SELF does not support all delivery mode -fields. */
151 lapic_send_ipi(icrlow, lapicid());
Kyösti Mälkki7aea15a2021-10-15 17:14:20 +0300152
153 /* In case of X2APIC force a short delay, to prevent deadlock in a case
154 * the immediately following code acquires some lock, like with printk().
155 */
156 while (CONFIG(X2APIC_ONLY) && i--)
157 cpu_relax();
Kyösti Mälkki710bdc42021-10-15 17:14:20 +0300158}
159
160static __always_inline void lapic_send_ipi_others(uint32_t icrlow)
161{
162 lapic_send_ipi(LAPIC_DEST_ALLBUT | icrlow, 0);
163}
164
Julius Wernercd49cce2019-03-05 16:53:33 -0800165#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200166/* If we need to go back to sipi wait, we use the long non-inlined version of
Kyösti Mälkki36c90172021-05-29 22:50:22 +0300167 * this function in lapic_cpu_stop.c
Sven Schnelle51676b12012-07-29 19:18:03 +0200168 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600169static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000170{
Sven Schnelle51676b12012-07-29 19:18:03 +0200171 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100172 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000173}
Sven Schnelle51676b12012-07-29 19:18:03 +0200174#else
175void stop_this_cpu(void);
176#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000177
Kyösti Mälkki242f1d92021-06-06 16:58:19 +0300178void enable_lapic(void);
179void disable_lapic(void);
180void setup_lapic(void);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300181
Eric Biedermanc84c1902004-10-14 20:13:01 +0000182#endif /* CPU_X86_LAPIC_H */