blob: f7fecf134207fa91d80cdec7d97e8ddf020e0418 [file] [log] [blame]
Martin Roth239b5df2022-07-26 22:18:26 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
Eric Biedermanc84c1902004-10-14 20:13:01 +00003#ifndef CPU_X86_LAPIC_H
4#define CPU_X86_LAPIC_H
5
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -07006#include <arch/cpu.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +00007#include <cpu/x86/lapic_def.h>
8#include <cpu/x86/msr.h>
Elyes Haouas8823ba12022-12-05 08:48:50 +01009#include <device/mmio.h>
Patrick Georgibd79c5e2014-11-28 22:35:36 +010010#include <halt.h>
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010011#include <stdint.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +000012
Kyösti Mälkki41e62162021-05-31 12:38:41 +030013static __always_inline uint32_t xapic_read(unsigned int reg)
14{
15 return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
16}
17
18static __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
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020023static __always_inline void xapic_send_ipi(uint32_t icrlow, uint32_t icrhi)
Arthur Heymans6f77ff72021-05-21 09:32:45 +020024{
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020025 xapic_write(LAPIC_ICR2, icrhi);
Kyösti Mälkkib31b0332021-05-31 14:41:15 +030026 xapic_write(LAPIC_ICR, icrlow);
Arthur Heymans6f77ff72021-05-21 09:32:45 +020027}
28
Arthur Heymansa4ceba42021-05-21 09:32:45 +020029static __always_inline int xapic_busy(void)
30{
31 return xapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
32}
33
Kyösti Mälkki41e62162021-05-31 12:38:41 +030034static __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
45static __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
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020056static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t icrhi)
Kyösti Mälkki41e62162021-05-31 12:38:41 +030057{
58 msr_t icr;
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +020059 icr.hi = icrhi;
Kyösti Mälkki41e62162021-05-31 12:38:41 +030060 icr.lo = icrlow;
61 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
62}
63
Kyösti Mälkkic8d26c02021-06-06 17:07:25 +030064static __always_inline bool is_x2apic_mode(void)
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070065{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030066 if (CONFIG(XAPIC_ONLY))
67 return false;
68
69 if (CONFIG(X2APIC_ONLY))
70 return true;
71
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070072 msr_t msr;
73 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070074 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070075}
76
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010077static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000078{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030079 if (is_x2apic_mode())
80 return x2apic_read(reg);
81 else
82 return xapic_read(reg);
Eric Biedermanc84c1902004-10-14 20:13:01 +000083}
84
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010085static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000086{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030087 if (is_x2apic_mode())
88 x2apic_write(reg, v);
89 else
90 xapic_write(reg, v);
Eric Biedermanc84c1902004-10-14 20:13:01 +000091}
92
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +030093static __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;
Kyösti Mälkkib31b0332021-05-31 14:41:15 +0300108 xapic_write(reg, value);
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +0300109 }
110}
111
Arthur Heymans6f77ff72021-05-21 09:32:45 +0200112static __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
Kyösti Mälkki0c1158b2022-01-03 14:54:27 +0200117 xapic_send_ipi(icrlow, SET_LAPIC_DEST_FIELD(apicid));
Arthur Heymans6f77ff72021-05-21 09:32:45 +0200118}
119
Arthur Heymansa4ceba42021-05-21 09:32:45 +0200120static __always_inline int lapic_busy(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000121{
Arthur Heymansa4ceba42021-05-21 09:32:45 +0200122 if (is_x2apic_mode())
123 return 0;
124 else
125 return xapic_busy();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000126}
127
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700128static __always_inline unsigned int initial_lapicid(void)
129{
130 uint32_t lapicid;
Felix Held49be1a92022-02-09 22:07:29 +0100131 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
Wonkyu Kima04256f2021-04-27 01:52:57 -0700132 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700133 else
134 lapicid = cpuid_ebx(1) >> 24;
135 return lapicid;
136}
137
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100138static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000139{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700140 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;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000146}
147
Kyösti Mälkki710bdc42021-10-15 17:14:20 +0300148static __always_inline void lapic_send_ipi_self(uint32_t icrlow)
149{
Kyösti Mälkki7aea15a2021-10-15 17:14:20 +0300150 int i = 1000;
151
Kyösti Mälkki710bdc42021-10-15 17:14:20 +0300152 /* LAPIC_DEST_SELF does not support all delivery mode -fields. */
153 lapic_send_ipi(icrlow, lapicid());
Kyösti Mälkki7aea15a2021-10-15 17:14:20 +0300154
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 */
Arthur Heymansf158c9c2022-08-31 09:43:45 +0200158 const bool x2apic = is_x2apic_mode();
159
160 while (x2apic && i--)
Kyösti Mälkki7aea15a2021-10-15 17:14:20 +0300161 cpu_relax();
Kyösti Mälkki710bdc42021-10-15 17:14:20 +0300162}
163
164static __always_inline void lapic_send_ipi_others(uint32_t icrlow)
165{
166 lapic_send_ipi(LAPIC_DEST_ALLBUT | icrlow, 0);
167}
168
Julius Wernercd49cce2019-03-05 16:53:33 -0800169#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200170/* 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 +0300171 * this function in lapic_cpu_stop.c
Sven Schnelle51676b12012-07-29 19:18:03 +0200172 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600173static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000174{
Sven Schnelle51676b12012-07-29 19:18:03 +0200175 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100176 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000177}
Sven Schnelle51676b12012-07-29 19:18:03 +0200178#else
179void stop_this_cpu(void);
180#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000181
Kyösti Mälkki242f1d92021-06-06 16:58:19 +0300182void enable_lapic(void);
Subrata Banik2125a172022-07-12 10:55:21 +0000183void enable_lapic_mode(bool try_set_x2apic);
Kyösti Mälkki242f1d92021-06-06 16:58:19 +0300184void disable_lapic(void);
Kyösti Mälkki9ec72272021-10-17 08:34:31 +0300185void setup_lapic_interrupts(void);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300186
Eric Biedermanc84c1902004-10-14 20:13:01 +0000187#endif /* CPU_X86_LAPIC_H */