svn commit: r293873 - in head/sys: conf dev/hyperv/vmbus modules/hyperv/vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Thu Jan 14 03:05:13 UTC 2016


Author: sephe
Date: Thu Jan 14 03:05:10 2016
New Revision: 293873
URL: https://svnweb.freebsd.org/changeset/base/293873

Log:
  hyperv: implement an event timer
  
  Submitted by:		Howard Su <howard0su at gmail.com>
  Reviewed by:		delphij, royger, adrian
  Approved by:		adrian (mentor)
  Sponsored by:		Microsoft OSTC
  Differential Revision:	https://reviews.freebsd.org/D4676

Added:
  head/sys/dev/hyperv/vmbus/hv_et.c   (contents, props changed)
Modified:
  head/sys/conf/files.amd64
  head/sys/conf/files.i386
  head/sys/dev/hyperv/vmbus/hv_hv.c
  head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
  head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
  head/sys/modules/hyperv/vmbus/Makefile

Modified: head/sys/conf/files.amd64
==============================================================================
--- head/sys/conf/files.amd64	Thu Jan 14 02:58:28 2016	(r293872)
+++ head/sys/conf/files.amd64	Thu Jan 14 03:05:10 2016	(r293873)
@@ -273,6 +273,7 @@ dev/hyperv/vmbus/hv_channel.c				optiona
 dev/hyperv/vmbus/hv_channel_mgmt.c			optional	hyperv
 dev/hyperv/vmbus/hv_connection.c			optional	hyperv
 dev/hyperv/vmbus/hv_hv.c				optional	hyperv
+dev/hyperv/vmbus/hv_et.c				optional	hyperv
 dev/hyperv/vmbus/hv_ring_buffer.c			optional	hyperv
 dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c			optional	hyperv
 dev/nfe/if_nfe.c		optional	nfe pci

Modified: head/sys/conf/files.i386
==============================================================================
--- head/sys/conf/files.i386	Thu Jan 14 02:58:28 2016	(r293872)
+++ head/sys/conf/files.i386	Thu Jan 14 03:05:10 2016	(r293873)
@@ -247,6 +247,7 @@ dev/hyperv/vmbus/hv_channel.c				optiona
 dev/hyperv/vmbus/hv_channel_mgmt.c			optional	hyperv
 dev/hyperv/vmbus/hv_connection.c			optional	hyperv
 dev/hyperv/vmbus/hv_hv.c				optional	hyperv
+dev/hyperv/vmbus/hv_et.c				optional	hyperv
 dev/hyperv/vmbus/hv_ring_buffer.c			optional	hyperv
 dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c			optional	hyperv
 dev/ichwd/ichwd.c		optional ichwd

