Synchronize rdtsc instructions

The CPU can arbitrarily reorder calls to rdtsc, significantly
reducing the precision of timing using the CPUs time stamp counter.
Unfortunately the method of synchronizing rdtsc is different
on AMD and Intel CPUs. There is a generic method, using the cpuid
instruction, but that uses up a lot of registers, and is very slow.
Hence, use the correct lfence/mfence instructions (for CPUs that
we know support it)

Change-Id: I17ecb48d283f38f23148c13159aceda704c64ea5
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/1422
Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Tested-by: build bot (Jenkins)
This commit is contained in:
Stefan Reinauer 2012-08-07 14:44:51 -07:00 committed by Stefan Reinauer
parent 4c29d7f27d
commit 0db6820b10
10 changed files with 40 additions and 4 deletions

View File

@ -25,6 +25,7 @@ config CPU_AMD_AGESA
default y if CPU_AMD_AGESA_FAMILY15 default y if CPU_AMD_AGESA_FAMILY15
default y if CPU_AMD_AGESA_FAMILY15_TN default y if CPU_AMD_AGESA_FAMILY15_TN
default n default n
select TSC_SYNC_LFENCE
if CPU_AMD_AGESA if CPU_AMD_AGESA

View File

@ -3,6 +3,7 @@ config CPU_AMD_MODEL_10XXX
select SSE select SSE
select SSE2 select SSE2
select MMCONF_SUPPORT_DEFAULT select MMCONF_SUPPORT_DEFAULT
select TSC_SYNC_LFENCE
if CPU_AMD_MODEL_10XXX if CPU_AMD_MODEL_10XXX
config CPU_ADDR_BITS config CPU_ADDR_BITS

View File

@ -3,6 +3,7 @@ config CPU_AMD_MODEL_FXX
select MMX select MMX
select SSE select SSE
select SSE2 select SSE2
select TSC_SYNC_LFENCE
if CPU_AMD_MODEL_FXX if CPU_AMD_MODEL_FXX
config UDELAY_IO config UDELAY_IO

View File

@ -2,3 +2,4 @@ config CPU_INTEL_MODEL_1067X
bool bool
select SMP select SMP
select SSE2 select SSE2
select TSC_SYNC_MFENCE

View File

@ -4,9 +4,9 @@ config CPU_INTEL_MODEL_106CX
select SSE2 select SSE2
select UDELAY_LAPIC select UDELAY_LAPIC
select AP_IN_SIPI_WAIT select AP_IN_SIPI_WAIT
select TSC_SYNC_MFENCE
config CPU_ADDR_BITS config CPU_ADDR_BITS
int int
default 32 default 32

View File

@ -14,6 +14,7 @@ config CPU_SPECIFIC_OPTIONS
select SMM_TSEG select SMM_TSEG
select MICROCODE_IN_CBFS select MICROCODE_IN_CBFS
#select AP_IN_SIPI_WAIT #select AP_IN_SIPI_WAIT
select TSC_SYNC_MFENCE
config BOOTBLOCK_CPU_INIT config BOOTBLOCK_CPU_INIT
string string

View File

@ -4,3 +4,4 @@ config CPU_INTEL_MODEL_6EX
select SSE2 select SSE2
select UDELAY_LAPIC select UDELAY_LAPIC
select AP_IN_SIPI_WAIT select AP_IN_SIPI_WAIT
select TSC_SYNC_MFENCE

View File

@ -4,3 +4,4 @@ config CPU_INTEL_MODEL_6FX
select SSE2 select SSE2
select UDELAY_LAPIC select UDELAY_LAPIC
select AP_IN_SIPI_WAIT select AP_IN_SIPI_WAIT
select TSC_SYNC_MFENCE

View File

@ -23,6 +23,22 @@ config TSC_CALIBRATE_WITH_IO
bool bool
default n default n
config TSC_SYNC_LFENCE
bool
default n
help
The CPU driver should select this if the CPU needs
to execute an lfence instruction in order to synchronize
rdtsc. This is true for all modern AMD CPUs.
config TSC_SYNC_MFENCE
bool
default n
help
The CPU driver should select this if the CPU needs
to execute an mfence instruction in order to synchronize
rdtsc. This is true for all modern Intel CPUs.
config XIP_ROM_SIZE config XIP_ROM_SIZE
hex hex
default ROM_SIZE if ROMCC default ROM_SIZE if ROMCC

View File

@ -1,6 +1,14 @@
#ifndef CPU_X86_TSC_H #ifndef CPU_X86_TSC_H
#define CPU_X86_TSC_H #define CPU_X86_TSC_H
#if CONFIG_TSC_SYNC_MFENCE
#define TSC_SYNC "mfence\n"
#elif CONFIG_TSC_SYNC_LFENCE
#define TSC_SYNC "lfence\n"
#else
#define TSC_SYNC
#endif
struct tsc_struct { struct tsc_struct {
unsigned lo; unsigned lo;
unsigned hi; unsigned hi;
@ -10,7 +18,8 @@ typedef struct tsc_struct tsc_t;
static inline tsc_t rdtsc(void) static inline tsc_t rdtsc(void)
{ {
tsc_t res; tsc_t res;
__asm__ __volatile__ ( asm volatile (
TSC_SYNC
"rdtsc" "rdtsc"
: "=a" (res.lo), "=d"(res.hi) /* outputs */ : "=a" (res.lo), "=d"(res.hi) /* outputs */
); );
@ -22,7 +31,11 @@ static inline tsc_t rdtsc(void)
static inline unsigned long long rdtscll(void) static inline unsigned long long rdtscll(void)
{ {
unsigned long long val; unsigned long long val;
asm volatile ("rdtsc" : "=A" (val)); asm volatile (
TSC_SYNC
"rdtsc"
: "=A" (val)
);
return val; return val;
} }
#endif #endif