david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Use plain C in timer_rdtsc for division instead of inline asssembly.

This also fixes a bug in rdtsc_currticks when the result did not fix in %eax

Signed-off-by: Alexey Zaytsev <zaytsev.a@protei.ru>
This commit is contained in:
Alexey Zaytsev 2008-03-06 16:06:58 +03:00 committed by Alexey Zaytsev
parent 4704abbc50
commit 8de54ef9aa
1 changed files with 19 additions and 41 deletions

View File

@ -14,54 +14,32 @@
#define rdtscll(val) \ #define rdtscll(val) \
__asm__ __volatile__ ("rdtsc" : "=A" (val)) __asm__ __volatile__ ("rdtsc" : "=A" (val))
static unsigned long long calibrate_tsc(void)
/* Measure how many clocks we get in one microsecond */
static inline uint64_t calibrate_tsc(void)
{ {
uint32_t startlow, starthigh;
uint32_t endlow, endhigh;
rdtsc(startlow,starthigh); uint64_t rdtsc_start;
i386_timer2_udelay(USECS_IN_MSEC/2); uint64_t rdtsc_end;
rdtsc(endlow,endhigh);
/* 64-bit subtract - gcc just messes up with long longs */ rdtscll(rdtsc_start);
/* XXX ORLY? Check it. */ i386_timer2_udelay(USECS_IN_MSEC);
__asm__("subl %2,%0\n\t" rdtscll(rdtsc_end);
"sbbl %3,%1"
:"=a" (endlow), "=d" (endhigh) return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC;
:"g" (startlow), "g" (starthigh),
"0" (endlow), "1" (endhigh));
/* Error: ECPUTOOFAST */
if (endhigh)
goto bad_ctc;
endlow *= MSECS_IN_SEC*2;
return endlow;
/*
* The CTC wasn't reliable: we got a hit on the very first read,
* or the CPU was so fast/slow that the quotient wouldn't fit in
* 32 bits..
*/
bad_ctc:
return 0;
} }
static uint32_t clocks_per_second = 0;
static uint32_t clocks_per_usec = 0;
/* We measure time in microseconds. */
static tick_t rdtsc_currticks(void) static tick_t rdtsc_currticks(void)
{ {
uint32_t clocks_high, clocks_low; uint64_t clocks;
uint32_t currticks;
/* Read the Time Stamp Counter */ /* Read the Time Stamp Counter */
rdtsc(clocks_low, clocks_high); rdtscll(clocks);
/* currticks = clocks / clocks_per_tick; */ return clocks / clocks_per_usec;
__asm__("divl %1"
:"=a" (currticks)
:"r" (clocks_per_second/USECS_IN_SEC), "0" (clocks_low), "d" (clocks_high));
return currticks;
} }
static int rdtsc_ts_init(void) static int rdtsc_ts_init(void)
@ -71,10 +49,10 @@ static int rdtsc_ts_init(void)
get_cpuinfo(&cpu_info); get_cpuinfo(&cpu_info);
if (cpu_info.features & X86_FEATURE_TSC) { if (cpu_info.features & X86_FEATURE_TSC) {
clocks_per_second = calibrate_tsc(); clocks_per_usec= calibrate_tsc();
if (clocks_per_second) { if (clocks_per_usec) {
DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n", DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n",
clocks_per_second/(1000*1000)); clocks_per_usec);
return 0; return 0;
} }
} }