diff options
author | glebius <glebius@FreeBSD.org> | 2016-08-12 04:01:16 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2016-08-12 04:01:16 +0000 |
commit | 31dd439280dad5066313b92d89838db63d850228 (patch) | |
tree | 2cca4241e42ffa267711f2516135c081337a1624 /sys/dev/hyperv/vmbus | |
parent | 3a81e075fa773707432d8e3f71cbc9348670536e (diff) | |
download | FreeBSD-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.c | 24 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_channel_mgmt.c | 16 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_connection.c | 54 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_hv.c | 96 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_vmbus_priv.h | 15 |
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 { |