xref: /openbmc/u-boot/arch/x86/include/asm/lapic.h (revision 0c9075e9)
13eafce05SSimon Glass /*
23eafce05SSimon Glass  * From Coreboot file of same name
33eafce05SSimon Glass  *
43eafce05SSimon Glass  * Copyright (C) 2014 Google, Inc
53eafce05SSimon Glass  *
63eafce05SSimon Glass  * SPDX-License-Identifier:	GPL-2.0
73eafce05SSimon Glass  */
83eafce05SSimon Glass 
93eafce05SSimon Glass #ifndef _ARCH_ASM_LAPIC_H
103eafce05SSimon Glass #define _ARCH_ASM_LAPIC_H
113eafce05SSimon Glass 
123eafce05SSimon Glass #include <asm/io.h>
133eafce05SSimon Glass #include <asm/lapic_def.h>
143eafce05SSimon Glass #include <asm/msr.h>
153eafce05SSimon Glass #include <asm/processor.h>
163eafce05SSimon Glass 
17*0c9075e9SSimon Glass /* See if I need to initialize the local apic */
18*0c9075e9SSimon Glass #if CONFIG_SMP || CONFIG_IOAPIC
19*0c9075e9SSimon Glass #  define NEED_LAPIC 1
20*0c9075e9SSimon Glass #else
21*0c9075e9SSimon Glass #  define NEED_LAPIC 0
22*0c9075e9SSimon Glass #endif
23*0c9075e9SSimon Glass 
243eafce05SSimon Glass static inline __attribute__((always_inline))
253eafce05SSimon Glass 		unsigned long lapic_read(unsigned long reg)
263eafce05SSimon Glass {
273eafce05SSimon Glass 	return readl(LAPIC_DEFAULT_BASE + reg);
283eafce05SSimon Glass }
293eafce05SSimon Glass 
303eafce05SSimon Glass static inline __attribute__((always_inline))
313eafce05SSimon Glass 		void lapic_write(unsigned long reg, unsigned long val)
323eafce05SSimon Glass {
333eafce05SSimon Glass 	writel(val, LAPIC_DEFAULT_BASE + reg);
343eafce05SSimon Glass }
353eafce05SSimon Glass 
363eafce05SSimon Glass static inline __attribute__((always_inline)) void lapic_wait_icr_idle(void)
373eafce05SSimon Glass {
383eafce05SSimon Glass 	do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
393eafce05SSimon Glass }
403eafce05SSimon Glass 
413eafce05SSimon Glass static inline void enable_lapic(void)
423eafce05SSimon Glass {
433eafce05SSimon Glass 	msr_t msr;
443eafce05SSimon Glass 
453eafce05SSimon Glass 	msr = msr_read(LAPIC_BASE_MSR);
463eafce05SSimon Glass 	msr.hi &= 0xffffff00;
47*0c9075e9SSimon Glass 	msr.lo |= LAPIC_BASE_MSR_ENABLE;
48*0c9075e9SSimon Glass 	msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
49*0c9075e9SSimon Glass 	msr.lo |= LAPIC_DEFAULT_BASE;
503eafce05SSimon Glass 	msr_write(LAPIC_BASE_MSR, msr);
513eafce05SSimon Glass }
523eafce05SSimon Glass 
533eafce05SSimon Glass static inline void disable_lapic(void)
543eafce05SSimon Glass {
553eafce05SSimon Glass 	msr_t msr;
563eafce05SSimon Glass 
573eafce05SSimon Glass 	msr = msr_read(LAPIC_BASE_MSR);
583eafce05SSimon Glass 	msr.lo &= ~(1 << 11);
593eafce05SSimon Glass 	msr_write(LAPIC_BASE_MSR, msr);
603eafce05SSimon Glass }
613eafce05SSimon Glass 
623eafce05SSimon Glass static inline __attribute__((always_inline)) unsigned long lapicid(void)
633eafce05SSimon Glass {
643eafce05SSimon Glass 	return lapic_read(LAPIC_ID) >> 24;
653eafce05SSimon Glass }
663eafce05SSimon Glass 
67*0c9075e9SSimon Glass #if !CONFIG_AP_IN_SIPI_WAIT
68*0c9075e9SSimon Glass /* If we need to go back to sipi wait, we use the long non-inlined version of
69*0c9075e9SSimon Glass  * this function in lapic_cpu_init.c
70*0c9075e9SSimon Glass  */
71*0c9075e9SSimon Glass static inline __attribute__((always_inline)) void stop_this_cpu(void)
72*0c9075e9SSimon Glass {
73*0c9075e9SSimon Glass 	/* Called by an AP when it is ready to halt and wait for a new task */
74*0c9075e9SSimon Glass 	for (;;)
75*0c9075e9SSimon Glass 		cpu_hlt();
76*0c9075e9SSimon Glass }
77*0c9075e9SSimon Glass #else
78*0c9075e9SSimon Glass void stop_this_cpu(void);
79*0c9075e9SSimon Glass #endif
80*0c9075e9SSimon Glass 
81*0c9075e9SSimon Glass #define xchg(ptr, v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), \
82*0c9075e9SSimon Glass 							sizeof(*(ptr))))
83*0c9075e9SSimon Glass 
84*0c9075e9SSimon Glass struct __xchg_dummy { unsigned long a[100]; };
85*0c9075e9SSimon Glass #define __xg(x) ((struct __xchg_dummy *)(x))
86*0c9075e9SSimon Glass 
87*0c9075e9SSimon Glass /*
88*0c9075e9SSimon Glass  * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
89*0c9075e9SSimon Glass  * Note 2: xchg has side effect, so that attribute volatile is necessary,
90*0c9075e9SSimon Glass  *	  but generally the primitive is invalid, *ptr is output argument. --ANK
91*0c9075e9SSimon Glass  */
92*0c9075e9SSimon Glass static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
93*0c9075e9SSimon Glass 				   int size)
94*0c9075e9SSimon Glass {
95*0c9075e9SSimon Glass 	switch (size) {
96*0c9075e9SSimon Glass 	case 1:
97*0c9075e9SSimon Glass 		__asm__ __volatile__("xchgb %b0,%1"
98*0c9075e9SSimon Glass 			: "=q" (x)
99*0c9075e9SSimon Glass 			: "m" (*__xg(ptr)), "0" (x)
100*0c9075e9SSimon Glass 			: "memory");
101*0c9075e9SSimon Glass 		break;
102*0c9075e9SSimon Glass 	case 2:
103*0c9075e9SSimon Glass 		__asm__ __volatile__("xchgw %w0,%1"
104*0c9075e9SSimon Glass 			: "=r" (x)
105*0c9075e9SSimon Glass 			: "m" (*__xg(ptr)), "0" (x)
106*0c9075e9SSimon Glass 			: "memory");
107*0c9075e9SSimon Glass 		break;
108*0c9075e9SSimon Glass 	case 4:
109*0c9075e9SSimon Glass 		__asm__ __volatile__("xchgl %0,%1"
110*0c9075e9SSimon Glass 			: "=r" (x)
111*0c9075e9SSimon Glass 			: "m" (*__xg(ptr)), "0" (x)
112*0c9075e9SSimon Glass 			: "memory");
113*0c9075e9SSimon Glass 		break;
114*0c9075e9SSimon Glass 	}
115*0c9075e9SSimon Glass 
116*0c9075e9SSimon Glass 	return x;
117*0c9075e9SSimon Glass }
118*0c9075e9SSimon Glass 
119*0c9075e9SSimon Glass static inline void lapic_write_atomic(unsigned long reg, unsigned long v)
120*0c9075e9SSimon Glass {
121*0c9075e9SSimon Glass 	(void)xchg((volatile unsigned long *)(LAPIC_DEFAULT_BASE + reg), v);
122*0c9075e9SSimon Glass }
123*0c9075e9SSimon Glass 
124*0c9075e9SSimon Glass 
125*0c9075e9SSimon Glass #ifdef X86_GOOD_APIC
126*0c9075e9SSimon Glass # define FORCE_READ_AROUND_WRITE 0
127*0c9075e9SSimon Glass # define lapic_read_around(x) lapic_read(x)
128*0c9075e9SSimon Glass # define lapic_write_around(x, y) lapic_write((x), (y))
129*0c9075e9SSimon Glass #else
130*0c9075e9SSimon Glass # define FORCE_READ_AROUND_WRITE 1
131*0c9075e9SSimon Glass # define lapic_read_around(x) lapic_read(x)
132*0c9075e9SSimon Glass # define lapic_write_around(x, y) lapic_write_atomic((x), (y))
133*0c9075e9SSimon Glass #endif
134*0c9075e9SSimon Glass 
135*0c9075e9SSimon Glass static inline int lapic_remote_read(int apicid, int reg, unsigned long *pvalue)
136*0c9075e9SSimon Glass {
137*0c9075e9SSimon Glass 	int timeout;
138*0c9075e9SSimon Glass 	unsigned long status;
139*0c9075e9SSimon Glass 	int result;
140*0c9075e9SSimon Glass 	lapic_wait_icr_idle();
141*0c9075e9SSimon Glass 	lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
142*0c9075e9SSimon Glass 	lapic_write_around(LAPIC_ICR, LAPIC_DM_REMRD | (reg >> 4));
143*0c9075e9SSimon Glass 	timeout = 0;
144*0c9075e9SSimon Glass 	do {
145*0c9075e9SSimon Glass 		status = lapic_read(LAPIC_ICR) & LAPIC_ICR_RR_MASK;
146*0c9075e9SSimon Glass 	} while (status == LAPIC_ICR_RR_INPROG && timeout++ < 1000);
147*0c9075e9SSimon Glass 
148*0c9075e9SSimon Glass 	result = -1;
149*0c9075e9SSimon Glass 	if (status == LAPIC_ICR_RR_VALID) {
150*0c9075e9SSimon Glass 		*pvalue = lapic_read(LAPIC_RRR);
151*0c9075e9SSimon Glass 		result = 0;
152*0c9075e9SSimon Glass 	}
153*0c9075e9SSimon Glass 	return result;
154*0c9075e9SSimon Glass }
155*0c9075e9SSimon Glass 
156*0c9075e9SSimon Glass 
157*0c9075e9SSimon Glass void lapic_setup(void);
158*0c9075e9SSimon Glass 
159*0c9075e9SSimon Glass #if CONFIG_SMP
160*0c9075e9SSimon Glass struct device;
161*0c9075e9SSimon Glass int start_cpu(struct device *cpu);
162*0c9075e9SSimon Glass #endif /* CONFIG_SMP */
163*0c9075e9SSimon Glass 
164*0c9075e9SSimon Glass int boot_cpu(void);
165*0c9075e9SSimon Glass 
166*0c9075e9SSimon Glass /**
167*0c9075e9SSimon Glass  * struct x86_cpu_priv - Information about a single CPU
168*0c9075e9SSimon Glass  *
169*0c9075e9SSimon Glass  * @apic_id: Advanced Programmable Interrupt Controller Identifier, which is
170*0c9075e9SSimon Glass  * just a number representing the CPU core
171*0c9075e9SSimon Glass  *
172*0c9075e9SSimon Glass  * TODO: Move this to driver model once lifecycle is understood
173*0c9075e9SSimon Glass  */
174*0c9075e9SSimon Glass struct x86_cpu_priv {
175*0c9075e9SSimon Glass 	int apic_id;
176*0c9075e9SSimon Glass 	int start_err;
177*0c9075e9SSimon Glass };
178*0c9075e9SSimon Glass 
1793eafce05SSimon Glass #endif
180