vmbus_et.c revision 297176
11832Swollman/*- 21832Swollman * Copyright (c) 2015 Microsoft Corp. 31832Swollman * All rights reserved. 41832Swollman * 51832Swollman * Redistribution and use in source and binary forms, with or without 61832Swollman * modification, are permitted provided that the following conditions 71832Swollman * are met: 81832Swollman * 1. Redistributions of source code must retain the above copyright 91832Swollman * notice, this list of conditions and the following disclaimer. 101832Swollman * 2. Redistributions in binary form must reproduce the above copyright 111832Swollman * notice, this list of conditions and the following disclaimer in the 121832Swollman * documentation and/or other materials provided with the distribution. 131832Swollman * 141832Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151832Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161832Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171832Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181832Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191832Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201832Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211832Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221832Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231832Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241832Swollman * SUCH DAMAGE. 251832Swollman */ 261832Swollman 271832Swollman#include <sys/cdefs.h> 281832Swollman__FBSDID("$FreeBSD: head/sys/dev/hyperv/vmbus/hv_et.c 297176 2016-03-22 05:48:51Z sephe $"); 2950473Speter 301832Swollman#include <sys/param.h> 311832Swollman#include <sys/proc.h> 3221060Speter#include <sys/systm.h> 3321060Speter#include <sys/smp.h> 341832Swollman#include <sys/time.h> 351832Swollman#include <sys/timeet.h> 361832Swollman 378858Srgrimes#include "hv_vmbus_priv.h" 381832Swollman 398858Srgrimes#define HV_TIMER_FREQUENCY (10 * 1000 * 1000LL) /* 100ns period */ 401832Swollman#define HV_MAX_DELTA_TICKS 0xffffffffLL 411832Swollman#define HV_MIN_DELTA_TICKS 1LL 421832Swollman 431832Swollmanstatic struct eventtimer et; 441832Swollmanstatic uint64_t periodticks[MAXCPU]; 451832Swollman 461832Swollmanstatic inline uint64_t 471832Swollmansbintime2tick(sbintime_t time) 481832Swollman{ 491832Swollman struct timespec val; 501832Swollman 511832Swollman val = sbttots(time); 521832Swollman return val.tv_sec * HV_TIMER_FREQUENCY + val.tv_nsec / 100; 531832Swollman} 541832Swollman 551832Swollmanstatic int 561832Swollmanhv_et_start(struct eventtimer *et, sbintime_t firsttime, sbintime_t periodtime) 571832Swollman{ 581832Swollman union hv_timer_config timer_cfg; 591832Swollman uint64_t current; 601832Swollman 611832Swollman timer_cfg.as_uint64 = 0; 621832Swollman timer_cfg.auto_enable = 1; 631832Swollman timer_cfg.sintx = HV_VMBUS_TIMER_SINT; 641832Swollman 651832Swollman periodticks[curcpu] = sbintime2tick(periodtime); 661832Swollman if (firsttime == 0) 671832Swollman firsttime = periodtime; 681832Swollman 691832Swollman current = rdmsr(HV_X64_MSR_TIME_REF_COUNT); 701832Swollman current += sbintime2tick(firsttime); 711832Swollman 721832Swollman wrmsr(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64); 731832Swollman wrmsr(HV_X64_MSR_STIMER0_COUNT, current); 741832Swollman 751832Swollman return (0); 761832Swollman} 771832Swollman 781832Swollmanstatic int 791832Swollmanhv_et_stop(struct eventtimer *et) 801832Swollman{ 811832Swollman wrmsr(HV_X64_MSR_STIMER0_CONFIG, 0); 821832Swollman wrmsr(HV_X64_MSR_STIMER0_COUNT, 0); 831832Swollman 841832Swollman return (0); 851832Swollman} 861832Swollman 871832Swollmanvoid 881832Swollmanhv_et_intr(struct trapframe *frame) 891832Swollman{ 901832Swollman union hv_timer_config timer_cfg; 911832Swollman struct trapframe *oldframe; 921832Swollman struct thread *td; 931832Swollman 941832Swollman if (periodticks[curcpu] != 0) { 951832Swollman uint64_t tick = sbintime2tick(periodticks[curcpu]); 961832Swollman timer_cfg.as_uint64 = rdmsr(HV_X64_MSR_STIMER0_CONFIG); 971832Swollman timer_cfg.enable = 0; 981832Swollman timer_cfg.auto_enable = 1; 991832Swollman timer_cfg.periodic = 1; 1001832Swollman periodticks[curcpu] = 0; 1011832Swollman 1021832Swollman wrmsr(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64); 1031832Swollman wrmsr(HV_X64_MSR_STIMER0_COUNT, tick); 1041832Swollman } 1051832Swollman 1061832Swollman if (et.et_active) { 1071832Swollman td = curthread; 1081832Swollman td->td_intr_nesting_level++; 1091832Swollman oldframe = td->td_intr_frame; 1101832Swollman td->td_intr_frame = frame; 1111832Swollman et.et_event_cb(&et, et.et_arg); 1121832Swollman td->td_intr_frame = oldframe; 1131832Swollman td->td_intr_nesting_level--; 1141832Swollman } 1151832Swollman} 1161832Swollman 1171832Swollmanvoid 1181832Swollmanhv_et_init(void) 1191832Swollman{ 1201832Swollman et.et_name = "HyperV"; 1211832Swollman et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU | ET_FLAGS_PERIODIC; 1221832Swollman et.et_quality = 1000; 1231832Swollman et.et_frequency = HV_TIMER_FREQUENCY; 1241832Swollman et.et_min_period = (1LL << 32) / HV_TIMER_FREQUENCY; 1251832Swollman et.et_max_period = HV_MAX_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY); 1261832Swollman et.et_start = hv_et_start; 1271832Swollman et.et_stop = hv_et_stop; 1281832Swollman et.et_priv = &et; 1291832Swollman et_register(&et); 1301832Swollman} 1311832Swollman 1321832Swollman