libpayload: Generalize and redistribute timekeeping code
The timekeeping code in libpayload was dependent on rdtsc, and when it was split up by arch, that code was duplicated even though it was mostly the same. This change factors out actually reading the count from the timer and the speed of the timer and puts the definitions of ndelay, udelay, mdelay and delay into generic code. Then, in x86, the timer_hz and timer_get_raw_value functions which used to be in depthcharge were moved over to libpayload's arch/x86/timer.c. In ARM where there isn't a single, canonical timer, those functions are omitted with the intention that they'll be implemented by a specific timer driver chosen elsewhere. Change-Id: I9c919bed712ace941f417c1d58679d667b2d8269 Signed-off-by: Gabe Black <gabeblack@google.com> Reviewed-on: http://review.coreboot.org/2717 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
parent
6a0b3611c5
commit
5c0b7abe78
|
@ -52,50 +52,3 @@ unsigned int get_cpu_speed(void)
|
||||||
|
|
||||||
return cpu_khz;
|
return cpu_khz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _delay(unsigned long long delta)
|
|
||||||
{
|
|
||||||
/* FIXME */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of nanoseconds.
|
|
||||||
*
|
|
||||||
* @param n Number of nanoseconds to delay for.
|
|
||||||
*/
|
|
||||||
void ndelay(unsigned int n)
|
|
||||||
{
|
|
||||||
_delay((unsigned long long)n * cpu_khz / 1000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of microseconds.
|
|
||||||
*
|
|
||||||
* @param n Number of microseconds to delay for.
|
|
||||||
*/
|
|
||||||
void udelay(unsigned int n)
|
|
||||||
{
|
|
||||||
_delay((unsigned long long)n * cpu_khz / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of milliseconds.
|
|
||||||
*
|
|
||||||
* @param m Number of milliseconds to delay for.
|
|
||||||
*/
|
|
||||||
void mdelay(unsigned int m)
|
|
||||||
{
|
|
||||||
_delay((unsigned long long)m * cpu_khz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of seconds.
|
|
||||||
*
|
|
||||||
* @param s Number of seconds to delay for.
|
|
||||||
*/
|
|
||||||
void delay(unsigned int s)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i=0; i<1000; i++)
|
|
||||||
_delay((unsigned long long)s * cpu_khz);
|
|
||||||
}
|
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libpayload.h>
|
#include <libpayload.h>
|
||||||
// #include <arch/rdtsc.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ingroup arch
|
* @ingroup arch
|
||||||
|
@ -48,80 +47,19 @@ u32 cpu_khz;
|
||||||
*/
|
*/
|
||||||
unsigned int get_cpu_speed(void)
|
unsigned int get_cpu_speed(void)
|
||||||
{
|
{
|
||||||
#if 0
|
/* FIXME */
|
||||||
unsigned long long start, end;
|
|
||||||
|
|
||||||
/* Set up the PPC port - disable the speaker, enable the T2 gate. */
|
|
||||||
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
|
|
||||||
|
|
||||||
/* Set the PIT to Mode 0, counter 2, word access. */
|
|
||||||
outb(0xB0, 0x43);
|
|
||||||
|
|
||||||
/* Load the counter with 0xffff. */
|
|
||||||
outb(0xff, 0x42);
|
|
||||||
outb(0xff, 0x42);
|
|
||||||
|
|
||||||
/* Read the number of ticks during the period. */
|
|
||||||
start = rdtsc();
|
|
||||||
while (!(inb(0x61) & 0x20)) ;
|
|
||||||
end = rdtsc();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The clock rate is 1193180 Hz, the number of milliseconds for a
|
|
||||||
* period of 0xffff is 1193180 / (0xFFFF * 1000) or .0182.
|
|
||||||
* Multiply that by the number of measured clocks to get the kHz value.
|
|
||||||
*/
|
|
||||||
cpu_khz = (unsigned int)((end - start) * 1193180U / (1000 * 0xffff));
|
|
||||||
#else
|
|
||||||
cpu_khz = 200 * 1024;
|
cpu_khz = 200 * 1024;
|
||||||
#endif
|
|
||||||
return cpu_khz;
|
return cpu_khz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _delay(unsigned long long delta)
|
uint64_t timer_hz(void)
|
||||||
{
|
{
|
||||||
#if 0
|
/* FIXME */
|
||||||
unsigned long long timeout = rdtsc() + delta;
|
return 0;
|
||||||
while (rdtsc() < timeout) ;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
uint64_t timer_raw_value(void)
|
||||||
* Delay for a specified number of nanoseconds.
|
|
||||||
*
|
|
||||||
* @param n Number of nanoseconds to delay for.
|
|
||||||
*/
|
|
||||||
void ndelay(unsigned int n)
|
|
||||||
{
|
{
|
||||||
_delay(n * cpu_khz / 1000000);
|
/* FIXME */
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of microseconds.
|
|
||||||
*
|
|
||||||
* @param n Number of microseconds to delay for.
|
|
||||||
*/
|
|
||||||
void udelay(unsigned int n)
|
|
||||||
{
|
|
||||||
_delay(n * cpu_khz / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of milliseconds.
|
|
||||||
*
|
|
||||||
* @param m Number of milliseconds to delay for.
|
|
||||||
*/
|
|
||||||
void mdelay(unsigned int m)
|
|
||||||
{
|
|
||||||
_delay(m * cpu_khz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of seconds.
|
|
||||||
*
|
|
||||||
* @param s Number of seconds to delay for.
|
|
||||||
*/
|
|
||||||
void delay(unsigned int s)
|
|
||||||
{
|
|
||||||
_delay(s * cpu_khz * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file i386/timer.c
|
* @file x86/timer.c
|
||||||
* i386 specific timer routines
|
* x86 specific timer routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libpayload.h>
|
#include <libpayload.h>
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
* @ingroup arch
|
* @ingroup arch
|
||||||
* Global variable containing the speed of the processor in KHz.
|
* Global variable containing the speed of the processor in KHz.
|
||||||
*/
|
*/
|
||||||
u32 cpu_khz;
|
uint32_t cpu_khz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the speed of the processor for use in delays.
|
* Calculate the speed of the processor for use in delays.
|
||||||
|
@ -77,50 +77,12 @@ unsigned int get_cpu_speed(void)
|
||||||
return cpu_khz;
|
return cpu_khz;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _delay(unsigned long long delta)
|
uint64_t timer_hz(void)
|
||||||
{
|
{
|
||||||
unsigned long long timeout = rdtsc() + delta;
|
return lib_sysinfo.cpu_khz * 1000;
|
||||||
while (rdtsc() < timeout) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
uint64_t timer_raw_value(void)
|
||||||
* Delay for a specified number of nanoseconds.
|
|
||||||
*
|
|
||||||
* @param n Number of nanoseconds to delay for.
|
|
||||||
*/
|
|
||||||
void ndelay(unsigned int n)
|
|
||||||
{
|
{
|
||||||
_delay((unsigned long long)n * cpu_khz / 1000000);
|
return rdtsc();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of microseconds.
|
|
||||||
*
|
|
||||||
* @param n Number of microseconds to delay for.
|
|
||||||
*/
|
|
||||||
void udelay(unsigned int n)
|
|
||||||
{
|
|
||||||
_delay((unsigned long long)n * cpu_khz / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of milliseconds.
|
|
||||||
*
|
|
||||||
* @param m Number of milliseconds to delay for.
|
|
||||||
*/
|
|
||||||
void mdelay(unsigned int m)
|
|
||||||
{
|
|
||||||
_delay((unsigned long long)m * cpu_khz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delay for a specified number of seconds.
|
|
||||||
*
|
|
||||||
* @param s Number of seconds to delay for.
|
|
||||||
*/
|
|
||||||
void delay(unsigned int s)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i=0; i<1000; i++)
|
|
||||||
_delay((unsigned long long)s * cpu_khz);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -407,8 +407,12 @@ int get_multiboot_info(struct sysinfo_t *info);
|
||||||
|
|
||||||
int lib_get_sysinfo(void);
|
int lib_get_sysinfo(void);
|
||||||
|
|
||||||
/* Timer functions - defined by each architecture. */
|
/* Timer functions. */
|
||||||
|
/* Defined by each architecture. */
|
||||||
unsigned int get_cpu_speed(void);
|
unsigned int get_cpu_speed(void);
|
||||||
|
uint64_t timer_hz(void);
|
||||||
|
uint64_t timer_raw_value(void);
|
||||||
|
/* Generic. */
|
||||||
void ndelay(unsigned int n);
|
void ndelay(unsigned int n);
|
||||||
void udelay(unsigned int n);
|
void udelay(unsigned int n);
|
||||||
void mdelay(unsigned int n);
|
void mdelay(unsigned int n);
|
||||||
|
|
|
@ -46,21 +46,23 @@ static struct {
|
||||||
suseconds_t usecs;
|
suseconds_t usecs;
|
||||||
} clock;
|
} clock;
|
||||||
|
|
||||||
#define TICKS_PER_SEC (cpu_khz * 1000)
|
|
||||||
#define TICKS_PER_USEC (cpu_khz / 1000)
|
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_X86
|
|
||||||
static void update_clock(void)
|
static void update_clock(void)
|
||||||
{
|
{
|
||||||
u64 delta = rdtsc() - clock.ticks;
|
u64 delta = timer_raw_value() - clock.ticks;
|
||||||
int secs;
|
int secs;
|
||||||
|
static uint64_t ticks_per_sec = 0;
|
||||||
|
static uint64_t ticks_per_usec = 0;
|
||||||
|
if (!ticks_per_sec) {
|
||||||
|
ticks_per_sec = timer_hz();
|
||||||
|
ticks_per_usec = timer_hz() / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
clock.ticks += delta;
|
clock.ticks += delta;
|
||||||
|
|
||||||
secs = (int) (delta / TICKS_PER_SEC);
|
secs = (int) (delta / ticks_per_sec);
|
||||||
clock.secs += secs;
|
clock.secs += secs;
|
||||||
delta -= (secs * TICKS_PER_SEC);
|
delta -= (secs * ticks_per_sec);
|
||||||
clock.usecs += (int) (delta / TICKS_PER_USEC);
|
clock.usecs += (int)(delta / ticks_per_usec);
|
||||||
|
|
||||||
if (clock.usecs > 1000000) {
|
if (clock.usecs > 1000000) {
|
||||||
clock.usecs -= 1000000;
|
clock.usecs -= 1000000;
|
||||||
|
@ -110,15 +112,11 @@ static void gettimeofday_init(void)
|
||||||
clock.secs = (days * 86400) + (tm.tm_hour * 3600) +
|
clock.secs = (days * 86400) + (tm.tm_hour * 3600) +
|
||||||
(tm.tm_min * 60) + tm.tm_sec;
|
(tm.tm_min * 60) + tm.tm_sec;
|
||||||
}
|
}
|
||||||
#endif // CONFIG_NVRAM
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static void update_clock(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gettimeofday_init(void)
|
static void gettimeofday_init(void)
|
||||||
{
|
{
|
||||||
|
/* Record the number of ticks */
|
||||||
|
clock.ticks = timer_raw_value();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -145,3 +143,49 @@ int gettimeofday(struct timeval *tv, void *tz)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void _delay(uint64_t delta)
|
||||||
|
{
|
||||||
|
uint64_t start = timer_raw_value();
|
||||||
|
while (timer_raw_value() - start < delta) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay for a specified number of nanoseconds.
|
||||||
|
*
|
||||||
|
* @param n Number of nanoseconds to delay for.
|
||||||
|
*/
|
||||||
|
void ndelay(unsigned int n)
|
||||||
|
{
|
||||||
|
_delay((uint64_t)n * timer_hz() / 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay for a specified number of microseconds.
|
||||||
|
*
|
||||||
|
* @param n Number of microseconds to delay for.
|
||||||
|
*/
|
||||||
|
void udelay(unsigned int n)
|
||||||
|
{
|
||||||
|
_delay((uint64_t)n * timer_hz() / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay for a specified number of milliseconds.
|
||||||
|
*
|
||||||
|
* @param m Number of milliseconds to delay for.
|
||||||
|
*/
|
||||||
|
void mdelay(unsigned int m)
|
||||||
|
{
|
||||||
|
_delay((uint64_t)m * timer_hz() / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay for a specified number of seconds.
|
||||||
|
*
|
||||||
|
* @param s Number of seconds to delay for.
|
||||||
|
*/
|
||||||
|
void delay(unsigned int s)
|
||||||
|
{
|
||||||
|
_delay((uint64_t)s * timer_hz());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue