summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsephe <sephe@FreeBSD.org>2016-10-17 05:53:38 +0000
committersephe <sephe@FreeBSD.org>2016-10-17 05:53:38 +0000
commit8805b157602c7a0963d947649e1c61b2ff537024 (patch)
tree3c6d5b2c1d2f0061dbb63f8e3025374950eb6d01 /sys
parentb30b53b1101ef1c8ace1fce012be03dcaae894bc (diff)
downloadFreeBSD-src-8805b157602c7a0963d947649e1c61b2ff537024.zip
FreeBSD-src-8805b157602c7a0963d947649e1c61b2ff537024.tar.gz
MFC 303945,303947-303949,303989,303992,303998,304001,304002,304109,304111
303945 hyperv/vmbus: Add macro to get channel packet data length. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7455 303947 hyperv/vmbus: Add APIs for various types of transactions. Reviewed by: Jun Su <junsu microsoft com> Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7456 303948 hyperv/hn: Switch to vmbus xact APIs for NVS initialization Reviewed by: Jun Su <junsu microsoft com> Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7457 303949 hyperv/vmbus: Use xact APIs to implement post message Hypercall APIs Avoid code duplication. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7458 303989 hyperv/hn: Simplify NDIS configuration. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7466 303992 hyperv/hn: Simplify NDIS initialization. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7467 303998 hyperv/hn: Switch to vmbus xact APIs for NVS RXBUF connection. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7469 304001 hyperv/hn: Switch to vmbus xact APIs for NVS chimney buffer connection. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7470 304002 hyperv/hn: Simplify RXBUF disconnection. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7472 304109 hyperv/hn: Simplify chimney sending buffer disconnection. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7479 304111 hyperv/hn: Switch to vmbus xact APIs for sub-channel alloc request. Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D7480
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files.amd641
-rw-r--r--sys/conf/files.i3861
-rw-r--r--sys/dev/hyperv/include/vmbus.h5
-rw-r--r--sys/dev/hyperv/include/vmbus_xact.h59
-rw-r--r--sys/dev/hyperv/netvsc/hv_net_vsc.c443
-rw-r--r--sys/dev/hyperv/netvsc/hv_net_vsc.h2
-rw-r--r--sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c13
-rw-r--r--sys/dev/hyperv/netvsc/hv_rndis.h4
-rw-r--r--sys/dev/hyperv/netvsc/hv_rndis_filter.c91
-rw-r--r--sys/dev/hyperv/netvsc/if_hnreg.h165
-rw-r--r--sys/dev/hyperv/netvsc/if_hnvar.h6
-rw-r--r--sys/dev/hyperv/vmbus/vmbus.c233
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_var.h2
-rw-r--r--sys/dev/hyperv/vmbus/vmbus_xact.c313
-rw-r--r--sys/modules/hyperv/vmbus/Makefile3
15 files changed, 901 insertions, 440 deletions
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 7750159..b4eec09a 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -308,6 +308,7 @@ dev/hyperv/vmbus/vmbus_br.c optional hyperv
dev/hyperv/vmbus/vmbus_chan.c optional hyperv
dev/hyperv/vmbus/vmbus_et.c optional hyperv
dev/hyperv/vmbus/vmbus_if.m optional hyperv
+dev/hyperv/vmbus/vmbus_xact.c optional hyperv
dev/hyperv/vmbus/amd64/hyperv_machdep.c optional hyperv
dev/hyperv/vmbus/amd64/vmbus_vector.S optional hyperv
dev/nfe/if_nfe.c optional nfe pci
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
index c6cb85e..a5878b0 100644
--- a/sys/conf/files.i386
+++ b/sys/conf/files.i386
@@ -265,6 +265,7 @@ dev/hyperv/vmbus/vmbus_br.c optional hyperv
dev/hyperv/vmbus/vmbus_chan.c optional hyperv
dev/hyperv/vmbus/vmbus_et.c optional hyperv
dev/hyperv/vmbus/vmbus_if.m optional hyperv
+dev/hyperv/vmbus/vmbus_xact.c optional hyperv
dev/hyperv/vmbus/i386/hyperv_machdep.c optional hyperv
dev/hyperv/vmbus/i386/vmbus_vector.S optional hyperv
dev/ichwd/ichwd.c optional ichwd
diff --git a/sys/dev/hyperv/include/vmbus.h b/sys/dev/hyperv/include/vmbus.h
index 8fde588..0a16e6e 100644
--- a/sys/dev/hyperv/include/vmbus.h
+++ b/sys/dev/hyperv/include/vmbus.h
@@ -89,6 +89,11 @@ struct vmbus_chanpkt_hdr {
(const void *)((const uint8_t *)(pkt) + \
VMBUS_CHANPKT_GETLEN((pkt)->cph_hlen))
+/* Include padding */
+#define VMBUS_CHANPKT_DATALEN(pkt) \
+ (VMBUS_CHANPKT_GETLEN((pkt)->cph_tlen) -\
+ VMBUS_CHANPKT_GETLEN((pkt)->cph_hlen))
+
struct vmbus_rxbuf_desc {
uint32_t rb_len;
uint32_t rb_ofs;
diff --git a/sys/dev/hyperv/include/vmbus_xact.h b/sys/dev/hyperv/include/vmbus_xact.h
new file mode 100644
index 0000000..c2919aa
--- /dev/null
+++ b/sys/dev/hyperv/include/vmbus_xact.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VMBUS_XACT_H_
+#define _VMBUS_XACT_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+struct vmbus_xact;
+struct vmbus_xact_ctx;
+
+struct vmbus_xact_ctx *vmbus_xact_ctx_create(bus_dma_tag_t dtag,
+ size_t req_size, size_t resp_size,
+ size_t priv_size);
+void vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx);
+struct vmbus_xact *vmbus_xact_get(struct vmbus_xact_ctx *ctx,
+ size_t req_len);
+void vmbus_xact_put(struct vmbus_xact *xact);
+
+void *vmbus_xact_req_data(const struct vmbus_xact *xact);
+bus_addr_t vmbus_xact_req_paddr(const struct vmbus_xact *xact);
+void *vmbus_xact_priv(const struct vmbus_xact *xact,
+ size_t priv_len);
+void vmbus_xact_activate(struct vmbus_xact *xact);
+void vmbus_xact_deactivate(struct vmbus_xact *xact);
+const void *vmbus_xact_wait(struct vmbus_xact *xact,
+ size_t *resp_len);
+void vmbus_xact_wakeup(struct vmbus_xact *xact,
+ const void *data, size_t dlen);
+void vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx,
+ const void *data, size_t dlen);
+
+#endif /* !_VMBUS_XACT_H_ */
diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c
index 9aa310a..2288d84 100644
--- a/sys/dev/hyperv/netvsc/hv_net_vsc.c
+++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c
@@ -45,9 +45,11 @@
#include <machine/atomic.h>
#include <dev/hyperv/include/hyperv.h>
-#include "hv_net_vsc.h"
-#include "hv_rndis.h"
-#include "hv_rndis_filter.h"
+#include <dev/hyperv/include/vmbus_xact.h>
+#include <dev/hyperv/netvsc/hv_net_vsc.h>
+#include <dev/hyperv/netvsc/hv_rndis.h>
+#include <dev/hyperv/netvsc/hv_rndis_filter.h>
+#include <dev/hyperv/netvsc/if_hnreg.h>
MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver");
@@ -70,7 +72,7 @@ static void hv_nv_on_receive(netvsc_dev *net_dev,
const struct vmbus_chanpkt_hdr *pkt);
static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
- const struct nvsp_msg_ *msg);
+ const struct nvsp_msg_ *msg, int);
static struct hn_send_ctx hn_send_ctx_none =
HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
@@ -147,10 +149,14 @@ hv_nv_get_next_send_section(netvsc_dev *net_dev)
static int
hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
{
+ struct vmbus_xact *xact;
+ struct hn_nvs_rxbuf_conn *conn;
+ const struct hn_nvs_rxbuf_connresp *resp;
+ size_t resp_len;
struct hn_send_ctx sndc;
netvsc_dev *net_dev;
- nvsp_msg *init_pkt;
- int ret = 0;
+ uint32_t status;
+ int error;
net_dev = hv_nv_get_outbound_net_device(sc);
if (!net_dev) {
@@ -162,7 +168,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (net_dev->rx_buf == NULL) {
device_printf(sc->hn_dev, "allocate rxbuf failed\n");
- return ENOMEM;
+ return (ENOMEM);
}
/*
@@ -172,74 +178,76 @@ hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
* Only primary channel has RXBUF connected to it. Sub-channels
* just share this RXBUF.
*/
- ret = vmbus_chan_gpadl_connect(sc->hn_prichan,
+ error = vmbus_chan_gpadl_connect(sc->hn_prichan,
net_dev->rxbuf_dma.hv_paddr, net_dev->rx_buf_size,
&net_dev->rx_buf_gpadl_handle);
- if (ret != 0) {
- device_printf(sc->hn_dev, "rxbuf gpadl connect failed: %d\n",
- ret);
+ if (error) {
+ if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n",
+ error);
goto cleanup;
}
-
- /* sema_wait(&ext->channel_init_sema); KYS CHECK */
- /* Notify the NetVsp of the gpadl handle */
- init_pkt = &net_dev->channel_init_packet;
+ /*
+ * Connect RXBUF to NVS.
+ */
- memset(init_pkt, 0, sizeof(nvsp_msg));
+ xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn));
+ if (xact == NULL) {
+ if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n");
+ error = ENXIO;
+ goto cleanup;
+ }
- init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf;
- init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
- net_dev->rx_buf_gpadl_handle;
- init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
- NETVSC_RECEIVE_BUFFER_ID;
+ conn = vmbus_xact_req_data(xact);
+ conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN;
+ conn->nvs_gpadl = net_dev->rx_buf_gpadl_handle;
+ conn->nvs_sig = HN_NVS_RXBUF_SIG;
- /* Send the gpadl notification request */
+ hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
+ vmbus_xact_activate(xact);
- hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
- ret = vmbus_chan_send(sc->hn_prichan,
+ error = vmbus_chan_send(sc->hn_prichan,
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
- init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
- if (ret != 0) {
+ conn, sizeof(*conn), (uint64_t)(uintptr_t)&sndc);
+ if (error != 0) {
+ if_printf(sc->hn_ifp, "send nvs rxbuf conn failed: %d\n",
+ error);
+ vmbus_xact_deactivate(xact);
+ vmbus_xact_put(xact);
goto cleanup;
}
- sema_wait(&net_dev->channel_init_sema);
-
- /* Check the response */
- if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status
- != nvsp_status_success) {
- ret = EINVAL;
+ resp = vmbus_xact_wait(xact, &resp_len);
+ if (resp_len < sizeof(*resp)) {
+ if_printf(sc->hn_ifp, "invalid rxbuf conn resp length %zu\n",
+ resp_len);
+ vmbus_xact_put(xact);
+ error = EINVAL;
+ goto cleanup;
+ }
+ if (resp->nvs_type != HN_NVS_TYPE_RXBUF_CONNRESP) {
+ if_printf(sc->hn_ifp, "not rxbuf conn resp, type %u\n",
+ resp->nvs_type);
+ vmbus_xact_put(xact);
+ error = EINVAL;
goto cleanup;
}
- net_dev->rx_section_count =
- init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections;
-
- net_dev->rx_sections = malloc(net_dev->rx_section_count *
- sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_WAITOK);
- memcpy(net_dev->rx_sections,
- init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections,
- net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section));
-
+ status = resp->nvs_status;
+ vmbus_xact_put(xact);
- /*
- * For first release, there should only be 1 section that represents
- * the entire receive buffer
- */
- if (net_dev->rx_section_count != 1
- || net_dev->rx_sections->offset != 0) {
- ret = EINVAL;
+ if (status != HN_NVS_STATUS_OK) {
+ if_printf(sc->hn_ifp, "rxbuf conn failed: %x\n", status);
+ error = EIO;
goto cleanup;
}
+ net_dev->rx_section_count = 1;
- goto exit;
+ return (0);
cleanup:
hv_nv_destroy_rx_buffer(net_dev);
-
-exit:
- return (ret);
+ return (error);
}
/*
@@ -249,9 +257,13 @@ static int
hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
{
struct hn_send_ctx sndc;
+ struct vmbus_xact *xact;
+ struct hn_nvs_chim_conn *chim;
+ const struct hn_nvs_chim_connresp *resp;
+ size_t resp_len;
+ uint32_t status, sectsz;
netvsc_dev *net_dev;
- nvsp_msg *init_pkt;
- int ret = 0;
+ int error;
net_dev = hv_nv_get_outbound_net_device(sc);
if (!net_dev) {
@@ -263,7 +275,7 @@ hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
BUS_DMA_WAITOK | BUS_DMA_ZERO);
if (net_dev->send_buf == NULL) {
device_printf(sc->hn_dev, "allocate chimney txbuf failed\n");
- return ENOMEM;
+ return (ENOMEM);
}
/*
@@ -273,48 +285,77 @@ hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
* Only primary channel has chimney sending buffer connected to it.
* Sub-channels just share this chimney sending buffer.
*/
- ret = vmbus_chan_gpadl_connect(sc->hn_prichan,
+ error = vmbus_chan_gpadl_connect(sc->hn_prichan,
net_dev->txbuf_dma.hv_paddr, net_dev->send_buf_size,
&net_dev->send_buf_gpadl_handle);
- if (ret != 0) {
- device_printf(sc->hn_dev, "chimney sending buffer gpadl "
- "connect failed: %d\n", ret);
+ if (error) {
+ if_printf(sc->hn_ifp, "chimney sending buffer gpadl "
+ "connect failed: %d\n", error);
goto cleanup;
}
- /* Notify the NetVsp of the gpadl handle */
-
- init_pkt = &net_dev->channel_init_packet;
+ /*
+ * Connect chimney sending buffer to NVS
+ */
- memset(init_pkt, 0, sizeof(nvsp_msg));
+ xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim));
+ if (xact == NULL) {
+ if_printf(sc->hn_ifp, "no xact for nvs chim conn\n");
+ error = ENXIO;
+ goto cleanup;
+ }
- init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf;
- init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle =
- net_dev->send_buf_gpadl_handle;
- init_pkt->msgs.vers_1_msgs.send_rx_buf.id =
- NETVSC_SEND_BUFFER_ID;
+ chim = vmbus_xact_req_data(xact);
+ chim->nvs_type = HN_NVS_TYPE_CHIM_CONN;
+ chim->nvs_gpadl = net_dev->send_buf_gpadl_handle;
+ chim->nvs_sig = HN_NVS_CHIM_SIG;
- /* Send the gpadl notification request */
+ hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
+ vmbus_xact_activate(xact);
- hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
- ret = vmbus_chan_send(sc->hn_prichan,
+ error = vmbus_chan_send(sc->hn_prichan,
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
- init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
- if (ret != 0) {
+ chim, sizeof(*chim), (uint64_t)(uintptr_t)&sndc);
+ if (error) {
+ if_printf(sc->hn_ifp, "send nvs chim conn failed: %d\n",
+ error);
+ vmbus_xact_deactivate(xact);
+ vmbus_xact_put(xact);
+ goto cleanup;
+ }
+
+ resp = vmbus_xact_wait(xact, &resp_len);
+ if (resp_len < sizeof(*resp)) {
+ if_printf(sc->hn_ifp, "invalid chim conn resp length %zu\n",
+ resp_len);
+ vmbus_xact_put(xact);
+ error = EINVAL;
+ goto cleanup;
+ }
+ if (resp->nvs_type != HN_NVS_TYPE_CHIM_CONNRESP) {
+ if_printf(sc->hn_ifp, "not chim conn resp, type %u\n",
+ resp->nvs_type);
+ vmbus_xact_put(xact);
+ error = EINVAL;
goto cleanup;
}
- sema_wait(&net_dev->channel_init_sema);
+ status = resp->nvs_status;
+ sectsz = resp->nvs_sectsz;
+ vmbus_xact_put(xact);
- /* Check the response */
- if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status
- != nvsp_status_success) {
- ret = EINVAL;
+ if (status != HN_NVS_STATUS_OK) {
+ if_printf(sc->hn_ifp, "chim conn failed: %x\n", status);
+ error = EIO;
goto cleanup;
}
+ if (sectsz == 0) {
+ if_printf(sc->hn_ifp, "zero chimney sending buffer "
+ "section size\n");
+ return 0;
+ }
- net_dev->send_section_size =
- init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size;
+ net_dev->send_section_size = sectsz;
net_dev->send_section_count =
net_dev->send_buf_size / net_dev->send_section_size;
net_dev->bitsmap_words = howmany(net_dev->send_section_count,
@@ -323,13 +364,15 @@ hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC,
M_WAITOK | M_ZERO);
- goto exit;
+ if (bootverbose) {
+ if_printf(sc->hn_ifp, "chimney sending buffer %u/%u\n",
+ net_dev->send_section_size, net_dev->send_section_count);
+ }
+ return 0;
cleanup:
hv_nv_destroy_send_buffer(net_dev);
-
-exit:
- return (ret);
+ return (error);
}
/*
@@ -338,34 +381,27 @@ exit:
static int
hv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
{
- nvsp_msg *revoke_pkt;
int ret = 0;
- /*
- * If we got a section count, it means we received a
- * send_rx_buf_complete msg
- * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
- * we need to send a revoke msg here
- */
if (net_dev->rx_section_count) {
- /* Send the revoke receive buffer */
- revoke_pkt = &net_dev->revoke_packet;
- memset(revoke_pkt, 0, sizeof(nvsp_msg));
+ struct hn_nvs_rxbuf_disconn disconn;
- revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf;
- revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id =
- NETVSC_RECEIVE_BUFFER_ID;
+ /*
+ * Disconnect RXBUF from NVS.
+ */
+ memset(&disconn, 0, sizeof(disconn));
+ disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN;
+ disconn.nvs_sig = HN_NVS_RXBUF_SIG;
ret = vmbus_chan_send(net_dev->sc->hn_prichan,
- VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg),
+ VMBUS_CHANPKT_TYPE_INBAND, 0, &disconn, sizeof(disconn),
(uint64_t)(uintptr_t)&hn_send_ctx_none);
- /*
- * If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
- */
if (ret != 0) {
+ if_printf(net_dev->sc->hn_ifp,
+ "send rxbuf disconn failed: %d\n", ret);
return (ret);
}
+ net_dev->rx_section_count = 0;
}
/* Tear down the gpadl on the vsp end */
@@ -388,12 +424,6 @@ hv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
net_dev->rx_buf = NULL;
}
- if (net_dev->rx_sections) {
- free(net_dev->rx_sections, M_NETVSC);
- net_dev->rx_sections = NULL;
- net_dev->rx_section_count = 0;
- }
-
return (ret);
}
@@ -403,33 +433,24 @@ hv_nv_destroy_rx_buffer(netvsc_dev *net_dev)
static int
hv_nv_destroy_send_buffer(netvsc_dev *net_dev)
{
- nvsp_msg *revoke_pkt;
int ret = 0;
- /*
- * If we got a section count, it means we received a
- * send_rx_buf_complete msg
- * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore,
- * we need to send a revoke msg here
- */
if (net_dev->send_section_size) {
- /* Send the revoke send buffer */
- revoke_pkt = &net_dev->revoke_packet;
- memset(revoke_pkt, 0, sizeof(nvsp_msg));
+ struct hn_nvs_chim_disconn disconn;
- revoke_pkt->hdr.msg_type =
- nvsp_msg_1_type_revoke_send_buf;
- revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id =
- NETVSC_SEND_BUFFER_ID;
+ /*
+ * Disconnect chimney sending buffer from NVS.
+ */
+ memset(&disconn, 0, sizeof(disconn));
+ disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN;
+ disconn.nvs_sig = HN_NVS_CHIM_SIG;
ret = vmbus_chan_send(net_dev->sc->hn_prichan,
- VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg),
+ VMBUS_CHANPKT_TYPE_INBAND, 0, &disconn, sizeof(disconn),
(uint64_t)(uintptr_t)&hn_send_ctx_none);
- /*
- * If we failed here, we might as well return and have a leak
- * rather than continue and a bugchk
- */
if (ret != 0) {
+ if_printf(net_dev->sc->hn_ifp,
+ "send chim disconn failed: %d\n", ret);
return (ret);
}
}
@@ -462,45 +483,64 @@ hv_nv_destroy_send_buffer(netvsc_dev *net_dev)
return (ret);
}
-
-/*
- * Attempt to negotiate the caller-specified NVSP version
- *
- * For NVSP v2, Server 2008 R2 does not set
- * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers
- * to the negotiated version, so we cannot rely on that.
- */
static int
hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev,
- uint32_t nvsp_ver)
+ uint32_t nvs_ver)
{
struct hn_send_ctx sndc;
- nvsp_msg *init_pkt;
- int ret;
+ struct vmbus_xact *xact;
+ struct hn_nvs_init *init;
+ const struct hn_nvs_init_resp *resp;
+ size_t resp_len;
+ uint32_t status;
+ int error;
+
+ xact = vmbus_xact_get(sc->hn_xact, sizeof(*init));
+ if (xact == NULL) {
+ if_printf(sc->hn_ifp, "no xact for nvs init\n");
+ return (ENXIO);
+ }
- init_pkt = &net_dev->channel_init_packet;
- memset(init_pkt, 0, sizeof(nvsp_msg));
- init_pkt->hdr.msg_type = nvsp_msg_type_init;
+ init = vmbus_xact_req_data(xact);
+ init->nvs_type = HN_NVS_TYPE_INIT;
+ init->nvs_ver_min = nvs_ver;
+ init->nvs_ver_max = nvs_ver;
- /*
- * Specify parameter as the only acceptable protocol version
- */
- init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver;
- init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver;
+ vmbus_xact_activate(xact);
+ hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
- /* Send the init request */
- hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
- ret = vmbus_chan_send(sc->hn_prichan,
+ error = vmbus_chan_send(sc->hn_prichan,
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
- init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
- if (ret != 0)
- return (-1);
-
- sema_wait(&net_dev->channel_init_sema);
+ init, sizeof(*init), (uint64_t)(uintptr_t)&sndc);
+ if (error) {
+ if_printf(sc->hn_ifp, "send nvs init failed: %d\n", error);
+ vmbus_xact_deactivate(xact);
+ vmbus_xact_put(xact);
+ return (error);
+ }
- if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success)
+ resp = vmbus_xact_wait(xact, &resp_len);
+ if (resp_len < sizeof(*resp)) {
+ if_printf(sc->hn_ifp, "invalid init resp length %zu\n",
+ resp_len);
+ vmbus_xact_put(xact);
+ return (EINVAL);
+ }
+ if (resp->nvs_type != HN_NVS_TYPE_INIT_RESP) {
+ if_printf(sc->hn_ifp, "not init resp, type %u\n",
+ resp->nvs_type);
+ vmbus_xact_put(xact);
return (EINVAL);
+ }
+
+ status = resp->nvs_status;
+ vmbus_xact_put(xact);
+ if (status != HN_NVS_STATUS_OK) {
+ if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n",
+ nvs_ver);
+ return (EINVAL);
+ }
return (0);
}
@@ -512,33 +552,19 @@ hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev,
static int
hv_nv_send_ndis_config(struct hn_softc *sc, uint32_t mtu)
{
- netvsc_dev *net_dev;
- nvsp_msg *init_pkt;
- int ret;
-
- net_dev = hv_nv_get_outbound_net_device(sc);
- if (!net_dev)
- return (-ENODEV);
-
- /*
- * Set up configuration packet, write MTU
- * Indicate we are capable of handling VLAN tags
- */
- init_pkt = &net_dev->channel_init_packet;
- memset(init_pkt, 0, sizeof(nvsp_msg));
- init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config;
- init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu;
- init_pkt->
- msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q
- = 1;
-
- /* Send the configuration packet */
- ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
- init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&hn_send_ctx_none);
- if (ret != 0)
- return (-EINVAL);
-
- return (0);
+ struct hn_nvs_ndis_conf conf;
+ int error;
+
+ memset(&conf, 0, sizeof(conf));
+ conf.nvs_type = HN_NVS_TYPE_NDIS_CONF;
+ conf.nvs_mtu = mtu;
+ conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN;
+
+ error = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
+ &conf, sizeof(conf), (uint64_t)(uintptr_t)&hn_send_ctx_none);
+ if (error)
+ if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
+ return (error);
}
/*
@@ -548,8 +574,6 @@ static int
hv_nv_connect_to_vsp(struct hn_softc *sc)
{
netvsc_dev *net_dev;
- nvsp_msg *init_pkt;
- uint32_t ndis_version;
uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1,
NVSP_PROTOCOL_VERSION_2,
NVSP_PROTOCOL_VERSION_4,
@@ -559,6 +583,7 @@ hv_nv_connect_to_vsp(struct hn_softc *sc)
int ret = 0;
device_t dev = sc->hn_dev;
struct ifnet *ifp = sc->hn_ifp;
+ struct hn_nvs_ndis_init ndis;
net_dev = hv_nv_get_outbound_net_device(sc);
@@ -591,37 +616,23 @@ hv_nv_connect_to_vsp(struct hn_softc *sc)
ret = hv_nv_send_ndis_config(sc, ifp->if_mtu);
/*
- * Send the NDIS version
+ * Initialize NDIS.
*/
- init_pkt = &net_dev->channel_init_packet;
-
- memset(init_pkt, 0, sizeof(nvsp_msg));
-
- if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) {
- ndis_version = NDIS_VERSION_6_1;
- } else {
- ndis_version = NDIS_VERSION_6_30;
- }
-
- init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers;
- init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers =
- (ndis_version & 0xFFFF0000) >> 16;
- init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers =
- ndis_version & 0xFFFF;
- /* Send the init request */
+ memset(&ndis, 0, sizeof(ndis));
+ ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
+ ndis.nvs_ndis_major = NDIS_VERSION_MAJOR_6;
+ if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4)
+ ndis.nvs_ndis_minor = NDIS_VERSION_MINOR_1;
+ else
+ ndis.nvs_ndis_minor = NDIS_VERSION_MINOR_30;
ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0,
- init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&hn_send_ctx_none);
+ &ndis, sizeof(ndis), (uint64_t)(uintptr_t)&hn_send_ctx_none);
if (ret != 0) {
+ if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", ret);
goto cleanup;
}
- /*
- * TODO: BUGBUG - We have to wait for the above msg since the netvsp
- * uses KMCL which acknowledges packet (completion packet)
- * since our Vmbus always set the VMBUS_CHANPKT_FLAG_RC flag
- */
- /* sema_wait(&NetVscChannel->channel_init_sema); */
/* Post the big receive buffer to NetVSP */
if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
@@ -742,19 +753,18 @@ hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
}
void
-hn_nvs_sent_wakeup(struct hn_send_ctx *sndc __unused,
- struct netvsc_dev_ *net_dev, struct vmbus_channel *chan __unused,
- const struct nvsp_msg_ *msg)
+hn_nvs_sent_xact(struct hn_send_ctx *sndc,
+ struct netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused,
+ const struct nvsp_msg_ *msg, int dlen)
{
- /* Copy the response back */
- memcpy(&net_dev->channel_init_packet, msg, sizeof(nvsp_msg));
- sema_post(&net_dev->channel_init_sema);
+
+ vmbus_xact_wakeup(sndc->hn_cbarg, msg, dlen);
}
static void
hn_nvs_sent_none(struct hn_send_ctx *sndc __unused,
struct netvsc_dev_ *net_dev __unused, struct vmbus_channel *chan __unused,
- const struct nvsp_msg_ *msg __unused)
+ const struct nvsp_msg_ *msg __unused, int dlen __unused)
{
/* EMPTY */
}
@@ -788,7 +798,8 @@ hv_nv_on_send_completion(netvsc_dev *net_dev, struct vmbus_channel *chan,
struct hn_send_ctx *sndc;
sndc = (struct hn_send_ctx *)(uintptr_t)pkt->cph_xactid;
- sndc->hn_cb(sndc, net_dev, chan, VMBUS_CHANPKT_CONST_DATA(pkt));
+ sndc->hn_cb(sndc, net_dev, chan, VMBUS_CHANPKT_CONST_DATA(pkt),
+ VMBUS_CHANPKT_DATALEN(pkt));
/*
* NOTE:
* 'sndc' CAN NOT be accessed anymore, since it can be freed by
diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h
index 81eb041..a861c3e 100644
--- a/sys/dev/hyperv/netvsc/hv_net_vsc.h
+++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h
@@ -1060,7 +1060,6 @@ typedef struct netvsc_dev_ {
uint32_t rx_buf_size;
uint32_t rx_buf_gpadl_handle;
uint32_t rx_section_count;
- nvsp_1_rx_buf_section *rx_sections;
/* Used for NetVSP initialization protocol */
struct sema channel_init_sema;
@@ -1243,6 +1242,7 @@ typedef struct hn_softc {
struct taskqueue *hn_tx_taskq;
struct sysctl_oid *hn_tx_sysctl_tree;
struct sysctl_oid *hn_rx_sysctl_tree;
+ struct vmbus_xact_ctx *hn_xact;
} hn_softc_t;
/*
diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
index b3dc6d1..4653e77 100644
--- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
+++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
@@ -115,6 +115,7 @@ __FBSDID("$FreeBSD$");
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/hyperv/include/vmbus_xact.h>
#include "hv_net_vsc.h"
#include "hv_rndis.h"
@@ -124,6 +125,9 @@ __FBSDID("$FreeBSD$");
/* Short for Hyper-V network interface */
#define NETVSC_DEVNAME "hn"
+#define HN_XACT_REQ_SIZE (2 * PAGE_SIZE)
+#define HN_XACT_RESP_SIZE (2 * PAGE_SIZE)
+
/*
* It looks like offset 0 of buf is reserved to hold the softc pointer.
* The sc pointer evidently not needed, and is not presently populated.
@@ -542,6 +546,11 @@ netvsc_attach(device_t dev)
IFCAP_LRO;
ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist | CSUM_TSO;
+ sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
+ HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
+ if (sc->hn_xact == NULL)
+ goto failed;
+
error = hv_rf_on_device_add(sc, &device_info, ring_cnt,
&sc->hn_rx_ring[0]);
if (error)
@@ -643,6 +652,7 @@ netvsc_detach(device_t dev)
if (sc->hn_tx_taskq != hn_tx_taskq)
taskqueue_free(sc->hn_tx_taskq);
+ vmbus_xact_ctx_destroy(sc->hn_xact);
return (0);
}
@@ -782,7 +792,8 @@ hn_txeof(struct hn_tx_ring *txr)
static void
hn_tx_done(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
- struct vmbus_channel *chan, const struct nvsp_msg_ *msg __unused)
+ struct vmbus_channel *chan, const struct nvsp_msg_ *msg __unused,
+ int dlen __unused)
{
struct hn_txdesc *txd = sndc->hn_cbarg;
struct hn_tx_ring *txr;
diff --git a/sys/dev/hyperv/netvsc/hv_rndis.h b/sys/dev/hyperv/netvsc/hv_rndis.h
index da2b408..6527668 100644
--- a/sys/dev/hyperv/netvsc/hv_rndis.h
+++ b/sys/dev/hyperv/netvsc/hv_rndis.h
@@ -41,6 +41,10 @@
#define NDIS_VERSION_6_1 0x00060001
#define NDIS_VERSION_6_30 0x0006001e
+#define NDIS_VERSION_MAJOR_6 6
+#define NDIS_VERSION_MINOR_1 1
+#define NDIS_VERSION_MINOR_30 30
+
#define NDIS_VERSION (NDIS_VERSION_5_1)
/*
diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c
index e7e74b6..5e3473b 100644
--- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c
+++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c
@@ -46,9 +46,11 @@ __FBSDID("$FreeBSD$");
#include <vm/pmap.h>
#include <dev/hyperv/include/hyperv.h>
-#include "hv_net_vsc.h"
-#include "hv_rndis.h"
-#include "hv_rndis_filter.h"
+#include <dev/hyperv/include/vmbus_xact.h>
+#include <dev/hyperv/netvsc/hv_net_vsc.h>
+#include <dev/hyperv/netvsc/hv_rndis.h>
+#include <dev/hyperv/netvsc/hv_rndis_filter.h>
+#include <dev/hyperv/netvsc/if_hnreg.h>
struct hv_rf_recvinfo {
const ndis_8021q_info *vlan_info;
@@ -91,10 +93,10 @@ hv_rf_send_offload_request(struct hn_softc *sc,
static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
- const struct nvsp_msg_ *msg);
+ const struct nvsp_msg_ *msg, int dlen);
static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
- const struct nvsp_msg_ *msg);
+ const struct nvsp_msg_ *msg, int dlen);
/*
* Set the Per-Packet-Info with the specified type
@@ -1060,12 +1062,16 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
int ret;
netvsc_dev *net_dev;
rndis_device *rndis_dev;
- nvsp_msg *init_pkt;
rndis_offload_params offloads;
struct rndis_recv_scale_cap rsscaps;
uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
device_t dev = sc->hn_dev;
+ struct hn_nvs_subch_req *req;
+ const struct hn_nvs_subch_resp *resp;
+ size_t resp_len;
+ struct vmbus_xact *xact;
+ uint32_t status, nsubch;
rndis_dev = hv_get_rndis_device();
if (rndis_dev == NULL) {
@@ -1153,36 +1159,65 @@ hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
goto out;
}
- /* request host to create sub channels */
- init_pkt = &net_dev->channel_init_packet;
- memset(init_pkt, 0, sizeof(nvsp_msg));
+ /*
+ * Ask NVS to allocate sub-channels.
+ */
+ xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
+ if (xact == NULL) {
+ if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
+ ret = ENXIO;
+ goto out;
+ }
- init_pkt->hdr.msg_type = nvsp_msg5_type_subchannel;
- init_pkt->msgs.vers_5_msgs.subchannel_request.op =
- NVSP_SUBCHANNE_ALLOCATE;
- init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
- net_dev->num_channel - 1;
+ req = vmbus_xact_req_data(xact);
+ req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
+ req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
+ req->nvs_nsubch = net_dev->num_channel - 1;
+
+ hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
+ vmbus_xact_activate(xact);
- hn_send_ctx_init_simple(&sndc, hn_nvs_sent_wakeup, NULL);
ret = vmbus_chan_send(sc->hn_prichan,
VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC,
- init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)&sndc);
+ req, sizeof(*req), (uint64_t)(uintptr_t)&sndc);
if (ret != 0) {
- device_printf(dev, "Fail to allocate subchannel\n");
+ if_printf(sc->hn_ifp, "send nvs subch req failed: %d\n", ret);
+ vmbus_xact_deactivate(xact);
+ vmbus_xact_put(xact);
goto out;
}
- sema_wait(&net_dev->channel_init_sema);
-
- if (init_pkt->msgs.vers_5_msgs.subchn_complete.status !=
- nvsp_status_success) {
- ret = ENODEV;
- device_printf(dev, "sub channel complete error\n");
+ resp = vmbus_xact_wait(xact, &resp_len);
+ if (resp_len < sizeof(*resp)) {
+ if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
+ resp_len);
+ vmbus_xact_put(xact);
+ ret = EINVAL;
goto out;
}
+ if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
+ if_printf(sc->hn_ifp, "not subch resp, type %u\n",
+ resp->nvs_type);
+ vmbus_xact_put(xact);
+ ret = EINVAL;
+ goto out;
+ }
+
+ status = resp->nvs_status;
+ nsubch = resp->nvs_nsubch;
+ vmbus_xact_put(xact);
- net_dev->num_channel = 1 +
- init_pkt->msgs.vers_5_msgs.subchn_complete.num_subchannels;
+ if (status != HN_NVS_STATUS_OK) {
+ if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
+ ret = EIO;
+ goto out;
+ }
+ if (nsubch > net_dev->num_channel - 1) {
+ if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
+ nsubch, net_dev->num_channel - 1);
+ nsubch = net_dev->num_channel - 1;
+ }
+ net_dev->num_channel = nsubch + 1;
ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
@@ -1239,7 +1274,8 @@ hv_rf_on_close(struct hn_softc *sc)
static void
hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
- struct vmbus_channel *chan __unused, const struct nvsp_msg_ *msg __unused)
+ struct vmbus_channel *chan __unused, const struct nvsp_msg_ *msg __unused,
+ int dlen __unused)
{
if (sndc->hn_chim_idx != NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX)
hn_chim_free(net_dev, sndc->hn_chim_idx);
@@ -1247,7 +1283,8 @@ hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
static void
hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
- struct vmbus_channel *chan __unused, const struct nvsp_msg_ *msg __unused)
+ struct vmbus_channel *chan __unused, const struct nvsp_msg_ *msg __unused,
+ int dlen __unused)
{
rndis_request *request = sndc->hn_cbarg;
diff --git a/sys/dev/hyperv/netvsc/if_hnreg.h b/sys/dev/hyperv/netvsc/if_hnreg.h
new file mode 100644
index 0000000..109ece0
--- /dev/null
+++ b/sys/dev/hyperv/netvsc/if_hnreg.h
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_HNREG_H_
+#define _IF_HNREG_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#define HN_NVS_RXBUF_SIG 0xcafe
+#define HN_NVS_CHIM_SIG 0xface
+
+#define HN_NVS_STATUS_OK 1
+
+#define HN_NVS_TYPE_INIT 1
+#define HN_NVS_TYPE_INIT_RESP 2
+#define HN_NVS_TYPE_NDIS_INIT 100
+#define HN_NVS_TYPE_RXBUF_CONN 101
+#define HN_NVS_TYPE_RXBUF_CONNRESP 102
+#define HN_NVS_TYPE_RXBUF_DISCONN 103
+#define HN_NVS_TYPE_CHIM_CONN 104
+#define HN_NVS_TYPE_CHIM_CONNRESP 105
+#define HN_NVS_TYPE_CHIM_DISCONN 106
+#define HN_NVS_TYPE_NDIS_CONF 125
+#define HN_NVS_TYPE_SUBCH_REQ 133
+#define HN_NVS_TYPE_SUBCH_RESP 133 /* same as SUBCH_REQ */
+
+/*
+ * Any size less than this one will _not_ work, e.g. hn_nvs_init
+ * only has 12B valid data, however, if only 12B data were sent,
+ * Hypervisor would never reply.
+ */
+#define HN_NVS_REQSIZE_MIN 32
+
+struct hn_nvs_init {
+ uint32_t nvs_type; /* HN_NVS_TYPE_INIT */
+ uint32_t nvs_ver_min;
+ uint32_t nvs_ver_max;
+ uint8_t nvs_rsvd[20];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_init) >= HN_NVS_REQSIZE_MIN);
+
+struct hn_nvs_init_resp {
+ uint32_t nvs_type; /* HN_NVS_TYPE_INIT_RESP */
+ uint32_t nvs_ver; /* deprecated */
+ uint32_t nvs_rsvd;
+ uint32_t nvs_status; /* HN_NVS_STATUS_ */
+} __packed;
+
+/* No reponse */
+struct hn_nvs_ndis_conf {
+ uint32_t nvs_type; /* HN_NVS_TYPE_NDIS_CONF */
+ uint32_t nvs_mtu;
+ uint32_t nvs_rsvd;
+ uint64_t nvs_caps; /* HN_NVS_NDIS_CONF_ */
+ uint8_t nvs_rsvd1[12];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_ndis_conf) >= HN_NVS_REQSIZE_MIN);
+
+#define HN_NVS_NDIS_CONF_SRIOV 0x0004
+#define HN_NVS_NDIS_CONF_VLAN 0x0008
+
+/* No response */
+struct hn_nvs_ndis_init {
+ uint32_t nvs_type; /* HN_NVS_TYPE_NDIS_INIT */
+ uint32_t nvs_ndis_major; /* NDIS_VERSION_MAJOR_ */
+ uint32_t nvs_ndis_minor; /* NDIS_VERSION_MINOR_ */
+ uint8_t nvs_rsvd[20];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_ndis_init) >= HN_NVS_REQSIZE_MIN);
+
+struct hn_nvs_rxbuf_conn {
+ uint32_t nvs_type; /* HN_NVS_TYPE_RXBUF_CONN */
+ uint32_t nvs_gpadl; /* RXBUF vmbus GPADL */
+ uint16_t nvs_sig; /* HN_NVS_RXBUF_SIG */
+ uint8_t nvs_rsvd[22];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_rxbuf_conn) >= HN_NVS_REQSIZE_MIN);
+
+struct hn_nvs_rxbuf_sect {
+ uint32_t nvs_start;
+ uint32_t nvs_slotsz;
+ uint32_t nvs_slotcnt;
+ uint32_t nvs_end;
+} __packed;
+
+struct hn_nvs_rxbuf_connresp {
+ uint32_t nvs_type; /* HN_NVS_TYPE_RXBUF_CONNRESP */
+ uint32_t nvs_status; /* HN_NVS_STATUS_ */
+ uint32_t nvs_nsect; /* # of elem in nvs_sect */
+ struct hn_nvs_rxbuf_sect nvs_sect[];
+} __packed;
+
+/* No response */
+struct hn_nvs_rxbuf_disconn {
+ uint32_t nvs_type; /* HN_NVS_TYPE_RXBUF_DISCONN */
+ uint16_t nvs_sig; /* HN_NVS_RXBUF_SIG */
+ uint8_t nvs_rsvd[26];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_rxbuf_disconn) >= HN_NVS_REQSIZE_MIN);
+
+struct hn_nvs_chim_conn {
+ uint32_t nvs_type; /* HN_NVS_TYPE_CHIM_CONN */
+ uint32_t nvs_gpadl; /* chimney buf vmbus GPADL */
+ uint16_t nvs_sig; /* NDIS_NVS_CHIM_SIG */
+ uint8_t nvs_rsvd[22];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_chim_conn) >= HN_NVS_REQSIZE_MIN);
+
+struct hn_nvs_chim_connresp {
+ uint32_t nvs_type; /* HN_NVS_TYPE_CHIM_CONNRESP */
+ uint32_t nvs_status; /* HN_NVS_STATUS_ */
+ uint32_t nvs_sectsz; /* section size */
+} __packed;
+
+/* No response */
+struct hn_nvs_chim_disconn {
+ uint32_t nvs_type; /* HN_NVS_TYPE_CHIM_DISCONN */
+ uint16_t nvs_sig; /* HN_NVS_CHIM_SIG */
+ uint8_t nvs_rsvd[26];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_chim_disconn) >= HN_NVS_REQSIZE_MIN);
+
+#define HN_NVS_SUBCH_OP_ALLOC 1
+
+struct hn_nvs_subch_req {
+ uint32_t nvs_type; /* HN_NVS_TYPE_SUBCH_REQ */
+ uint32_t nvs_op; /* HN_NVS_SUBCH_OP_ */
+ uint32_t nvs_nsubch;
+ uint8_t nvs_rsvd[20];
+} __packed;
+CTASSERT(sizeof(struct hn_nvs_subch_req) >= HN_NVS_REQSIZE_MIN);
+
+struct hn_nvs_subch_resp {
+ uint32_t nvs_type; /* HN_NVS_TYPE_SUBCH_RESP */
+ uint32_t nvs_status; /* HN_NVS_STATUS_ */
+ uint32_t nvs_nsubch;
+} __packed;
+
+#endif /* !_IF_HNREG_H_ */
diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h
index 6e5fb50..39f01ff 100644
--- a/sys/dev/hyperv/netvsc/if_hnvar.h
+++ b/sys/dev/hyperv/netvsc/if_hnvar.h
@@ -40,7 +40,7 @@ struct hn_send_ctx;
typedef void (*hn_sent_callback_t)
(struct hn_send_ctx *, struct netvsc_dev_ *,
- struct vmbus_channel *, const struct nvsp_msg_ *);
+ struct vmbus_channel *, const struct nvsp_msg_ *, int);
struct hn_send_ctx {
hn_sent_callback_t hn_cb;
@@ -75,9 +75,9 @@ hn_send_ctx_init_simple(struct hn_send_ctx *sndc, hn_sent_callback_t cb,
NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX, 0);
}
-void hn_nvs_sent_wakeup(struct hn_send_ctx *sndc,
+void hn_nvs_sent_xact(struct hn_send_ctx *sndc,
struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
- const struct nvsp_msg_ *msg);
+ const struct nvsp_msg_ *msg, int dlen);
void hn_chim_free(struct netvsc_dev_ *net_dev, uint32_t chim_idx);
#endif /* !_IF_HNVAR_H_ */
diff --git a/sys/dev/hyperv/vmbus/vmbus.c b/sys/dev/hyperv/vmbus/vmbus.c
index 05c9c5b..6753c9e 100644
--- a/sys/dev/hyperv/vmbus/vmbus.c
+++ b/sys/dev/hyperv/vmbus/vmbus.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <contrib/dev/acpica/include/acpi.h>
#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/include/vmbus_xact.h>
#include <dev/hyperv/vmbus/hyperv_reg.h>
#include <dev/hyperv/vmbus/hyperv_var.h>
#include <dev/hyperv/vmbus/vmbus_reg.h>
@@ -62,25 +63,10 @@ __FBSDID("$FreeBSD$");
#define VMBUS_GPADL_START 0xe1e10
struct vmbus_msghc {
- struct hypercall_postmsg_in *mh_inprm;
+ struct vmbus_xact *mh_xact;
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_probe(device_t);
static int vmbus_attach(device_t);
static int vmbus_detach(device_t);
@@ -116,15 +102,6 @@ static int vmbus_doattach(struct vmbus_softc *);
static void vmbus_event_proc_dummy(struct vmbus_softc *,
int);
-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);
-
static struct vmbus_softc *vmbus_sc;
extern inthand_t IDTVEC(vmbus_isr);
@@ -182,85 +159,6 @@ vmbus_get_softc(void)
return vmbus_sc;
}
-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_PARAM_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;
-}
-
void
vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
{
@@ -269,7 +167,7 @@ vmbus_msghc_reset(struct vmbus_msghc *mh, size_t dsize)
if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
panic("invalid data size %zu", dsize);
- inprm = mh->mh_inprm;
+ inprm = vmbus_xact_req_data(mh->mh_xact);
memset(inprm, 0, HYPERCALL_POSTMSGIN_SIZE);
inprm->hc_connid = VMBUS_CONNID_MESSAGE;
inprm->hc_msgtype = HYPERV_MSGTYPE_CHANNEL;
@@ -280,63 +178,50 @@ struct vmbus_msghc *
vmbus_msghc_get(struct vmbus_softc *sc, size_t dsize)
{
struct vmbus_msghc *mh;
+ struct vmbus_xact *xact;
if (dsize > HYPERCALL_POSTMSGIN_DSIZE_MAX)
panic("invalid data size %zu", dsize);
- mh = vmbus_msghc_get1(sc->vmbus_msg_hc, VMBUS_MSGHC_CTXF_DESTROY);
- if (mh == NULL)
- return NULL;
+ xact = vmbus_xact_get(sc->vmbus_xc,
+ dsize + __offsetof(struct hypercall_postmsg_in, hc_data[0]));
+ if (xact == NULL)
+ return (NULL);
+
+ mh = vmbus_xact_priv(xact, sizeof(*mh));
+ mh->mh_xact = xact;
vmbus_msghc_reset(mh, dsize);
- return mh;
+ return (mh);
}
void
-vmbus_msghc_put(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+vmbus_msghc_put(struct vmbus_softc *sc __unused, 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);
+ vmbus_xact_put(mh->mh_xact);
}
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");
+ struct hypercall_postmsg_in *inprm;
- vmbus_msghc_free(mh);
- vmbus_msghc_ctx_free(mhc);
+ inprm = vmbus_xact_req_data(mh->mh_xact);
+ return (inprm->hc_data);
}
int
vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
{
sbintime_t time = SBT_1MS;
+ struct hypercall_postmsg_in *inprm;
+ bus_addr_t inprm_paddr;
int i;
+ inprm = vmbus_xact_req_data(mh->mh_xact);
+ inprm_paddr = vmbus_xact_req_paddr(mh->mh_xact);
+
/*
* Save the input parameter so that we could restore the input
* parameter if the Hypercall failed.
@@ -345,7 +230,7 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
* 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);
+ memcpy(&mh->mh_inprm_save, inprm, HYPERCALL_POSTMSGIN_SIZE);
/*
* In order to cope with transient failures, e.g. insufficient
@@ -357,7 +242,7 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
for (i = 0; i < HC_RETRY_MAX; ++i) {
uint64_t status;
- status = hypercall_post_message(mh->mh_inprm_dma.hv_paddr);
+ status = hypercall_post_message(inprm_paddr);
if (status == HYPERCALL_STATUS_SUCCESS)
return 0;
@@ -366,8 +251,7 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
time *= 2;
/* Restore input parameter and try again */
- memcpy(mh->mh_inprm, &mh->mh_inprm_save,
- HYPERCALL_POSTMSGIN_SIZE);
+ memcpy(inprm, &mh->mh_inprm_save, HYPERCALL_POSTMSGIN_SIZE);
}
#undef HC_RETRY_MAX
@@ -376,62 +260,30 @@ vmbus_msghc_exec_noresult(struct vmbus_msghc *mh)
}
int
-vmbus_msghc_exec(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+vmbus_msghc_exec(struct vmbus_softc *sc __unused, 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);
-
+ vmbus_xact_activate(mh->mh_xact);
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);
- }
+ if (error)
+ vmbus_xact_deactivate(mh->mh_xact);
return error;
}
const struct vmbus_message *
-vmbus_msghc_wait_result(struct vmbus_softc *sc, struct vmbus_msghc *mh)
+vmbus_msghc_wait_result(struct vmbus_softc *sc __unused, 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;
+ size_t resp_len;
- mtx_unlock(&mhc->mhc_active_lock);
-
- return mh->mh_resp;
+ return (vmbus_xact_wait(mh->mh_xact, &resp_len));
}
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);
+ vmbus_xact_ctx_wakeup(sc->vmbus_xc, msg, sizeof(*msg));
}
uint32_t
@@ -1187,9 +1039,10 @@ vmbus_doattach(struct vmbus_softc *sc)
/*
* 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) {
+ sc->vmbus_xc = vmbus_xact_ctx_create(bus_get_dma_tag(sc->vmbus_dev),
+ HYPERCALL_POSTMSGIN_SIZE, VMBUS_MSG_SIZE,
+ sizeof(struct vmbus_msghc));
+ if (sc->vmbus_xc == NULL) {
ret = ENXIO;
goto cleanup;
}
@@ -1244,9 +1097,9 @@ vmbus_doattach(struct vmbus_softc *sc)
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;
+ if (sc->vmbus_xc != NULL) {
+ vmbus_xact_ctx_destroy(sc->vmbus_xc);
+ sc->vmbus_xc = NULL;
}
free(sc->vmbus_chmap, M_DEVBUF);
mtx_destroy(&sc->vmbus_scan_lock);
@@ -1305,9 +1158,9 @@ 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;
+ if (sc->vmbus_xc != NULL) {
+ vmbus_xact_ctx_destroy(sc->vmbus_xc);
+ sc->vmbus_xc = NULL;
}
free(sc->vmbus_chmap, M_DEVBUF);
diff --git a/sys/dev/hyperv/vmbus/vmbus_var.h b/sys/dev/hyperv/vmbus/vmbus_var.h
index c278c15..47d9004 100644
--- a/sys/dev/hyperv/vmbus/vmbus_var.h
+++ b/sys/dev/hyperv/vmbus/vmbus_var.h
@@ -86,7 +86,7 @@ struct vmbus_softc {
u_long *vmbus_rx_evtflags;
/* compat evtflgs from host */
struct vmbus_channel **vmbus_chmap;
- struct vmbus_msghc_ctx *vmbus_msg_hc;
+ struct vmbus_xact_ctx *vmbus_xc;
struct vmbus_pcpu_data vmbus_pcpu[MAXCPU];
/*
diff --git a/sys/dev/hyperv/vmbus/vmbus_xact.c b/sys/dev/hyperv/vmbus/vmbus_xact.c
new file mode 100644
index 0000000..642c165
--- /dev/null
+++ b/sys/dev/hyperv/vmbus/vmbus_xact.c
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 2016 Microsoft Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+
+#include <dev/hyperv/include/hyperv_busdma.h>
+#include <dev/hyperv/include/vmbus_xact.h>
+
+struct vmbus_xact {
+ struct vmbus_xact_ctx *x_ctx;
+ void *x_priv;
+
+ void *x_req;
+ struct hyperv_dma x_req_dma;
+
+ const void *x_resp;
+ size_t x_resp_len;
+ void *x_resp0;
+};
+
+struct vmbus_xact_ctx {
+ uint32_t xc_flags;
+ size_t xc_req_size;
+ size_t xc_resp_size;
+ size_t xc_priv_size;
+
+ struct vmbus_xact *xc_free;
+ struct mtx xc_free_lock;
+
+ struct vmbus_xact *xc_active;
+ struct mtx xc_active_lock;
+};
+
+#define VMBUS_XACT_CTXF_DESTROY 0x0001
+
+static struct vmbus_xact *vmbus_xact_alloc(struct vmbus_xact_ctx *,
+ bus_dma_tag_t);
+static void vmbus_xact_free(struct vmbus_xact *);
+static struct vmbus_xact *vmbus_xact_get1(struct vmbus_xact_ctx *,
+ uint32_t);
+
+static struct vmbus_xact *
+vmbus_xact_alloc(struct vmbus_xact_ctx *ctx, bus_dma_tag_t parent_dtag)
+{
+ struct vmbus_xact *xact;
+
+ xact = malloc(sizeof(*xact), M_DEVBUF, M_WAITOK | M_ZERO);
+ xact->x_ctx = ctx;
+
+ /* XXX assume that page aligned is enough */
+ xact->x_req = hyperv_dmamem_alloc(parent_dtag, PAGE_SIZE, 0,
+ ctx->xc_req_size, &xact->x_req_dma, BUS_DMA_WAITOK);
+ if (xact->x_req == NULL) {
+ free(xact, M_DEVBUF);
+ return (NULL);
+ }
+ if (ctx->xc_priv_size != 0)
+ xact->x_priv = malloc(ctx->xc_priv_size, M_DEVBUF, M_WAITOK);
+ xact->x_resp0 = malloc(ctx->xc_resp_size, M_DEVBUF, M_WAITOK);
+
+ return (xact);
+}
+
+static void
+vmbus_xact_free(struct vmbus_xact *xact)
+{
+
+ hyperv_dmamem_free(&xact->x_req_dma, xact->x_req);
+ free(xact->x_resp0, M_DEVBUF);
+ if (xact->x_priv != NULL)
+ free(xact->x_priv, M_DEVBUF);
+ free(xact, M_DEVBUF);
+}
+
+static struct vmbus_xact *
+vmbus_xact_get1(struct vmbus_xact_ctx *ctx, uint32_t dtor_flag)
+{
+ struct vmbus_xact *xact;
+
+ mtx_lock(&ctx->xc_free_lock);
+
+ while ((ctx->xc_flags & dtor_flag) == 0 && ctx->xc_free == NULL)
+ mtx_sleep(&ctx->xc_free, &ctx->xc_free_lock, 0, "gxact", 0);
+ if (ctx->xc_flags & dtor_flag) {
+ /* Being destroyed */
+ xact = NULL;
+ } else {
+ xact = ctx->xc_free;
+ KASSERT(xact != NULL, ("no free xact"));
+ KASSERT(xact->x_resp == NULL, ("xact has pending response"));
+ ctx->xc_free = NULL;
+ }
+
+ mtx_unlock(&ctx->xc_free_lock);
+
+ return (xact);
+}
+
+struct vmbus_xact_ctx *
+vmbus_xact_ctx_create(bus_dma_tag_t dtag, size_t req_size, size_t resp_size,
+ size_t priv_size)
+{
+ struct vmbus_xact_ctx *ctx;
+
+ ctx = malloc(sizeof(*ctx), M_DEVBUF, M_WAITOK | M_ZERO);
+ ctx->xc_req_size = req_size;
+ ctx->xc_resp_size = resp_size;
+ ctx->xc_priv_size = priv_size;
+
+ ctx->xc_free = vmbus_xact_alloc(ctx, dtag);
+ if (ctx->xc_free == NULL) {
+ free(ctx, M_DEVBUF);
+ return (NULL);
+ }
+
+ mtx_init(&ctx->xc_free_lock, "vmbus xact free", NULL, MTX_DEF);
+ mtx_init(&ctx->xc_active_lock, "vmbus xact active", NULL, MTX_DEF);
+
+ return (ctx);
+}
+
+void
+vmbus_xact_ctx_destroy(struct vmbus_xact_ctx *ctx)
+{
+ struct vmbus_xact *xact;
+
+ mtx_lock(&ctx->xc_free_lock);
+ ctx->xc_flags |= VMBUS_XACT_CTXF_DESTROY;
+ mtx_unlock(&ctx->xc_free_lock);
+ wakeup(&ctx->xc_free);
+
+ xact = vmbus_xact_get1(ctx, 0);
+ if (xact == NULL)
+ panic("can't get xact");
+
+ vmbus_xact_free(xact);
+ mtx_destroy(&ctx->xc_free_lock);
+ mtx_destroy(&ctx->xc_active_lock);
+ free(ctx, M_DEVBUF);
+}
+
+struct vmbus_xact *
+vmbus_xact_get(struct vmbus_xact_ctx *ctx, size_t req_len)
+{
+ struct vmbus_xact *xact;
+
+ if (req_len > ctx->xc_req_size)
+ panic("invalid request size %zu", req_len);
+
+ xact = vmbus_xact_get1(ctx, VMBUS_XACT_CTXF_DESTROY);
+ if (xact == NULL)
+ return (NULL);
+
+ memset(xact->x_req, 0, req_len);
+ return (xact);
+}
+
+void
+vmbus_xact_put(struct vmbus_xact *xact)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ KASSERT(ctx->xc_active == NULL, ("pending active xact"));
+ xact->x_resp = NULL;
+
+ mtx_lock(&ctx->xc_free_lock);
+ KASSERT(ctx->xc_free == NULL, ("has free xact"));
+ ctx->xc_free = xact;
+ mtx_unlock(&ctx->xc_free_lock);
+ wakeup(&ctx->xc_free);
+}
+
+void *
+vmbus_xact_req_data(const struct vmbus_xact *xact)
+{
+
+ return (xact->x_req);
+}
+
+bus_addr_t
+vmbus_xact_req_paddr(const struct vmbus_xact *xact)
+{
+
+ return (xact->x_req_dma.hv_paddr);
+}
+
+void *
+vmbus_xact_priv(const struct vmbus_xact *xact, size_t priv_len)
+{
+
+ if (priv_len > xact->x_ctx->xc_priv_size)
+ panic("invalid priv size %zu", priv_len);
+ return (xact->x_priv);
+}
+
+void
+vmbus_xact_activate(struct vmbus_xact *xact)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ KASSERT(xact->x_resp == NULL, ("xact has pending response"));
+
+ mtx_lock(&ctx->xc_active_lock);
+ KASSERT(ctx->xc_active == NULL, ("pending active xact"));
+ ctx->xc_active = xact;
+ mtx_unlock(&ctx->xc_active_lock);
+}
+
+void
+vmbus_xact_deactivate(struct vmbus_xact *xact)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ mtx_lock(&ctx->xc_active_lock);
+ KASSERT(ctx->xc_active == xact, ("xact mismatch"));
+ ctx->xc_active = NULL;
+ mtx_unlock(&ctx->xc_active_lock);
+}
+
+const void *
+vmbus_xact_wait(struct vmbus_xact *xact, size_t *resp_len)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+ const void *resp;
+
+ mtx_lock(&ctx->xc_active_lock);
+
+ KASSERT(ctx->xc_active == xact, ("xact mismatch"));
+ while (xact->x_resp == NULL) {
+ mtx_sleep(&ctx->xc_active, &ctx->xc_active_lock, 0,
+ "wxact", 0);
+ }
+ ctx->xc_active = NULL;
+
+ resp = xact->x_resp;
+ *resp_len = xact->x_resp_len;
+
+ mtx_unlock(&ctx->xc_active_lock);
+
+ return (resp);
+}
+
+static void
+vmbus_xact_save_resp(struct vmbus_xact *xact, const void *data, size_t dlen)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+ size_t cplen = dlen;
+
+ mtx_assert(&ctx->xc_active_lock, MA_OWNED);
+
+ if (cplen > ctx->xc_resp_size) {
+ printf("vmbus: xact response truncated %zu -> %zu\n",
+ cplen, ctx->xc_resp_size);
+ cplen = ctx->xc_resp_size;
+ }
+
+ KASSERT(ctx->xc_active == xact, ("xact mismatch"));
+ memcpy(xact->x_resp0, data, cplen);
+ xact->x_resp_len = cplen;
+ xact->x_resp = xact->x_resp0;
+}
+
+void
+vmbus_xact_wakeup(struct vmbus_xact *xact, const void *data, size_t dlen)
+{
+ struct vmbus_xact_ctx *ctx = xact->x_ctx;
+
+ mtx_lock(&ctx->xc_active_lock);
+ vmbus_xact_save_resp(xact, data, dlen);
+ mtx_unlock(&ctx->xc_active_lock);
+ wakeup(&ctx->xc_active);
+}
+
+void
+vmbus_xact_ctx_wakeup(struct vmbus_xact_ctx *ctx, const void *data, size_t dlen)
+{
+ mtx_lock(&ctx->xc_active_lock);
+ KASSERT(ctx->xc_active != NULL, ("no pending xact"));
+ vmbus_xact_save_resp(ctx->xc_active, data, dlen);
+ mtx_unlock(&ctx->xc_active_lock);
+ wakeup(&ctx->xc_active);
+}
diff --git a/sys/modules/hyperv/vmbus/Makefile b/sys/modules/hyperv/vmbus/Makefile
index fe1e7fc..14eacf5 100644
--- a/sys/modules/hyperv/vmbus/Makefile
+++ b/sys/modules/hyperv/vmbus/Makefile
@@ -10,7 +10,8 @@ SRCS= hyperv.c \
vmbus.c \
vmbus_br.c \
vmbus_chan.c \
- vmbus_et.c
+ vmbus_et.c \
+ vmbus_xact.c
SRCS+= acpi_if.h bus_if.h device_if.h opt_acpi.h vmbus_if.h
# XXX: for assym.s
OpenPOWER on IntegriCloud