Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Jul 2016 04:52:11 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r302540 - in head/sys/dev/hyperv: include vmbus
Message-ID:  <201607110452.u6B4qBRc011099@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Mon Jul 11 04:52:11 2016
New Revision: 302540
URL: https://svnweb.freebsd.org/changeset/base/302540

Log:
  hyperv/vmbus: Implement a new set of APIs for post message Hypercall
  
  And use this new APIs for Initial Contact post message Hypercall.
  More post message Hypercalls will be converted.
  
  MFC after:	1 week
  Sponsored by:	Microsoft OSTC
  Differential Revision:	https://reviews.freebsd.org/D6830

Modified:
  head/sys/dev/hyperv/include/hyperv.h
  head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
  head/sys/dev/hyperv/vmbus/hv_connection.c
  head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
  head/sys/dev/hyperv/vmbus/hyperv.c
  head/sys/dev/hyperv/vmbus/hyperv_reg.h
  head/sys/dev/hyperv/vmbus/hyperv_var.h
  head/sys/dev/hyperv/vmbus/vmbus.c
  head/sys/dev/hyperv/vmbus/vmbus_reg.h
  head/sys/dev/hyperv/vmbus/vmbus_var.h

Modified: head/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- head/sys/dev/hyperv/include/hyperv.h	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/include/hyperv.h	Mon Jul 11 04:52:11 2016	(r302540)
@@ -77,10 +77,6 @@ typedef uint8_t	hv_bool_uint8_t;
 #define HV_VMBUS_VERSION_WIN8		((2 << 16) | (4))
 #define HV_VMBUS_VERSION_WIN8_1		((3 << 16) | (0))
 
-#define HV_VMBUS_VERSION_INVALID	-1
-
-#define HV_VMBUS_VERSION_CURRENT	HV_VMBUS_VERSION_WIN8_1
-
 /*
  * Make maximum size of pipe payload of 16K
  */
@@ -537,20 +533,6 @@ typedef struct {
 	uint32_t			child_rel_id;
 } __packed hv_vmbus_channel_relid_released;
 
-typedef struct {
-	hv_vmbus_channel_msg_header	header;
-	uint32_t			vmbus_version_requested;
-	uint32_t			padding2;
-	uint64_t			interrupt_page;
-	uint64_t			monitor_page_1;
-	uint64_t			monitor_page_2;
-} __packed hv_vmbus_channel_initiate_contact;
-
-typedef struct {
-	hv_vmbus_channel_msg_header header;
-	hv_bool_uint8_t		version_supported;
-} __packed hv_vmbus_channel_version_response;
-
 typedef hv_vmbus_channel_msg_header hv_vmbus_channel_unload;
 
 #define HW_MACADDR_LEN	6

Modified: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Mon Jul 11 04:52:11 2016	(r302540)
@@ -40,29 +40,30 @@
  * Internal functions
  */
 
-typedef void (*vmbus_msg_handler)(const hv_vmbus_channel_msg_header *msg);
-
 typedef struct hv_vmbus_channel_msg_table_entry {
 	hv_vmbus_channel_msg_type    messageType;
-	vmbus_msg_handler   messageHandler;
+	void		(*messageHandler)
+			(struct vmbus_softc *sc,
+			 const struct vmbus_message *msg);
 } hv_vmbus_channel_msg_table_entry;
 
 static void	vmbus_channel_on_offer_internal(void *context);
 static void	vmbus_channel_on_offer_rescind_internal(void *context);
 
-static void	vmbus_channel_on_offer(const hv_vmbus_channel_msg_header *hdr);
-static void	vmbus_channel_on_open_result(
-		    const hv_vmbus_channel_msg_header *hdr);
-static void	vmbus_channel_on_offer_rescind(
-		    const hv_vmbus_channel_msg_header *hdr);
-static void	vmbus_channel_on_gpadl_created(
-		    const hv_vmbus_channel_msg_header *hdr);
-static void	vmbus_channel_on_gpadl_torndown(
-		    const hv_vmbus_channel_msg_header *hdr);
-static void	vmbus_channel_on_offers_delivered(
-		    const hv_vmbus_channel_msg_header *hdr);
-static void	vmbus_channel_on_version_response(
-		    const hv_vmbus_channel_msg_header *hdr);
+static void	vmbus_channel_on_offer(struct vmbus_softc *,
+		    const struct vmbus_message *);
+static void	vmbus_channel_on_open_result(struct vmbus_softc *,
+		    const struct vmbus_message *);
+static void	vmbus_channel_on_offer_rescind(struct vmbus_softc *,
+		    const struct vmbus_message *);
+static void	vmbus_channel_on_gpadl_created(struct vmbus_softc *,
+		    const struct vmbus_message *);
+static void	vmbus_channel_on_gpadl_torndown(struct vmbus_softc *,
+		    const struct vmbus_message *);
+static void	vmbus_channel_on_offers_delivered(struct vmbus_softc *,
+		    const struct vmbus_message *);
+static void	vmbus_channel_on_version_response(struct vmbus_softc *,
+		    const struct vmbus_message *);
 
 /**
  * Channel message dispatch table
@@ -398,8 +399,11 @@ vmbus_channel_select_defcpu(struct hv_vm
  * object to process the offer synchronously
  */
 static void
