diff options
Diffstat (limited to 'sys/dev/hyperv')
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_net_vsc.c | 6 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 14 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_rndis_filter.c | 9 | ||||
-rw-r--r-- | sys/dev/hyperv/utilities/hv_heartbeat.c | 2 | ||||
-rw-r--r-- | sys/dev/hyperv/utilities/hv_kvp.c | 2 | ||||
-rw-r--r-- | sys/dev/hyperv/utilities/hv_shutdown.c | 2 | ||||
-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 | 14 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_hv.c | 168 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c | 98 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/hv_vmbus_priv.h | 30 |
12 files changed, 207 insertions, 178 deletions
diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c index f6d7d9e..11b3435 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.c +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c @@ -742,10 +742,8 @@ cleanup: * Free the packet buffers on the netvsc device packet queue. * Release other resources. */ - if (net_dev) { - sema_destroy(&net_dev->channel_init_sema); - free(net_dev, M_NETVSC); - } + sema_destroy(&net_dev->channel_init_sema); + free(net_dev, M_NETVSC); return (NULL); } diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index acc49b4..68c301a 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -136,6 +136,8 @@ __FBSDID("$FreeBSD$"); #define HN_LROENT_CNT_DEF 128 +#define HN_RING_CNT_DEF_MAX 8 + #define HN_RNDIS_MSG_LEN \ (sizeof(rndis_msg) + \ RNDIS_HASH_PPI_SIZE + \ @@ -280,12 +282,12 @@ static int hn_use_if_start = 0; SYSCTL_INT(_hw_hn, OID_AUTO, use_if_start, CTLFLAG_RDTUN, &hn_use_if_start, 0, "Use if_start TX method"); -static int hn_chan_cnt = 1; +static int hn_chan_cnt = 0; SYSCTL_INT(_hw_hn, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, &hn_chan_cnt, 0, "# of channels to use; each channel has one RX ring and one TX ring"); -static int hn_tx_ring_cnt = 1; +static int hn_tx_ring_cnt = 0; SYSCTL_INT(_hw_hn, OID_AUTO, tx_ring_cnt, CTLFLAG_RDTUN, &hn_tx_ring_cnt, 0, "# of TX rings to use"); @@ -460,8 +462,14 @@ netvsc_attach(device_t dev) * The # of RX rings to use is same as the # of channels to use. */ ring_cnt = hn_chan_cnt; - if (ring_cnt <= 0 || ring_cnt > mp_ncpus) + if (ring_cnt <= 0) { + /* Default */ + ring_cnt = mp_ncpus; + if (ring_cnt > HN_RING_CNT_DEF_MAX) + ring_cnt = HN_RING_CNT_DEF_MAX; + } else if (ring_cnt > mp_ncpus) { ring_cnt = mp_ncpus; + } tx_ring_cnt = hn_tx_ring_cnt; if (tx_ring_cnt <= 0 || tx_ring_cnt > ring_cnt) diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c index 1eb24fa..19da7e5 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -405,8 +405,7 @@ hv_rf_send_offload_request(struct hv_device *device, } cleanup: - if (request) - hv_put_rndis_request(rndis_dev, request); + hv_put_rndis_request(rndis_dev, request); return (ret); } @@ -907,10 +906,8 @@ hv_rf_halt_device(rndis_device *device) } device->state = RNDIS_DEV_UNINITIALIZED; - - if (request != NULL) { - hv_put_rndis_request(device, request); - } + + hv_put_rndis_request(device, request); return (0); } diff --git a/sys/dev/hyperv/utilities/hv_heartbeat.c b/sys/dev/hyperv/utilities/hv_heartbeat.c index 09bd28b..62de10b 100644 --- a/sys/dev/hyperv/utilities/hv_heartbeat.c +++ b/sys/dev/hyperv/utilities/hv_heartbeat.c @@ -59,7 +59,7 @@ hv_heartbeat_cb(void *context) hv_util_sc *softc; softc = (hv_util_sc*)context; - buf = softc->receive_buffer;; + buf = softc->receive_buffer; channel = softc->hv_dev->channel; ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE, &recvlen, diff --git a/sys/dev/hyperv/utilities/hv_kvp.c b/sys/dev/hyperv/utilities/hv_kvp.c index d71310b..50563c4 100644 --- a/sys/dev/hyperv/utilities/hv_kvp.c +++ b/sys/dev/hyperv/utilities/hv_kvp.c @@ -619,7 +619,7 @@ hv_kvp_process_request(void *context, int pending) hv_kvp_log_info("%s: entering hv_kvp_process_request\n", __func__); sc = (hv_kvp_sc*)context; - kvp_buf = sc->util_sc.receive_buffer;; + kvp_buf = sc->util_sc.receive_buffer; channel = sc->util_sc.hv_dev->channel; ret = hv_vmbus_channel_recv_packet(channel, kvp_buf, 2 * PAGE_SIZE, diff --git a/sys/dev/hyperv/utilities/hv_shutdown.c b/sys/dev/hyperv/utilities/hv_shutdown.c index 0beed5a..b0802af 100644 --- a/sys/dev/hyperv/utilities/hv_shutdown.c +++ b/sys/dev/hyperv/utilities/hv_shutdown.c @@ -63,7 +63,7 @@ hv_shutdown_cb(void *context) hv_util_sc *softc; softc = (hv_util_sc*)context; - buf = softc->receive_buffer;; + buf = softc->receive_buffer; channel = softc->hv_dev->channel; ret = hv_vmbus_channel_recv_packet(channel, buf, PAGE_SIZE, &recv_len, &request_id); diff --git a/sys/dev/hyperv/vmbus/hv_channel.c b/sys/dev/hyperv/vmbus/hv_channel.c index 03a3457..46d15bf 100644 --- a/sys/dev/hyperv/vmbus/hv_channel.c +++ b/sys/dev/hyperv/vmbus/hv_channel.c @@ -270,12 +270,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)); @@ -302,12 +302,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); @@ -496,13 +496,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, @@ -541,10 +541,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); @@ -583,10 +583,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)); @@ -599,10 +599,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 30f2504..42d3750 100644 --- a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c +++ b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c @@ -492,7 +492,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) { @@ -510,7 +510,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); } @@ -534,7 +534,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; @@ -553,7 +553,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); } /** @@ -578,7 +578,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) { @@ -598,7 +598,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); } /** @@ -618,7 +618,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; @@ -632,7 +632,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 e170298..44effef 100644 --- a/sys/dev/hyperv/vmbus/hv_connection.c +++ b/sys/dev/hyperv/vmbus/hv_connection.c @@ -96,26 +96,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); } @@ -124,12 +124,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 @@ -166,7 +166,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", diff --git a/sys/dev/hyperv/vmbus/hv_hv.c b/sys/dev/hyperv/vmbus/hv_hv.c index a87b5ce..b835a34 100644 --- a/sys/dev/hyperv/vmbus/hv_hv.c +++ b/sys/dev/hyperv/vmbus/hv_hv.c @@ -33,10 +33,10 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/kernel.h> #include <sys/malloc.h> #include <sys/pcpu.h> #include <sys/timetc.h> -#include <sys/kernel.h> #include <machine/bus.h> #include <machine/md_var.h> #include <vm/vm.h> @@ -48,9 +48,16 @@ __FBSDID("$FreeBSD$"); #define HV_NANOSECONDS_PER_SEC 1000000000L +#define HYPERV_INTERFACE 0x31237648 /* HV#1 */ static u_int hv_get_timecount(struct timecounter *tc); +u_int hyperv_features; +u_int hyperv_recommends; + +static u_int hyperv_pm_features; +static u_int hyperv_features3; + /** * Globals */ @@ -71,47 +78,6 @@ hv_get_timecount(struct timecounter *tc) } /** - * @brief Query the cpuid for presence of windows hypervisor - */ -int -hv_vmbus_query_hypervisor_presence(void) -{ - if (vm_guest != VM_GUEST_HV) - return (0); - - return (hv_high >= HV_X64_CPUID_MIN && hv_high <= HV_X64_CPUID_MAX); -} - -/** - * @brief Get version of the windows hypervisor - */ -static int -hv_vmbus_get_hypervisor_version(void) -{ - u_int regs[4]; - unsigned int maxLeaf; - unsigned int op; - - /* - * Its assumed that this is called after confirming that - * Viridian is present - * Query id and revision. - */ - op = HV_CPU_ID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION; - do_cpuid(op, regs); - - maxLeaf = regs[0]; - op = HV_CPU_ID_FUNCTION_HV_INTERFACE; - do_cpuid(op, regs); - - if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_VERSION) { - op = HV_CPU_ID_FUNCTION_MS_HV_VERSION; - do_cpuid(op, regs); - } - return (maxLeaf); -} - -/** * @brief Invoke the specified hypercall */ static uint64_t @@ -160,7 +126,6 @@ hv_vmbus_do_hypercall(uint64_t control, void* input, void* output) int hv_vmbus_init(void) { - int max_leaf; hv_vmbus_x64_msr_hypercall_contents hypercall_msr; void* virt_addr = 0; @@ -177,8 +142,6 @@ hv_vmbus_init(void) if (vm_guest != VM_GUEST_HV) goto cleanup; - max_leaf = hv_vmbus_get_hypervisor_version(); - /* * Write our OS info */ @@ -436,14 +399,117 @@ void hv_vmbus_synic_cleanup(void *arg) wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t); } -static void -hv_tc_init(void) +static bool +hyperv_identify(void) { + u_int regs[4]; + unsigned int maxLeaf; + unsigned int op; + if (vm_guest != VM_GUEST_HV) - return; + 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] != HYPERV_INTERFACE) + return (false); - /* register virtual timecounter */ - tc_init(&hv_timecounter); + 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]; + hyperv_pm_features = regs[2]; + hyperv_features3 = regs[3]; + + 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" /* MSR_VP_RUNTIME */ + "\002TMREFCNT" /* MSR_TIME_REF_COUNT */ + "\003SYNIC" /* MSRs for SynIC */ + "\004SYNTM" /* MSRs for SynTimer */ + "\005APIC" /* MSR_{EOI,ICR,TPR} */ + "\006HYPERCALL" /* MSR_{GUEST_OS_ID,HYPERCALL} */ + "\007VPINDEX" /* MSR_VP_INDEX */ + "\010RESET" /* MSR_RESET */ + "\011STATS" /* MSR_STATS_ */ + "\012REFTSC" /* MSR_REFERENCE_TSC */ + "\013IDLE" /* MSR_GUEST_IDLE */ + "\014TMFREQ" /* MSR_{TSC,APIC}_FREQUENCY */ + "\015DEBUG"); /* MSR_SYNTH_DEBUG_ */ + printf(" PM Features=max C%u, 0x%b\n", + HV_PM_FEATURE_CSTATE(hyperv_pm_features), + (hyperv_pm_features & ~HV_PM_FEATURE_CSTATE_MASK), + "\020" + "\005C3HPET"); /* HPET is required for C3 state */ + printf(" Features3=0x%b\n", hyperv_features3, + "\020" + "\001MWAIT" /* MWAIT */ + "\002DEBUG" /* guest debug support */ + "\003PERFMON" /* performance monitor */ + "\004PCPUDPE" /* physical CPU dynamic partition event */ + "\005XMMHC" /* hypercall input through XMM regs */ + "\006IDLE" /* guest idle support */ + "\007SLEEP" /* hypervisor sleep support */ + "\010NUMA" /* NUMA distance query support */ + "\011TMFREQ" /* timer frequency query (TSC, LAPIC) */ + "\012SYNCMC" /* inject synthetic machine checks */ + "\013CRASH" /* MSRs for guest crash */ + "\014DEBUGMSR" /* MSRs for guest debug */ + "\015NPIEP" /* NPIEP */ + "\016HVDIS"); /* disabling hypervisor */ + + 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); } -SYSINIT(hv_tc_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hv_tc_init, NULL); +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_drv_freebsd.c b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c index 669a532..8a07e45 100644 --- a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c +++ b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c @@ -117,8 +117,12 @@ handled: * message_pending and EOMing. Otherwise, the EOMing will * not deliver any more messages * since there is no empty slot + * + * NOTE: + * mb() is used here, since atomic_thread_fence_seq_cst() + * will become compiler fence on UP kernel. */ - atomic_thread_fence_seq_cst(); + mb(); if (msg->header.message_flags.u.message_pending) { /* @@ -190,8 +194,12 @@ hv_vmbus_isr(struct trapframe *frame) * message_pending and EOMing. Otherwise, the EOMing will * not deliver any more messages * since there is no empty slot + * + * NOTE: + * mb() is used here, since atomic_thread_fence_seq_cst() + * will become compiler fence on UP kernel. */ - atomic_thread_fence_seq_cst(); + mb(); if (msg->header.message_flags.u.message_pending) { /* @@ -383,80 +391,9 @@ vmbus_probe(device_t dev) { } #ifdef HYPERV -extern inthand_t IDTVEC(rsvd), IDTVEC(hv_vmbus_callback); - -/** - * @brief Find a free IDT slot and setup the interrupt handler. - */ -static int -vmbus_vector_alloc(void) -{ - int vector; - uintptr_t func; - struct gate_descriptor *ip; - - /* - * Search backwards form the highest IDT vector available for use - * as vmbus channel callback vector. We install 'hv_vmbus_callback' - * handler at that vector and use it to interrupt vcpus. - */ - vector = APIC_SPURIOUS_INT; - while (--vector >= APIC_IPI_INTS) { - ip = &idt[vector]; - func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); - if (func == (uintptr_t)&IDTVEC(rsvd)) { -#ifdef __i386__ - setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYS386IGT, - SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); -#else - setidt(vector , IDTVEC(hv_vmbus_callback), SDT_SYSIGT, - SEL_KPL, 0); +extern inthand_t IDTVEC(hv_vmbus_callback); #endif - return (vector); - } - } - return (0); -} - -/** - * @brief Restore the IDT slot to rsvd. - */ -static void -vmbus_vector_free(int vector) -{ - uintptr_t func; - struct gate_descriptor *ip; - - if (vector == 0) - return; - - KASSERT(vector >= APIC_IPI_INTS && vector < APIC_SPURIOUS_INT, - ("invalid vector %d", vector)); - - ip = &idt[vector]; - func = ((long)ip->gd_hioffset << 16 | ip->gd_looffset); - KASSERT(func == (uintptr_t)&IDTVEC(hv_vmbus_callback), - ("invalid vector %d", vector)); - - setidt(vector, IDTVEC(rsvd), SDT_SYSIGT, SEL_KPL, 0); -} - -#else /* HYPERV */ - -static int -vmbus_vector_alloc(void) -{ - return(0); -} - -static void -vmbus_vector_free(int vector) -{ -} - -#endif /* HYPERV */ - /** * @brief Main vmbus driver initialization routine. * @@ -489,12 +426,15 @@ vmbus_bus_init(void) return (ret); } +#ifdef HYPERV /* * Find a free IDT slot for vmbus callback. */ - hv_vmbus_g_context.hv_cb_vector = vmbus_vector_alloc(); - - if (hv_vmbus_g_context.hv_cb_vector == 0) { + hv_vmbus_g_context.hv_cb_vector = lapic_ipi_alloc(IDTVEC(hv_vmbus_callback)); +#else + hv_vmbus_g_context.hv_cb_vector = -1; +#endif + if (hv_vmbus_g_context.hv_cb_vector < 0) { if(bootverbose) printf("Error VMBUS: Cannot find free IDT slot for " "vmbus callback!\n"); @@ -587,7 +527,7 @@ vmbus_bus_init(void) } } - vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); + lapic_ipi_free(hv_vmbus_g_context.hv_cb_vector); cleanup: hv_vmbus_cleanup(); @@ -655,7 +595,7 @@ vmbus_bus_exit(void) } } - vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); + lapic_ipi_free(hv_vmbus_g_context.hv_cb_vector); return; } diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h index 1a0ed04..8410494 100644 --- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -208,10 +208,10 @@ typedef struct { struct taskqueue *hv_msg_tq[MAXCPU]; struct task hv_msg_task[MAXCPU]; /* - * Host use this vector to intrrupt guest for vmbus channel + * Host use this vector to interrupt guest for vmbus channel * event and msg. */ - unsigned int hv_cb_vector; + int hv_cb_vector; } hv_vmbus_context; /* @@ -471,10 +471,28 @@ 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 0x0002 /* MSR_TIME_REF_COUNT */ +#define HV_FEATURE_MSR_SYNIC 0x0004 /* MSRs for SynIC */ +#define HV_FEATURE_MSR_SYNTIMER 0x0008 /* MSRs for SynTimer */ +#define HV_FEATURE_MSR_APIC 0x0010 /* MSR_{EOI,ICR,TPR} */ +#define HV_FEATURE_MSR_HYPERCALL 0x0020 /* MSR_{GUEST_OS_ID,HYPERCALL} */ +#define HV_FEATURE_MSR_GUEST_IDLE 0x0400 /* MSR_GUEST_IDLE */ + +#define HV_PM_FEATURE_CSTATE_MASK 0x000f +#define HV_PM_FEATURE_C3_HPET 0x0010 /* C3 requires HPET */ +#define HV_PM_FEATURE_CSTATE(f) ((f) & HV_PM_FEATURE_CSTATE_MASK) + +#define HV_FEATURE3_MWAIT 0x0001 /* MWAIT */ +#define HV_FEATURE3_XMM_HYPERCALL 0x0010 /* hypercall input through XMM regs */ +#define HV_FEATURE3_GUEST_IDLE 0x0020 /* guest idle support */ +#define HV_FEATURE3_NUMA 0x0080 /* NUMA distance query support */ +#define HV_FEATURE3_TIME_FREQ 0x0100 /* timer frequency query (TSC, LAPIC) */ +#define HV_FEATURE3_MSR_CRASH 0x0400 /* MSRs for guest crash */ + /* * Define the format of the SIMP register */ @@ -628,6 +646,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 { @@ -704,7 +725,6 @@ uint16_t hv_vmbus_post_msg_via_msg_ipc( uint16_t hv_vmbus_signal_event(void *con_id); void hv_vmbus_synic_init(void *irq_arg); void hv_vmbus_synic_cleanup(void *arg); -int hv_vmbus_query_hypervisor_presence(void); struct hv_device* hv_vmbus_child_device_create( hv_guid device_type, |