1/*- 2 * Copyright (c) 2009 Adrian Chadd 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/clock.h> 36#include <sys/lock.h> 37#include <sys/mutex.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/time.h> 41 42#include <xen/xen_intr.h> 43#include <vm/vm.h> 44#include <vm/pmap.h> 45#include <machine/pmap.h> 46#include <xen/hypervisor.h> 47#include <machine/xen/xen-os.h> 48#include <machine/xen/xenfunc.h> 49#include <xen/interface/io/xenbus.h> 50#include <xen/interface/vcpu.h> 51#include <machine/cpu.h> 52 53#include <machine/xen/xen_clock_util.h> 54 55#include "clock_if.h" 56 57static int 58xen_rtc_probe(device_t dev) 59{ 60 device_set_desc(dev, "Xen Hypervisor Clock"); 61 printf("[XEN] xen_rtc_probe: probing Hypervisor RTC clock\n"); 62 if (! HYPERVISOR_shared_info) { 63 device_printf(dev, "No hypervisor shared page found; RTC can not start.\n"); 64 return (EINVAL); 65 } 66 return (0); 67} 68 69static int 70xen_rtc_attach(device_t dev) 71{ 72 printf("[XEN] xen_rtc_attach: attaching Hypervisor RTC clock\n"); 73 clock_register(dev, 1000000); 74 return(0); 75} 76 77static int 78xen_rtc_settime(device_t dev __unused, struct timespec *ts) 79{ 80 device_printf(dev, "[XEN] xen_rtc_settime\n"); 81 /* 82 * Don't return EINVAL here; just silently fail if the domain isn't privileged enough 83 * to set the TOD. 84 */ 85 return(0); 86} 87 88/* 89 * The Xen time structures document the hypervisor start time and the 90 * uptime-since-hypervisor-start (in nsec.) They need to be combined 91 * in order to calculate a TOD clock. 92 */ 93static int 94xen_rtc_gettime(device_t dev, struct timespec *ts) 95{ 96 struct timespec w_ts, u_ts; 97 98 device_printf(dev, "[XEN] xen_rtc_gettime\n"); 99 xen_fetch_wallclock(&w_ts); 100 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); 101 xen_fetch_uptime(&u_ts); 102 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); 103 104 timespecclear(ts); 105 timespecadd(ts, &w_ts); 106 timespecadd(ts, &u_ts); 107 108 device_printf(dev, "[XEN] xen_rtc_gettime: TOD %ld sec; %ld nsec\n", (long int) ts->tv_sec, (long int) ts->tv_nsec); 109 110 return(0); 111} 112 113static void 114xen_rtc_identify(driver_t *drv, device_t parent) 115{ 116 BUS_ADD_CHILD(parent, 0, "rtc", 0); 117} 118 119static device_method_t xen_rtc_methods[] = { 120 /* Device interface */ 121 DEVMETHOD(device_probe, xen_rtc_probe), 122 DEVMETHOD(device_attach, xen_rtc_attach), 123 DEVMETHOD(device_identify, xen_rtc_identify), 124 125 DEVMETHOD(device_detach, bus_generic_detach), 126 DEVMETHOD(device_shutdown, bus_generic_shutdown), 127 128 /* clock interface */ 129 DEVMETHOD(clock_gettime, xen_rtc_gettime), 130 DEVMETHOD(clock_settime, xen_rtc_settime), 131 132 { 0, 0 } 133}; 134 135 136static driver_t xen_rtc_driver = { 137 "rtc", 138 xen_rtc_methods, 139 0 140}; 141 142static devclass_t xen_rtc_devclass; 143 144DRIVER_MODULE(rtc, nexus, xen_rtc_driver, xen_rtc_devclass, 0, 0); 145