svn commit: r307278 - in stable/11/sys/dev/hyperv: include vmbus
Sepherosa Ziehau
sephe at FreeBSD.org
Fri Oct 14 07:27:32 UTC 2016
Author: sephe
Date: Fri Oct 14 07:27:29 2016
New Revision: 307278
URL: https://svnweb.freebsd.org/changeset/base/307278
Log:
MFC 302540
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.
Sponsored by: Microsoft OSTC
Differential Revision: https://reviews.freebsd.org/D6830
Modified:
stable/11/sys/dev/hyperv/include/hyperv.h
stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
stable/11/sys/dev/hyperv/vmbus/hv_connection.c
stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
stable/11/sys/dev/hyperv/vmbus/hyperv.c
stable/11/sys/dev/hyperv/vmbus/hyperv_reg.h
stable/11/sys/dev/hyperv/vmbus/hyperv_var.h
stable/11/sys/dev/hyperv/vmbus/vmbus.c
stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h
stable/11/sys/dev/hyperv/vmbus/vmbus_var.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- stable/11/sys/dev/hyperv/include/hyperv.h Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/include/hyperv.h Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/hv_channel_mgmt.c Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/hv_connection.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_connection.c Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/hv_connection.c Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/hv_vmbus_priv.h Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/hyperv.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hyperv.c Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/hyperv.c Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/hyperv_reg.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hyperv_reg.h Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/hyperv_reg.h Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/hyperv_var.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/hyperv_var.h Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/hyperv_var.h Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/vmbus.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus.c Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus.c Fri Oct 14 07:27:29 2016 (r307278)
@@ -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: stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h Fri Oct 14 07:26:19 2016 (r307277)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_reg.h Fri Oct 14 07:27:29 2016 (r307278)
@@ -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 ***
More information about the svn-src-all
mailing list