1dcb4b138SElliott Mitchell /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3dcb4b138SElliott Mitchell * 4dcb4b138SElliott Mitchell * Copyright (c) 2009 Adrian Chadd 5dcb4b138SElliott Mitchell * Copyright (c) 2012 Spectra Logic Corporation 6dcb4b138SElliott Mitchell * All rights reserved. 7dcb4b138SElliott Mitchell * 8dcb4b138SElliott Mitchell * Redistribution and use in source and binary forms, with or without 9dcb4b138SElliott Mitchell * modification, are permitted provided that the following conditions 10dcb4b138SElliott Mitchell * are met: 11dcb4b138SElliott Mitchell * 1. Redistributions of source code must retain the above copyright 12dcb4b138SElliott Mitchell * notice, this list of conditions and the following disclaimer. 13dcb4b138SElliott Mitchell * 2. Redistributions in binary form must reproduce the above copyright 14dcb4b138SElliott Mitchell * notice, this list of conditions and the following disclaimer in the 15dcb4b138SElliott Mitchell * documentation and/or other materials provided with the distribution. 16dcb4b138SElliott Mitchell * 17dcb4b138SElliott Mitchell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18dcb4b138SElliott Mitchell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19dcb4b138SElliott Mitchell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20dcb4b138SElliott Mitchell * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21dcb4b138SElliott Mitchell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22dcb4b138SElliott Mitchell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23dcb4b138SElliott Mitchell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24dcb4b138SElliott Mitchell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25dcb4b138SElliott Mitchell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26dcb4b138SElliott Mitchell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27dcb4b138SElliott Mitchell * SUCH DAMAGE. 28dcb4b138SElliott Mitchell * 29dcb4b138SElliott Mitchell */ 30dcb4b138SElliott Mitchell 31dcb4b138SElliott Mitchell /** 32dcb4b138SElliott Mitchell * \file dev/xen/timer/xen_timer.c 33dcb4b138SElliott Mitchell * \brief A timer driver for the Xen hypervisor's PV clock. 34dcb4b138SElliott Mitchell */ 35dcb4b138SElliott Mitchell 36dcb4b138SElliott Mitchell #include <sys/cdefs.h> 37dcb4b138SElliott Mitchell __FBSDID("$FreeBSD$"); 38dcb4b138SElliott Mitchell 39dcb4b138SElliott Mitchell #include <sys/param.h> 40dcb4b138SElliott Mitchell #include <sys/systm.h> 41dcb4b138SElliott Mitchell #include <sys/bus.h> 42dcb4b138SElliott Mitchell #include <sys/kernel.h> 43dcb4b138SElliott Mitchell #include <sys/module.h> 44dcb4b138SElliott Mitchell #include <sys/time.h> 45dcb4b138SElliott Mitchell #include <sys/timetc.h> 46dcb4b138SElliott Mitchell #include <sys/timeet.h> 47dcb4b138SElliott Mitchell #include <sys/smp.h> 48dcb4b138SElliott Mitchell #include <sys/limits.h> 49dcb4b138SElliott Mitchell #include <sys/clock.h> 50dcb4b138SElliott Mitchell #include <sys/proc.h> 51dcb4b138SElliott Mitchell 52dcb4b138SElliott Mitchell #include <xen/xen-os.h> 53dcb4b138SElliott Mitchell #include <xen/features.h> 54dcb4b138SElliott Mitchell #include <xen/xen_intr.h> 55dcb4b138SElliott Mitchell #include <xen/hypervisor.h> 56dcb4b138SElliott Mitchell #include <contrib/xen/io/xenbus.h> 57dcb4b138SElliott Mitchell #include <contrib/xen/vcpu.h> 58dcb4b138SElliott Mitchell #include <xen/error.h> 59dcb4b138SElliott Mitchell 60dcb4b138SElliott Mitchell #include <machine/cpu.h> 61dcb4b138SElliott Mitchell #include <machine/cpufunc.h> 62dcb4b138SElliott Mitchell #include <machine/clock.h> 63dcb4b138SElliott Mitchell #include <machine/_inttypes.h> 64dcb4b138SElliott Mitchell #include <machine/smp.h> 65dcb4b138SElliott Mitchell #include <machine/pvclock.h> 66dcb4b138SElliott Mitchell 67dcb4b138SElliott Mitchell #include <dev/xen/timer/timer.h> 68dcb4b138SElliott Mitchell 69dcb4b138SElliott Mitchell #include "clock_if.h" 70dcb4b138SElliott Mitchell 71dcb4b138SElliott Mitchell #define NSEC_IN_SEC 1000000000ULL 72dcb4b138SElliott Mitchell #define NSEC_IN_USEC 1000ULL 73dcb4b138SElliott Mitchell /* 18446744073 = int(2^64 / NSEC_IN_SC) = 1 ns in 64-bit fractions */ 74dcb4b138SElliott Mitchell #define FRAC_IN_NSEC 18446744073LL 75dcb4b138SElliott Mitchell 76dcb4b138SElliott Mitchell /* Xen timers may fire up to 100us off */ 77dcb4b138SElliott Mitchell #define XENTIMER_MIN_PERIOD_IN_NSEC 100*NSEC_IN_USEC 78dcb4b138SElliott Mitchell 79dcb4b138SElliott Mitchell /* 80dcb4b138SElliott Mitchell * The real resolution of the PV clock is 1ns, but the highest 81dcb4b138SElliott Mitchell * resolution that FreeBSD supports is 1us, so just use that. 82dcb4b138SElliott Mitchell */ 83dcb4b138SElliott Mitchell #define XENCLOCK_RESOLUTION 1 84dcb4b138SElliott Mitchell 85dcb4b138SElliott Mitchell #define XENTIMER_QUALITY 950 86dcb4b138SElliott Mitchell 87dcb4b138SElliott Mitchell struct xentimer_pcpu_data { 88dcb4b138SElliott Mitchell uint64_t timer; 89dcb4b138SElliott Mitchell uint64_t last_processed; 90dcb4b138SElliott Mitchell void *irq_handle; 91dcb4b138SElliott Mitchell }; 92dcb4b138SElliott Mitchell 93dcb4b138SElliott Mitchell DPCPU_DEFINE(struct xentimer_pcpu_data, xentimer_pcpu); 94dcb4b138SElliott Mitchell 95dcb4b138SElliott Mitchell DPCPU_DECLARE(struct vcpu_info *, vcpu_info); 96dcb4b138SElliott Mitchell 97dcb4b138SElliott Mitchell struct xentimer_softc { 98dcb4b138SElliott Mitchell device_t dev; 99dcb4b138SElliott Mitchell struct timecounter tc; 100dcb4b138SElliott Mitchell struct eventtimer et; 101dcb4b138SElliott Mitchell }; 102dcb4b138SElliott Mitchell 103dcb4b138SElliott Mitchell static void 104dcb4b138SElliott Mitchell xentimer_identify(driver_t *driver, device_t parent) 105dcb4b138SElliott Mitchell { 106dcb4b138SElliott Mitchell if (!xen_domain()) 107dcb4b138SElliott Mitchell return; 108dcb4b138SElliott Mitchell 109dcb4b138SElliott Mitchell /* Handle all Xen PV timers in one device instance. */ 110dcb4b138SElliott Mitchell if (devclass_get_device(devclass_find(driver->name), 0)) 111dcb4b138SElliott Mitchell return; 112dcb4b138SElliott Mitchell 113dcb4b138SElliott Mitchell BUS_ADD_CHILD(parent, 0, driver->name, 0); 114dcb4b138SElliott Mitchell } 115dcb4b138SElliott Mitchell 116dcb4b138SElliott Mitchell static int 117dcb4b138SElliott Mitchell xentimer_probe(device_t dev) 118dcb4b138SElliott Mitchell { 119dcb4b138SElliott Mitchell KASSERT((xen_domain()), ("Trying to use Xen timer on bare metal")); 120dcb4b138SElliott Mitchell /* 121dcb4b138SElliott Mitchell * In order to attach, this driver requires the following: 122dcb4b138SElliott Mitchell * - Vector callback support by the hypervisor, in order to deliver 123dcb4b138SElliott Mitchell * timer interrupts to the correct CPU for CPUs other than 0. 124dcb4b138SElliott Mitchell * - Access to the hypervisor shared info page, in order to look up 125dcb4b138SElliott Mitchell * each VCPU's timer information and the Xen wallclock time. 126dcb4b138SElliott Mitchell * - The hypervisor must say its PV clock is "safe" to use. 127dcb4b138SElliott Mitchell * - The hypervisor must support VCPUOP hypercalls. 128dcb4b138SElliott Mitchell * - The maximum number of CPUs supported by FreeBSD must not exceed 129dcb4b138SElliott Mitchell * the number of VCPUs supported by the hypervisor. 130dcb4b138SElliott Mitchell */ 131dcb4b138SElliott Mitchell #define XTREQUIRES(condition, reason...) \ 132dcb4b138SElliott Mitchell if (!(condition)) { \ 133dcb4b138SElliott Mitchell device_printf(dev, ## reason); \ 134dcb4b138SElliott Mitchell device_detach(dev); \ 135dcb4b138SElliott Mitchell return (ENXIO); \ 136dcb4b138SElliott Mitchell } 137dcb4b138SElliott Mitchell 138dcb4b138SElliott Mitchell if (xen_hvm_domain()) { 139dcb4b138SElliott Mitchell XTREQUIRES(xen_vector_callback_enabled, 140dcb4b138SElliott Mitchell "vector callbacks unavailable\n"); 141dcb4b138SElliott Mitchell XTREQUIRES(xen_feature(XENFEAT_hvm_safe_pvclock), 142dcb4b138SElliott Mitchell "HVM safe pvclock unavailable\n"); 143dcb4b138SElliott Mitchell } 144dcb4b138SElliott Mitchell XTREQUIRES(HYPERVISOR_shared_info != NULL, 145dcb4b138SElliott Mitchell "shared info page unavailable\n"); 146dcb4b138SElliott Mitchell XTREQUIRES(HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, 0, NULL) == 0, 147dcb4b138SElliott Mitchell "VCPUOPs interface unavailable\n"); 148dcb4b138SElliott Mitchell #undef XTREQUIRES 149dcb4b138SElliott Mitchell device_set_desc(dev, "Xen PV Clock"); 150dcb4b138SElliott Mitchell return (BUS_PROBE_NOWILDCARD); 151dcb4b138SElliott Mitchell } 152dcb4b138SElliott Mitchell 153dcb4b138SElliott Mitchell /** 154dcb4b138SElliott Mitchell * \brief Get the current time, in nanoseconds, since the hypervisor booted. 155dcb4b138SElliott Mitchell * 156dcb4b138SElliott Mitchell * \param vcpu vcpu_info structure to fetch the time from. 157dcb4b138SElliott Mitchell * 158dcb4b138SElliott Mitchell */ 159dcb4b138SElliott Mitchell static uint64_t 160dcb4b138SElliott Mitchell xen_fetch_vcpu_time(struct vcpu_info *vcpu) 161dcb4b138SElliott Mitchell { 162dcb4b138SElliott Mitchell struct pvclock_vcpu_time_info *time; 163dcb4b138SElliott Mitchell 164dcb4b138SElliott Mitchell time = (struct pvclock_vcpu_time_info *) &vcpu->time; 165dcb4b138SElliott Mitchell 166dcb4b138SElliott Mitchell return (pvclock_get_timecount(time)); 167dcb4b138SElliott Mitchell } 168dcb4b138SElliott Mitchell 169dcb4b138SElliott Mitchell static uint32_t 170dcb4b138SElliott Mitchell xentimer_get_timecount(struct timecounter *tc) 171dcb4b138SElliott Mitchell { 172dcb4b138SElliott Mitchell uint64_t vcpu_time; 173dcb4b138SElliott Mitchell 174dcb4b138SElliott Mitchell /* 175dcb4b138SElliott Mitchell * We don't disable preemption here because the worst that can 176dcb4b138SElliott Mitchell * happen is reading the vcpu_info area of a different CPU than 177dcb4b138SElliott Mitchell * the one we are currently running on, but that would also 178dcb4b138SElliott Mitchell * return a valid tc (and we avoid the overhead of 179dcb4b138SElliott Mitchell * critical_{enter/exit} calls). 180dcb4b138SElliott Mitchell */ 181dcb4b138SElliott Mitchell vcpu_time = xen_fetch_vcpu_time(DPCPU_GET(vcpu_info)); 182dcb4b138SElliott Mitchell 183dcb4b138SElliott Mitchell return (vcpu_time & UINT32_MAX); 184dcb4b138SElliott Mitchell } 185dcb4b138SElliott Mitchell 186dcb4b138SElliott Mitchell /** 187dcb4b138SElliott Mitchell * \brief Fetch the hypervisor boot time, known as the "Xen wallclock". 188dcb4b138SElliott Mitchell * 189dcb4b138SElliott Mitchell * \param ts Timespec to store the current stable value. 190dcb4b138SElliott Mitchell * \param version Pointer to store the corresponding wallclock version. 191dcb4b138SElliott Mitchell * 192dcb4b138SElliott Mitchell * \note This value is updated when Domain-0 shifts its clock to follow 193dcb4b138SElliott Mitchell * clock drift, e.g. as detected by NTP. 194dcb4b138SElliott Mitchell */ 195dcb4b138SElliott Mitchell static void 196dcb4b138SElliott Mitchell xen_fetch_wallclock(struct timespec *ts) 197dcb4b138SElliott Mitchell { 198dcb4b138SElliott Mitchell shared_info_t *src = HYPERVISOR_shared_info; 199dcb4b138SElliott Mitchell struct pvclock_wall_clock *wc; 200dcb4b138SElliott Mitchell 201dcb4b138SElliott Mitchell wc = (struct pvclock_wall_clock *) &src->wc_version; 202dcb4b138SElliott Mitchell 203dcb4b138SElliott Mitchell pvclock_get_wallclock(wc, ts); 204dcb4b138SElliott Mitchell } 205dcb4b138SElliott Mitchell 206dcb4b138SElliott Mitchell static void 207dcb4b138SElliott Mitchell xen_fetch_uptime(struct timespec *ts) 208dcb4b138SElliott Mitchell { 209dcb4b138SElliott Mitchell uint64_t uptime; 210dcb4b138SElliott Mitchell 211dcb4b138SElliott Mitchell uptime = xen_fetch_vcpu_time(DPCPU_GET(vcpu_info)); 212dcb4b138SElliott Mitchell 213dcb4b138SElliott Mitchell ts->tv_sec = uptime / NSEC_IN_SEC; 214dcb4b138SElliott Mitchell ts->tv_nsec = uptime % NSEC_IN_SEC; 215dcb4b138SElliott Mitchell } 216dcb4b138SElliott Mitchell 217dcb4b138SElliott Mitchell static int 218dcb4b138SElliott Mitchell xentimer_settime(device_t dev __unused, struct timespec *ts) 219dcb4b138SElliott Mitchell { 220dcb4b138SElliott Mitchell struct xen_platform_op settime; 221dcb4b138SElliott Mitchell int ret; 222dcb4b138SElliott Mitchell 223dcb4b138SElliott Mitchell /* 224dcb4b138SElliott Mitchell * Don't return EINVAL here; just silently fail if the domain isn't 225dcb4b138SElliott Mitchell * privileged enough to set the TOD. 226dcb4b138SElliott Mitchell */ 227dcb4b138SElliott Mitchell if (!xen_initial_domain()) 228dcb4b138SElliott Mitchell return (0); 229dcb4b138SElliott Mitchell 230dcb4b138SElliott Mitchell settime.cmd = XENPF_settime64; 231dcb4b138SElliott Mitchell settime.u.settime64.mbz = 0; 232dcb4b138SElliott Mitchell settime.u.settime64.secs = ts->tv_sec; 233dcb4b138SElliott Mitchell settime.u.settime64.nsecs = ts->tv_nsec; 234dcb4b138SElliott Mitchell settime.u.settime64.system_time = 235dcb4b138SElliott Mitchell xen_fetch_vcpu_time(DPCPU_GET(vcpu_info)); 236dcb4b138SElliott Mitchell 237dcb4b138SElliott Mitchell ret = HYPERVISOR_platform_op(&settime); 238dcb4b138SElliott Mitchell ret = ret != 0 ? xen_translate_error(ret) : 0; 239dcb4b138SElliott Mitchell if (ret != 0 && bootverbose) 240dcb4b138SElliott Mitchell device_printf(dev, "failed to set Xen PV clock: %d\n", ret); 241dcb4b138SElliott Mitchell 242dcb4b138SElliott Mitchell return (ret); 243dcb4b138SElliott Mitchell } 244dcb4b138SElliott Mitchell 245dcb4b138SElliott Mitchell /** 246dcb4b138SElliott Mitchell * \brief Return current time according to the Xen Hypervisor wallclock. 247dcb4b138SElliott Mitchell * 248dcb4b138SElliott Mitchell * \param dev Xentimer device. 249dcb4b138SElliott Mitchell * \param ts Pointer to store the wallclock time. 250dcb4b138SElliott Mitchell * 251dcb4b138SElliott Mitchell * \note The Xen time structures document the hypervisor start time and the 252dcb4b138SElliott Mitchell * uptime-since-hypervisor-start (in nsec.) They need to be combined 253dcb4b138SElliott Mitchell * in order to calculate a TOD clock. 254dcb4b138SElliott Mitchell */ 255dcb4b138SElliott Mitchell static int 256dcb4b138SElliott Mitchell xentimer_gettime(device_t dev, struct timespec *ts) 257dcb4b138SElliott Mitchell { 258dcb4b138SElliott Mitchell struct timespec u_ts; 259dcb4b138SElliott Mitchell 260dcb4b138SElliott Mitchell timespecclear(ts); 261dcb4b138SElliott Mitchell xen_fetch_wallclock(ts); 262dcb4b138SElliott Mitchell xen_fetch_uptime(&u_ts); 263dcb4b138SElliott Mitchell timespecadd(ts, &u_ts, ts); 264dcb4b138SElliott Mitchell 265dcb4b138SElliott Mitchell return (0); 266dcb4b138SElliott Mitchell } 267dcb4b138SElliott Mitchell 268dcb4b138SElliott Mitchell /** 269dcb4b138SElliott Mitchell * \brief Handle a timer interrupt for the Xen PV timer driver. 270dcb4b138SElliott Mitchell * 271dcb4b138SElliott Mitchell * \param arg Xen timer driver softc that is expecting the interrupt. 272dcb4b138SElliott Mitchell */ 273dcb4b138SElliott Mitchell static int 274dcb4b138SElliott Mitchell xentimer_intr(void *arg) 275dcb4b138SElliott Mitchell { 276dcb4b138SElliott Mitchell struct xentimer_softc *sc = (struct xentimer_softc *)arg; 277dcb4b138SElliott Mitchell struct xentimer_pcpu_data *pcpu = DPCPU_PTR(xentimer_pcpu); 278dcb4b138SElliott Mitchell 279dcb4b138SElliott Mitchell pcpu->last_processed = xen_fetch_vcpu_time(DPCPU_GET(vcpu_info)); 280dcb4b138SElliott Mitchell if (pcpu->timer != 0 && sc->et.et_active) 281dcb4b138SElliott Mitchell sc->et.et_event_cb(&sc->et, sc->et.et_arg); 282dcb4b138SElliott Mitchell 283dcb4b138SElliott Mitchell return (FILTER_HANDLED); 284dcb4b138SElliott Mitchell } 285dcb4b138SElliott Mitchell 286dcb4b138SElliott Mitchell static int 287dcb4b138SElliott Mitchell xentimer_vcpu_start_timer(int vcpu, uint64_t next_time) 288dcb4b138SElliott Mitchell { 289dcb4b138SElliott Mitchell struct vcpu_set_singleshot_timer single; 290dcb4b138SElliott Mitchell 291dcb4b138SElliott Mitchell single.timeout_abs_ns = next_time; 292dcb4b138SElliott Mitchell /* Get an event anyway, even if the timeout is already expired */ 293dcb4b138SElliott Mitchell single.flags = 0; 294dcb4b138SElliott Mitchell return (HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, vcpu, &single)); 295dcb4b138SElliott Mitchell } 296dcb4b138SElliott Mitchell 297dcb4b138SElliott Mitchell static int 298dcb4b138SElliott Mitchell xentimer_vcpu_stop_timer(int vcpu) 299dcb4b138SElliott Mitchell { 300dcb4b138SElliott Mitchell 301dcb4b138SElliott Mitchell return (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, vcpu, NULL)); 302dcb4b138SElliott Mitchell } 303dcb4b138SElliott Mitchell 304dcb4b138SElliott Mitchell /** 305dcb4b138SElliott Mitchell * \brief Set the next oneshot time for the current CPU. 306dcb4b138SElliott Mitchell * 307dcb4b138SElliott Mitchell * \param et Xen timer driver event timer to schedule on. 308dcb4b138SElliott Mitchell * \param first Delta to the next time to schedule the interrupt for. 309dcb4b138SElliott Mitchell * \param period Not used. 310dcb4b138SElliott Mitchell * 311dcb4b138SElliott Mitchell * \note See eventtimers(9) for more information. 312dcb4b138SElliott Mitchell * \note 313dcb4b138SElliott Mitchell * 314dcb4b138SElliott Mitchell * \returns 0 315dcb4b138SElliott Mitchell */ 316dcb4b138SElliott Mitchell static int 317dcb4b138SElliott Mitchell xentimer_et_start(struct eventtimer *et, 318dcb4b138SElliott Mitchell sbintime_t first, sbintime_t period) 319dcb4b138SElliott Mitchell { 320dcb4b138SElliott Mitchell int error; 321dcb4b138SElliott Mitchell struct xentimer_softc *sc = et->et_priv; 322dcb4b138SElliott Mitchell int cpu = PCPU_GET(vcpu_id); 323dcb4b138SElliott Mitchell struct xentimer_pcpu_data *pcpu = DPCPU_PTR(xentimer_pcpu); 324dcb4b138SElliott Mitchell struct vcpu_info *vcpu = DPCPU_GET(vcpu_info); 325dcb4b138SElliott Mitchell uint64_t first_in_ns, next_time; 326dcb4b138SElliott Mitchell #ifdef INVARIANTS 327dcb4b138SElliott Mitchell struct thread *td = curthread; 328dcb4b138SElliott Mitchell #endif 329dcb4b138SElliott Mitchell 330dcb4b138SElliott Mitchell KASSERT(td->td_critnest != 0, 331dcb4b138SElliott Mitchell ("xentimer_et_start called without preemption disabled")); 332dcb4b138SElliott Mitchell 333dcb4b138SElliott Mitchell /* See sbttots() for this formula. */ 334dcb4b138SElliott Mitchell first_in_ns = (((first >> 32) * NSEC_IN_SEC) + 335dcb4b138SElliott Mitchell (((uint64_t)NSEC_IN_SEC * (uint32_t)first) >> 32)); 336dcb4b138SElliott Mitchell 337dcb4b138SElliott Mitchell next_time = xen_fetch_vcpu_time(vcpu) + first_in_ns; 338dcb4b138SElliott Mitchell error = xentimer_vcpu_start_timer(cpu, next_time); 339dcb4b138SElliott Mitchell if (error) 340dcb4b138SElliott Mitchell panic("%s: Error %d setting singleshot timer to %"PRIu64"\n", 341dcb4b138SElliott Mitchell device_get_nameunit(sc->dev), error, next_time); 342dcb4b138SElliott Mitchell 343dcb4b138SElliott Mitchell pcpu->timer = next_time; 344dcb4b138SElliott Mitchell return (error); 345dcb4b138SElliott Mitchell } 346dcb4b138SElliott Mitchell 347dcb4b138SElliott Mitchell /** 348dcb4b138SElliott Mitchell * \brief Cancel the event timer's currently running timer, if any. 349dcb4b138SElliott Mitchell */ 350dcb4b138SElliott Mitchell static int 351dcb4b138SElliott Mitchell xentimer_et_stop(struct eventtimer *et) 352dcb4b138SElliott Mitchell { 353dcb4b138SElliott Mitchell int cpu = PCPU_GET(vcpu_id); 354dcb4b138SElliott Mitchell struct xentimer_pcpu_data *pcpu = DPCPU_PTR(xentimer_pcpu); 355dcb4b138SElliott Mitchell 356dcb4b138SElliott Mitchell pcpu->timer = 0; 357dcb4b138SElliott Mitchell return (xentimer_vcpu_stop_timer(cpu)); 358dcb4b138SElliott Mitchell } 359dcb4b138SElliott Mitchell 360dcb4b138SElliott Mitchell /** 361dcb4b138SElliott Mitchell * \brief Attach a Xen PV timer driver instance. 362dcb4b138SElliott Mitchell * 363dcb4b138SElliott Mitchell * \param dev Bus device object to attach. 364dcb4b138SElliott Mitchell * 365dcb4b138SElliott Mitchell * \note 366dcb4b138SElliott Mitchell * \returns EINVAL 367dcb4b138SElliott Mitchell */ 368dcb4b138SElliott Mitchell static int 369dcb4b138SElliott Mitchell xentimer_attach(device_t dev) 370dcb4b138SElliott Mitchell { 371dcb4b138SElliott Mitchell struct xentimer_softc *sc = device_get_softc(dev); 372dcb4b138SElliott Mitchell int error, i; 373dcb4b138SElliott Mitchell 374dcb4b138SElliott Mitchell sc->dev = dev; 375dcb4b138SElliott Mitchell 376dcb4b138SElliott Mitchell /* Bind an event channel to a VIRQ on each VCPU. */ 377dcb4b138SElliott Mitchell CPU_FOREACH(i) { 378dcb4b138SElliott Mitchell struct xentimer_pcpu_data *pcpu; 379dcb4b138SElliott Mitchell 380dcb4b138SElliott Mitchell pcpu = DPCPU_ID_PTR(i, xentimer_pcpu); 381dcb4b138SElliott Mitchell error = HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, i, NULL); 382dcb4b138SElliott Mitchell if (error) { 383dcb4b138SElliott Mitchell device_printf(dev, "Error disabling Xen periodic timer " 384dcb4b138SElliott Mitchell "on CPU %d\n", i); 385dcb4b138SElliott Mitchell return (error); 386dcb4b138SElliott Mitchell } 387dcb4b138SElliott Mitchell 388dcb4b138SElliott Mitchell error = xen_intr_bind_virq(dev, VIRQ_TIMER, i, xentimer_intr, 389dcb4b138SElliott Mitchell NULL, sc, INTR_TYPE_CLK, &pcpu->irq_handle); 390dcb4b138SElliott Mitchell if (error) { 391dcb4b138SElliott Mitchell device_printf(dev, "Error %d binding VIRQ_TIMER " 392dcb4b138SElliott Mitchell "to VCPU %d\n", error, i); 393dcb4b138SElliott Mitchell return (error); 394dcb4b138SElliott Mitchell } 395dcb4b138SElliott Mitchell xen_intr_describe(pcpu->irq_handle, "c%d", i); 396dcb4b138SElliott Mitchell } 397dcb4b138SElliott Mitchell 398dcb4b138SElliott Mitchell /* Register the event timer. */ 399dcb4b138SElliott Mitchell sc->et.et_name = "XENTIMER"; 400dcb4b138SElliott Mitchell sc->et.et_quality = XENTIMER_QUALITY; 401dcb4b138SElliott Mitchell sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 402dcb4b138SElliott Mitchell sc->et.et_frequency = NSEC_IN_SEC; 403dcb4b138SElliott Mitchell /* See tstosbt() for this formula */ 404dcb4b138SElliott Mitchell sc->et.et_min_period = (XENTIMER_MIN_PERIOD_IN_NSEC * 405dcb4b138SElliott Mitchell (((uint64_t)1 << 63) / 500000000) >> 32); 406dcb4b138SElliott Mitchell sc->et.et_max_period = ((sbintime_t)4 << 32); 407dcb4b138SElliott Mitchell sc->et.et_start = xentimer_et_start; 408dcb4b138SElliott Mitchell sc->et.et_stop = xentimer_et_stop; 409dcb4b138SElliott Mitchell sc->et.et_priv = sc; 410dcb4b138SElliott Mitchell et_register(&sc->et); 411dcb4b138SElliott Mitchell 412dcb4b138SElliott Mitchell /* Register the timecounter. */ 413dcb4b138SElliott Mitchell sc->tc.tc_name = "XENTIMER"; 414dcb4b138SElliott Mitchell sc->tc.tc_quality = XENTIMER_QUALITY; 415dcb4b138SElliott Mitchell /* 416dcb4b138SElliott Mitchell * FIXME: due to the lack of ordering during resume, FreeBSD cannot 417dcb4b138SElliott Mitchell * guarantee that the Xen PV timer is resumed before any other device 418dcb4b138SElliott Mitchell * attempts to make use of it, so mark it as not safe for suspension 419dcb4b138SElliott Mitchell * (ie: remove the TC_FLAGS_SUSPEND_SAFE flag). 420dcb4b138SElliott Mitchell * 421dcb4b138SElliott Mitchell * NB: This was not a problem in previous FreeBSD versions because the 422dcb4b138SElliott Mitchell * timer was directly attached to the nexus, but it is an issue now 423dcb4b138SElliott Mitchell * that the timer is attached to the xenpv bus, and thus resumed 424dcb4b138SElliott Mitchell * later. 425dcb4b138SElliott Mitchell * 426dcb4b138SElliott Mitchell * sc->tc.tc_flags = TC_FLAGS_SUSPEND_SAFE; 427dcb4b138SElliott Mitchell */ 428dcb4b138SElliott Mitchell /* 429dcb4b138SElliott Mitchell * The underlying resolution is in nanoseconds, since the timer info 430dcb4b138SElliott Mitchell * scales TSC frequencies using a fraction that represents time in 431dcb4b138SElliott Mitchell * terms of nanoseconds. 432dcb4b138SElliott Mitchell */ 433dcb4b138SElliott Mitchell sc->tc.tc_frequency = NSEC_IN_SEC; 434dcb4b138SElliott Mitchell sc->tc.tc_counter_mask = ~0u; 435dcb4b138SElliott Mitchell sc->tc.tc_get_timecount = xentimer_get_timecount; 436dcb4b138SElliott Mitchell sc->tc.tc_priv = sc; 437dcb4b138SElliott Mitchell tc_init(&sc->tc); 438dcb4b138SElliott Mitchell 439dcb4b138SElliott Mitchell /* Register the Hypervisor wall clock */ 440dcb4b138SElliott Mitchell clock_register(dev, XENCLOCK_RESOLUTION); 441dcb4b138SElliott Mitchell 442dcb4b138SElliott Mitchell return (0); 443dcb4b138SElliott Mitchell } 444dcb4b138SElliott Mitchell 445dcb4b138SElliott Mitchell static int 446dcb4b138SElliott Mitchell xentimer_detach(device_t dev) 447dcb4b138SElliott Mitchell { 448dcb4b138SElliott Mitchell 449dcb4b138SElliott Mitchell /* Implement Xen PV clock teardown - XXX see hpet_detach ? */ 450dcb4b138SElliott Mitchell /* If possible: 451dcb4b138SElliott Mitchell * 1. need to deregister timecounter 452dcb4b138SElliott Mitchell * 2. need to deregister event timer 453dcb4b138SElliott Mitchell * 3. need to deregister virtual IRQ event channels 454dcb4b138SElliott Mitchell */ 455dcb4b138SElliott Mitchell return (EBUSY); 456dcb4b138SElliott Mitchell } 457dcb4b138SElliott Mitchell 458dcb4b138SElliott Mitchell static void 459dcb4b138SElliott Mitchell xentimer_percpu_resume(void *arg) 460dcb4b138SElliott Mitchell { 461dcb4b138SElliott Mitchell device_t dev = (device_t) arg; 462dcb4b138SElliott Mitchell struct xentimer_softc *sc = device_get_softc(dev); 463dcb4b138SElliott Mitchell 464dcb4b138SElliott Mitchell xentimer_et_start(&sc->et, sc->et.et_min_period, 0); 465dcb4b138SElliott Mitchell } 466dcb4b138SElliott Mitchell 467dcb4b138SElliott Mitchell static int 468dcb4b138SElliott Mitchell xentimer_resume(device_t dev) 469dcb4b138SElliott Mitchell { 470dcb4b138SElliott Mitchell int error; 471dcb4b138SElliott Mitchell int i; 472dcb4b138SElliott Mitchell 473dcb4b138SElliott Mitchell /* Disable the periodic timer */ 474dcb4b138SElliott Mitchell CPU_FOREACH(i) { 475dcb4b138SElliott Mitchell error = HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, i, NULL); 476dcb4b138SElliott Mitchell if (error != 0) { 477dcb4b138SElliott Mitchell device_printf(dev, 478dcb4b138SElliott Mitchell "Error disabling Xen periodic timer on CPU %d\n", 479dcb4b138SElliott Mitchell i); 480dcb4b138SElliott Mitchell return (error); 481dcb4b138SElliott Mitchell } 482dcb4b138SElliott Mitchell } 483dcb4b138SElliott Mitchell 484dcb4b138SElliott Mitchell /* Reset the last uptime value */ 485dcb4b138SElliott Mitchell pvclock_resume(); 486dcb4b138SElliott Mitchell 487dcb4b138SElliott Mitchell /* Reset the RTC clock */ 488dcb4b138SElliott Mitchell inittodr(time_second); 489dcb4b138SElliott Mitchell 490dcb4b138SElliott Mitchell /* Kick the timers on all CPUs */ 491dcb4b138SElliott Mitchell smp_rendezvous(NULL, xentimer_percpu_resume, NULL, dev); 492dcb4b138SElliott Mitchell 493dcb4b138SElliott Mitchell if (bootverbose) 494dcb4b138SElliott Mitchell device_printf(dev, "resumed operation after suspension\n"); 495dcb4b138SElliott Mitchell 496dcb4b138SElliott Mitchell return (0); 497dcb4b138SElliott Mitchell } 498dcb4b138SElliott Mitchell 499dcb4b138SElliott Mitchell static int 500dcb4b138SElliott Mitchell xentimer_suspend(device_t dev) 501dcb4b138SElliott Mitchell { 502dcb4b138SElliott Mitchell return (0); 503dcb4b138SElliott Mitchell } 504dcb4b138SElliott Mitchell 505dcb4b138SElliott Mitchell /* 506dcb4b138SElliott Mitchell * Xen early clock init 507dcb4b138SElliott Mitchell */ 508dcb4b138SElliott Mitchell void 509dcb4b138SElliott Mitchell xen_clock_init(void) 510dcb4b138SElliott Mitchell { 511dcb4b138SElliott Mitchell } 512dcb4b138SElliott Mitchell 513dcb4b138SElliott Mitchell /* 514dcb4b138SElliott Mitchell * Xen PV DELAY function 515dcb4b138SElliott Mitchell * 516dcb4b138SElliott Mitchell * When running on PVH mode we don't have an emulated i8524, so 517dcb4b138SElliott Mitchell * make use of the Xen time info in order to code a simple DELAY 518dcb4b138SElliott Mitchell * function that can be used during early boot. 519dcb4b138SElliott Mitchell */ 520dcb4b138SElliott Mitchell void 521dcb4b138SElliott Mitchell xen_delay(int n) 522dcb4b138SElliott Mitchell { 523dcb4b138SElliott Mitchell struct vcpu_info *vcpu = &HYPERVISOR_shared_info->vcpu_info[0]; 524dcb4b138SElliott Mitchell uint64_t end_ns; 525dcb4b138SElliott Mitchell uint64_t current; 526dcb4b138SElliott Mitchell 527dcb4b138SElliott Mitchell end_ns = xen_fetch_vcpu_time(vcpu); 528dcb4b138SElliott Mitchell end_ns += n * NSEC_IN_USEC; 529dcb4b138SElliott Mitchell 530dcb4b138SElliott Mitchell for (;;) { 531dcb4b138SElliott Mitchell current = xen_fetch_vcpu_time(vcpu); 532dcb4b138SElliott Mitchell if (current >= end_ns) 533dcb4b138SElliott Mitchell break; 534dcb4b138SElliott Mitchell } 535dcb4b138SElliott Mitchell } 536dcb4b138SElliott Mitchell 537dcb4b138SElliott Mitchell static device_method_t xentimer_methods[] = { 538dcb4b138SElliott Mitchell DEVMETHOD(device_identify, xentimer_identify), 539dcb4b138SElliott Mitchell DEVMETHOD(device_probe, xentimer_probe), 540dcb4b138SElliott Mitchell DEVMETHOD(device_attach, xentimer_attach), 541dcb4b138SElliott Mitchell DEVMETHOD(device_detach, xentimer_detach), 542dcb4b138SElliott Mitchell DEVMETHOD(device_suspend, xentimer_suspend), 543dcb4b138SElliott Mitchell DEVMETHOD(device_resume, xentimer_resume), 544dcb4b138SElliott Mitchell /* clock interface */ 545dcb4b138SElliott Mitchell DEVMETHOD(clock_gettime, xentimer_gettime), 546dcb4b138SElliott Mitchell DEVMETHOD(clock_settime, xentimer_settime), 547dcb4b138SElliott Mitchell DEVMETHOD_END 548dcb4b138SElliott Mitchell }; 549dcb4b138SElliott Mitchell 550dcb4b138SElliott Mitchell static driver_t xentimer_driver = { 551dcb4b138SElliott Mitchell "xen_et", 552dcb4b138SElliott Mitchell xentimer_methods, 553dcb4b138SElliott Mitchell sizeof(struct xentimer_softc), 554dcb4b138SElliott Mitchell }; 555dcb4b138SElliott Mitchell 556dcb4b138SElliott Mitchell DRIVER_MODULE(xentimer, xenpv, xentimer_driver, 0, 0); 557dcb4b138SElliott Mitchell MODULE_DEPEND(xentimer, xenpv, 1, 1, 1); 558