summaryrefslogtreecommitdiff
path: root/sys/dev/xen/timer
diff options
context:
space:
mode:
authorRoger Pau Monné <royger@FreeBSD.org>2014-03-11 10:16:17 +0000
committerRoger Pau Monné <royger@FreeBSD.org>2014-03-11 10:16:17 +0000
commit09982c99b2ec5df06bf084d9c0ce113c192a330b (patch)
treef321423d5d9e9055745534e5c6c54b3517c431b4 /sys/dev/xen/timer
parent97baeefd5b42d5f43006928126733d63379d0c46 (diff)
Notes
Diffstat (limited to 'sys/dev/xen/timer')
-rw-r--r--sys/dev/xen/timer/timer.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/sys/dev/xen/timer/timer.c b/sys/dev/xen/timer/timer.c
index 354085bc183a..6c0a140ec762 100644
--- a/sys/dev/xen/timer/timer.c
+++ b/sys/dev/xen/timer/timer.c
@@ -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_info *dst, struct vcpu_time_info *src)
/**
* \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);