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