-vmbus_channel_on_offer(const hv_vmbus_channel_msg_header *hdr)
+vmbus_channel_on_offer(struct vmbus_softc *sc, const struct vmbus_message *msg)
 {
+	const hv_vmbus_channel_msg_header *hdr =
+	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
+
 	const hv_vmbus_channel_offer_channel *offer;
 	hv_vmbus_channel_offer_channel *copied;
 
@@ -476,8 +480,12 @@ vmbus_channel_on_offer_internal(void* co
  * synchronously
  */
 static void
-vmbus_channel_on_offer_rescind(const hv_vmbus_channel_msg_header *hdr)
+vmbus_channel_on_offer_rescind(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
 {
+	const hv_vmbus_channel_msg_header *hdr =
+	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
+
 	const hv_vmbus_channel_rescind_offer *rescind;
 	hv_vmbus_channel*		channel;
 
@@ -508,8 +516,8 @@ vmbus_channel_on_offer_rescind_internal(
  * @brief Invoked when all offers have been delivered.
  */
 static void
-vmbus_channel_on_offers_delivered(
-    const hv_vmbus_channel_msg_header *hdr __unused)
+vmbus_channel_on_offers_delivered(struct vmbus_softc *sc __unused,
+    const struct vmbus_message *msg __unused)
 {
 
 	mtx_lock(&vmbus_chwait_lock);
@@ -526,8 +534,12 @@ vmbus_channel_on_offers_delivered(
  * response and signal the requesting thread.
  */
 static void
-vmbus_channel_on_open_result(const hv_vmbus_channel_msg_header *hdr)
+vmbus_channel_on_open_result(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
 {
+	const hv_vmbus_channel_msg_header *hdr =
+	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
+
 	const hv_vmbus_channel_open_result *result;
 	hv_vmbus_channel_msg_info*	msg_info;
 	hv_vmbus_channel_msg_header*	requestHeader;
@@ -568,8 +580,12 @@ vmbus_channel_on_open_result(const hv_vm
  * response and signal the requesting thread.
  */
 static void
-vmbus_channel_on_gpadl_created(const hv_vmbus_channel_msg_header *hdr)
+vmbus_channel_on_gpadl_created(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
 {
+	const hv_vmbus_channel_msg_header *hdr =
+	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
+
 	const hv_vmbus_channel_gpadl_created *gpadl_created;
 	hv_vmbus_channel_msg_info*		msg_info;
 	hv_vmbus_channel_msg_header*		request_header;
@@ -610,8 +626,12 @@ vmbus_channel_on_gpadl_created(const hv_
  * response and signal the requesting thread
  */
 static void
-vmbus_channel_on_gpadl_torndown(const hv_vmbus_channel_msg_header *hdr)
+vmbus_channel_on_gpadl_torndown(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
 {
+	const hv_vmbus_channel_msg_header *hdr =
+	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
+
 	const hv_vmbus_channel_gpadl_torndown *gpadl_torndown;
 	hv_vmbus_channel_msg_info*		msg_info;
 	hv_vmbus_channel_msg_header*		requestHeader;
@@ -647,39 +667,11 @@ vmbus_channel_on_gpadl_torndown(const hv
     mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
 }
 
-/**
- * @brief Version response handler.
- *
- * This is invoked when we received a response
- * to our initiate contact request. Find the matching request, copy th
- * response and signal the requesting thread.
- */
 static void
-vmbus_channel_on_version_response(const hv_vmbus_channel_msg_header *hdr)
+vmbus_channel_on_version_response(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
 {
-	hv_vmbus_channel_msg_info*		msg_info;
-	hv_vmbus_channel_msg_header*		requestHeader;
-	hv_vmbus_channel_initiate_contact*	initiate;
-	const hv_vmbus_channel_version_response *versionResponse;
-
-	versionResponse = (const hv_vmbus_channel_version_response *)hdr;
-
-	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;
-	    if (requestHeader->message_type
-		== HV_CHANNEL_MESSAGE_INITIATED_CONTACT) {
-		initiate =
-		    (hv_vmbus_channel_initiate_contact*) requestHeader;
-		memcpy(&msg_info->response.version_response,
-		    versionResponse,
-		    sizeof(hv_vmbus_channel_version_response));
-		sema_post(&msg_info->wait_sema);
-	    }
-	}
-    mtx_unlock(&hv_vmbus_g_connection.channel_msg_lock);
-
+	vmbus_msghc_wakeup(sc, msg);
 }
 
 /**
@@ -865,5 +857,5 @@ vmbus_chan_msgproc(struct vmbus_softc *s
 
 	entry = &g_channel_message_table[msg_type];
 	if (entry->messageHandler)
-		entry->messageHandler(hdr);
+		entry->messageHandler(sc, msg);
 }

Modified: head/sys/dev/hyperv/vmbus/hv_connection.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_connection.c	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/hv_connection.c	Mon Jul 11 04:52:11 2016	(r302540)
@@ -39,6 +39,7 @@
 #include <vm/pmap.h>
 
 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
+#include <dev/hyperv/vmbus/hyperv_reg.h>
 #include <dev/hyperv/vmbus/vmbus_reg.h>
 #include <dev/hyperv/vmbus/vmbus_var.h>
 
@@ -49,97 +50,7 @@ hv_vmbus_connection hv_vmbus_g_connectio
 	{ .connect_state = HV_DISCONNECTED,
 	  .next_gpadl_handle = 0xE1E10, };
 
-uint32_t hv_vmbus_protocal_version = HV_VMBUS_VERSION_WS2008;
-
-static uint32_t
-hv_vmbus_get_next_version(uint32_t current_ver)
-{
-	switch (current_ver) {
-	case (HV_VMBUS_VERSION_WIN7):
-		return(HV_VMBUS_VERSION_WS2008);
-
-	case (HV_VMBUS_VERSION_WIN8):
-		return(HV_VMBUS_VERSION_WIN7);
-
-	case (HV_VMBUS_VERSION_WIN8_1):
-		return(HV_VMBUS_VERSION_WIN8);
-
-	case (HV_VMBUS_VERSION_WS2008):
-	default:
-		return(HV_VMBUS_VERSION_INVALID);
-	}
-}
-
-/**
- * Negotiate the highest supported hypervisor version.
- */
-static int
-hv_vmbus_negotiate_version(struct vmbus_softc *sc,
-    hv_vmbus_channel_msg_info *msg_info, uint32_t version)
-{
-	int					ret = 0;
-	hv_vmbus_channel_initiate_contact	*msg;
-
-	sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
-	msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
-
-	msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
-	msg->vmbus_version_requested = version;
-
-	msg->interrupt_page = sc->vmbus_evtflags_dma.hv_paddr;
-	msg->monitor_page_1 = sc->vmbus_mnf1_dma.hv_paddr;
-	msg->monitor_page_2 = sc->vmbus_mnf2_dma.hv_paddr;
-
-	/**
-	 * Add to list before we send the request since we may receive the
-	 * response before returning from this routine
-	 */
-	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(&hv_vmbus_g_connection.channel_msg_lock);
-
-	ret = hv_vmbus_post_message(
-		msg,
-		sizeof(hv_vmbus_channel_initiate_contact));
-
-	if (ret != 0) {
-		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(&hv_vmbus_g_connection.channel_msg_lock);
-		return (ret);
-	}
-
-	/**
-	 * Wait for the connection response
-	 */
-	ret = sema_timedwait(&msg_info->wait_sema, 5 * hz); /* KYS 5 seconds */
-
-	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(&hv_vmbus_g_connection.channel_msg_lock);
-
-	/**
-	 * Check if successful
-	 */
-	if (msg_info->response.version_response.version_supported) {
-		hv_vmbus_g_connection.connect_state = HV_CONNECTED;
-	} else {
-		ret = ECONNREFUSED;
-	}
-
-	return (ret);
-}
+uint32_t hv_vmbus_protocal_version;
 
 /**
  * Send a connect request on the partition service connection
@@ -147,10 +58,6 @@ hv_vmbus_negotiate_version(struct vmbus_
 int
 hv_vmbus_connect(struct vmbus_softc *sc)
 {
-	int					ret = 0;
-	uint32_t				version;
-	hv_vmbus_channel_msg_info*		msg_info = NULL;
-
 	/**
 	 * Make sure we are not connecting or connected
 	 */
@@ -171,60 +78,12 @@ hv_vmbus_connect(struct vmbus_softc *sc)
 	mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel",
 		NULL, MTX_DEF);
 
-	msg_info = (hv_vmbus_channel_msg_info*)
-		malloc(sizeof(hv_vmbus_channel_msg_info) +
-			sizeof(hv_vmbus_channel_initiate_contact),
-			M_DEVBUF, M_WAITOK | M_ZERO);
-
 	hv_vmbus_g_connection.channels = malloc(sizeof(hv_vmbus_channel*) *
 	    VMBUS_CHAN_MAX, M_DEVBUF, M_WAITOK | M_ZERO);
-	/*
-	 * Find the highest vmbus version number we can support.
-	 */
-	version = HV_VMBUS_VERSION_CURRENT;
-
-	do {
-		ret = hv_vmbus_negotiate_version(sc, msg_info, version);
-		if (ret == EWOULDBLOCK) {
-			/*
-			 * We timed out.
-			 */
-			goto cleanup;
-		}
-
-		if (hv_vmbus_g_connection.connect_state == HV_CONNECTED)
-			break;
-
-		version = hv_vmbus_get_next_version(version);
-	} while (version != HV_VMBUS_VERSION_INVALID);
-
-	hv_vmbus_protocal_version = version;
-	if (bootverbose)
-		printf("VMBUS: Protocol Version: %d.%d\n",
-		    version >> 16, version & 0xFFFF);
 
-	sema_destroy(&msg_info->wait_sema);
-	free(msg_info, M_DEVBUF);
+	hv_vmbus_g_connection.connect_state = HV_CONNECTED;
 
 	return (0);
-
-	/*
-	 * Cleanup after failure!
-	 */
-	cleanup:
-
-	hv_vmbus_g_connection.connect_state = HV_DISCONNECTED;
-
-	mtx_destroy(&hv_vmbus_g_connection.channel_lock);
-	mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock);
-
-	if (msg_info) {
-		sema_destroy(&msg_info->wait_sema);
-		free(msg_info, M_DEVBUF);
-	}
-
-	free(hv_vmbus_g_connection.channels, M_DEVBUF);
-	return (ret);
 }
 
 /**
@@ -330,7 +189,7 @@ int hv_vmbus_post_message(void *buffer, 
 	 */
 	for (retries = 0; retries < 20; retries++) {
 		ret = hv_vmbus_post_msg_via_msg_ipc(connId,
-		    VMBUS_MSGTYPE_CHANNEL, buffer, bufferLen);
+		    HYPERV_MSGTYPE_CHANNEL, buffer, bufferLen);
 		if (ret == HV_STATUS_SUCCESS)
 			return (0);
 

Modified: head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Mon Jul 11 04:52:11 2016	(r302540)
@@ -95,7 +95,6 @@ typedef union {
 	hv_vmbus_channel_open_result		open_result;
 	hv_vmbus_channel_gpadl_torndown		gpadl_torndown;
 	hv_vmbus_channel_gpadl_created		gpadl_created;
-	hv_vmbus_channel_version_response	version_response;
 } hv_vmbus_channel_msg_response;
 
 /*

Modified: head/sys/dev/hyperv/vmbus/hyperv.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hyperv.c	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/hyperv.c	Mon Jul 11 04:52:11 2016	(r302540)
@@ -118,6 +118,13 @@ hv_vmbus_do_hypercall(uint64_t value, vo
 	    in_paddr, out_paddr);
 }
 
+uint64_t
+hypercall_post_message(bus_addr_t msg_paddr)
+{
+	return hypercall_md(hypercall_context.hc_addr,
+	    HYPERCALL_POST_MESSAGE, msg_paddr, 0);
+}
+
 /**
  * @brief Post a message using the hypervisor message IPC.
  * (This involves a hypercall.)

Modified: head/sys/dev/hyperv/vmbus/hyperv_reg.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/hyperv_reg.h	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/hyperv_reg.h	Mon Jul 11 04:52:11 2016	(r302540)
@@ -29,6 +29,8 @@
 #ifndef _HYPERV_REG_H_
 #define _HYPERV_REG_H_
 
+#include <sys/param.h>
+
 /*
  * Hyper-V Synthetic MSRs
  */
@@ -130,4 +132,41 @@
 #define CPUID_LEAF_HV_LIMITS		0x40000005
 #define CPUID_LEAF_HV_HWFEATURES	0x40000006
 
+/*
+ * Hyper-V message types
+ */
+#define HYPERV_MSGTYPE_NONE		0
+#define HYPERV_MSGTYPE_CHANNEL		1
+#define HYPERV_MSGTYPE_TIMER_EXPIRED	0x80000010
+
+/*
+ * Hypercall status codes
+ */
+#define HYPERCALL_STATUS_SUCCESS	0x0000
+
+/*
+ * Hypercall input values
+ */
+#define HYPERCALL_POST_MESSAGE		0x005c
+
+/*
+ * Hypercall input parameters
+ */
+
+/*
+ * HYPERCALL_POST_MESSAGE
+ */
+#define HYPERCALL_POSTMSGIN_DSIZE_MAX	240
+#define HYPERCALL_POSTMSGIN_SIZE	256
+#define HYPERCALL_POSTMSGIN_ALIGN	8
+
+struct hypercall_postmsg_in {
+	uint32_t	hc_connid;
+	uint32_t	hc_rsvd;
+	uint32_t	hc_msgtype;	/* HYPERV_MSGTYPE_ */
+	uint32_t	hc_dsize;
+	uint8_t		hc_data[HYPERCALL_POSTMSGIN_DSIZE_MAX];
+} __packed;
+CTASSERT(sizeof(struct hypercall_postmsg_in) == HYPERCALL_POSTMSGIN_SIZE);
+
 #endif	/* !_HYPERV_REG_H_ */

Modified: head/sys/dev/hyperv/vmbus/hyperv_var.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/hyperv_var.h	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/hyperv_var.h	Mon Jul 11 04:52:11 2016	(r302540)
@@ -38,4 +38,6 @@
 extern u_int	hyperv_features;
 extern u_int	hyperv_recommends;
 
+uint64_t	hypercall_post_message(bus_addr_t msg_paddr);
+
 #endif	/* !_HYPERV_VAR_H_ */

Modified: head/sys/dev/hyperv/vmbus/vmbus.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/vmbus.c	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/vmbus.c	Mon Jul 11 04:52:11 2016	(r302540)
@@ -69,10 +69,354 @@ __FBSDID("$FreeBSD$");
 #include <contrib/dev/acpica/include/acpi.h>
 #include "acpi_if.h"
 
+/*
+ * NOTE: DO NOT CHANGE THESE
+ */
+#define VMBUS_CONNID_MESSAGE		1
+#define VMBUS_CONNID_EVENT		2
+
+struct vmbus_msghc {
+	struct hypercall_postmsg_in	*mh_inprm;
+	struct hypercall_postmsg_in	mh_inprm_save;
+	struct hyperv_dma		mh_inprm_dma;
+
+	struct vmbus_message		*mh_resp;
+	struct vmbus_message		mh_resp0;
+};
+
+struct vmbus_msghc_ctx {
+	struct vmbus_msghc		*mhc_free;
+	struct mtx			mhc_free_lock;
+	uint32_t			mhc_flags;
+
+	struct vmbus_msghc		*mhc_active;
+	struct mtx			mhc_active_lock;
+};
+
+#define VMBUS_MSGHC_CTXF_DESTROY	0x0001
+
+static int			vmbus_init(struct vmbus_softc *);
+static int			vmbus_init_contact(struct vmbus_softc *,
+				    uint32_t);
+
+static struct vmbus_msghc_ctx	*vmbus_msghc_ctx_create(bus_dma_tag_t);
+static void			vmbus_msghc_ctx_destroy(
+				    struct vmbus_msghc_ctx *);
+static void			vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *);
+static struct vmbus_msghc	*vmbus_msghc_alloc(bus_dma_tag_t);
+static void			vmbus_msghc_free(struct vmbus_msghc *);
+static struct vmbus_msghc	*vmbus_msghc_get1(struct vmbus_msghc_ctx *,
+				    uint32_t);
+
 struct vmbus_softc	*vmbus_sc;
 
 extern inthand_t IDTVEC(vmbus_isr);
 
+static const uint32_t		vmbus_version[] = {
+	HV_VMBUS_VERSION_WIN8_1,
+	HV_VMBUS_VERSION_WIN8,
+	HV_VMBUS_VERSION_WIN7,
+	HV_VMBUS_VERSION_WS2008
+};
+
+static struct vmbus_msghc *
+vmbus_msghc_alloc(bus_dma_tag_t parent_dtag)
+{
+	struct vmbus_msghc *mh;
+
+	mh = malloc(sizeof(*mh), M_DEVBUF, M_WAITOK | M_ZERO);
+
+	mh->mh_inprm = hyperv_dmamem_alloc(parent_dtag,
+	    HYPERCALL_POSTMSGIN_ALIGN, 0, HYPERCALL_POSTMSGIN_SIZE,
+	    &mh->mh_inprm_dma, BUS_DMA_WAITOK);
+	if (mh->mh_inprm == NULL) {
+		free(mh, M_DEVBUF);
+		return NULL;
+	}
+	return mh;
+}
+
+static void
+vmbus_msghc_free(struct vmbus_msghc *mh)
+{
+	hyperv_dmamem_free(&mh->mh_inprm_dma, mh->mh_inprm);
+	free(mh, M_DEVBUF);
+}
+
+static void
+vmbus_msghc_ctx_free(struct vmbus_msghc_ctx *mhc)
+{
+	KASSERT(mhc->mhc_active == NULL, ("still have active msg hypercall"));
+	KASSERT(mhc->mhc_free == NULL, ("still have hypercall msg"));
+
+	mtx_destroy(&mhc->mhc_free_lock);
+	mtx_destroy(&mhc->mhc_active_lock);
+	free(mhc, M_DEVBUF);
+}
+
+static struct vmbus_msghc_ctx *
+vmbus_msghc_ctx_create(bus_dma_tag_t parent_dtag)
+{
+	struct vmbus_msghc_ctx *mhc;
+
+	mhc = malloc(sizeof(*mhc), M_DEVBUF, M_WAITOK | M_ZERO);
+	mtx_init(&mhc->mhc_free_lock, "vmbus msghc free", NULL, MTX_DEF);
+	mtx_init(&mhc->mhc_active_lock, "vmbus msghc act", NULL, MTX_DEF);
+
+	mhc->mhc_free = vmbus_msghc_alloc(parent_dtag);
+	if (mhc->mhc_free == NULL) {
+		vmbus_msghc_ctx_free(mhc);
+		return NULL;
+	}
+	return mhc;
+}
+
+static struct vmbus_msghc *
+vmbus_msghc_get1(struct vmbus_msghc_ctx *mhc, uint32_t dtor_flag)
+{
+	struct vmbus_msghc *mh;
+
+	mtx_lock(&mhc->mhc_free_lock);
+
+	while ((mhc->mhc_flags & dtor_flag) == 0 && mhc->mhc_free == NULL) {
+		mtx_sleep(&mhc->mhc_free, &mhc->mhc_free_lock, 0,
+		    "gmsghc", 0);
+	}
+	if (mhc->mhc_flags & dtor_flag) {
+		/* Being destroyed */
+		mh = NULL;
+	} else {
+		mh = mhc->mhc_free;
+		KASSERT(mh != NULL, ("no free hypercall msg"));
+		KASSERT(mh->mh_resp == NULL,
+		    ("hypercall msg has pending response"));
+		mhc->mhc_free = NULL;
+	}
+
+	mtx_unlock(&mhc->mhc_free_lock);
+
+	return mh;
+}
+
+struct vmbus_msghc *
+vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
+{
+	struct hypercall_postmsg_in *inprm;
+	struct vmbus_msghc *mh;
+
+	if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
+		return NULL;
+
+	mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
+	if (mh == NULL)
+		return NULL;
+
+	inprm = mh->mh_inprm;
+	memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
+	inprm->hc_connid = VMBUS_CONNID_MESSAGE;
+	inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
+	inprm->hc_dsize = dsize;
+
+	return mh;
+}
+
+void
+vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+{
+	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
+
+	KASSERT(mhc->mhc_active == NULL, ("msg hypercall is active"));
+	mh->mh_resp = NULL;
+
+	mtx_lock(&mhc->mhc_free_lock);
+	KASSERT(mhc->mhc_free == NULL, ("has free hypercall msg"));
+	mhc->mhc_free = mh;
+	mtx_unlock(&mhc->mhc_free_lock);
+	wakeup(&mhc->mhc_free);
+}
+
+void *
+vmbus_msghc_dataptr(struct vmbus_msghc *mh)
+{
+	return mh->mh_inprm->hc_data;
+}
+
+static void
+vmbus_msghc_ctx_destroy(struct vmbus_msghc_ctx *mhc)
+{
+	struct vmbus_msghc *mh;
+
+	mtx_lock(&mhc->mhc_free_lock);
+	mhc->mhc_flags |= VMBUS_MSGHC_CTXF_DESTROY;
+	mtx_unlock(&mhc->mhc_free_lock);
+	wakeup(&mhc->mhc_free);
+
+	mh = vmbus_msghc_get1(mhc, 0);
+	if (mh == NULL)
+		panic("can't get msghc");
+
+	vmbus_msghc_free(mh);
+	vmbus_msghc_ctx_free(mhc);
+}
+
+int
+vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
+{
+	sbintime_t time = SBT_1MS;
+	int i;
+
+	/*
+	 * Save the input parameter so that we could restore the input
+	 * parameter if the Hypercall failed.
+	 *
+	 * XXX
+	 * Is this really necessary?!  i.e. Will the Hypercall ever
+	 * overwrite the input parameter?
+	 */
+	memcpy(&mh->mh_inprm_save, mh->mh_inprm, HYPERCALL_POSTMSGIN_SIZE);
+
+	/*
+	 * In order to cope with transient failures, e.g. insufficient
+	 * resources on host side, we retry the post message Hypercall
+	 * several times.  20 retries seem sufficient.
+	 */
+#define HC_RETRY_MAX	20
+
+	for (i = 0; i < HC_RETRY_MAX; ++i) {
+		uint64_t status;
+
+		status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr);
+		if (status == HYPERCALL_STATUS_SUCCESS)
+			return 0;
+
+		pause_sbt("hcpmsg", time, 0, C_HARDCLOCK);
+		if (time < SBT_1S * 2)
+			time *= 2;
+
+		/* Restore input parameter and try again */
+		memcpy(mh->mh_inprm, &mh->mh_inprm_save,
+		    HYPERCALL_POSTMSGIN_SIZE);
+	}
+
+#undef HC_RETRY_MAX
+
+	return EIO;
+}
+
+int
+vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+{
+	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
+	int error;
+
+	KASSERT(mh->mh_resp == NULL, ("hypercall msg has pending response"));
+
+	mtx_lock(&mhc->mhc_active_lock);
+	KASSERT(mhc->mhc_active == NULL, ("pending active msg hypercall"));
+	mhc->mhc_active = mh;
+	mtx_unlock(&mhc->mhc_active_lock);
+
+	error = vmbus_msghc_exec_noresult(mh);
+	if (error) {
+		mtx_lock(&mhc->mhc_active_lock);
+		KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
+		mhc->mhc_active = NULL;
+		mtx_unlock(&mhc->mhc_active_lock);
+	}
+	return error;
+}
+
+const struct vmbus_message *
+vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+{
+	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
+
+	mtx_lock(&mhc->mhc_active_lock);
+
+	KASSERT(mhc->mhc_active == mh, ("msghc mismatch"));
+	while (mh->mh_resp == NULL) {
+		mtx_sleep(&mhc->mhc_active, &mhc->mhc_active_lock, 0,
+		    "wmsghc", 0);
+	}
+	mhc->mhc_active = NULL;
+
+	mtx_unlock(&mhc->mhc_active_lock);
+
+	return mh->mh_resp;
+}
+
+void
+vmbus_msghc_wakeup(struct vmbus_softc *sc, const struct vmbus_message *msg)
+{
+	struct vmbus_msghc_ctx *mhc = sc->vmbus_msg_hc;
+	struct vmbus_msghc *mh;
+
+	mtx_lock(&mhc->mhc_active_lock);
+
+	mh = mhc->mhc_active;
+	KASSERT(mh != NULL, ("no pending msg hypercall"));
+	memcpy(&mh->mh_resp0, msg, sizeof(mh->mh_resp0));
+	mh->mh_resp = &mh->mh_resp0;
+
+	mtx_unlock(&mhc->mhc_active_lock);
+	wakeup(&mhc->mhc_active);
+}
+
+static int
+vmbus_init_contact(struct vmbus_softc *sc, uint32_t version)
+{
+	struct vmbus_chanmsg_init_contact *req;
+	const struct vmbus_chanmsg_version_resp *resp;
+	const struct vmbus_message *msg;
+	struct vmbus_msghc *mh;
+	int error, supp = 0;
+
+	mh = vmbus_msghc_get(sc, sizeof(*req));
+	if (mh == NULL)
+		return ENXIO;
+
+	req = vmbus_msghc_dataptr(mh);
+	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_INIT_CONTACT;
+	req->chm_ver = version;
+	req->chm_evtflags = sc->vmbus_evtflags_dma.hv_paddr;
+	req->chm_mnf1 = sc->vmbus_mnf1_dma.hv_paddr;
+	req->chm_mnf2 = sc->vmbus_mnf2_dma.hv_paddr;
+
+	error = vmbus_msghc_exec(sc, mh);
+	if (error) {
+		vmbus_msghc_put(sc, mh);
+		return error;
+	}
+
+	msg = vmbus_msghc_wait_result(sc, mh);
+	resp = (const struct vmbus_chanmsg_version_resp *)msg->msg_data;
+	supp = resp->chm_supp;
+
+	vmbus_msghc_put(sc, mh);
+
+	return (supp ? 0 : EOPNOTSUPP);
+}
+
+static int
+vmbus_init(struct vmbus_softc *sc)
+{
+	int i;
+
+	for (i = 0; i < nitems(vmbus_version); ++i) {
+		int error;
+
+		error = vmbus_init_contact(sc, vmbus_version[i]);
+		if (!error) {
+			hv_vmbus_protocal_version = vmbus_version[i];
+			device_printf(sc->vmbus_dev, "version %u.%u\n",
+			    (hv_vmbus_protocal_version >> 16),
+			    (hv_vmbus_protocal_version & 0xffff));
+			return 0;
+		}
+	}
+	return ENXIO;
+}
+
 static void
 vmbus_msg_task(void *xsc, int pending __unused)
 {
@@ -81,19 +425,19 @@ vmbus_msg_task(void *xsc, int pending __
 
 	msg = VMBUS_PCPU_GET(sc, message, curcpu) + VMBUS_SINT_MESSAGE;
 	for (;;) {
-		if (msg->msg_type == VMBUS_MSGTYPE_NONE) {
+		if (msg->msg_type == HYPERV_MSGTYPE_NONE) {
 			/* No message */
 			break;
-		} else if (msg->msg_type == VMBUS_MSGTYPE_CHANNEL) {
+		} else if (msg->msg_type == HYPERV_MSGTYPE_CHANNEL) {
 			/* Channel message */
 			vmbus_chan_msgproc(sc,
 			    __DEVOLATILE(const struct vmbus_message *, msg));
 		}
 
-		msg->msg_type = VMBUS_MSGTYPE_NONE;
+		msg->msg_type = HYPERV_MSGTYPE_NONE;
 		/*
 		 * Make sure the write to msg_type (i.e. set to
-		 * VMBUS_MSGTYPE_NONE) happens before we read the
+		 * HYPERV_MSGTYPE_NONE) happens before we read the
 		 * msg_flags and EOMing. Otherwise, the EOMing will
 		 * not deliver any more messages since there is no
 		 * empty slot
@@ -127,14 +471,14 @@ vmbus_handle_intr1(struct vmbus_softc *s
 	 * TODO: move this to independent IDT vector.
 	 */
 	msg = msg_base + VMBUS_SINT_TIMER;
-	if (msg->msg_type == VMBUS_MSGTYPE_TIMER_EXPIRED) {
-		msg->msg_type = VMBUS_MSGTYPE_NONE;
+	if (msg->msg_type == HYPERV_MSGTYPE_TIMER_EXPIRED) {
+		msg->msg_type = HYPERV_MSGTYPE_NONE;
 
 		vmbus_et_intr(frame);
 
 		/*
 		 * Make sure the write to msg_type (i.e. set to
-		 * VMBUS_MSGTYPE_NONE) happens before we read the
+		 * HYPERV_MSGTYPE_NONE) happens before we read the
 		 * msg_flags and EOMing. Otherwise, the EOMing will
 		 * not deliver any more messages since there is no
 		 * empty slot
@@ -166,7 +510,7 @@ vmbus_handle_intr1(struct vmbus_softc *s
 	 * Check messages.  Mainly management stuffs; ultra low rate.
 	 */
 	msg = msg_base + VMBUS_SINT_MESSAGE;
-	if (__predict_false(msg->msg_type != VMBUS_MSGTYPE_NONE)) {
+	if (__predict_false(msg->msg_type != HYPERV_MSGTYPE_NONE)) {
 		taskqueue_enqueue(VMBUS_PCPU_GET(sc, message_tq, cpu),
 		    VMBUS_PCPU_PTR(sc, message_task, cpu));
 	}
@@ -620,6 +964,16 @@ vmbus_bus_init(void)
 	sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
 
 	/*
+	 * Create context for "post message" Hypercalls
+	 */
+	sc->vmbus_msg_hc = vmbus_msghc_ctx_create(
+	    bus_get_dma_tag(sc->vmbus_dev));
+	if (sc->vmbus_msg_hc == NULL) {
+		ret = ENXIO;
+		goto cleanup;
+	}
+
+	/*
 	 * Allocate DMA stuffs.
 	 */
 	ret = vmbus_dma_alloc(sc);
@@ -648,6 +1002,10 @@ vmbus_bus_init(void)
 	if (ret != 0)
 		goto cleanup;
 
+	ret = vmbus_init(sc);
+	if (ret != 0)
+		goto cleanup;
+
 	if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 ||
 	    hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)
 		sc->vmbus_event_proc = vmbus_event_proc_compat;
@@ -665,6 +1023,10 @@ vmbus_bus_init(void)
 cleanup:
 	vmbus_intr_teardown(sc);
 	vmbus_dma_free(sc);
+	if (sc->vmbus_msg_hc != NULL) {
+		vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
+		sc->vmbus_msg_hc = NULL;
+	}
 
 	return (ret);
 }
@@ -737,6 +1099,11 @@ vmbus_detach(device_t dev)
 	vmbus_intr_teardown(sc);
 	vmbus_dma_free(sc);
 
+	if (sc->vmbus_msg_hc != NULL) {
+		vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
+		sc->vmbus_msg_hc = NULL;
+	}
+
 	return (0);
 }
 

Modified: head/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_reg.h	Mon Jul 11 04:50:32 2016	(r302539)
+++ head/sys/dev/hyperv/vmbus/vmbus_reg.h	Mon Jul 11 04:52:11 2016	(r302540)
@@ -39,7 +39,7 @@
 #define VMBUS_MSG_SIZE			256
 
 struct vmbus_message {
-	uint32_t	msg_type;	/* VMBUS_MSGTYPE_ */
+	uint32_t	msg_type;	/* HYPERV_MSGTYPE_ */
 	uint8_t		msg_dsize;	/* data size */
 	uint8_t		msg_flags;	/* VMBUS_MSGFLAG_ */
 	uint16_t	msg_rsvd;
@@ -48,10 +48,6 @@ struct vmbus_message {
 } __packed;
 CTASSERT(sizeof(struct vmbus_message) == VMBUS_MSG_SIZE);
 
-#define VMBUS_MSGTYPE_NONE		0
-#define VMBUS_MSGTYPE_CHANNEL		1
-#define VMBUS_MSGTYPE_TIMER_EXPIRED	0x80000010
-
 #define VMBUS_MSGFLAG_PENDING		0x01
 
 /*
@@ -81,4 +77,34 @@ CTASSERT(sizeof(struct vmbus_evtflags) =
 #define VMBUS_CHAN_MAX_COMPAT	256
 #define VMBUS_CHAN_MAX		(VMBUS_EVTFLAG_LEN * VMBUS_EVTFLAGS_MAX)
 
+/*
+ * Channel messages
+ * - Embedded in vmbus_message.msg_data, e.g. response.
+ * - Embedded in hypercall_postmsg_in.hc_data, e.g. request.
+ */
+
+#define VMBUS_CHANMSG_TYPE_INIT_CONTACT		14	/* REQ */
+#define VMBUS_CHANMSG_TYPE_VERSION_RESP		15	/* RESP */
+
+struct vmbus_chanmsg_hdr {
+	uint32_t	chm_type;	/* VMBUS_CHANMSG_TYPE_ */
+	uint32_t	chm_rsvd;
+} __packed;
+
+/* VMBUS_CHANMSG_TYPE_INIT_CONTACT */
+struct vmbus_chanmsg_init_contact {
+	struct vmbus_chanmsg_hdr chm_hdr;
+	uint32_t	chm_ver;
+	uint32_t	chm_rsvd;
+	uint64_t	chm_evtflags;
+	uint64_t	chm_mnf1;
+	uint64_t	chm_mnf2;
+} __packed;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201607110452.u6B4qBRc011099>