blob: 2de5dd57df0c29b980253440a1997554882a2ac5 [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{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030013 if (CONFIG(XAPIC_ONLY))
14 return false;
15
16 if (CONFIG(X2APIC_ONLY))
17 return true;
18
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070019 msr_t msr;
20 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070021 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070022}
23
24static inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
25{
26 msr_t icr;
27 icr.hi = apicid;
28 icr.lo = icrlow;
29 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
30}
31
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010032static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000033{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070034 uint32_t value, index;
35 msr_t msr;
36
37 if (is_x2apic_mode()) {
38 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
39 msr = rdmsr(index);
40 value = msr.lo;
41 } else {
42 value = read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
43 }
44 return value;
Eric Biedermanc84c1902004-10-14 20:13:01 +000045}
46
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010047static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000048{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070049 msr_t msr;
50 uint32_t index;
51 if (is_x2apic_mode()) {
52 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
53 msr.hi = 0x0;
54 msr.lo = v;
55 wrmsr(index, msr);
56 } else {
57 write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
58 }
Eric Biedermanc84c1902004-10-14 20:13:01 +000059}
60
Aaron Durbin75a62e72018-09-13 02:10:45 -060061static __always_inline void lapic_wait_icr_idle(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000062{
Lee Leahy91d1e762017-03-07 14:31:19 -080063 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
Eric Biedermanc84c1902004-10-14 20:13:01 +000064}
65
Eric Biedermanc84c1902004-10-14 20:13:01 +000066static inline void enable_lapic(void)
67{
Eric Biedermanc84c1902004-10-14 20:13:01 +000068 msr_t msr;
69 msr = rdmsr(LAPIC_BASE_MSR);
70 msr.hi &= 0xffffff00;
Kyösti Mälkkiff284f62017-08-18 12:11:16 +030071 msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
72 msr.lo |= LAPIC_DEFAULT_BASE;
73 msr.lo |= LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +000074 wrmsr(LAPIC_BASE_MSR, msr);
75}
76
77static inline void disable_lapic(void)
78{
79 msr_t msr;
80 msr = rdmsr(LAPIC_BASE_MSR);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +030081 msr.lo &= ~LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +000082 wrmsr(LAPIC_BASE_MSR, msr);
83}
84
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070085static __always_inline unsigned int initial_lapicid(void)
86{
87 uint32_t lapicid;
Wonkyu Kima04256f2021-04-27 01:52:57 -070088 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
89 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070090 else
91 lapicid = cpuid_ebx(1) >> 24;
92 return lapicid;
93}
94
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010095static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000096{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070097 uint32_t lapicid = lapic_read(LAPIC_ID);
98
99 /* check x2apic mode and return accordingly */
100 if (!is_x2apic_mode())
101 lapicid >>= 24;
102 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000103}
104
Julius Wernercd49cce2019-03-05 16:53:33 -0800105#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200106/* If we need to go back to sipi wait, we use the long non-inlined version of
107 * this function in lapic_cpu_init.c
108 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600109static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000110{
Sven Schnelle51676b12012-07-29 19:18:03 +0200111 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100112 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000113}
Sven Schnelle51676b12012-07-29 19:18:03 +0200114#else
115void stop_this_cpu(void);
116#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000117
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100118static inline void lapic_write_atomic(unsigned long reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000119{
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100120 volatile uint32_t *ptr;
121
122 ptr = (volatile uint32_t *)(LAPIC_DEFAULT_BASE + reg);
123
124 asm volatile ("xchgl %0, %1\n"
125 : "+r" (v), "+m" (*(ptr))
126 : : "memory", "cc");
Eric Biedermanc84c1902004-10-14 20:13:01 +0000127}
128
Eric Biedermanc84c1902004-10-14 20:13:01 +0000129# define lapic_read_around(x) lapic_read(x)
Lee Leahyae3fd342017-03-07 12:55:23 -0800130# define lapic_write_around(x, y) lapic_write_atomic((x), (y))
Eric Biedermanc84c1902004-10-14 20:13:01 +0000131
Felix Held215ac3b2020-10-30 15:40:54 +0100132void lapic_virtual_wire_mode_init(void);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000133
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300134/* See if I need to initialize the local APIC */
135static inline int need_lapic_init(void)
136{
Julius Wernercd49cce2019-03-05 16:53:33 -0800137 return CONFIG(SMP) || CONFIG(IOAPIC);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300138}
Eric Biedermanc84c1902004-10-14 20:13:01 +0000139
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300140static inline void setup_lapic(void)
141{
142 if (need_lapic_init())
Felix Held215ac3b2020-10-30 15:40:54 +0100143 lapic_virtual_wire_mode_init();
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300144 else
145 disable_lapic();
146}
147
Eric Biedermanc84c1902004-10-14 20:13:01 +0000148#endif /* CPU_X86_LAPIC_H */