diff options
author | Alexey Zaytsev <alexey.zaytsev@gmail.com> | 2008-03-06 16:06:58 +0300 |
---|---|---|
committer | Alexey Zaytsev <zaytsev.a@protei.ru> | 2008-03-06 16:06:58 +0300 |
commit | 8de54ef9aa9817d878ad6a7ddef29e92615a5963 (patch) | |
tree | 0202077f13ad1ea6863ee62fbbce4bb6c25809a9 /src/arch/i386/drivers | |
parent | 4704abbc5075c13230e00dd30b559c6e8ca07dbb (diff) | |
download | ipxe-8de54ef9aa9817d878ad6a7ddef29e92615a5963.tar.gz |
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>
Diffstat (limited to 'src/arch/i386/drivers')
-rw-r--r-- | src/arch/i386/drivers/timer_rdtsc.c | 64 |
1 files changed, 21 insertions, 43 deletions
diff --git a/src/arch/i386/drivers/timer_rdtsc.c b/src/arch/i386/drivers/timer_rdtsc.c index 57b8826c..09b7df2f 100644 --- a/src/arch/i386/drivers/timer_rdtsc.c +++ b/src/arch/i386/drivers/timer_rdtsc.c @@ -14,54 +14,32 @@ #define rdtscll(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); - i386_timer2_udelay(USECS_IN_MSEC/2); - rdtsc(endlow,endhigh); - - /* 64-bit subtract - gcc just messes up with long longs */ - /* XXX ORLY? Check it. */ - __asm__("subl %2,%0\n\t" - "sbbl %3,%1" - :"=a" (endlow), "=d" (endhigh) - :"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; + + uint64_t rdtsc_start; + uint64_t rdtsc_end; + + rdtscll(rdtsc_start); + i386_timer2_udelay(USECS_IN_MSEC); + rdtscll(rdtsc_end); + + return (rdtsc_end - rdtsc_start) / USECS_IN_MSEC; } -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) { - uint32_t clocks_high, clocks_low; - uint32_t currticks; + uint64_t clocks; /* Read the Time Stamp Counter */ - rdtsc(clocks_low, clocks_high); - - /* currticks = clocks / clocks_per_tick; */ - __asm__("divl %1" - :"=a" (currticks) - :"r" (clocks_per_second/USECS_IN_SEC), "0" (clocks_low), "d" (clocks_high)); + rdtscll(clocks); - return currticks; + return clocks / clocks_per_usec; } static int rdtsc_ts_init(void) @@ -71,10 +49,10 @@ static int rdtsc_ts_init(void) get_cpuinfo(&cpu_info); if (cpu_info.features & X86_FEATURE_TSC) { - clocks_per_second = calibrate_tsc(); - if (clocks_per_second) { + clocks_per_usec= calibrate_tsc(); + if (clocks_per_usec) { DBG("RDTSC ticksource installed. CPU running at %ld Mhz\n", - clocks_per_second/(1000*1000)); + clocks_per_usec); return 0; } } |