Port-alpha archive

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

Re: Alpha timecounter



> Date: Thu, 2 Nov 2017 09:23:26 +0100
> From: Martin Husemann <martin%duskware.de@localhost>
> 
> I tested it too. I get two "PCC: local cc desynchronized" messages
> at boot time and then everything seems to be working fine. Ran full
> atf tests and the hardwareclockbackward (for a few minutes only
> though, have it still running).

Oops.  The `PCC: local cc desynchronized' message means it _didn't_
work, and the system probably switched you to using the clockinterrupt
timecounter.  Check `sysctl kern.timecounter' to see.

Maybe, if it happened at boot time, the cross-CPU calibration simply
had not yet run.  So try the attached patch instead?
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	2 Nov 2017 15:08:27 -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,
@@ -124,6 +130,13 @@ cc_init(timecounter_get_t getcc, uint64_
 	cc_timecounter.tc_frequency = freq;
 	cc_timecounter.tc_name = name;
 	cc_timecounter.tc_quality = quality;
+
+	/* Calibrate the local CPU and prime it before we try to use it.  */
+	kpreempt_disable();
+	cc_calibrate_cpu(&cc_timecounter);
+	cc_global = cc_get_timecount_local(&cc_timecounter);
+	kpreempt_enable();
+
 	tc_init(&cc_timecounter);
 
 	return &cc_timecounter;
@@ -132,8 +145,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 +199,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