blob: 87a4cc1e31ad63e556527a49a303e956c0da1482 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/* **********************************************************
2 * Copyright 2002 VMware, Inc. All rights reserved. -- VMware Confidential
3 * **********************************************************/
4
5
6#ifndef _SMP_H_
7#define _SMP_H_
8#include "stdint.h"
9#include "defs.h"
10#define MAX_CPUS 32
11
12#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24))
13
14typedef struct {
15 uint32_t signature; // "_MP_"
16 uint32_t phys_addr;
17 uint8_t length;
18 uint8_t spec_rev;
19 uint8_t checksum;
20 uint8_t feature[5];
21} floating_pointer_struct_t;
22
23#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
24typedef struct {
25 uint32_t signature; // "PCMP"
26 uint16_t length;
27 uint8_t spec_rev;
28 uint8_t checksum;
29 char oem[8];
30 char productid[12];
31 uint32_t oem_ptr;
32 uint16_t oem_size;
33 uint16_t oem_count;
34 uint32_t lapic_addr;
35 uint32_t reserved;
36} mp_config_table_header_t;
37
38/* Followed by entries */
39
40#define MP_PROCESSOR 0
41#define MP_BUS 1
42#define MP_IOAPIC 2
43#define MP_INTSRC 3
44#define MP_LINTSRC 4
45
46typedef struct {
47 uint8_t type; /* MP_PROCESSOR */
48 uint8_t apic_id; /* Local APIC number */
49 uint8_t apic_ver; /* Its versions */
50 uint8_t cpu_flag;
51#define CPU_ENABLED 1 /* Processor is available */
52#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
Martin Roth4dcd13d2016-02-24 13:53:07 -080053 uint32_t cpu_signature;
Martin Roth9b1b3352016-02-24 12:27:06 -080054#define CPU_STEPPING_MASK 0x0F
55#define CPU_MODEL_MASK 0xF0
56#define CPU_FAMILY_MASK 0xF00
57 uint32_t featureflag; /* CPUID feature value */
58 uint32_t reserved[2];
59} mp_processor_entry_t;
60
61typedef struct {
62 uint8_t type; // has value MP_BUS
63 uint8_t busid;
64 char bustype[6];
65} mp_bus_entry_t;
66
67/* We don't understand the others */
68
69typedef struct {
70 uint8_t type; // set to MP_IOAPIC
71 uint8_t apicid;
72 uint8_t apicver;
73 uint8_t flags;
74#define MPC_APIC_USABLE 0x01
75 uint32_t apicaddr;
76} mp_io_apic_entry_t;
77
78
79typedef struct {
80 uint8_t type;
81 uint8_t irqtype;
82 uint16_t irqflag;
83 uint8_t srcbus;
84 uint8_t srcbusirq;
85 uint8_t dstapic;
86 uint8_t dstirq;
87} mp_interrupt_entry_t;
88
89#define MP_INT_VECTORED 0
90#define MP_INT_NMI 1
91#define MP_INT_SMI 2
92#define MP_INT_EXTINT 3
93
94#define MP_IRQDIR_DEFAULT 0
95#define MP_IRQDIR_HIGH 1
96#define MP_IRQDIR_LOW 3
97
98
99typedef struct {
100 uint8_t type;
101 uint8_t irqtype;
102 uint16_t irqflag;
103 uint8_t srcbusid;
104 uint8_t srcbusirq;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800105 uint8_t destapic;
Martin Roth9b1b3352016-02-24 12:27:06 -0800106#define MP_APIC_ALL 0xFF
107 uint8_t destapiclint;
108} mp_local_interrupt_entry_t;
109
110#define RSDPSignature ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
111typedef struct {
112 char signature[8]; // "RSD "
113 uint8_t checksum;
114 char oemid[6];
Martin Roth4dcd13d2016-02-24 13:53:07 -0800115 uint8_t revision;
Martin Roth9b1b3352016-02-24 12:27:06 -0800116 uint32_t rsdt;
117 uint32_t length;
118 uint32_t xrsdt[2];
119 uint8_t xsum;
120} rsdp_t;
121
122#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24))
123#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24))
124typedef struct {
125 char signature[4]; // "RSDT"
126 uint32_t length;
Martin Roth4dcd13d2016-02-24 13:53:07 -0800127 uint8_t revision;
Martin Roth9b1b3352016-02-24 12:27:06 -0800128 uint8_t checksum;
129 char oemid[18];
130 char cid[4];
131 char cver[4];
132} rsdt_t;
133
134#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24))
135typedef struct {
Martin Roth4dcd13d2016-02-24 13:53:07 -0800136 uint8_t type;
Martin Roth9b1b3352016-02-24 12:27:06 -0800137 uint8_t length;
138 uint8_t acpi_id;
139 uint8_t apic_id; /* Local APIC number */
140 uint32_t enabled;
141} madt_processor_entry_t;
142
143/* APIC definitions */
144/*
145 * APIC registers
146 */
147#define APICR_ID 0x02
148#define APICR_ESR 0x28
149#define APICR_ICRLO 0x30
150#define APICR_ICRHI 0x31
151
152/* APIC destination shorthands */
153#define APIC_DEST_DEST 0
154#define APIC_DEST_LOCAL 1
155#define APIC_DEST_ALL_INC 2
156#define APIC_DEST_ALL_EXC 3
157
158/* APIC IPI Command Register format */
159#define APIC_ICRHI_RESERVED 0x00ffffff
160#define APIC_ICRHI_DEST_MASK 0xff000000
161#define APIC_ICRHI_DEST_OFFSET 24
162
163#define APIC_ICRLO_RESERVED 0xfff32000
164#define APIC_ICRLO_DEST_MASK 0x000c0000
165#define APIC_ICRLO_DEST_OFFSET 18
166#define APIC_ICRLO_TRIGGER_MASK 0x00008000
167#define APIC_ICRLO_TRIGGER_OFFSET 15
168#define APIC_ICRLO_LEVEL_MASK 0x00004000
169#define APIC_ICRLO_LEVEL_OFFSET 14
170#define APIC_ICRLO_STATUS_MASK 0x00001000
171#define APIC_ICRLO_STATUS_OFFSET 12
172#define APIC_ICRLO_DESTMODE_MASK 0x00000800
173#define APIC_ICRLO_DESTMODE_OFFSET 11
174#define APIC_ICRLO_DELMODE_MASK 0x00000700
175#define APIC_ICRLO_DELMODE_OFFSET 8
176#define APIC_ICRLO_VECTOR_MASK 0x000000ff
177#define APIC_ICRLO_VECTOR_OFFSET 0
178
179/* APIC trigger types (edge/level) */
180#define APIC_TRIGGER_EDGE 0
181#define APIC_TRIGGER_LEVEL 1
182
183/* APIC delivery modes */
184#define APIC_DELMODE_FIXED 0
185#define APIC_DELMODE_LOWEST 1
186#define APIC_DELMODE_SMI 2
187#define APIC_DELMODE_NMI 4
188#define APIC_DELMODE_INIT 5
189#define APIC_DELMODE_STARTUP 6
190#define APIC_DELMODE_EXTINT 7
191typedef uint32_t apic_register_t[4];
192
193extern volatile apic_register_t *APIC;
194
195unsigned smp_my_cpu_num();
196
197void smp_init_bsp(void);
198void smp_init_aps(void);
199
200void smp_boot_ap(unsigned cpu_num);
201void smp_ap_booted(unsigned cpu_num);
202
203typedef struct {
204 unsigned int slock;
205} spinlock_t;
206
207struct barrier_s
208{
209 spinlock_t mutex;
210 spinlock_t lck;
211 int maxproc;
212 volatile int count;
213 spinlock_t st1;
214 spinlock_t st2;
215 spinlock_t s_lck;
216 int s_maxproc;
217 volatile int s_count;
218 spinlock_t s_st1;
219 spinlock_t s_st2;
220};
221
222void barrier();
223void s_barrier();
224void barrier_init(int max);
225void s_barrier_init(int max);
226
227static inline void
228__GET_CPUID(int ax, uint32_t *regs)
229{
230 __asm__ __volatile__("\t"
231 /* save ebx in case -fPIC is being used */
232 "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
233 : "=a" (regs[0]), "=D" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
234 : "a" (ax)
235 : "memory"
236 );
237}
238
239#define GET_CPUID(_ax,_bx,_cx,_dx) { \
240 uint32_t regs[4]; \
241 __GET_CPUID(_ax,regs); \
242 _ax = regs[0]; \
243 _bx = regs[1]; \
244 _cx = regs[2]; \
245 _dx = regs[3]; \
246}
247
248/*
249 * Checked against the Intel manual and GCC --hpreg
250 *
251 * volatile because the tsc always changes without the compiler knowing it.
252 */
253static inline uint64_t
254RDTSC(void)
255{
256 uint64_t tim;
257
258 __asm__ __volatile__(
259 "rdtsc"
260 : "=A" (tim)
261 );
262
263 return tim;
264}
265
266static inline uint64_t __GET_MSR(int cx)
267{
268 uint64_t msr;
269
270 __asm__ __volatile__(
271 "rdmsr"
272 : "=A" (msr)
273 : "c" (cx)
274 );
275
276 return msr;
277}
278
279#define __GCC_OUT(s, s2, port, val) do { \
280 __asm__( \
281 "out" #s " %" #s2 "1, %w0" \
282 : \
283 : "Nd" (port), "a" (val) \
284 ); \
285} while (0)
286#define OUTB(port, val) __GCC_OUT(b, b, port, val)
287
288static inline void spin_wait(spinlock_t *lck)
289{
290 if (cpu_id.fid.bits.mon) {
291 /* Use monitor/mwait for a low power, low contention spin */
292 asm volatile(
293 "movl $0,%%ecx\n\t"
294 "movl %%ecx, %%edx\n\t"
295 "1:\n\t"
296 "movl %%edi,%%eax\n\t"
297 "monitor\n\t"
298 "cmpb $0,(%%edi)\n\t"
299 "jne 2f\n\t"
300 "movl %%ecx, %%eax\n\t"
301 "mwait\n\t"
302 "jmp 1b\n"
303 "2:"
304 : : "D" (lck): "%eax", "%ecx", "%edx"
305 );
306 } else {
307 /* No monitor/mwait so just spin with a lot of nop's */
308 int inc = 0x400;
309 asm volatile(
310 "1:\t"
311 "cmpb $0,%1\n\t"
312 "jne 2f\n\t"
313 "rep ; nop\n\t"
314 "jmp 1b\n"
315 "2:"
316 : : "c" (inc), "m" (lck->slock): "memory"
317 );
318 }
319}
320
321static inline void spin_lock(spinlock_t *lck)
322{
323 if (cpu_id.fid.bits.mon) {
324 /* Use monitor/mwait for a low power, low contention spin */
325 asm volatile(
326 "\n1:\t"
327 " ; lock;decb (%%edi)\n\t"
328 "jns 3f\n"
329 "movl $0,%%ecx\n\t"
330 "movl %%ecx, %%edx\n\t"
331 "2:\t"
332 "movl %%edi,%%eax\n\t"
333 "monitor\n\t"
334 "movl %%ecx, %%eax\n\t"
335 "mwait\n\t"
336 "cmpb $0,(%%edi)\n\t"
337 "jle 2b\n\t"
338 "jmp 1b\n"
339 "3:\n\t"
340 : : "D" (lck): "%eax", "%ecx", "%edx"
341 );
342 } else {
343 /* No monitor/mwait so just spin with a lot of nop's */
344 int inc = 0x400;
345 asm volatile(
346 "\n1:\t"
347 " ; lock;decb %0\n\t"
348 "jns 3f\n"
349 "2:\t"
350 "rep;nop\n\t"
351 "cmpb $0,%0\n\t"
352 "jle 2b\n\t"
353 "jmp 1b\n"
354 "3:\n\t"
355 : "+m" (lck->slock) : "c" (inc) : "memory"
356 );
357 }
358}
359
360static inline void spin_unlock(spinlock_t *lock)
361{
362 asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory");
363}
364
365
366#endif /* _SMP_H_ */