summaryrefslogtreecommitdiffstats
path: root/sys/dev/hyperv/vmbus
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2016-08-12 04:01:16 +0000
committerglebius <glebius@FreeBSD.org>2016-08-12 04:01:16 +0000
commit31dd439280dad5066313b92d89838db63d850228 (patch)
tree2cca4241e42ffa267711f2516135c081337a1624 /sys/dev/hyperv/vmbus
parent3a81e075fa773707432d8e3f71cbc9348670536e (diff)
downloadFreeBSD-src-31dd439280dad5066313b92d89838db63d850228.zip
FreeBSD-src-31dd439280dad5066313b92d89838db63d850228.tar.gz
Release 6 errata notices for 10.3-RELEASE, all related to Microsoft Hyper-V.
Submitted by: Dexuan Cui <decui microsoft.com>, gjb Approved by: so
Diffstat (limited to 'sys/dev/hyperv/vmbus')
-rw-r--r--sys/dev/hyperv/vmbus/hv_channel.c24
-rw-r--r--sys/dev/hyperv/vmbus/hv_channel_mgmt.c16
-rw-r--r--sys/dev/hyperv/vmbus/hv_connection.c54
-rw-r--r--sys/dev/hyperv/vmbus/hv_hv.c96
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_priv.h15
5 files changed, 156 insertions, 49 deletions
diff --git a/sys/dev/hyperv/vmbus/hv_channel.c b/sys/dev/hyperv/vmbus/hv_channel.c
index 7037768..c144910 100644
--- a/sys/dev/hyperv/vmbus/hv_channel.c
+++ b/sys/dev/hyperv/vmbus/hv_channel.c
@@ -180,12 +180,12 @@ hv_vmbus_channel_open(
if (user_data_len)
memcpy(open_msg->user_data, user_data, user_data_len);
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(
&hv_vmbus_g_connection.channel_msg_anchor,
open_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(
open_msg, sizeof(hv_vmbus_channel_open_channel));
@@ -212,12 +212,12 @@ hv_vmbus_channel_open(
}
cleanup:
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(
&hv_vmbus_g_connection.channel_msg_anchor,
open_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
sema_destroy(&open_info->wait_sema);
free(open_info, M_DEVBUF);
@@ -401,13 +401,13 @@ hv_vmbus_channel_establish_gpadl(
gpadl_msg->child_rel_id = channel->offer_msg.child_rel_id;
gpadl_msg->gpadl = next_gpadl_handle;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(
&hv_vmbus_g_connection.channel_msg_anchor,
msg_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(
gpadl_msg,
@@ -446,10 +446,10 @@ hv_vmbus_channel_establish_gpadl(
cleanup:
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor,
msg_info, msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
sema_destroy(&msg_info->wait_sema);
free(msg_info, M_DEVBUF);
@@ -488,10 +488,10 @@ hv_vmbus_channel_teardown_gpdal(
msg->child_rel_id = channel->offer_msg.child_rel_id;
msg->gpadl = gpadl_handle;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_msg_anchor,
info, msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(msg,
sizeof(hv_vmbus_channel_gpadl_teardown));
@@ -504,10 +504,10 @@ cleanup:
/*
* Received a torndown response
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(&hv_vmbus_g_connection.channel_msg_anchor,
info, msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
sema_destroy(&info->wait_sema);
free(info, M_DEVBUF);
diff --git a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
index 4ccb647..a55f464 100644
--- a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
+++ b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
@@ -567,7 +567,7 @@ vmbus_channel_on_open_result(hv_vmbus_channel_msg_header* hdr)
/*
* Find the open msg, copy the result and signal/unblock the wait event
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor,
msg_list_entry) {
@@ -585,7 +585,7 @@ vmbus_channel_on_open_result(hv_vmbus_channel_msg_header* hdr)
}
}
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
}
@@ -609,7 +609,7 @@ vmbus_channel_on_gpadl_created(hv_vmbus_channel_msg_header* hdr)
/* Find the establish msg, copy the result and signal/unblock
* the wait event
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor,
msg_list_entry) {
request_header = (hv_vmbus_channel_msg_header*) msg_info->msg;
@@ -628,7 +628,7 @@ vmbus_channel_on_gpadl_created(hv_vmbus_channel_msg_header* hdr)
}
}
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
}
/**
@@ -653,7 +653,7 @@ vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr)
* wait event.
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor,
msg_list_entry) {
@@ -673,7 +673,7 @@ vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr)
}
}
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
}
/**
@@ -693,7 +693,7 @@ vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr)
versionResponse = (hv_vmbus_channel_version_response*)hdr;
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_FOREACH(msg_info, &hv_vmbus_g_connection.channel_msg_anchor,
msg_list_entry) {
requestHeader = (hv_vmbus_channel_msg_header*) msg_info->msg;
@@ -707,7 +707,7 @@ vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr)
sema_post(&msg_info->wait_sema);
}
}
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
}
diff --git a/sys/dev/hyperv/vmbus/hv_connection.c b/sys/dev/hyperv/vmbus/hv_connection.c
index cfdc9bb..f39616f 100644
--- a/sys/dev/hyperv/vmbus/hv_connection.c
+++ b/sys/dev/hyperv/vmbus/hv_connection.c
@@ -101,26 +101,26 @@ hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
* Add to list before we send the request since we may receive the
* response before returning from this routine
*/
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_INSERT_TAIL(
&hv_vmbus_g_connection.channel_msg_anchor,
msg_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
ret = hv_vmbus_post_message(
msg,
sizeof(hv_vmbus_channel_initiate_contact));
if (ret != 0) {
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(
&hv_vmbus_g_connection.channel_msg_anchor,
msg_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
return (ret);
}
@@ -129,12 +129,12 @@ hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
*/
ret = sema_timedwait(&msg_info->wait_sema, 5 * hz); /* KYS 5 seconds */
- mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_lock(&hv_vmbus_g_connection.channel_msg_lock);
TAILQ_REMOVE(
&hv_vmbus_g_connection.channel_msg_anchor,
msg_info,
msg_list_entry);
- mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
+ mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
/**
* Check if successful
@@ -173,7 +173,7 @@ hv_vmbus_connect(void) {
TAILQ_INIT(&hv_vmbus_g_connection.channel_msg_anchor);
mtx_init(&hv_vmbus_g_connection.channel_msg_lock, "vmbus channel msg",
- NULL, MTX_SPIN);
+ NULL, MTX_DEF);
TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor);
mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel",
@@ -476,31 +476,35 @@ hv_vmbus_on_events(void *arg)
/**
* Send a msg on the vmbus's message connection
*/
-int hv_vmbus_post_message(void *buffer, size_t bufferLen) {
- int ret = 0;
+int hv_vmbus_post_message(void *buffer, size_t bufferLen)
+{
hv_vmbus_connection_id connId;
- unsigned retries = 0;
+ sbintime_t time = SBT_1MS;
+ int retries;
+ int ret;
- /* NetScaler delays from previous code were consolidated here */
- static int delayAmount[] = {100, 100, 100, 500, 500, 5000, 5000, 5000};
+ connId.as_uint32_t = 0;
+ connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID;
- /* for(each entry in delayAmount) try to post message,
- * delay a little bit before retrying
+ /*
+ * We retry to cope with transient failures caused by host side's
+ * insufficient resources. 20 times should suffice in practice.
*/
- for (retries = 0;
- retries < sizeof(delayAmount)/sizeof(delayAmount[0]); retries++) {
- connId.as_uint32_t = 0;
- connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID;
- ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, bufferLen);
- if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
- break;
- /* TODO: KYS We should use a blocking wait call */
- DELAY(delayAmount[retries]);
+ for (retries = 0; retries < 20; retries++) {
+ ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer,
+ bufferLen);
+ if (ret == HV_STATUS_SUCCESS)
+ return (0);
+
+ pause_sbt("pstmsg", time, 0, C_HARDCLOCK);
+ if (time < SBT_1S * 2)
+ time *= 2;
}
- KASSERT(ret == 0, ("Error VMBUS: Message Post Failed\n"));
+ KASSERT(ret == HV_STATUS_SUCCESS,
+ ("Error VMBUS: Message Post Failed, ret=%d\n", ret));
- return (ret);
+ return (EAGAIN);
}
/**
diff --git a/sys/dev/hyperv/vmbus/hv_hv.c b/sys/dev/hyperv/vmbus/hv_hv.c
index ca5641f..f4cca18 100644
--- a/sys/dev/hyperv/vmbus/hv_hv.c
+++ b/sys/dev/hyperv/vmbus/hv_hv.c
@@ -33,6 +33,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/pcpu.h>
#include <sys/timetc.h>
@@ -50,6 +51,9 @@ __FBSDID("$FreeBSD$");
static u_int hv_get_timecount(struct timecounter *tc);
+u_int hyperv_features;
+u_int hyperv_recommends;
+
/**
* Globals
*/
@@ -211,8 +215,6 @@ hv_vmbus_init(void)
hv_vmbus_g_context.hypercall_page = virt_addr;
- tc_init(&hv_timecounter); /* register virtual timecount */
-
hv_et_init();
return (0);
@@ -427,3 +429,93 @@ void hv_vmbus_synic_cleanup(void *arg)
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
}
+static bool
+hyperv_identify(void)
+{
+ u_int regs[4];
+ unsigned int maxLeaf;
+ unsigned int op;
+
+ if (vm_guest != VM_GUEST_HV)
+ return (false);
+
+ op = HV_CPU_ID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION;
+ do_cpuid(op, regs);
+ maxLeaf = regs[0];
+ if (maxLeaf < HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS)
+ return (false);
+
+ op = HV_CPU_ID_FUNCTION_HV_INTERFACE;
+ do_cpuid(op, regs);
+ if (regs[0] != 0x31237648 /* HV#1 */)
+ return (false);
+
+ op = HV_CPU_ID_FUNCTION_MS_HV_FEATURES;
+ do_cpuid(op, regs);
+ if ((regs[0] & HV_FEATURE_MSR_HYPERCALL) == 0) {
+ /*
+ * Hyper-V w/o Hypercall is impossible; someone
+ * is faking Hyper-V.
+ */
+ return (false);
+ }
+ hyperv_features = regs[0];
+
+ op = HV_CPU_ID_FUNCTION_MS_HV_VERSION;
+ do_cpuid(op, regs);
+ printf("Hyper-V Version: %d.%d.%d [SP%d]\n",
+ regs[1] >> 16, regs[1] & 0xffff, regs[0], regs[2]);
+
+ printf(" Features: 0x%b\n", hyperv_features,
+ "\020"
+ "\001VPRUNTIME"
+ "\002TMREFCNT"
+ "\003SYNCIC"
+ "\004SYNCTM"
+ "\005APIC"
+ "\006HYERCALL"
+ "\007VPINDEX"
+ "\010RESET"
+ "\011STATS"
+ "\012REFTSC"
+ "\013IDLE"
+ "\014TMFREQ"
+ "\015DEBUG");
+
+ op = HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION;
+ do_cpuid(op, regs);
+ hyperv_recommends = regs[0];
+ if (bootverbose)
+ printf(" Recommends: %08x %08x\n", regs[0], regs[1]);
+
+ op = HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS;
+ do_cpuid(op, regs);
+ if (bootverbose) {
+ printf(" Limits: Vcpu:%d Lcpu:%d Int:%d\n",
+ regs[0], regs[1], regs[2]);
+ }
+
+ if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE) {
+ op = HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE;
+ do_cpuid(op, regs);
+ if (bootverbose) {
+ printf(" HW Features: %08x AMD: %08x\n",
+ regs[0], regs[3]);
+ }
+ }
+
+ return (true);
+}
+
+static void
+hyperv_init(void *dummy __unused)
+{
+ if (!hyperv_identify())
+ return;
+
+ if (hyperv_features & HV_FEATURE_MSR_TIME_REFCNT) {
+ /* Register virtual timecount */
+ tc_init(&hv_timecounter);
+ }
+}
+SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init, NULL);
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
index 13a35c4..bf103ab 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
@@ -70,6 +70,7 @@ typedef uint16_t hv_vmbus_status;
* You did not supply enough message buffers to send a message.
*/
+#define HV_STATUS_SUCCESS ((uint16_t)0)
#define HV_STATUS_INSUFFICIENT_BUFFERS ((uint16_t)0x0013)
typedef void (*hv_vmbus_channel_callback)(void *context);
@@ -471,10 +472,17 @@ typedef enum {
HV_CPU_ID_FUNCTION_MS_HV_VERSION = 0x40000002,
HV_CPU_ID_FUNCTION_MS_HV_FEATURES = 0x40000003,
HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION = 0x40000004,
- HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS = 0x40000005
-
+ HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS = 0x40000005,
+ HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE = 0x40000006
} hv_vmbus_cpuid_function;
+#define HV_FEATURE_MSR_TIME_REFCNT (1 << 1)
+#define HV_FEATURE_MSR_SYNCIC (1 << 2)
+#define HV_FEATURE_MSR_STIMER (1 << 3)
+#define HV_FEATURE_MSR_APIC (1 << 4)
+#define HV_FEATURE_MSR_HYPERCALL (1 << 5)
+#define HV_FEATURE_MSR_GUEST_IDLE (1 << 10)
+
/*
* Define the format of the SIMP register
*/
@@ -628,6 +636,9 @@ typedef enum {
extern hv_vmbus_context hv_vmbus_g_context;
extern hv_vmbus_connection hv_vmbus_g_connection;
+extern u_int hyperv_features;
+extern u_int hyperv_recommends;
+
typedef void (*vmbus_msg_handler)(hv_vmbus_channel_msg_header *msg);
typedef struct hv_vmbus_channel_msg_table_entry {
OpenPOWER on IntegriCloud