Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Mar 2014 10:16:17 +0000 (UTC)
From:      Roger Pau Monné <royger@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r263007 - head/sys/dev/xen/timer
Message-ID:  <201403111016.s2BAGHxE019046@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: royger
Date: Tue Mar 11 10:16:17 2014
New Revision: 263007
URL: http://svnweb.freebsd.org/changeset/base/263007

Log:
  xen: rework xen timer so it can be used early in boot process
  
  This should not introduce any functional change, and makes the
  functions suitable to be called before we have actually mapped the
  vcpu_info struct on a per-cpu basis.
  
  Approved by: gibbs
  Sponsored by: Citrix Systems R&D
  
  dev/xen/timer/timer.c:
   - Remove citrical_{enter/exit}, the clock code will already be called
     with preemption disabled when needed. Add a comment to that regard
     in xentimer_get_timecount.
   - Allow xen_fetch_vcpu_time to be called with a specifc vcpu_info
     that will be used to fetch current time.
   - Assert that xentimer_et_start will always be called with preemption
     disabled.

Modified:
  head/sys/dev/xen/timer/timer.c

Modified: head/sys/dev/xen/timer/timer.c
==============================================================================
--- head/sys/dev/xen/timer/timer.c	Tue Mar 11 10:15:25 2014	(r263006)
+++ head/sys/dev/xen/timer/timer.c	Tue Mar 11 10:16:17 2014	(r263007)
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/smp.h>
 #include <sys/limits.h>
 #include <sys/clock.h>
+#include <sys/proc.h>
 
 #include <xen/xen-os.h>
 #include <xen/features.h>
@@ -230,22 +231,22 @@ xen_fetch_vcpu_tinfo(struct vcpu_time_in
 /**
  * \brief Get the current time, in nanoseconds, since the hypervisor booted.
  *
+ * \param vcpu		vcpu_info structure to fetch the time from.
+ *
  * \note This function returns the current CPU's idea of this value, unless
  *       it happens to be less than another CPU's previously determined value.
  */
 static uint64_t
-xen_fetch_vcpu_time(void)
+xen_fetch_vcpu_time(struct vcpu_info *vcpu)
 {
 	struct vcpu_time_info dst;
 	struct vcpu_time_info *src;
 	uint32_t pre_version;
 	uint64_t now;
 	volatile uint64_t last;
-	struct vcpu_info *vcpu = DPCPU_GET(vcpu_info);
 
 	src = &vcpu->time;
 
-	critical_enter();
 	do {
 		pre_version = xen_fetch_vcpu_tinfo(&dst, src);
 		barrier();
@@ -266,16 +267,24 @@ xen_fetch_vcpu_time(void)
 		}
 	} while (!atomic_cmpset_64(&xen_timer_last_time, last, now));
 
-	critical_exit();
-
 	return (now);
 }
 
 static uint32_t
 xentimer_get_timecount(struct timecounter *tc)
 {
+	uint64_t vcpu_time;
+
+	/*
+	 * We don't disable preemption here because the worst that can
+	 * happen is reading the vcpu_info area of a different CPU than
+	 * the one we are currently running on, but that would also
+	 * return a valid tc (and we avoid the overhead of
+	 * critical_{enter/exit} calls).
+	 */
+	vcpu_time = xen_fetch_vcpu_time(DPCPU_GET(vcpu_info));
 
-	return ((uint32_t)xen_fetch_vcpu_time() & UINT_MAX);
+	return (vcpu_time & UINT32_MAX);
 }
 
 /**
@@ -305,7 +314,10 @@ xen_fetch_wallclock(struct timespec *ts)
 static void
 xen_fetch_uptime(struct timespec *ts)
 {
-	uint64_t uptime = xen_fetch_vcpu_time();
+	uint64_t uptime;
+
+	uptime = xen_fetch_vcpu_time(DPCPU_GET(vcpu_info));
+
 	ts->tv_sec = uptime / NSEC_IN_SEC;
 	ts->tv_nsec = uptime % NSEC_IN_SEC;
 }
@@ -354,7 +366,7 @@ xentimer_intr(void *arg)
 	struct xentimer_softc *sc = (struct xentimer_softc *)arg;
 	struct xentimer_pcpu_data *pcpu = DPCPU_PTR(xentimer_pcpu);
 
-	pcpu->last_processed = xen_fetch_vcpu_time();
+	pcpu->last_processed = xen_fetch_vcpu_time(DPCPU_GET(vcpu_info));
 	if (pcpu->timer != 0 && sc->et.et_active)
 		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
 
@@ -398,7 +410,14 @@ xentimer_et_start(struct eventtimer *et,
 	struct xentimer_softc *sc = et->et_priv;
 	int cpu = PCPU_GET(vcpu_id);
 	struct xentimer_pcpu_data *pcpu = DPCPU_PTR(xentimer_pcpu);
+	struct vcpu_info *vcpu = DPCPU_GET(vcpu_info);
 	uint64_t first_in_ns, next_time;
+#ifdef INVARIANTS
+	struct thread *td = curthread;
+#endif
+
+	KASSERT(td->td_critnest != 0,
+	    ("xentimer_et_start called without preemption disabled"));
 
 	/* See sbttots() for this formula. */
 	first_in_ns = (((first >> 32) * NSEC_IN_SEC) +
@@ -415,7 +434,7 @@ xentimer_et_start(struct eventtimer *et,
 	do {
 		if (++i == 60)
 			panic("can't schedule timer");
-		next_time = xen_fetch_vcpu_time() + first_in_ns;
+		next_time = xen_fetch_vcpu_time(vcpu) + first_in_ns;
 		error = xentimer_vcpu_start_timer(cpu, next_time);
 	} while (error == -ETIME);
 



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