summaryrefslogtreecommitdiffstats
path: root/sys/i386/xen
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>2013-08-29 23:11:58 +0000
committergibbs <gibbs@FreeBSD.org>2013-08-29 23:11:58 +0000
commitf5ff33730e4d7c8ed7baf90dfb75a20ee45fdfd0 (patch)
treed3a1d0f880bba269983f967cc4477ca719a19d07 /sys/i386/xen
parent76248c6467c383919f68dde031fabc532f64d2f0 (diff)
downloadFreeBSD-src-f5ff33730e4d7c8ed7baf90dfb75a20ee45fdfd0.zip
FreeBSD-src-f5ff33730e4d7c8ed7baf90dfb75a20ee45fdfd0.tar.gz
Introduce a new, HVM compatible, paravirtualized timer driver for Xen.
Use this new driver for both PV and HVM instances. This driver requires a Xen hypervisor that supports vector callbacks, VCPUOP hypercalls, and reports that it has a "safe PV clock". New timer driver: Submitted by: will Sponsored by: Spectra Logic Corporation PV port to new driver, and bug fixes: Submitted by: Roger Pau Monné Sponsored by: Citrix Systems R&D sys/dev/xen/timer/timer.c: - Register a PV timer device driver which (currently) implements device_{identify,probe,attach} and stubs device_detach. The detach routine requires functionality not provided by timecounters(4). The suspend and resume routines need additional work (due to Xen requiring that the hypercalls be executed on the target VCPU), and aren't needed for our purposes. - Make sure there can only be one device instance of this driver, and that it only registers one eventtimers(4) and one timecounters(4) device interface. Make both interfaces use PCPU data as needed. - Match, with a few style cleanups & API differences, the Xen versions of the "fetch time" functions. - Document the magic scale_delta() better for the i386 version. - When registering the event timer, bind a separate event channel for the timer VIRQ to the device's event timer interrupt handler for each active VCPU. Describe each interrupt as "xen_et:c%d", so they can be identified per CPU in "vmstat -i" or "show intrcnt" in KDB. - When scheduling a timer into the hypervisor, try up to 60 times if the hypervisor rejects the time as being in the past. In the common case, this retry shouldn't happen, and if it does, it should only happen once. This is because the event timer advertises a minimum period of 100usec, which is only less than the usual hypercall round trip time about 1 out of every 100 tries. (Unlike other similar drivers, this one actually checks whether the hypervisor accepted the singleshot timer set hypercall.) - Implement a RTC PV clock based on the hypervisor wallclock. sys/conf/files: - Add dev/xen/timer/timer.c if the kernel configuration includes either the XEN or XENHVM options. sys/conf/files.i386: sys/i386/include/xen/xen_clock_util.h: sys/i386/xen/clock.c: sys/i386/xen/xen_clock_util.c: sys/i386/xen/mp_machdep.c: sys/i386/xen/xen_rtc.c: - Remove previous PV timer used in i386 XEN PV kernels, the new timer introduced in this change is used instead (so we share the same code between PVHVM and PV). MFC after: 2 weeks
Diffstat (limited to 'sys/i386/xen')
-rw-r--r--sys/i386/xen/clock.c358
-rw-r--r--sys/i386/xen/mp_machdep.c4
-rw-r--r--sys/i386/xen/xen_clock_util.c102
-rw-r--r--sys/i386/xen/xen_rtc.c146
4 files changed, 6 insertions, 604 deletions
diff --git a/sys/i386/xen/clock.c b/sys/i386/xen/clock.c
index 524fa14..075f567 100644
--- a/sys/i386/xen/clock.c
+++ b/sys/i386/xen/clock.c
@@ -79,7 +79,6 @@ __FBSDID("$FreeBSD$");
#include <x86/isa/isa.h>
#include <isa/rtc.h>
-#include <xen/xen_intr.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/pmap.h>
@@ -88,7 +87,7 @@ __FBSDID("$FreeBSD$");
#include <machine/xen/xenfunc.h>
#include <xen/interface/vcpu.h>
#include <machine/cpu.h>
-#include <machine/xen/xen_clock_util.h>
+#include <xen/xen_intr.h>
/*
* 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
@@ -117,6 +116,7 @@ struct mtx clock_lock;
mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE)
#define RTC_LOCK mtx_lock_spin(&clock_lock)
#define RTC_UNLOCK mtx_unlock_spin(&clock_lock)
+#define NS_PER_TICK (1000000000ULL/hz)
int adjkerntz; /* local offset from GMT in seconds */
int clkintr_pending;
@@ -124,22 +124,10 @@ int pscnt = 1;
int psdiv = 1;
int wall_cmos_clock;
u_int timer_freq = TIMER_FREQ;
-static int independent_wallclock;
-static int xen_disable_rtc_set;
static u_long cyc2ns_scale;
-static struct timespec shadow_tv;
-static uint32_t shadow_tv_version; /* XXX: lazy locking */
static uint64_t processed_system_time; /* stime (ns) at last processing. */
-static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
-
-int ap_cpu_initclocks(int cpu);
-
-SYSCTL_INT(_machdep, OID_AUTO, independent_wallclock,
- CTLFLAG_RW, &independent_wallclock, 0, "");
-SYSCTL_INT(_machdep, OID_AUTO, xen_disable_rtc_set,
- CTLFLAG_RW, &xen_disable_rtc_set, 1, "");
-
+extern volatile uint64_t xen_timer_last_time;
#define do_div(n,base) ({ \
unsigned long __upper, __low, __high, __mod, __base; \
@@ -156,12 +144,6 @@ SYSCTL_INT(_machdep, OID_AUTO, xen_disable_rtc_set,
})
-#define NS_PER_TICK (1000000000ULL/hz)
-
-#define rdtscll(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
-
-
/* convert from cycles(64bits) => nanoseconds (64bits)
* basic equation:
* ns = cycles / (freq / ns_per_sec)
@@ -184,208 +166,13 @@ static inline void set_cyc2ns_scale(unsigned long cpu_mhz)
static inline unsigned long long cycles_2_ns(unsigned long long cyc)
{
- return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
-/*
- * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
- * yielding a 64-bit result.
- */
-static inline uint64_t
-scale_delta(uint64_t delta, uint32_t mul_frac, int shift)
-{
- uint64_t product;
- uint32_t tmp1, tmp2;
-
- if ( shift < 0 )
- delta >>= -shift;
- else
- delta <<= shift;
-
- __asm__ (
- "mul %5 ; "
- "mov %4,%%eax ; "
- "mov %%edx,%4 ; "
- "mul %5 ; "
- "xor %5,%5 ; "
- "add %4,%%eax ; "
- "adc %5,%%edx ; "
- : "=A" (product), "=r" (tmp1), "=r" (tmp2)
- : "a" ((uint32_t)delta), "1" ((uint32_t)(delta >> 32)), "2" (mul_frac) );
-
- return product;
-}
-
-static uint64_t
-get_nsec_offset(struct shadow_time_info *shadow)
-{
- uint64_t now, delta;
- rdtscll(now);
- delta = now - shadow->tsc_timestamp;
- return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
-}
-
-static void update_wallclock(void)
-{
- shared_info_t *s = HYPERVISOR_shared_info;
-
- do {
- shadow_tv_version = s->wc_version;
- rmb();
- shadow_tv.tv_sec = s->wc_sec;
- shadow_tv.tv_nsec = s->wc_nsec;
- rmb();
- }
- while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
-
-}
-
-static void
-add_uptime_to_wallclock(void)
-{
- struct timespec ut;
-
- xen_fetch_uptime(&ut);
- timespecadd(&shadow_tv, &ut);
-}
-
-/*
- * Reads a consistent set of time-base values from Xen, into a shadow data
- * area. Must be called with the xtime_lock held for writing.
- */
-static void __get_time_values_from_xen(void)
-{
- shared_info_t *s = HYPERVISOR_shared_info;
- struct vcpu_time_info *src;
- struct shadow_time_info *dst;
- uint32_t pre_version, post_version;
- struct pcpu *pc;
-
- pc = pcpu_find(smp_processor_id());
- src = &s->vcpu_info[smp_processor_id()].time;
- dst = &pc->pc_shadow_time;
-
- spinlock_enter();
- do {
- pre_version = dst->version = src->version;
- rmb();
- dst->tsc_timestamp = src->tsc_timestamp;
- dst->system_timestamp = src->system_time;
- dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
- dst->tsc_shift = src->tsc_shift;
- rmb();
- post_version = src->version;
- }
- while ((pre_version & 1) | (pre_version ^ post_version));
-
- dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
- spinlock_exit();
-}
-
-
-static inline int time_values_up_to_date(int cpu)
-{
- struct vcpu_time_info *src;
- struct shadow_time_info *dst;
- struct pcpu *pc;
-
- src = &HYPERVISOR_shared_info->vcpu_info[cpu].time;
- pc = pcpu_find(cpu);
- dst = &pc->pc_shadow_time;
-
- rmb();
- return (dst->version == src->version);
+ return ((cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR);
}
-static unsigned xen_get_timecount(struct timecounter *tc);
-
-static struct timecounter xen_timecounter = {
- xen_get_timecount, /* get_timecount */
- 0, /* no poll_pps */
- ~0u, /* counter_mask */
- 0, /* frequency */
- "ixen", /* name */
- 0 /* quality */
-};
-
-static struct eventtimer xen_et;
-
-struct xen_et_state {
- int mode;
-#define MODE_STOP 0
-#define MODE_PERIODIC 1
-#define MODE_ONESHOT 2
- int64_t period;
- int64_t next;
-};
-
-static DPCPU_DEFINE(struct xen_et_state, et_state);
-
-static int
-clkintr(void *arg)
-{
- int64_t now;
- int cpu = smp_processor_id();
- struct pcpu *pc = pcpu_find(cpu);
- struct shadow_time_info *shadow = &pc->pc_shadow_time;
- struct xen_et_state *state = DPCPU_PTR(et_state);
-
- do {
- __get_time_values_from_xen();
- now = shadow->system_timestamp + get_nsec_offset(shadow);
- } while (!time_values_up_to_date(cpu));
-
- /* Process elapsed ticks since last call. */
- processed_system_time = now;
- if (state->mode == MODE_PERIODIC) {
- while (now >= state->next) {
- state->next += state->period;
- if (xen_et.et_active)
- xen_et.et_event_cb(&xen_et, xen_et.et_arg);
- }
- HYPERVISOR_set_timer_op(state->next + 50000);
- } else if (state->mode == MODE_ONESHOT) {
- if (xen_et.et_active)
- xen_et.et_event_cb(&xen_et, xen_et.et_arg);
- }
- /*
- * Take synchronised time from Xen once a minute if we're not
- * synchronised ourselves, and we haven't chosen to keep an independent
- * time base.
- */
-
- if (shadow_tv_version != HYPERVISOR_shared_info->wc_version &&
- !independent_wallclock) {
- printf("[XEN] hypervisor wallclock nudged; nudging TOD.\n");
- update_wallclock();
- add_uptime_to_wallclock();
- tc_setclock(&shadow_tv);
- }
-
- /* XXX TODO */
- return (FILTER_HANDLED);
-}
static uint32_t
getit(void)
{
- struct shadow_time_info *shadow;
- uint64_t time;
- uint32_t local_time_version;
- struct pcpu *pc;
-
- pc = pcpu_find(smp_processor_id());
- shadow = &pc->pc_shadow_time;
-
- do {
- local_time_version = shadow->version;
- barrier();
- time = shadow->system_timestamp + get_nsec_offset(shadow);
- if (!time_values_up_to_date(smp_processor_id()))
- __get_time_values_from_xen(/*cpu */);
- barrier();
- } while (local_time_version != shadow->version);
-
- return (time);
+ return (xen_timer_last_time);
}
@@ -489,43 +276,12 @@ DELAY(int n)
#endif
}
-
-/*
- * Restore all the timers non-atomically (XXX: should be atomically).
- *
- * This function is called from pmtimer_resume() to restore all the timers.
- * This should not be necessary, but there are broken laptops that do not
- * restore all the timers on resume.
- */
-void
-timer_restore(void)
-{
- struct xen_et_state *state = DPCPU_PTR(et_state);
- struct pcpu *pc;
-
- /* Get timebases for new environment. */
- __get_time_values_from_xen();
-
- /* Reset our own concept of passage of system time. */
- pc = pcpu_find(0);
- processed_system_time = pc->pc_shadow_time.system_timestamp;
- state->next = processed_system_time;
-}
-
void
startrtclock()
{
- unsigned long long alarm;
uint64_t __cpu_khz;
uint32_t cpu_khz;
struct vcpu_time_info *info;
- struct pcpu *pc;
-
- pc = pcpu_find(0);
-
- /* initialize xen values */
- __get_time_values_from_xen();
- processed_system_time = pc->pc_shadow_time.system_timestamp;
__cpu_khz = 1000000ULL << 32;
info = &HYPERVISOR_shared_info->vcpu_info[0].time;
@@ -544,12 +300,6 @@ startrtclock()
set_cyc2ns_scale(cpu_khz/1000);
tsc_freq = cpu_khz * 1000;
-
- timer_freq = 1000000000LL;
- xen_timecounter.tc_frequency = timer_freq >> 9;
- tc_init(&xen_timecounter);
-
- rdtscll(alarm);
}
/*
@@ -783,116 +533,20 @@ resettodr()
}
#endif
-static int
-xen_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
-{
- struct xen_et_state *state = DPCPU_PTR(et_state);
- struct shadow_time_info *shadow;
- int64_t fperiod;
- struct pcpu *pc;
-
- __get_time_values_from_xen();
-
- if (period != 0) {
- state->mode = MODE_PERIODIC;
- state->period = (1000000000LLU * period) >> 32;
- } else {
- state->mode = MODE_ONESHOT;
- state->period = 0;
- }
- if (first != 0)
- fperiod = (1000000000LLU * first) >> 32;
- else
- fperiod = state->period;
-
- pc = pcpu_find(smp_processor_id());
- shadow = &pc->pc_shadow_time;
- state->next = shadow->system_timestamp + get_nsec_offset(shadow);
- state->next += fperiod;
- HYPERVISOR_set_timer_op(state->next + 50000);
- return (0);
-}
-
-static int
-xen_et_stop(struct eventtimer *et)
-{
- struct xen_et_state *state = DPCPU_PTR(et_state);
-
- state->mode = MODE_STOP;
- HYPERVISOR_set_timer_op(0);
- return (0);
-}
-
/*
* Start clocks running.
*/
void
cpu_initclocks(void)
{
- xen_intr_handle_t time_irq;
- int error;
-
- HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, 0, NULL);
- error = xen_intr_bind_virq(root_bus, VIRQ_TIMER, 0,
- clkintr, NULL, NULL, INTR_TYPE_CLK, &time_irq);
- if (error)
- panic("failed to register clock interrupt\n");
- /* should fast clock be enabled ? */
-
- bzero(&xen_et, sizeof(xen_et));
- xen_et.et_name = "ixen";
- xen_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
- ET_FLAGS_PERCPU;
- xen_et.et_quality = 600;
- xen_et.et_frequency = 1000000000;
- xen_et.et_min_period = 0x00400000LL;
- xen_et.et_max_period = (0xfffffffeLLU << 32) / xen_et.et_frequency;
- xen_et.et_start = xen_et_start;
- xen_et.et_stop = xen_et_stop;
- xen_et.et_priv = NULL;
- et_register(&xen_et);
-
cpu_initclocks_bsp();
}
-int
-ap_cpu_initclocks(int cpu)
-{
- xen_intr_handle_t time_irq;
- int error;
-
- HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL);
- error = xen_intr_bind_virq(root_bus, VIRQ_TIMER, cpu,
- clkintr, NULL, NULL, INTR_TYPE_CLK, &time_irq);
- if (error)
- panic("failed to register clock interrupt\n");
-
- return (0);
-}
-
-static uint32_t
-xen_get_timecount(struct timecounter *tc)
-{
- uint64_t clk;
- struct shadow_time_info *shadow;
- struct pcpu *pc;
-
- pc = pcpu_find(smp_processor_id());
- shadow = &pc->pc_shadow_time;
-
- __get_time_values_from_xen();
-
- clk = shadow->system_timestamp + get_nsec_offset(shadow);
-
- return (uint32_t)(clk >> 9);
-
-}
-
/* Return system time offset by ticks */
uint64_t
get_system_time(int ticks)
{
- return processed_system_time + (ticks * NS_PER_TICK);
+ return (processed_system_time + (ticks * NS_PER_TICK));
}
int
diff --git a/sys/i386/xen/mp_machdep.c b/sys/i386/xen/mp_machdep.c
index 407731a..c070172 100644
--- a/sys/i386/xen/mp_machdep.c
+++ b/sys/i386/xen/mp_machdep.c
@@ -153,7 +153,6 @@ static cpuset_t hyperthreading_cpus_mask;
extern void Xhypervisor_callback(void);
extern void failsafe_callback(void);
extern void pmap_lazyfix_action(void);
-extern int ap_cpu_initclocks(int cpu);
DPCPU_DEFINE(xen_intr_handle_t, ipi_port[NR_IPIS]);
DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
@@ -495,9 +494,6 @@ xen_smp_cpu_init(unsigned int cpu)
printf("[XEN] IPI cpu=%d port=%d vector=CALL_FUNCTION_VECTOR (%d)\n",
cpu, xen_intr_port(irq_handle), CALL_FUNCTION_VECTOR);
- if ((cpu != 0) && ((rc = ap_cpu_initclocks(cpu)) != 0))
- goto fail;
-
return 0;
fail:
diff --git a/sys/i386/xen/xen_clock_util.c b/sys/i386/xen/xen_clock_util.c
deleted file mode 100644
index c124515..0000000
--- a/sys/i386/xen/xen_clock_util.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*-
- * Copyright (c) 2009 Adrian Chadd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/clock.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/time.h>
-
-#include <xen/xen-os.h>
-#include <xen/xen_intr.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/pmap.h>
-#include <xen/hypervisor.h>
-#include <machine/xen/xenfunc.h>
-#include <xen/interface/io/xenbus.h>
-#include <xen/interface/vcpu.h>
-#include <machine/cpu.h>
-
-#include <machine/xen/xen_clock_util.h>
-
-/*
- * Read the current hypervisor start time (wall clock) from Xen.
- */
-void
-xen_fetch_wallclock(struct timespec *ts)
-{
- shared_info_t *s = HYPERVISOR_shared_info;
- uint32_t ts_version;
-
- do {
- ts_version = s->wc_version;
- rmb();
- ts->tv_sec = s->wc_sec;
- ts->tv_nsec = s->wc_nsec;
- rmb();
- }
- while ((s->wc_version & 1) | (ts_version ^ s->wc_version));
-}
-
-/*
- * Read the current hypervisor system uptime value from Xen.
- */
-void
-xen_fetch_uptime(struct timespec *ts)
-{
- shared_info_t *s = HYPERVISOR_shared_info;
- struct vcpu_time_info *src;
- struct shadow_time_info dst;
- uint32_t pre_version, post_version;
-
- src = &s->vcpu_info[smp_processor_id()].time;
-
- spinlock_enter();
- do {
- pre_version = dst.version = src->version;
- rmb();
- dst.system_timestamp = src->system_time;
- rmb();
- post_version = src->version;
- }
- while ((pre_version & 1) | (pre_version ^ post_version));
-
- spinlock_exit();
-
- ts->tv_sec = dst.system_timestamp / 1000000000;
- ts->tv_nsec = dst.system_timestamp % 1000000000;
-}
diff --git a/sys/i386/xen/xen_rtc.c b/sys/i386/xen/xen_rtc.c
deleted file mode 100644
index 8dc3ecb..0000000
--- a/sys/i386/xen/xen_rtc.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*-
- * Copyright (c) 2009 Adrian Chadd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/clock.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/time.h>
-
-#include <xen/xen-os.h>
-#include <xen/xen_intr.h>
-#include <xen/hypervisor.h>
-#include <xen/interface/io/xenbus.h>
-#include <xen/interface/vcpu.h>
-
-#include <vm/vm.h>
-#include <vm/pmap.h>
-
-#include <machine/pmap.h>
-#include <machine/xen/xenfunc.h>
-#include <machine/cpu.h>
-
-#include <machine/xen/xen_clock_util.h>
-
-#include "clock_if.h"
-
-static int
-xen_rtc_probe(device_t dev)
-{
- device_set_desc(dev, "Xen Hypervisor Clock");
- printf("[XEN] xen_rtc_probe: probing Hypervisor RTC clock\n");
- if (! HYPERVISOR_shared_info) {
- device_printf(dev, "No hypervisor shared page found; RTC can not start.\n");
- return (EINVAL);
- }
- return (0);
-}
-
-static int
-xen_rtc_attach(device_t dev)
-{
- printf("[XEN] xen_rtc_attach: attaching Hypervisor RTC clock\n");
- clock_register(dev, 1000000);
- return(0);
-}
-
-static int
-xen_rtc_settime(device_t dev __unused, struct timespec *ts)
-{
- device_printf(dev, "[XEN] xen_rtc_settime\n");
- /*
- * Don't return EINVAL here; just silently fail if the domain isn't privileged enough
- * to set the TOD.
- */
- return(0);
-}
-
-/*
- * The Xen time structures document the hypervisor start time and the
- * uptime-since-hypervisor-start (in nsec.) They need to be combined
- * in order to calculate a TOD clock.
- */
-static int
-xen_rtc_gettime(device_t dev, struct timespec *ts)
-{
- struct timespec w_ts, u_ts;
-
- device_printf(dev, "[XEN] xen_rtc_gettime\n");
- xen_fetch_wallclock(&w_ts);
- device_printf(dev, "[XEN] xen_rtc_gettime: wallclock %ld sec; %ld nsec\n", (long int) w_ts.tv_sec, (long int) w_ts.tv_nsec);
- xen_fetch_uptime(&u_ts);
- device_printf(dev, "[XEN] xen_rtc_gettime: uptime %ld sec; %ld nsec\n", (long int) u_ts.tv_sec, (long int) u_ts.tv_nsec);
-
- timespecclear(ts);
- timespecadd(ts, &w_ts);
- timespecadd(ts, &u_ts);
-
- device_printf(dev, "[XEN] xen_rtc_gettime: TOD %ld sec; %ld nsec\n", (long int) ts->tv_sec, (long int) ts->tv_nsec);
-
- return(0);
-}
-
-static void
-xen_rtc_identify(driver_t *drv, device_t parent)
-{
- BUS_ADD_CHILD(parent, 0, "rtc", 0);
-}
-
-static device_method_t xen_rtc_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, xen_rtc_probe),
- DEVMETHOD(device_attach, xen_rtc_attach),
- DEVMETHOD(device_identify, xen_rtc_identify),
-
- DEVMETHOD(device_detach, bus_generic_detach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
-
- /* clock interface */
- DEVMETHOD(clock_gettime, xen_rtc_gettime),
- DEVMETHOD(clock_settime, xen_rtc_settime),
-
- { 0, 0 }
-};
-
-
-static driver_t xen_rtc_driver = {
- "rtc",
- xen_rtc_methods,
- 0
-};
-
-static devclass_t xen_rtc_devclass;
-
-DRIVER_MODULE(rtc, nexus, xen_rtc_driver, xen_rtc_devclass, 0, 0);
OpenPOWER on IntegriCloud