vmbus_et.c revision 300834
1293873Ssephe/*- 2298446Ssephe * Copyright (c) 2015,2016 Microsoft Corp. 3293873Ssephe * All rights reserved. 4293873Ssephe * 5293873Ssephe * Redistribution and use in source and binary forms, with or without 6293873Ssephe * modification, are permitted provided that the following conditions 7293873Ssephe * are met: 8293873Ssephe * 1. Redistributions of source code must retain the above copyright 9293873Ssephe * notice, this list of conditions and the following disclaimer. 10293873Ssephe * 2. Redistributions in binary form must reproduce the above copyright 11293873Ssephe * notice, this list of conditions and the following disclaimer in the 12293873Ssephe * documentation and/or other materials provided with the distribution. 13293873Ssephe * 14293873Ssephe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15293873Ssephe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16293873Ssephe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17293873Ssephe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18293873Ssephe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19293873Ssephe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20293873Ssephe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21293873Ssephe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22293873Ssephe * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23293873Ssephe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24293873Ssephe * SUCH DAMAGE. 25293873Ssephe */ 26293873Ssephe 27293873Ssephe#include <sys/cdefs.h> 28293873Ssephe__FBSDID("$FreeBSD: head/sys/dev/hyperv/vmbus/hv_et.c 300834 2016-05-27 07:29:31Z sephe $"); 29293873Ssephe 30293873Ssephe#include <sys/param.h> 31298449Ssephe#include <sys/bus.h> 32298449Ssephe#include <sys/kernel.h> 33298449Ssephe#include <sys/module.h> 34293873Ssephe#include <sys/proc.h> 35293873Ssephe#include <sys/systm.h> 36293873Ssephe#include <sys/smp.h> 37293873Ssephe#include <sys/time.h> 38293873Ssephe#include <sys/timeet.h> 39293873Ssephe 40300827Ssephe#include <dev/hyperv/vmbus/hv_vmbus_priv.h> 41300827Ssephe#include <dev/hyperv/vmbus/hyperv_reg.h> 42300834Ssephe#include <dev/hyperv/vmbus/hyperv_var.h> 43293873Ssephe 44293873Ssephe#define HV_TIMER_FREQUENCY (10 * 1000 * 1000LL) /* 100ns period */ 45293873Ssephe#define HV_MAX_DELTA_TICKS 0xffffffffLL 46293873Ssephe#define HV_MIN_DELTA_TICKS 1LL 47293873Ssephe 48300827Ssephe#define MSR_HV_STIMER0_CFG_SINT \ 49300827Ssephe ((((uint64_t)HV_VMBUS_TIMER_SINT) << MSR_HV_STIMER_CFG_SINT_SHIFT) & \ 50300827Ssephe MSR_HV_STIMER_CFG_SINT_MASK) 51300827Ssephe 52300834Ssephe/* 53300834Ssephe * Two additionally required features: 54300834Ssephe * - SynIC is needed for interrupt generation. 55300834Ssephe * - Time reference counter is needed to set ABS reference count to 56300834Ssephe * STIMER0_COUNT. 57300834Ssephe */ 58300834Ssephe#define CPUID_HV_ET_MASK (CPUID_HV_MSR_TIME_REFCNT | \ 59300834Ssephe CPUID_HV_MSR_SYNIC | \ 60300834Ssephe CPUID_HV_MSR_SYNTIMER) 61300834Ssephe 62298449Ssephestatic struct eventtimer *et; 63293873Ssephe 64293873Ssephestatic inline uint64_t 65293873Ssephesbintime2tick(sbintime_t time) 66293873Ssephe{ 67293873Ssephe struct timespec val; 68293873Ssephe 69293873Ssephe val = sbttots(time); 70293873Ssephe return val.tv_sec * HV_TIMER_FREQUENCY + val.tv_nsec / 100; 71293873Ssephe} 72293873Ssephe 73293873Ssephestatic int 74293873Ssephehv_et_start(struct eventtimer *et, sbintime_t firsttime, sbintime_t periodtime) 75293873Ssephe{ 76300827Ssephe uint64_t current, config; 77293873Ssephe 78300827Ssephe config = MSR_HV_STIMER_CFG_AUTOEN | MSR_HV_STIMER0_CFG_SINT; 79293873Ssephe 80300827Ssephe current = rdmsr(MSR_HV_TIME_REF_COUNT); 81293873Ssephe current += sbintime2tick(firsttime); 82293873Ssephe 83300827Ssephe wrmsr(MSR_HV_STIMER0_CONFIG, config); 84300827Ssephe wrmsr(MSR_HV_STIMER0_COUNT, current); 85293873Ssephe 86293873Ssephe return (0); 87293873Ssephe} 88293873Ssephe 89293873Ssephestatic int 90293873Ssephehv_et_stop(struct eventtimer *et) 91293873Ssephe{ 92300827Ssephe wrmsr(MSR_HV_STIMER0_CONFIG, 0); 93300827Ssephe wrmsr(MSR_HV_STIMER0_COUNT, 0); 94293873Ssephe 95293873Ssephe return (0); 96293873Ssephe} 97293873Ssephe 98293873Ssephevoid 99293873Ssephehv_et_intr(struct trapframe *frame) 100293873Ssephe{ 101293873Ssephe struct trapframe *oldframe; 102293873Ssephe struct thread *td; 103293873Ssephe 104298449Ssephe if (et->et_active) { 105293873Ssephe td = curthread; 106293873Ssephe td->td_intr_nesting_level++; 107293873Ssephe oldframe = td->td_intr_frame; 108293873Ssephe td->td_intr_frame = frame; 109298449Ssephe et->et_event_cb(et, et->et_arg); 110293873Ssephe td->td_intr_frame = oldframe; 111293873Ssephe td->td_intr_nesting_level--; 112293873Ssephe } 113293873Ssephe} 114293873Ssephe 115298449Ssephestatic void 116298568Ssephehv_et_identify(driver_t *driver, device_t parent) 117293873Ssephe{ 118300834Ssephe if (device_find_child(parent, "hv_et", -1) != NULL || 119300834Ssephe (hyperv_features & CPUID_HV_ET_MASK) != CPUID_HV_ET_MASK) 120298449Ssephe return; 121298449Ssephe 122298449Ssephe device_add_child(parent, "hv_et", -1); 123293873Ssephe} 124293873Ssephe 125298449Ssephestatic int 126298449Ssephehv_et_probe(device_t dev) 127298449Ssephe{ 128298449Ssephe device_set_desc(dev, "Hyper-V event timer"); 129298449Ssephe 130298449Ssephe return (BUS_PROBE_NOWILDCARD); 131298449Ssephe} 132298449Ssephe 133298449Ssephestatic int 134298449Ssephehv_et_attach(device_t dev) 135298449Ssephe{ 136298449Ssephe /* XXX: need allocate SINT and remove global et */ 137298449Ssephe et = device_get_softc(dev); 138298449Ssephe 139298449Ssephe et->et_name = "Hyper-V"; 140298449Ssephe et->et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 141298449Ssephe et->et_quality = 1000; 142298449Ssephe et->et_frequency = HV_TIMER_FREQUENCY; 143298449Ssephe et->et_min_period = HV_MIN_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY); 144298449Ssephe et->et_max_period = HV_MAX_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY); 145298449Ssephe et->et_start = hv_et_start; 146298449Ssephe et->et_stop = hv_et_stop; 147298449Ssephe et->et_priv = dev; 148298449Ssephe 149298449Ssephe return (et_register(et)); 150298449Ssephe} 151298449Ssephe 152298449Ssephestatic int 153298449Ssephehv_et_detach(device_t dev) 154298449Ssephe{ 155298449Ssephe return (et_deregister(et)); 156298449Ssephe} 157298449Ssephe 158298449Ssephestatic device_method_t hv_et_methods[] = { 159298449Ssephe DEVMETHOD(device_identify, hv_et_identify), 160298449Ssephe DEVMETHOD(device_probe, hv_et_probe), 161298449Ssephe DEVMETHOD(device_attach, hv_et_attach), 162298449Ssephe DEVMETHOD(device_detach, hv_et_detach), 163298449Ssephe 164298449Ssephe DEVMETHOD_END 165298449Ssephe}; 166298449Ssephe 167298449Ssephestatic driver_t hv_et_driver = { 168298449Ssephe "hv_et", 169298449Ssephe hv_et_methods, 170298449Ssephe sizeof(struct eventtimer) 171298449Ssephe}; 172298449Ssephe 173298449Ssephestatic devclass_t hv_et_devclass; 174298449SsepheDRIVER_MODULE(hv_et, vmbus, hv_et_driver, hv_et_devclass, NULL, 0); 175298449SsepheMODULE_VERSION(hv_et, 1); 176