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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to