Author: jkim
Date: Mon Mar 14 22:05:59 2011
New Revision: 219646
URL: http://svn.freebsd.org/changeset/base/219646

Log:
  When TSC is unavailable, broken or disabled and the current timecounter has
  better quality than i8254 timer, use it for DELAY(9).

Modified:
  head/sys/x86/isa/clock.c

Modified: head/sys/x86/isa/clock.c
==============================================================================
--- head/sys/x86/isa/clock.c    Mon Mar 14 19:31:43 2011        (r219645)
+++ head/sys/x86/isa/clock.c    Mon Mar 14 22:05:59 2011        (r219646)
@@ -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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to