x86: add TSC_CONSTANT_RATE option

Some boards use the local apic for udelay(), but they also provide
their own implementation of udelay() for SMM. The reason for using
the local apic for udelay() in ramstage is to not have to pay the
penalty of calibrating the TSC frequency. Therefore provide a
TSC_CONSTANT_RATE option to indicate that TSC calibration is not
needed. Instead rely on the presence of a tsc_freq_mhz() function
provided by the cpu/board.  Additionally, assume that if
TSC_CONSTANT_RATE is selected the udelay() function in SMM will
be the tsc.

Change-Id: I1629c2fbe3431772b4e80495160584fb6f599e9e
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/3168
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Aaron Durbin 2013-05-01 15:27:09 -05:00 committed by Ronald G. Minnich
parent 7cb1ba9a61
commit 8e73b5d952
4 changed files with 39 additions and 3 deletions

View File

@ -25,6 +25,13 @@ config UDELAY_TSC
bool bool
default n default n
config TSC_CONSTANT_RATE
def_bool n
depends on UDELAY_TSC
help
This option asserts that the TSC ticks at a known constant rate.
Therefore, no TSC calibration is required.
config TSC_MONOTONIC_TIMER config TSC_MONOTONIC_TIMER
def_bool n def_bool n
depends on UDELAY_TSC depends on UDELAY_TSC

View File

@ -1,2 +1,6 @@
ramstage-$(CONFIG_UDELAY_TSC) += delay_tsc.c ramstage-$(CONFIG_UDELAY_TSC) += delay_tsc.c
romstage-$(CONFIG_TSC_CONSTANT_RATE) += delay_tsc.c
ifeq ($(CONFIG_HAVE_SMI_HANDLER),y)
smm-$(CONFIG_TSC_CONSTANT_RATE) += delay_tsc.c
endif

View File

@ -5,8 +5,16 @@
#include <smp/spinlock.h> #include <smp/spinlock.h>
#include <delay.h> #include <delay.h>
#if !defined(__PRE_RAM__)
static unsigned long clocks_per_usec; static unsigned long clocks_per_usec;
#if CONFIG_TSC_CONSTANT_RATE
static unsigned long calibrate_tsc(void)
{
return tsc_freq_mhz();
}
#else /* CONFIG_TSC_CONSTANT_RATE */
#if !CONFIG_TSC_CALIBRATE_WITH_IO #if !CONFIG_TSC_CALIBRATE_WITH_IO
#define CLOCK_TICK_RATE 1193180U /* Underlying HZ */ #define CLOCK_TICK_RATE 1193180U /* Underlying HZ */
@ -139,6 +147,7 @@ static unsigned long long calibrate_tsc(void)
#endif /* CONFIG_TSC_CALIBRATE_WITH_IO */ #endif /* CONFIG_TSC_CALIBRATE_WITH_IO */
#endif /* CONFIG_TSC_CONSTANT_RATE */
void init_timer(void) void init_timer(void)
{ {
@ -148,15 +157,27 @@ void init_timer(void)
} }
} }
static inline unsigned long get_clocks_per_usec(void)
{
init_timer();
return clocks_per_usec;
}
#else /* !defined(__PRE_RAM__) */
/* romstage calls into cpu/board specific function every time. */
static inline unsigned long get_clocks_per_usec(void)
{
return tsc_freq_mhz();
}
#endif /* !defined(__PRE_RAM__) */
void udelay(unsigned us) void udelay(unsigned us)
{ {
unsigned long long count; unsigned long long count;
unsigned long long stop; unsigned long long stop;
unsigned long long clocks; unsigned long long clocks;
init_timer();
clocks = us; clocks = us;
clocks *= clocks_per_usec; clocks *= get_clocks_per_usec();
count = rdtscll(); count = rdtscll();
stop = clocks + count; stop = clocks + count;
while(stop > count) { while(stop > count) {
@ -165,7 +186,7 @@ void udelay(unsigned us)
} }
} }
#if CONFIG_TSC_MONOTONIC_TIMER #if CONFIG_TSC_MONOTONIC_TIMER && !defined(__PRE_RAM__) && !defined(__SMM__)
#include <timer.h> #include <timer.h>
static struct monotonic_counter { static struct monotonic_counter {

View File

@ -40,4 +40,8 @@ static inline unsigned long long rdtscll(void)
} }
#endif #endif
#if CONFIG_TSC_CONSTANT_RATE
unsigned long tsc_freq_mhz(void);
#endif
#endif /* CPU_X86_TSC_H */ #endif /* CPU_X86_TSC_H */