blob: 5d07ce75c5bc5cb2957184ba07ea6a4c3226437e [file] [log] [blame]
/* **********************************************************
* Copyright 2002 VMware, Inc. All rights reserved. -- VMware Confidential
* **********************************************************/
#ifndef _SMP_H_
#define _SMP_H_
#include "stdint.h"
#include "defs.h"
#define MAX_CPUS 32
#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24))
typedef struct {
uint32_t signature; // "_MP_"
uint32_t phys_addr;
uint8_t length;
uint8_t spec_rev;
uint8_t checksum;
uint8_t feature[5];
} floating_pointer_struct_t;
#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
typedef struct {
uint32_t signature; // "PCMP"
uint16_t length;
uint8_t spec_rev;
uint8_t checksum;
char oem[8];
char productid[12];
uint32_t oem_ptr;
uint16_t oem_size;
uint16_t oem_count;
uint32_t lapic_addr;
uint32_t reserved;
} mp_config_table_header_t;
/* Followed by entries */
#define MP_PROCESSOR 0
#define MP_BUS 1
#define MP_IOAPIC 2
#define MP_INTSRC 3
#define MP_LINTSRC 4
typedef struct {
uint8_t type; /* MP_PROCESSOR */
uint8_t apic_id; /* Local APIC number */
uint8_t apic_ver; /* Its versions */
uint8_t cpu_flag;
#define CPU_ENABLED 1 /* Processor is available */
#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */
uint32_t cpu_signature;
#define CPU_STEPPING_MASK 0x0F
#define CPU_MODEL_MASK 0xF0
#define CPU_FAMILY_MASK 0xF00
uint32_t featureflag; /* CPUID feature value */
uint32_t reserved[2];
} mp_processor_entry_t;
typedef struct {
uint8_t type; // has value MP_BUS
uint8_t busid;
char bustype[6];
} mp_bus_entry_t;
/* We don't understand the others */
typedef struct {
uint8_t type; // set to MP_IOAPIC
uint8_t apicid;
uint8_t apicver;
uint8_t flags;
#define MPC_APIC_USABLE 0x01
uint32_t apicaddr;
} mp_io_apic_entry_t;
typedef struct {
uint8_t type;
uint8_t irqtype;
uint16_t irqflag;
uint8_t srcbus;
uint8_t srcbusirq;
uint8_t dstapic;
uint8_t dstirq;
} mp_interrupt_entry_t;
#define MP_INT_VECTORED 0
#define MP_INT_NMI 1
#define MP_INT_SMI 2
#define MP_INT_EXTINT 3
#define MP_IRQDIR_DEFAULT 0
#define MP_IRQDIR_HIGH 1
#define MP_IRQDIR_LOW 3
typedef struct {
uint8_t type;
uint8_t irqtype;
uint16_t irqflag;
uint8_t srcbusid;
uint8_t srcbusirq;
uint8_t destapic;
#define MP_APIC_ALL 0xFF
uint8_t destapiclint;
} mp_local_interrupt_entry_t;
#define RSDPSignature ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
typedef struct {
char signature[8]; // "RSD "
uint8_t checksum;
char oemid[6];
uint8_t revision;
uint32_t rsdt;
uint32_t length;
uint32_t xrsdt[2];
uint8_t xsum;
} rsdp_t;
#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24))
#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24))
typedef struct {
char signature[4]; // "RSDT"
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oemid[18];
char cid[4];
char cver[4];
} rsdt_t;
#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24))
typedef struct {
uint8_t type;
uint8_t length;
uint8_t acpi_id;
uint8_t apic_id; /* Local APIC number */
uint32_t enabled;
} madt_processor_entry_t;
/* APIC definitions */
/*
* APIC registers
*/
#define APICR_ID 0x02
#define APICR_ESR 0x28
#define APICR_ICRLO 0x30
#define APICR_ICRHI 0x31
/* APIC destination shorthands */
#define APIC_DEST_DEST 0
#define APIC_DEST_LOCAL 1
#define APIC_DEST_ALL_INC 2
#define APIC_DEST_ALL_EXC 3
/* APIC IPI Command Register format */
#define APIC_ICRHI_RESERVED 0x00ffffff
#define APIC_ICRHI_DEST_MASK 0xff000000
#define APIC_ICRHI_DEST_OFFSET 24
#define APIC_ICRLO_RESERVED 0xfff32000
#define APIC_ICRLO_DEST_MASK 0x000c0000
#define APIC_ICRLO_DEST_OFFSET 18
#define APIC_ICRLO_TRIGGER_MASK 0x00008000
#define APIC_ICRLO_TRIGGER_OFFSET 15
#define APIC_ICRLO_LEVEL_MASK 0x00004000
#define APIC_ICRLO_LEVEL_OFFSET 14
#define APIC_ICRLO_STATUS_MASK 0x00001000
#define APIC_ICRLO_STATUS_OFFSET 12
#define APIC_ICRLO_DESTMODE_MASK 0x00000800
#define APIC_ICRLO_DESTMODE_OFFSET 11
#define APIC_ICRLO_DELMODE_MASK 0x00000700
#define APIC_ICRLO_DELMODE_OFFSET 8
#define APIC_ICRLO_VECTOR_MASK 0x000000ff
#define APIC_ICRLO_VECTOR_OFFSET 0
/* APIC trigger types (edge/level) */
#define APIC_TRIGGER_EDGE 0
#define APIC_TRIGGER_LEVEL 1
/* APIC delivery modes */
#define APIC_DELMODE_FIXED 0
#define APIC_DELMODE_LOWEST 1
#define APIC_DELMODE_SMI 2
#define APIC_DELMODE_NMI 4
#define APIC_DELMODE_INIT 5
#define APIC_DELMODE_STARTUP 6
#define APIC_DELMODE_EXTINT 7
typedef uint32_t apic_register_t[4];
extern volatile apic_register_t *APIC;
unsigned smp_my_cpu_num();
void smp_init_bsp(void);
void smp_init_aps(void);
void smp_boot_ap(unsigned cpu_num);
void smp_ap_booted(unsigned cpu_num);
typedef struct {
unsigned int slock;
} spinlock_t;
struct barrier_s
{
spinlock_t mutex;
spinlock_t lck;
int maxproc;
volatile int count;
spinlock_t st1;
spinlock_t st2;
spinlock_t s_lck;
int s_maxproc;
volatile int s_count;
spinlock_t s_st1;
spinlock_t s_st2;
};
void barrier();
void s_barrier();
void barrier_init(int max);
void s_barrier_init(int max);
static inline void
__GET_CPUID(int ax, uint32_t *regs)
{
__asm__ __volatile__("\t"
/* save ebx in case -fPIC is being used */
"push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
: "=a" (regs[0]), "=D" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
: "a" (ax)
: "memory"
);
}
#define GET_CPUID(_ax,_bx,_cx,_dx) { \
uint32_t regs[4]; \
__GET_CPUID(_ax,regs); \
_ax = regs[0]; \
_bx = regs[1]; \
_cx = regs[2]; \
_dx = regs[3]; \
}
/*
* Checked against the Intel manual and GCC --hpreg
*
* volatile because the tsc always changes without the compiler knowing it.
*/
static inline uint64_t
RDTSC(void)
{
uint64_t tim;
__asm__ __volatile__(
"rdtsc"
: "=A" (tim)
);
return tim;
}
static inline uint64_t __GET_MSR(int cx)
{
uint64_t msr;
__asm__ __volatile__(
"rdmsr"
: "=A" (msr)
: "c" (cx)
);
return msr;
}
#define __GCC_OUT(s, s2, port, val) do { \
__asm__( \
"out" #s " %" #s2 "1, %w0" \
: \
: "Nd" (port), "a" (val) \
); \
} while (0)
#define OUTB(port, val) __GCC_OUT(b, b, port, val)
static inline void spin_wait(spinlock_t *lck)
{
if (cpu_id.fid.bits.mon) {
/* Use monitor/mwait for a low power, low contention spin */
asm volatile(
"movl $0,%%ecx\n\t"
"movl %%ecx, %%edx\n\t"
"1:\n\t"
"movl %%edi,%%eax\n\t"
"monitor\n\t"
"cmpb $0,(%%edi)\n\t"
"jne 2f\n\t"
"movl %%ecx, %%eax\n\t"
"mwait\n\t"
"jmp 1b\n"
"2:"
: : "D" (lck): "%eax", "%ecx", "%edx"
);
} else {
/* No monitor/mwait so just spin with a lot of nop's */
int inc = 0x400;
asm volatile(
"1:\t"
"cmpb $0,%1\n\t"
"jne 2f\n\t"
"rep ; nop\n\t"
"jmp 1b\n"
"2:"
: : "c" (inc), "m" (lck->slock): "memory"
);
}
}
static inline void spin_lock(spinlock_t *lck)
{
if (cpu_id.fid.bits.mon) {
/* Use monitor/mwait for a low power, low contention spin */
asm volatile(
"\n1:\t"
" ; lock;decb (%%edi)\n\t"
"jns 3f\n"
"movl $0,%%ecx\n\t"
"movl %%ecx, %%edx\n\t"
"2:\t"
"movl %%edi,%%eax\n\t"
"monitor\n\t"
"movl %%ecx, %%eax\n\t"
"mwait\n\t"
"cmpb $0,(%%edi)\n\t"
"jle 2b\n\t"
"jmp 1b\n"
"3:\n\t"
: : "D" (lck): "%eax", "%ecx", "%edx"
);
} else {
/* No monitor/mwait so just spin with a lot of nop's */
int inc = 0x400;
asm volatile(
"\n1:\t"
" ; lock;decb %0\n\t"
"jns 3f\n"
"2:\t"
"rep;nop\n\t"
"cmpb $0,%0\n\t"
"jle 2b\n\t"
"jmp 1b\n"
"3:\n\t"
: "+m" (lck->slock) : "c" (inc) : "memory"
);
}
}
static inline void spin_unlock(spinlock_t *lock)
{
asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory");
}
#endif /* _SMP_H_ */