Index: sys/dev/hyperv/include/hyperv.h =================================================================== --- sys/dev/hyperv/include/hyperv.h +++ sys/dev/hyperv/include/hyperv.h @@ -82,7 +82,6 @@ #define VMBUS_VERSION_MAJOR(ver) (((uint32_t)(ver)) >> 16) #define VMBUS_VERSION_MINOR(ver) (((uint32_t)(ver)) & 0xffff) -#define HV_MAX_PAGE_BUFFER_COUNT 32 #define HV_MAX_MULTIPAGE_BUFFER_COUNT 32 #define HV_ALIGN_UP(value, align) \ @@ -227,12 +226,6 @@ typedef struct { int length; int offset; - uint64_t pfn; -} __packed hv_vmbus_page_buffer; - -typedef struct { - int length; - int offset; uint64_t pfn_array[HV_MAX_MULTIPAGE_BUFFER_COUNT]; } __packed hv_vmbus_multipage_buffer; @@ -375,14 +368,6 @@ hv_vmbus_packet_type type, uint32_t flags); -int hv_vmbus_channel_send_packet_pagebuffer( - hv_vmbus_channel* channel, - hv_vmbus_page_buffer page_buffers[], - uint32_t page_count, - void* buffer, - uint32_t buffer_len, - uint64_t request_id); - int hv_vmbus_channel_send_packet_multipagebuffer( hv_vmbus_channel* channel, hv_vmbus_multipage_buffer* multi_page_buffer, Index: sys/dev/hyperv/include/vmbus.h =================================================================== --- /dev/null +++ sys/dev/hyperv/include/vmbus.h @@ -0,0 +1,49 @@ +/*- + * 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_H_ +#define _VMBUS_H_ + +#include + +/* This is actually vmbus_gpa_range.gpa_page[1] */ +struct vmbus_gpa { + uint32_t gpa_len; + uint32_t gpa_ofs; + uint64_t gpa_page; +} __packed; + +#define VMBUS_CHAN_SGLIST_MAX 32 + +struct hv_vmbus_channel; + +int vmbus_chan_send_sglist(struct hv_vmbus_channel *chan, + struct vmbus_gpa sg[], int sglen, void *data, int dlen, + uint64_t xactid); + +#endif /* !_VMBUS_H_ */ Index: sys/dev/hyperv/netvsc/hv_net_vsc.h =================================================================== --- sys/dev/hyperv/netvsc/hv_net_vsc.h +++ sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -57,6 +57,7 @@ #include #include +#include #define HN_USE_TXDESC_BUFRING @@ -1082,8 +1083,6 @@ typedef void (*pfn_on_send_rx_completion)(struct hv_vmbus_channel *, void *); #define NETVSC_DEVICE_RING_BUFFER_SIZE (128 * PAGE_SIZE) -#define NETVSC_PACKET_MAXPAGE 32 - #define NETVSC_VLAN_PRIO_MASK 0xe000 #define NETVSC_VLAN_PRIO_SHIFT 13 @@ -1132,8 +1131,8 @@ void *rndis_mesg; uint32_t tot_data_buf_len; void *data; - uint32_t page_buf_count; - hv_vmbus_page_buffer page_buffers[NETVSC_PACKET_MAXPAGE]; + uint32_t gpa_cnt; + struct vmbus_gpa gpa[VMBUS_CHAN_SGLIST_MAX]; } netvsc_packet; typedef struct { Index: sys/dev/hyperv/netvsc/hv_net_vsc.c =================================================================== --- sys/dev/hyperv/netvsc/hv_net_vsc.c +++ sys/dev/hyperv/netvsc/hv_net_vsc.c @@ -816,9 +816,8 @@ send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = pkt->send_buf_section_size; - if (pkt->page_buf_count) { - ret = hv_vmbus_channel_send_packet_pagebuffer(chan, - pkt->page_buffers, pkt->page_buf_count, + if (pkt->gpa_cnt) { + ret = vmbus_chan_send_sglist(chan, pkt->gpa, pkt->gpa_cnt, &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt); } else { ret = hv_vmbus_channel_send_packet(chan, Index: sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c =================================================================== --- sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -154,7 +154,7 @@ #define HN_TX_DATA_MAXSIZE IP_MAXPACKET #define HN_TX_DATA_SEGSIZE PAGE_SIZE #define HN_TX_DATA_SEGCNT_MAX \ - (NETVSC_PACKET_MAXPAGE - HV_RF_NUM_TX_RESERVED_PAGE_BUFS) + (VMBUS_CHAN_SGLIST_MAX - HV_RF_NUM_TX_RESERVED_PAGE_BUFS) #define HN_DIRECT_TX_SIZE_DEF 128 @@ -998,7 +998,7 @@ packet->send_buf_section_idx = send_buf_section_idx; packet->send_buf_section_size = packet->tot_data_buf_len; - packet->page_buf_count = 0; + packet->gpa_cnt = 0; txr->hn_tx_chimney++; goto done; } @@ -1024,24 +1024,24 @@ } *m_head0 = m_head; - packet->page_buf_count = nsegs + HV_RF_NUM_TX_RESERVED_PAGE_BUFS; + packet->gpa_cnt = nsegs + HV_RF_NUM_TX_RESERVED_PAGE_BUFS; /* send packet with page buffer */ - packet->page_buffers[0].pfn = atop(txd->rndis_msg_paddr); - packet->page_buffers[0].offset = txd->rndis_msg_paddr & PAGE_MASK; - packet->page_buffers[0].length = rndis_msg_size; + packet->gpa[0].gpa_page = atop(txd->rndis_msg_paddr); + packet->gpa[0].gpa_ofs = txd->rndis_msg_paddr & PAGE_MASK; + packet->gpa[0].gpa_len = rndis_msg_size; /* * Fill the page buffers with mbuf info starting at index * HV_RF_NUM_TX_RESERVED_PAGE_BUFS. */ for (i = 0; i < nsegs; ++i) { - hv_vmbus_page_buffer *pb = &packet->page_buffers[ + struct vmbus_gpa *gpa = &packet->gpa[ i + HV_RF_NUM_TX_RESERVED_PAGE_BUFS]; - pb->pfn = atop(segs[i].ds_addr); - pb->offset = segs[i].ds_addr & PAGE_MASK; - pb->length = segs[i].ds_len; + gpa->gpa_page = atop(segs[i].ds_addr); + gpa->gpa_ofs = segs[i].ds_addr & PAGE_MASK; + gpa->gpa_len = segs[i].ds_len; } packet->send_buf_section_idx = Index: sys/dev/hyperv/netvsc/hv_rndis_filter.h =================================================================== --- sys/dev/hyperv/netvsc/hv_rndis_filter.h +++ sys/dev/hyperv/netvsc/hv_rndis_filter.h @@ -74,7 +74,6 @@ /* Simplify allocation by having a netvsc packet inline */ netvsc_packet pkt; - hv_vmbus_page_buffer buffer; /* * The max request size is sizeof(rndis_msg) + PAGE_SIZE. Index: sys/dev/hyperv/netvsc/hv_rndis_filter.c =================================================================== --- sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -248,26 +248,23 @@ packet->is_data_pkt = FALSE; packet->tot_data_buf_len = request->request_msg.msg_len; - packet->page_buf_count = 1; + packet->gpa_cnt = 1; - packet->page_buffers[0].pfn = + packet->gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT; - packet->page_buffers[0].length = request->request_msg.msg_len; - packet->page_buffers[0].offset = + packet->gpa[0].gpa_len = request->request_msg.msg_len; + packet->gpa[0].gpa_ofs = (unsigned long)&request->request_msg & (PAGE_SIZE - 1); - if (packet->page_buffers[0].offset + - packet->page_buffers[0].length > PAGE_SIZE) { - packet->page_buf_count = 2; - packet->page_buffers[0].length = - PAGE_SIZE - packet->page_buffers[0].offset; - packet->page_buffers[1].pfn = + if (packet->gpa[0].gpa_ofs + packet->gpa[0].gpa_len > PAGE_SIZE) { + packet->gpa_cnt = 2; + packet->gpa[0].gpa_len = PAGE_SIZE - packet->gpa[0].gpa_ofs; + packet->gpa[1].gpa_page = hv_get_phys_addr((char*)&request->request_msg + - packet->page_buffers[0].length) >> PAGE_SHIFT; - packet->page_buffers[1].offset = 0; - packet->page_buffers[1].length = - request->request_msg.msg_len - - packet->page_buffers[0].length; + packet->gpa[0].gpa_len) >> PAGE_SHIFT; + packet->gpa[1].gpa_ofs = 0; + packet->gpa[1].gpa_len = request->request_msg.msg_len - + packet->gpa[0].gpa_len; } packet->compl.send.send_completion_context = request; /* packet */ @@ -289,7 +286,7 @@ memcpy(dest, &request->request_msg, request->request_msg.msg_len); packet->send_buf_section_idx = send_buf_section_idx; packet->send_buf_section_size = packet->tot_data_buf_len; - packet->page_buf_count = 0; + packet->gpa_cnt = 0; goto sendit; } /* Failed to allocate chimney send buffer; move on */ Index: sys/dev/hyperv/vmbus/hv_channel.c =================================================================== --- sys/dev/hyperv/vmbus/hv_channel.c +++ sys/dev/hyperv/vmbus/hv_channel.c @@ -672,70 +672,44 @@ return (ret); } -/** - * @brief Send a range of single-page buffer packets using - * a GPADL Direct packet type - */ int -hv_vmbus_channel_send_packet_pagebuffer( - hv_vmbus_channel* channel, - hv_vmbus_page_buffer page_buffers[], - uint32_t page_count, - void* buffer, - uint32_t buffer_len, - uint64_t request_id) +vmbus_chan_send_sglist(struct hv_vmbus_channel *chan, + struct vmbus_gpa sg[], int sglen, void *data, int dlen, uint64_t xactid) { + struct vmbus_chanpkt_sglist pkt; + int pktlen, pad_pktlen, hlen, error; + struct iovec iov[4]; + boolean_t send_evt; + uint64_t pad = 0; + + KASSERT(sglen < VMBUS_CHAN_SGLIST_MAX, + ("invalid sglist len %d", sglen)); + + hlen = __offsetof(struct vmbus_chanpkt_sglist, cp_gpa[sglen]); + pktlen = hlen + dlen; + pad_pktlen = roundup2(pktlen, VMBUS_CHANPKT_SIZE_ALIGN); + + pkt.cp_hdr.cph_type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT; + pkt.cp_hdr.cph_flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; + pkt.cp_hdr.cph_data_ofs = hlen >> VMBUS_CHANPKT_SIZE_SHIFT; + pkt.cp_hdr.cph_len = pad_pktlen >> VMBUS_CHANPKT_SIZE_SHIFT; + pkt.cp_hdr.cph_xactid = xactid; + pkt.cp_rsvd = 0; + pkt.cp_gpa_cnt = sglen; - int ret = 0; - boolean_t need_sig; - uint32_t packet_len; - uint32_t page_buflen; - uint32_t packetLen_aligned; - struct iovec iov[4]; - hv_vmbus_channel_packet_page_buffer desc; - uint32_t descSize; - uint64_t alignedData = 0; - - if (page_count > HV_MAX_PAGE_BUFFER_COUNT) - return (EINVAL); - - /* - * Adjust the size down since hv_vmbus_channel_packet_page_buffer - * is the largest size we support - */ - descSize = __offsetof(hv_vmbus_channel_packet_page_buffer, range); - page_buflen = sizeof(hv_vmbus_page_buffer) * page_count; - packet_len = descSize + page_buflen + buffer_len; - packetLen_aligned = HV_ALIGN_UP(packet_len, sizeof(uint64_t)); - - /* Setup the descriptor */ - desc.type = HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT; - desc.flags = HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; - /* in 8-bytes granularity */ - desc.data_offset8 = (descSize + page_buflen) >> 3; - desc.length8 = (uint16_t) (packetLen_aligned >> 3); - desc.transaction_id = request_id; - desc.range_count = page_count; - - iov[0].iov_base = &desc; - iov[0].iov_len = descSize; - - iov[1].iov_base = page_buffers; - iov[1].iov_len = page_buflen; - - iov[2].iov_base = buffer; - iov[2].iov_len = buffer_len; - - iov[3].iov_base = &alignedData; - iov[3].iov_len = packetLen_aligned - packet_len; - - ret = hv_ring_buffer_write(&channel->outbound, iov, 4, &need_sig); - - /* TODO: We should determine if this is optional */ - if (ret == 0 && need_sig) - vmbus_chan_send_event(channel); - - return (ret); + iov[0].iov_base = &pkt; + iov[0].iov_len = sizeof(pkt); + iov[1].iov_base = sg; + iov[1].iov_len = sizeof(struct vmbus_gpa) * sglen; + iov[2].iov_base = data; + iov[2].iov_len = dlen; + iov[3].iov_base = &pad; + iov[3].iov_len = pad_pktlen - pktlen; + + error = hv_ring_buffer_write(&chan->outbound, iov, 4, &send_evt); + if (!error && send_evt) + vmbus_chan_send_event(chan); + return error; } /** Index: sys/dev/hyperv/vmbus/hv_vmbus_priv.h =================================================================== --- sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -44,20 +44,6 @@ /* * The format must be the same as hv_vm_data_gpa_direct */ -typedef struct hv_vmbus_channel_packet_page_buffer { - uint16_t type; - uint16_t data_offset8; - uint16_t length8; - uint16_t flags; - uint64_t transaction_id; - uint32_t reserved; - uint32_t range_count; - hv_vmbus_page_buffer range[HV_MAX_PAGE_BUFFER_COUNT]; -} __packed hv_vmbus_channel_packet_page_buffer; - -/* - * The format must be the same as hv_vm_data_gpa_direct - */ typedef struct hv_vmbus_channel_packet_multipage_buffer { uint16_t type; uint16_t data_offset8; Index: sys/dev/hyperv/vmbus/vmbus_reg.h =================================================================== --- sys/dev/hyperv/vmbus/vmbus_reg.h +++ sys/dev/hyperv/vmbus/vmbus_reg.h @@ -30,8 +30,9 @@ #define _VMBUS_REG_H_ #include -#include #include /* XXX for hyperv_guid */ +#include +#include /* * Hyper-V SynIC message format. @@ -135,6 +136,13 @@ struct vmbus_chanpkt_hdr cp_hdr; } __packed; +struct vmbus_chanpkt_sglist { + struct vmbus_chanpkt_hdr cp_hdr; + uint32_t cp_rsvd; + uint32_t cp_gpa_cnt; + struct vmbus_gpa cp_gpa[]; +} __packed; + /* * Channel messages * - Embedded in vmbus_message.msg_data, e.g. response and notification.