Added: head/sys/dev/hyperv/vmbus/hv_et.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/hyperv/vmbus/hv_et.c	Thu Jan 14 03:05:10 2016	(r293873)
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2015 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/smp.h>
+#include <sys/time.h>
+#include <sys/timeet.h>
+
+#include "hv_vmbus_priv.h"
+
+#define HV_TIMER_FREQUENCY		(10 * 1000 * 1000LL) /* 100ns period */
+#define HV_MAX_DELTA_TICKS		0xffffffffLL
+#define HV_MIN_DELTA_TICKS		1LL
+
+static struct eventtimer et;
+static uint64_t periodticks[MAXCPU];
+
+static inline uint64_t
+sbintime2tick(sbintime_t time)
+{
+	struct timespec val;
+
+	val = sbttots(time);
+	return val.tv_sec * HV_TIMER_FREQUENCY + val.tv_nsec / 100;
+}
+
+static int
+hv_et_start(struct eventtimer *et, sbintime_t firsttime, sbintime_t periodtime)
+{
+	union hv_timer_config timer_cfg;
+	uint64_t current;
+
+	timer_cfg.as_uint64 = 0;
+	timer_cfg.auto_enable = 1;
+	timer_cfg.sintx = HV_VMBUS_MESSAGE_SINT;
+
+	periodticks[curcpu] = sbintime2tick(periodtime);
+	if (firsttime == 0)
+		firsttime = periodtime;
+
+	current = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
+	current += sbintime2tick(firsttime);
+
+	wrmsr(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
+	wrmsr(HV_X64_MSR_STIMER0_COUNT, current);
+
+	return (0);
+}
+
+static int
+hv_et_stop(struct eventtimer *et)
+{
+	wrmsr(HV_X64_MSR_STIMER0_CONFIG, 0);
+	wrmsr(HV_X64_MSR_STIMER0_COUNT, 0);
+
+	return (0);
+}
+
+void
+hv_et_intr(struct trapframe *frame)
+{
+	union hv_timer_config timer_cfg;
+	struct trapframe *oldframe;
+	struct thread *td;
+
+	if (periodticks[curcpu] != 0) {
+		uint64_t tick = sbintime2tick(periodticks[curcpu]);
+		timer_cfg.as_uint64 = rdmsr(HV_X64_MSR_STIMER0_CONFIG);
+		timer_cfg.enable = 0;
+		timer_cfg.auto_enable = 1;
+		timer_cfg.periodic = 1;
+		periodticks[curcpu] = 0;
+
+		wrmsr(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
+		wrmsr(HV_X64_MSR_STIMER0_COUNT, tick);
+	}
+
+	if (et.et_active) {
+		td = curthread;
+		td->td_intr_nesting_level++;
+		oldframe = td->td_intr_frame;
+		td->td_intr_frame = frame;
+		et.et_event_cb(&et, et.et_arg);
+		td->td_intr_frame = oldframe;
+		td->td_intr_nesting_level--;
+	}
+}
+
+void
+hv_et_init(void)
+{
+	et.et_name = "HyperV";
+	et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU | ET_FLAGS_PERIODIC;
+	et.et_quality = 1000;
+	et.et_frequency = HV_TIMER_FREQUENCY;
+	et.et_min_period = (1LL << 32) / HV_TIMER_FREQUENCY;
+	et.et_max_period = HV_MAX_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY);
+	et.et_start = hv_et_start;
+	et.et_stop = hv_et_stop;
+	et.et_priv = &et;
+	et_register(&et);
+}
+

Modified: head/sys/dev/hyperv/vmbus/hv_hv.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_hv.c	Thu Jan 14 02:58:28 2016	(r293872)
+++ head/sys/dev/hyperv/vmbus/hv_hv.c	Thu Jan 14 03:05:10 2016	(r293873)
@@ -45,12 +45,6 @@ __FBSDID("$FreeBSD$");
 
 #include "hv_vmbus_priv.h"
 
-#define HV_X64_MSR_GUEST_OS_ID		0x40000000
-
-#define HV_X64_CPUID_MIN		0x40000005
-#define HV_X64_CPUID_MAX		0x4000ffff
-#define HV_X64_MSR_TIME_REF_COUNT	0x40000020
-
 #define HV_NANOSECONDS_PER_SEC		1000000000L
 
 
@@ -218,6 +212,8 @@ hv_vmbus_init(void) 
 	hv_vmbus_g_context.hypercall_page = virt_addr;
 
 	tc_init(&hv_timecounter); /* register virtual timecount */
+
+	hv_et_init();
 	
 	return (0);
 

Modified: head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c	Thu Jan 14 02:58:28 2016	(r293872)
+++ head/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c	Thu Jan 14 03:05:10 2016	(r293873)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/proc.h>
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/systm.h>
@@ -153,7 +154,7 @@ handled:
  * message to process - an event or a channel message.
  */
 static inline int
-hv_vmbus_isr(void *unused) 
+hv_vmbus_isr(struct trapframe *frame)
 {
 	int				cpu;
 	hv_vmbus_message*		msg;
@@ -193,11 +194,35 @@ hv_vmbus_isr(void *unused) 
 	page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
 	msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
 
+	/* we call eventtimer process the message */
+	if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) {
+		msg->header.message_type = HV_MESSAGE_TYPE_NONE;
+
+		/*
+		 * Make sure the write to message_type (ie set to
+		 * HV_MESSAGE_TYPE_NONE) happens before we read the
+		 * message_pending and EOMing. Otherwise, the EOMing will
+		 * not deliver any more messages
+		 * since there is no empty slot
+		 */
+		wmb();
+
+		if (msg->header.message_flags.u.message_pending) {
+			/*
+			 * This will cause message queue rescan to possibly
+			 * deliver another msg from the hypervisor
+			 */
+			wrmsr(HV_X64_MSR_EOM, 0);
+		}
+		hv_et_intr(frame);
+		return (FILTER_HANDLED);
+	}
+
 	if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
 		swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
 	}
 
-	return FILTER_HANDLED;
+	return (FILTER_HANDLED);
 }
 
 #ifdef HV_DEBUG_INTR 
