summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroyger <royger@FreeBSD.org>2014-03-11 10:16:17 +0000
committerroyger <royger@FreeBSD.org>2014-03-11 10:16:17 +0000
commit064afe26b0b317ff63aad248bbe3d26fd11f91b8 (patch)
treef321423d5d9e9055745534e5c6c54b3517c431b4
parent4df602a6bf5fb29881afd7bd076a9b24951de9f1 (diff)
downloadFreeBSD-src-064afe26b0b317ff63aad248bbe3d26fd11f91b8.zip
FreeBSD-src-064afe26b0b317ff63aad248bbe3d26fd11f91b8.tar.gz
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.
-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 354085b..6c0a140 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);
OpenPOWER on IntegriCloud