diff options
author | Jung-uk Kim <jkim@FreeBSD.org> | 2011-03-14 22:05:59 +0000 |
---|---|---|
committer | Jung-uk Kim <jkim@FreeBSD.org> | 2011-03-14 22:05:59 +0000 |
commit | 856e88c1f5fc35d780735427adca6fbae8f12270 (patch) | |
tree | 5a60ca33d66de9bf8dc9b38cd1b796fc7f15a76e /sys/x86/isa | |
parent | 12ad0bb143be3473aa66b33cc3e711d2cfe5be25 (diff) | |
download | src-856e88c1f5fc35d780735427adca6fbae8f12270.tar.gz src-856e88c1f5fc35d780735427adca6fbae8f12270.zip |
When TSC is unavailable, broken or disabled and the current timecounter has
better quality than i8254 timer, use it for DELAY(9).
Notes
Notes:
svn path=/head/; revision=219646
Diffstat (limited to 'sys/x86/isa')
-rw-r--r-- | sys/x86/isa/clock.c | 53 |
1 files changed, 43 insertions, 10 deletions
diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c index cb34eb4af101..f0016b297d48 100644 --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -245,6 +245,42 @@ getit(void) return ((high << 8) | low); } +static __inline void +delay_tsc(int n) +{ + uint64_t start, end, now; + + sched_pin(); + start = rdtsc(); + end = start + (tsc_freq * n) / 1000000; + do { + cpu_spinwait(); + now = rdtsc(); + } while (now < end || (now > start && end < start)); + sched_unpin(); +} + +static __inline void +delay_timecounter(struct timecounter *tc, int n) +{ + uint64_t end, now; + u_int last, mask, u; + + mask = tc->tc_counter_mask; + last = tc->tc_get_timecount(tc) & mask; + end = tc->tc_frequency * n / 1000000; + now = 0; + do { + cpu_spinwait(); + u = tc->tc_get_timecount(tc) & mask; + if (u < last) + now += mask - last + u + 1; + else + now += u - last; + last = u; + } while (now < end); +} + /* * Wait "n" microseconds. * Relies on timer 1 counting down from (i8254_freq / hz) @@ -253,6 +289,7 @@ getit(void) void DELAY(int n) { + struct timecounter *tc; int delta, prev_tick, tick, ticks_left; #ifdef DELAYDEBUG @@ -262,16 +299,12 @@ DELAY(int n) #endif if (tsc_freq != 0) { - uint64_t start, end, now; - - sched_pin(); - start = rdtsc(); - end = start + (tsc_freq * n) / 1000000; - do { - cpu_spinwait(); - now = rdtsc(); - } while (now < end || (now > start && end < start)); - sched_unpin(); + delay_tsc(n); + return; + } + tc = timecounter; + if (tc->tc_quality > 0) { + delay_timecounter(tc, n); return; } #ifdef DELAYDEBUG |