blob: 8108174ecd21a1289bf0e07694dd1edbf989ef0b [file] [log] [blame]
Eric Biedermanc84c1902004-10-14 20:13:01 +00001#ifndef CPU_X86_LAPIC_H
2#define CPU_X86_LAPIC_H
3
4#include <cpu/x86/lapic_def.h>
5#include <cpu/x86/msr.h>
Patrick Georgibd79c5e2014-11-28 22:35:36 +01006#include <halt.h>
Kyösti Mälkki5a5c8862014-01-26 14:41:54 +02007#include <smp/node.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +00008
Aaron Durbin75a62e72018-09-13 02:10:45 -06009static __always_inline unsigned long lapic_read(unsigned long reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000010{
11 return *((volatile unsigned long *)(LAPIC_DEFAULT_BASE+reg));
12}
13
Aaron Durbin75a62e72018-09-13 02:10:45 -060014static __always_inline void lapic_write(unsigned long reg, unsigned long v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000015{
16 *((volatile unsigned long *)(LAPIC_DEFAULT_BASE+reg)) = v;
17}
18
Aaron Durbin75a62e72018-09-13 02:10:45 -060019static __always_inline void lapic_wait_icr_idle(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000020{
Lee Leahy91d1e762017-03-07 14:31:19 -080021 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
Eric Biedermanc84c1902004-10-14 20:13:01 +000022}
23
Eric Biedermanc84c1902004-10-14 20:13:01 +000024static inline void enable_lapic(void)
25{
Eric Biedermanc84c1902004-10-14 20:13:01 +000026 msr_t msr;
27 msr = rdmsr(LAPIC_BASE_MSR);
28 msr.hi &= 0xffffff00;
Kyösti Mälkkiff284f62017-08-18 12:11:16 +030029 msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
30 msr.lo |= LAPIC_DEFAULT_BASE;
31 msr.lo |= LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +000032 wrmsr(LAPIC_BASE_MSR, msr);
33}
34
35static inline void disable_lapic(void)
36{
37 msr_t msr;
38 msr = rdmsr(LAPIC_BASE_MSR);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +030039 msr.lo &= ~LAPIC_BASE_MSR_ENABLE;
Eric Biedermanc84c1902004-10-14 20:13:01 +000040 wrmsr(LAPIC_BASE_MSR, msr);
41}
42
Aaron Durbin75a62e72018-09-13 02:10:45 -060043static __always_inline unsigned long lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000044{
45 return lapic_read(LAPIC_ID) >> 24;
46}
47
Julius Wernercd49cce2019-03-05 16:53:33 -080048#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +020049/* If we need to go back to sipi wait, we use the long non-inlined version of
50 * this function in lapic_cpu_init.c
51 */
Aaron Durbin75a62e72018-09-13 02:10:45 -060052static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +000053{
Sven Schnelle51676b12012-07-29 19:18:03 +020054 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +010055 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +000056}
Sven Schnelle51676b12012-07-29 19:18:03 +020057#else
58void stop_this_cpu(void);
59#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +000060
Stefan Reinauer35b6bbb2010-03-28 21:26:54 +000061#if !defined(__PRE_RAM__)
Eric Biedermanc84c1902004-10-14 20:13:01 +000062
Lee Leahy6a566d72017-03-07 17:45:12 -080063#define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
64 sizeof(*(ptr))))
Eric Biedermanc84c1902004-10-14 20:13:01 +000065
66struct __xchg_dummy { unsigned long a[100]; };
67#define __xg(x) ((struct __xchg_dummy *)(x))
68
69/*
70 * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
71 * Note 2: xchg has side effect, so that attribute volatile is necessary,
72 * but generally the primitive is invalid, *ptr is output argument. --ANK
73 */
Lee Leahy6a566d72017-03-07 17:45:12 -080074static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
75 int size)
Eric Biedermanc84c1902004-10-14 20:13:01 +000076{
77 switch (size) {
Lee Leahydb469a62017-03-08 10:05:16 -080078 case 1:
79 __asm__ __volatile__("xchgb %b0,%1"
Lee Leahy74f1dc02017-03-08 10:08:08 -080080 : "=q" (x)
81 : "m" (*__xg(ptr)), "0" (x)
82 : "memory");
Lee Leahydb469a62017-03-08 10:05:16 -080083 break;
84 case 2:
85 __asm__ __volatile__("xchgw %w0,%1"
Lee Leahy74f1dc02017-03-08 10:08:08 -080086 : "=r" (x)
87 : "m" (*__xg(ptr)), "0" (x)
88 : "memory");
Lee Leahydb469a62017-03-08 10:05:16 -080089 break;
90 case 4:
91 __asm__ __volatile__("xchgl %0,%1"
Lee Leahy74f1dc02017-03-08 10:08:08 -080092 : "=r" (x)
93 : "m" (*__xg(ptr)), "0" (x)
94 : "memory");
Lee Leahydb469a62017-03-08 10:05:16 -080095 break;
Eric Biedermanc84c1902004-10-14 20:13:01 +000096 }
97 return x;
98}
99
Stefan Reinauer68524062008-08-02 15:15:23 +0000100static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000101{
Patrick Georgi1a341652012-03-11 19:42:33 +0100102 (void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE+reg), v);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000103}
104
105
Myles Watson0bc61542009-10-17 13:25:07 +0000106#ifdef X86_GOOD_APIC
Eric Biedermanc84c1902004-10-14 20:13:01 +0000107# define FORCE_READ_AROUND_WRITE 0
108# define lapic_read_around(x) lapic_read(x)
Lee Leahyae3fd342017-03-07 12:55:23 -0800109# define lapic_write_around(x, y) lapic_write((x), (y))
Eric Biedermanc84c1902004-10-14 20:13:01 +0000110#else
111# define FORCE_READ_AROUND_WRITE 1
112# define lapic_read_around(x) lapic_read(x)
Lee Leahyae3fd342017-03-07 12:55:23 -0800113# define lapic_write_around(x, y) lapic_write_atomic((x), (y))
Eric Biedermanc84c1902004-10-14 20:13:01 +0000114#endif
115
116static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
117{
118 int timeout;
119 unsigned long status;
120 int result;
121 lapic_wait_icr_idle();
122 lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
123 lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
124 timeout = 0;
125 do {
126#if 0
127 udelay(100);
128#endif
129 status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
130 } while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
131
132 result = -1;
133 if (status == LAPIC_ICR_RR_VALID) {
134 *pvalue = lapic_read(LAPIC_RRR);
135 result = 0;
136 }
137 return result;
138}
139
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300140void do_lapic_init(void);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000141
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300142/* See if I need to initialize the local APIC */
143static inline int need_lapic_init(void)
144{
Julius Wernercd49cce2019-03-05 16:53:33 -0800145 return CONFIG(SMP) || CONFIG(IOAPIC);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300146}
Eric Biedermanc84c1902004-10-14 20:13:01 +0000147
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300148static inline void setup_lapic(void)
149{
150 if (need_lapic_init())
151 do_lapic_init();
152 else
153 disable_lapic();
154}
155
Eric Biedermanc84c1902004-10-14 20:13:01 +0000156struct device;
157int start_cpu(struct device *cpu);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000158
Stefan Reinauer35b6bbb2010-03-28 21:26:54 +0000159#endif /* !__PRE_RAM__ */
Eric Biedermanc84c1902004-10-14 20:13:01 +0000160
Eric Biedermanc84c1902004-10-14 20:13:01 +0000161#endif /* CPU_X86_LAPIC_H */