Port-alpha archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Alpha timecounter



> Date: Wed, 1 Nov 2017 16:41:29 +0000
> From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
> 
> The attached compile-tested patch attempts to fix it by enforcing a
> global ordering, and calling tc_gonebad if the calibration fails to
> keep it within 1sec.  The patch is for code that is nominally MI,
> kern_cctr.c, but only alpha uses it.

Made a mistake in a little tweak just before I sent it, so that the
timecounter would pretty much unconditionally conclude the timecounter
has gone bad.  Attached patch should avoid that.
Index: sys/kern/kern_cctr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_cctr.c,v
retrieving revision 1.9
diff -p -u -r1.9 kern_cctr.c
--- sys/kern/kern_cctr.c	3 Jan 2009 03:31:23 -0000	1.9
+++ sys/kern/kern_cctr.c	1 Nov 2017 17:04:58 -0000
@@ -95,6 +95,12 @@ void cc_calibrate_cpu(struct cpu_info *)
 
 static int64_t cc_cal_val;  /* last calibrate time stamp */
 
+/*
+ * Highest cc witnessed globally.  We assume the calibration happens
+ * once a second.
+ */
+static volatile u_int cc_global __cacheline_aligned;
+
 static struct timecounter cc_timecounter = {
 	.tc_get_timecount	= cc_get_timecount,
 	.tc_poll_pps		= cc_calibrate,
@@ -132,8 +138,8 @@ cc_init(timecounter_get_t getcc, uint64_
 /*
  * pick up tick count scaled to reference tick count
  */
-u_int
-cc_get_timecount(struct timecounter *tc)
+static u_int
+cc_get_timecount_local(struct timecounter *tc)
 {
 	struct cpu_info *ci;
 	int64_t rcc, cc, ncsw;
@@ -186,6 +192,37 @@ cc_get_timecount(struct timecounter *tc)
 }
 
 /*
+ * advance the global view of the clock by our tick count and return it
+ */
+u_int
+cc_get_timecount(struct timecounter *tc)
+{
+	u_int freq = tc->tc_frequency;
+	u_int local, global, result;
+
+	do {
+		local = cc_get_timecount_local(tc);
+		global = cc_global;
+		if ((local - global) < freq) {
+			/* We're ahead, so use our counter.  */
+			result = local;
+		} else {
+			/* We're behind or desynced, so use the global.  */
+			result = global + 1;
+		}
+	} while (atomic_cas_uint(&cc_global, global, result) != global);
+
+	if (__predict_false((local - global) > freq &&
+		(global - local) > freq)) {
+		/* More than 1sec away from global: bad.  */
+		printf("%s: local cc desynchronized\n", tc->tc_name);
+		tc_gonebad(tc);
+	}
+
+	return result;
+}
+
+/*
  * called once per clock tick via the pps callback
  * for the calibration of the TSC counters.
  * it is called only for the PRIMARY cpu. all


Home | Main Index | Thread Index | Old Index