@@ -227,7 +252,7 @@ hv_vector_handler(struct trapframe *trap
 	hv_intr_count++;
 #endif
 
-	hv_vmbus_isr(NULL); 
+	hv_vmbus_isr(trap_frame);
 
 	/*
 	 * Enable preemption.

Modified: head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Thu Jan 14 02:58:28 2016	(r293872)
+++ head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Thu Jan 14 03:05:10 2016	(r293873)
@@ -359,11 +359,6 @@ typedef struct {
 	struct sema				control_sema;
 } hv_vmbus_connection;
 
-/*
- * Declare the MSR used to identify the guest OS
- */
-#define HV_X64_MSR_GUEST_OS_ID	0x40000000
-
 typedef union {
 	uint64_t as_uint64_t;
 	struct {
@@ -380,10 +375,6 @@ typedef union {
 	} u;
 } hv_vmbus_x64_msr_guest_os_id_contents;
 
-/*
- *  Declare the MSR used to setup pages used to communicate with the hypervisor
- */
-#define HV_X64_MSR_HYPERCALL	0x40000001
 
 typedef union {
 	uint64_t as_uint64_t;
@@ -513,6 +504,22 @@ typedef union {
 } hv_vmbus_synic_sint;
 
 /*
+ * Timer configuration register.
+ */
+union hv_timer_config {
+	uint64_t as_uint64;
+	struct {
+		uint64_t enable:1;
+		uint64_t periodic:1;
+		uint64_t lazy:1;
+		uint64_t auto_enable:1;
+		uint64_t reserved_z0:12;
+		uint64_t sintx:4;
+		uint64_t reserved_z1:44;
+	};
+};
+
+/*
  * Define syn_ic control register
  */
 typedef union _hv_vmbus_synic_scontrol {
@@ -542,8 +549,21 @@ typedef union {
 	uint32_t	flags32[HV_EVENT_FLAGS_DWORD_COUNT];
 } hv_vmbus_synic_event_flags;
 
+#define HV_X64_CPUID_MIN	(0x40000005)
+#define HV_X64_CPUID_MAX	(0x4000ffff)
+
+/*
+ * Declare the MSR used to identify the guest OS
+ */
+#define HV_X64_MSR_GUEST_OS_ID	(0x40000000)
+/*
+ *  Declare the MSR used to setup pages used to communicate with the hypervisor
+ */
+#define HV_X64_MSR_HYPERCALL	(0x40000001)
 /* MSR used to provide vcpu index */
-#define	HV_X64_MSR_VP_INDEX   (0x40000002)
+#define	HV_X64_MSR_VP_INDEX	(0x40000002)
+
+#define HV_X64_MSR_TIME_REF_COUNT      (0x40000020)
 
 /*
  * Define synthetic interrupt controller model specific registers
@@ -572,6 +592,18 @@ typedef union {
 #define HV_X64_MSR_SINT15     (0x4000009F)
 
 /*
+ * Synthetic Timer MSRs. Four timers per vcpu.
+ */
+#define HV_X64_MSR_STIMER0_CONFIG		0x400000B0
+#define HV_X64_MSR_STIMER0_COUNT		0x400000B1
+#define HV_X64_MSR_STIMER1_CONFIG		0x400000B2
+#define HV_X64_MSR_STIMER1_COUNT		0x400000B3
+#define HV_X64_MSR_STIMER2_CONFIG		0x400000B4
+#define HV_X64_MSR_STIMER2_COUNT		0x400000B5
+#define HV_X64_MSR_STIMER3_CONFIG		0x400000B6
+#define HV_X64_MSR_STIMER3_COUNT		0x400000B7
+
+/*
  * Declare the various hypercall operations
  */
 typedef enum {
@@ -678,6 +710,11 @@ int			hv_vmbus_post_message(void *buffer
 int			hv_vmbus_set_event(hv_vmbus_channel *channel);
 void			hv_vmbus_on_events(void *);
 
+/**
+ * Event Timer interfaces
+ */
+void			hv_et_init(void);
+void			hv_et_intr(struct trapframe*);
 
 /*
  * The guest OS needs to register the guest ID with the hypervisor.

Modified: head/sys/modules/hyperv/vmbus/Makefile
==============================================================================
--- head/sys/modules/hyperv/vmbus/Makefile	Thu Jan 14 02:58:28 2016	(r293872)
+++ head/sys/modules/hyperv/vmbus/Makefile	Thu Jan 14 03:05:10 2016	(r293873)
@@ -7,6 +7,7 @@ KMOD=	hv_vmbus
 SRCS=	hv_channel.c \
 	hv_channel_mgmt.c \
 	hv_connection.c \
+	hv_et.c \
 	hv_hv.c \
 	hv_ring_buffer.c \
 	hv_vmbus_drv_freebsd.c \


More information about the svn-src-all mailing list