diff options
author | sephe <sephe@FreeBSD.org> | 2016-10-17 05:53:38 +0000 |
---|---|---|
committer | sephe <sephe@FreeBSD.org> | 2016-10-17 05:53:38 +0000 |
commit | 8805b157602c7a0963d947649e1c61b2ff537024 (patch) | |
tree | 3c6d5b2c1d2f0061dbb63f8e3025374950eb6d01 /sys | |
parent | b30b53b1101ef1c8ace1fce012be03dcaae894bc (diff) | |
download | FreeBSD-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.amd64 | 1 | ||||
-rw-r--r-- | sys/conf/files.i386 | 1 | ||||
-rw-r--r-- | sys/dev/hyperv/include/vmbus.h | 5 | ||||
-rw-r--r-- | sys/dev/hyperv/include/vmbus_xact.h | 59 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_net_vsc.c | 443 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_net_vsc.h | 2 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 13 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_rndis.h | 4 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_rndis_filter.c | 91 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/if_hnreg.h | 165 | ||||
-rw-r--r-- | sys/dev/hyperv/netvsc/if_hnvar.h | 6 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus.c | 233 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_var.h | 2 | ||||
-rw-r--r-- | sys/dev/hyperv/vmbus/vmbus_xact.c | 313 | ||||
-rw-r--r-- | sys/modules/hyperv/vmbus/Makefile | 3 |
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 |