Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Mar 2011 22:05:59 +0000 (UTC)
From:      Jung-uk Kim <jkim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r219646 - head/sys/x86/isa
Message-ID:  <201103142205.p2EM5x6E012664@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103142205.p2EM5x6E012664>