blob: 717fc9aa3847555503abab8f9a2898522619510b [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
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070011static inline bool is_x2apic_mode(void)
12{
13 msr_t msr;
14 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070015 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070016}
17
18static inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
19{
20 msr_t icr;
21 icr.hi = apicid;
22 icr.lo = icrlow;
23 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
24}
25
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010026static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000027{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070028 uint32_t value, index;
29 msr_t msr;
30
31 if (is_x2apic_mode()) {
32 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
33 msr = rdmsr(index);
34 value = msr.lo;
35 } else {
36 value = read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
37 }
38 return value;
Eric Biedermanc84c1902004-10-14 20:13:01 +000039}
40
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010041static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000042{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070043 msr_t msr;
44 uint32_t index;
45 if (is_x2apic_mode()) {
46 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
47 msr.hi = 0x0;
48 msr.lo = v;
49 wrmsr(index, msr);
50 } else {
51 write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
52 }
Eric Biedermanc84c1902004-10-14 20:13:01 +000053}
54
Aaron Durbin75a62e72018-09-13 02:10:45 -060055static __always_inline void lapic_wait_icr_idle(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000056{
Lee Leahy91d1e762017-03-07 14:31:19 -080057 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
Eric Biedermanc84c1902004-10-14 20:13:01 +000058}
59
Eric Biedermanc84c1902004-10-14 20:13:01 +000060static inline void enable_lapic(void)
61{
Eric Biedermanc84c1902004-10-14 20:13:01 +000062 msr_t msr;
63 msr = rdmsr(LAPIC_BASE_MSR);
64 msr.hi &= 0xffffff00;
Kyösti Mälkkiff284f62017-08-18 12:11:16 +030065 msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
66 msr.lo |= LAPIC_DEFAULT_BASE;
67 msr.lo |= LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +000068 wrmsr(LAPIC_BASE_MSR, msr);
69}
70
71static inline void disable_lapic(void)
72{
73 msr_t msr;
74 msr = rdmsr(LAPIC_BASE_MSR);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +030075 msr.lo &= ~LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +000076 wrmsr(LAPIC_BASE_MSR, msr);
77}
78
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070079static __always_inline unsigned int initial_lapicid(void)
80{
81 uint32_t lapicid;
Wonkyu Kima04256f2021-04-27 01:52:57 -070082 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
83 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070084 else
85 lapicid = cpuid_ebx(1) >> 24;
86 return lapicid;
87}
88
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010089static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000090{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070091 uint32_t lapicid = lapic_read(LAPIC_ID);
92
93 /* check x2apic mode and return accordingly */
94 if (!is_x2apic_mode())
95 lapicid >>= 24;
96 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +000097}
98
Julius Wernercd49cce2019-03-05 16:53:33 -080099#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200100/* If we need to go back to sipi wait, we use the long non-inlined version of
101 * this function in lapic_cpu_init.c
102 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600103static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000104{
Sven Schnelle51676b12012-07-29 19:18:03 +0200105 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100106 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000107}
Sven Schnelle51676b12012-07-29 19:18:03 +0200108#else
109void stop_this_cpu(void);
110#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000111
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100112static inline void lapic_write_atomic(unsigned long reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000113{
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100114 volatile uint32_t *ptr;
115
116 ptr = (volatile uint32_t *)(LAPIC_DEFAULT_BASE + reg);
117
118 asm volatile ("xchgl %0, %1\n"
119 : "+r" (v), "+m" (*(ptr))
120 : : "memory", "cc");
Eric Biedermanc84c1902004-10-14 20:13:01 +0000121}
122
Eric Biedermanc84c1902004-10-14 20:13:01 +0000123# define lapic_read_around(x) lapic_read(x)
Lee Leahyae3fd342017-03-07 12:55:23 -0800124# define lapic_write_around(x, y) lapic_write_atomic((x), (y))
Eric Biedermanc84c1902004-10-14 20:13:01 +0000125
Felix Held215ac3b2020-10-30 15:40:54 +0100126void lapic_virtual_wire_mode_init(void);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000127
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300128/* See if I need to initialize the local APIC */
129static inline int need_lapic_init(void)
130{
Julius Wernercd49cce2019-03-05 16:53:33 -0800131 return CONFIG(SMP) || CONFIG(IOAPIC);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300132}
Eric Biedermanc84c1902004-10-14 20:13:01 +0000133
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300134static inline void setup_lapic(void)
135{
136 if (need_lapic_init())
Felix Held215ac3b2020-10-30 15:40:54 +0100137 lapic_virtual_wire_mode_init();
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300138 else
139 disable_lapic();
140}
141
Eric Biedermanc84c1902004-10-14 20:13:01 +0000142struct device;
143int start_cpu(struct device *cpu);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000144
Eric Biedermanc84c1902004-10-14 20:13:01 +0000145#endif /* CPU_X86_LAPIC_H */