From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id BC02D2E41 for ; Tue, 21 Apr 2015 21:34:45 +0200 (CEST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga101.jf.intel.com with ESMTP; 21 Apr 2015 12:34:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,617,1422950400"; d="scan'208";a="683557343" Received: from irsmsx106.ger.corp.intel.com ([163.33.3.31]) by orsmga001.jf.intel.com with ESMTP; 21 Apr 2015 12:34:41 -0700 Received: from irsmsx109.ger.corp.intel.com ([169.254.13.95]) by IRSMSX106.ger.corp.intel.com ([169.254.8.204]) with mapi id 14.03.0224.002; Tue, 21 Apr 2015 20:34:41 +0100 From: "Butler, Siobhan A" To: Stephen Hemminger , "alexmay@microsoft.com" Thread-Topic: [dpdk-dev] [PATCH v4 5/7] hv: poll mode driver Thread-Index: AQHQfFlcXPZUy7PdBkehQEtOQ6R6uZ1X25Yw Date: Tue, 21 Apr 2015 19:34:39 +0000 Message-ID: <0C5AFCA4B3408848ADF2A3073F7D8CC86D5A6905@IRSMSX109.ger.corp.intel.com> References: <1429637564-5656-1-git-send-email-stephen@networkplumber.org> <1429637564-5656-6-git-send-email-stephen@networkplumber.org> In-Reply-To: <1429637564-5656-6-git-send-email-stephen@networkplumber.org> Accept-Language: en-IE, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [163.33.239.181] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Cc: "dev@dpdk.org" , Stas Egorov , Stephen Hemminger Subject: Re: [dpdk-dev] [PATCH v4 5/7] hv: poll mode driver X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Apr 2015 19:34:48 -0000 Hi Stephen=20 Will you have documentation to go along with these changes? Thanks Siobhan > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Stephen > Hemminger > Sent: Tuesday, April 21, 2015 6:33 PM > To: alexmay@microsoft.com > Cc: dev@dpdk.org; Stas Egorov; Stephen Hemminger > Subject: [dpdk-dev] [PATCH v4 5/7] hv: poll mode driver >=20 > From: Stephen Hemminger >=20 > This is new Poll Mode driver for using hyper-v virtual network > interface. >=20 > Signed-off-by: Stas Egorov > Signed-off-by: Stephen Hemminger > --- > lib/Makefile | 1 + > lib/librte_pmd_hyperv/Makefile | 28 + > lib/librte_pmd_hyperv/hyperv.h | 169 ++++ > lib/librte_pmd_hyperv/hyperv_drv.c | 1653 > +++++++++++++++++++++++++++++++++ > lib/librte_pmd_hyperv/hyperv_drv.h | 558 +++++++++++ > lib/librte_pmd_hyperv/hyperv_ethdev.c | 332 +++++++ > lib/librte_pmd_hyperv/hyperv_logs.h | 69 ++ > lib/librte_pmd_hyperv/hyperv_rxtx.c | 403 ++++++++ > lib/librte_pmd_hyperv/hyperv_rxtx.h | 35 + > mk/rte.app.mk | 4 + > 10 files changed, 3252 insertions(+) > create mode 100644 lib/librte_pmd_hyperv/Makefile > create mode 100644 lib/librte_pmd_hyperv/hyperv.h > create mode 100644 lib/librte_pmd_hyperv/hyperv_drv.c > create mode 100644 lib/librte_pmd_hyperv/hyperv_drv.h > create mode 100644 lib/librte_pmd_hyperv/hyperv_ethdev.c > create mode 100644 lib/librte_pmd_hyperv/hyperv_logs.h > create mode 100644 lib/librte_pmd_hyperv/hyperv_rxtx.c > create mode 100644 lib/librte_pmd_hyperv/hyperv_rxtx.h >=20 > diff --git a/lib/Makefile b/lib/Makefile > index d94355d..6c1daf2 100644 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -47,6 +47,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) +=3D > librte_pmd_i40e > DIRS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) +=3D librte_pmd_fm10k > DIRS-$(CONFIG_RTE_LIBRTE_MLX4_PMD) +=3D librte_pmd_mlx4 > DIRS-$(CONFIG_RTE_LIBRTE_ENIC_PMD) +=3D librte_pmd_enic > +DIRS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D librte_pmd_hyperv > DIRS-$(CONFIG_RTE_LIBRTE_PMD_BOND) +=3D librte_pmd_bond > DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) +=3D librte_pmd_ring > DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) +=3D librte_pmd_pcap > diff --git a/lib/librte_pmd_hyperv/Makefile > b/lib/librte_pmd_hyperv/Makefile > new file mode 100644 > index 0000000..4ba08c8 > --- /dev/null > +++ b/lib/librte_pmd_hyperv/Makefile > @@ -0,0 +1,28 @@ > +# BSD LICENSE > +# > +# Copyright(c) 2013-2015 Brocade Communications Systems, Inc. > +# All rights reserved. > + > +include $(RTE_SDK)/mk/rte.vars.mk > + > +# > +# library name > +# > +LIB =3D librte_pmd_hyperv.a > + > +CFLAGS +=3D -O3 > +CFLAGS +=3D $(WERROR_FLAGS) > + > +# > +# all source are stored in SRCS-y > +# > +SRCS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D hyperv_ethdev.c > +SRCS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D hyperv_rxtx.c > +SRCS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D hyperv_drv.c > + > +# this lib depends upon: > +DEPDIRS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D lib/librte_eal lib/librte_ether > +DEPDIRS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D lib/librte_mempool > lib/librte_mbuf > +DEPDIRS-$(CONFIG_RTE_LIBRTE_HV_PMD) +=3D lib/librte_malloc > + > +include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/lib/librte_pmd_hyperv/hyperv.h > b/lib/librte_pmd_hyperv/hyperv.h > new file mode 100644 > index 0000000..5f66d8a > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv.h > @@ -0,0 +1,169 @@ > +/*- > + * Copyright (c) 2013-2015 Brocade Communications Systems, Inc. > + * All rights reserved. > + */ > + > +#ifndef _HYPERV_H_ > +#define _HYPERV_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "hyperv_logs.h" > + > +#define PAGE_SHIFT 12 > +#define PAGE_SIZE (1 << PAGE_SHIFT) > + > +/* > + * Tunable ethdev params > + */ > +#define HV_MIN_RX_BUF_SIZE 1024 > +#define HV_MAX_RX_PKT_LEN 4096 > +#define HV_MAX_MAC_ADDRS 1 > +#define HV_MAX_RX_QUEUES 1 > +#define HV_MAX_TX_QUEUES 1 > +#define HV_MAX_PKT_BURST 32 > +#define HV_MAX_LINK_REQ 10 > + > +/* > + * List of resources mapped from kspace > + * need to be the same as defined in hv_uio.c > + */ > +enum { > + TXRX_RING_MAP, > + INT_PAGE_MAP, > + MON_PAGE_MAP, > + RECV_BUF_MAP > +}; > + > +/* > + * Statistics > + */ > +struct hv_stats { > + uint64_t opkts; > + uint64_t obytes; > + uint64_t oerrors; > + > + uint64_t ipkts; > + uint64_t ibytes; > + uint64_t ierrors; > + uint64_t rx_nombuf; > +}; > + > +struct hv_data; > +struct netvsc_packet; > +struct rndis_msg; > +typedef void (*receive_callback_t)(struct hv_data *hv, struct rndis_msg > *msg, > + struct netvsc_packet *pkt); > + > +/* > + * Main driver structure > + */ > +struct hv_data { > + int vmbus_device; > + uint8_t monitor_bit; > + uint8_t monitor_group; > + uint8_t kernel_initialized; > + int uio_fd; > + /* Flag indicates channel state. If closed, RX/TX shouldn't work > further */ > + uint8_t closed; > + /* Flag indicates whether HALT rndis request was received by host */ > + uint8_t hlt_req_sent; > + /* Flag indicates pending state for HALT request */ > + uint8_t hlt_req_pending; > + /* Counter for RNDIS requests */ > + uint32_t new_request_id; > + /* State of RNDIS device */ > + uint8_t rndis_dev_state; > + /* Number of transmitted packets but not completed yet by Hyper-V > */ > + int num_outstanding_sends; > + /* Max pkt len to fit in rx mbufs */ > + uint32_t max_rx_pkt_len; > + > + uint8_t jumbo_frame_support; > + > + struct hv_vmbus_ring_buffer *in; > + struct hv_vmbus_ring_buffer *out; > + > + /* Size of each ring_buffer(in/out) */ > + uint32_t rb_size; > + /* Size of data in each ring_buffer(in/out) */ > + uint32_t rb_data_size; > + > + void *int_page; > + struct hv_vmbus_monitor_page *monitor_pages; > + void *recv_interrupt_page; > + void *send_interrupt_page; > + void *ring_pages; > + void *recv_buf; > + > + uint8_t link_req_cnt; > + uint32_t link_status; > + uint8_t hw_mac_addr[ETHER_ADDR_LEN]; > + struct rndis_request *req; > + struct netvsc_packet *netvsc_packet; > + struct nvsp_msg *rx_comp_msg; > + struct hv_rx_queue *rxq; > + struct hv_tx_queue *txq; > + struct hv_vm_packet_descriptor *desc; > + receive_callback_t receive_callback; > + int pkt_rxed; > + > + uint32_t debug; > + struct hv_stats stats; > +}; > + > +/* > + * Extern functions declarations > + */ > +int hyperv_dev_tx_queue_setup(struct rte_eth_dev *dev, > + uint16_t queue_idx, > + uint16_t nb_desc, > + unsigned int socket_id, > + const struct rte_eth_txconf *tx_conf); > + > +void hyperv_dev_tx_queue_release(void *ptxq); > + > +int hyperv_dev_rx_queue_setup(struct rte_eth_dev *dev, > + uint16_t queue_idx, > + uint16_t nb_desc, > + unsigned int socket_id, > + const struct rte_eth_rxconf *rx_conf, > + struct rte_mempool *mp); > + > +void hyperv_dev_rx_queue_release(void *prxq); > + > +uint16_t > +hyperv_recv_pkts(void *prxq, > + struct rte_mbuf **rx_pkts, uint16_t nb_pkts); > + > +uint16_t > +hyperv_xmit_pkts(void *ptxq, > + struct rte_mbuf **tx_pkts, uint16_t nb_pkts); > + > +int hv_rf_on_device_add(struct hv_data *hv); > +int hv_rf_on_device_remove(struct hv_data *hv); > +int hv_rf_on_send(struct hv_data *hv, struct netvsc_packet *pkt); > +int hv_rf_on_open(struct hv_data *hv); > +int hv_rf_on_close(struct hv_data *hv); > +int hv_rf_set_device_mac(struct hv_data *hv, uint8_t *mac); > +void hyperv_start_rx(struct hv_data *hv); > +void hyperv_stop_rx(struct hv_data *hv); > +int hyperv_get_buffer(struct hv_data *hv, void *buffer, uint32_t > bufferlen); > +void hyperv_scan_comps(struct hv_data *hv, int allow_rx_drop); > +uint8_t hyperv_get_link_status(struct hv_data *hv); > +int hyperv_set_rx_mode(struct hv_data *hv, uint8_t promisc, uint8_t > mcast); > + > +inline int rte_hv_dev_atomic_write_link_status(struct rte_eth_dev *dev, > + struct rte_eth_link *link); > +inline int rte_hv_dev_atomic_read_link_status(struct rte_eth_dev *dev, > + struct rte_eth_link *link); > + > +#endif /* _HYPERV_H_ */ > diff --git a/lib/librte_pmd_hyperv/hyperv_drv.c > b/lib/librte_pmd_hyperv/hyperv_drv.c > new file mode 100644 > index 0000000..4a37966 > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv_drv.c > @@ -0,0 +1,1653 @@ > +/*- > + * Copyright (c) 2009-2012 Microsoft Corp. > + * Copyright (c) 2010-2012 Citrix Inc. > + * Copyright (c) 2012 NetApp Inc. > + * Copyright (c) 2013-2015 Brocade Communications Systems, Inc. > + * 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 th= e > + * documentation and/or other materials provided with the distributio= n. > + * > + * 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 "hyperv.h" > +#include "hyperv_drv.h" > +#include "hyperv_rxtx.h" > + > +#define LOOP_CNT 10000 > +#define MAC_STRLEN 14 > +#define MAC_PARAM_STR "NetworkAddress" > + > +#define hex "0123456789abcdef" > +#define high(x) hex[(x & 0xf0) >> 4] > +#define low(x) hex[x & 0x0f] > + > +static int hv_rf_on_receive(struct hv_data *hv, struct netvsc_packet *pk= t); > + > +/* > + * Ring buffer > + */ > + > +/* Amount of space to write to */ > +#define HV_BYTES_AVAIL_TO_WRITE(r, w, z) \ > + (((w) >=3D (r)) ? ((z) - ((w) - (r))) : ((r) - (w))) > + > +/* > + * Get number of bytes available to read and to write to > + * for the specified ring buffer > + */ > +static inline void > +get_ring_buffer_avail_bytes( > + struct hv_data *hv, > + struct hv_vmbus_ring_buffer *ring_buffer, > + uint32_t *read, > + uint32_t *write) > +{ > + rte_compiler_barrier(); > + > + /* > + * Capture the read/write indices before they changed > + */ > + uint32_t read_loc =3D ring_buffer->read_index; > + uint32_t write_loc =3D ring_buffer->write_index; > + > + *write =3D HV_BYTES_AVAIL_TO_WRITE( > + read_loc, write_loc, hv->rb_data_size); > + *read =3D hv->rb_data_size - *write; > +} > + > +/* > + * Helper routine to copy from source to ring buffer. > + * > + * Assume there is enough room. Handles wrap-around in dest case only! > + */ > +static uint32_t > +copy_to_ring_buffer( > + struct hv_vmbus_ring_buffer *ring_buffer, > + uint32_t ring_buffer_size, > + uint32_t start_write_offset, > + char *src, > + uint32_t src_len) > +{ > + char *ring_buf =3D (char *)ring_buffer->buffer; > + uint32_t fragLen; > + > + if (src_len > ring_buffer_size - start_write_offset) { > + /* wrap-around detected! */ > + fragLen =3D ring_buffer_size - start_write_offset; > + rte_memcpy(ring_buf + start_write_offset, src, fragLen); > + rte_memcpy(ring_buf, src + fragLen, src_len - fragLen); > + } else { > + rte_memcpy(ring_buf + start_write_offset, src, src_len); > + } > + > + start_write_offset +=3D src_len; > + start_write_offset %=3D ring_buffer_size; > + > + return start_write_offset; > +} > + > +/* > + * Helper routine to copy to dest from ring buffer. > + * > + * Assume there is enough room. Handles wrap-around in src case only! > + */ > +static uint32_t > +copy_from_ring_buffer( > + struct hv_data *hv, > + struct hv_vmbus_ring_buffer *ring_buffer, > + char *dest, > + uint32_t dest_len, > + uint32_t start_read_offset) > +{ > + uint32_t fragLen; > + char *ring_buf =3D (char *)ring_buffer->buffer; > + > + if (dest_len > hv->rb_data_size - start_read_offset) { > + /* wrap-around detected at the src */ > + fragLen =3D hv->rb_data_size - start_read_offset; > + rte_memcpy(dest, ring_buf + start_read_offset, fragLen); > + rte_memcpy(dest + fragLen, ring_buf, dest_len - fragLen); > + } else { > + rte_memcpy(dest, ring_buf + start_read_offset, dest_len); > + } > + > + start_read_offset +=3D dest_len; > + start_read_offset %=3D hv->rb_data_size; > + > + return start_read_offset; > +} > + > +/* > + * Write to the ring buffer. > + */ > +static int > +hv_ring_buffer_write( > + struct hv_data *hv, > + struct hv_vmbus_sg_buffer_list sg_buffers[], > + uint32_t sg_buffer_count) > +{ > + struct hv_vmbus_ring_buffer *ring_buffer =3D hv->out; > + uint32_t i =3D 0; > + uint32_t byte_avail_to_write; > + uint32_t byte_avail_to_read; > + uint32_t total_bytes_to_write =3D 0; > + volatile uint32_t next_write_location; > + uint64_t prev_indices =3D 0; > + > + for (i =3D 0; i < sg_buffer_count; i++) > + total_bytes_to_write +=3D sg_buffers[i].length; > + > + total_bytes_to_write +=3D sizeof(uint64_t); > + > + get_ring_buffer_avail_bytes(hv, ring_buffer, &byte_avail_to_read, > + &byte_avail_to_write); > + > + /* > + * If there is only room for the packet, assume it is full. > + * Otherwise, the next time around, we think the ring buffer > + * is empty since the read index =3D=3D write index > + */ > + if (byte_avail_to_write <=3D total_bytes_to_write) { > + PMD_PERROR_LOG(hv, DBG_RB, > + "byte_avail_to_write =3D %u, > total_bytes_to_write =3D %u", > + byte_avail_to_write, total_bytes_to_write); > + return -EAGAIN; > + } > + > + /* > + * Write to the ring buffer > + */ > + next_write_location =3D ring_buffer->write_index; > + > + for (i =3D 0; i < sg_buffer_count; i++) { > + next_write_location =3D copy_to_ring_buffer(ring_buffer, > + hv->rb_data_size, next_write_location, > + (char *) sg_buffers[i].data, > sg_buffers[i].length); > + } > + > + /* > + * Set previous packet start > + */ > + prev_indices =3D (uint64_t)ring_buffer->write_index << 32; > + > + next_write_location =3D copy_to_ring_buffer( > + ring_buffer, hv->rb_data_size, next_write_location, > + (char *) &prev_indices, sizeof(uint64_t)); > + > + /* > + * Make sure we flush all writes before updating the writeIndex > + */ > + rte_compiler_barrier(); > + > + /* > + * Now, update the write location > + */ > + ring_buffer->write_index =3D next_write_location; > + > + return 0; > +} > + > +/* > + * Read without advancing the read index. > + */ > +static int > +hv_ring_buffer_peek(struct hv_data *hv, void *buffer, uint32_t > buffer_len) > +{ > + struct hv_vmbus_ring_buffer *ring_buffer =3D hv->in; > + uint32_t bytesAvailToWrite; > + uint32_t bytesAvailToRead; > + > + get_ring_buffer_avail_bytes(hv, ring_buffer, > + &bytesAvailToRead, > + &bytesAvailToWrite); > + > + /* Make sure there is something to read */ > + if (bytesAvailToRead < buffer_len) > + return -EAGAIN; > + > + copy_from_ring_buffer(hv, ring_buffer, > + (char *)buffer, buffer_len, ring_buffer->read_index); > + > + return 0; > +} > + > +/* > + * Read and advance the read index. > + */ > +static int > +hv_ring_buffer_read(struct hv_data *hv, void *buffer, > + uint32_t buffer_len, uint32_t offset) > +{ > + struct hv_vmbus_ring_buffer *ring_buffer =3D hv->in; > + uint32_t bytes_avail_to_write; > + uint32_t bytes_avail_to_read; > + uint32_t next_read_location =3D 0; > + uint64_t prev_indices =3D 0; > + > + if (buffer_len <=3D 0) > + return -EINVAL; > + > + get_ring_buffer_avail_bytes( > + hv, > + ring_buffer, > + &bytes_avail_to_read, > + &bytes_avail_to_write); > + > + /* > + * Make sure there is something to read > + */ > + if (bytes_avail_to_read < buffer_len) { > + PMD_PERROR_LOG(hv, DBG_RB, "bytes_avail_to_read =3D > %u, buffer_len =3D %u", > + bytes_avail_to_read, buffer_len); > + return -EAGAIN; > + } > + > + next_read_location =3D (ring_buffer->read_index + offset) % hv- > >rb_data_size; > + > + next_read_location =3D copy_from_ring_buffer( > + hv, > + ring_buffer, > + (char *) buffer, > + buffer_len, > + next_read_location); > + > + next_read_location =3D copy_from_ring_buffer( > + hv, > + ring_buffer, > + (char *) &prev_indices, > + sizeof(uint64_t), > + next_read_location); > + > + /* > + * Make sure all reads are done before we update the read index > since > + * the writer may start writing to the read area once the read index > + * is updated. > + */ > + rte_compiler_barrier(); > + > + /* > + * Update the read index > + */ > + ring_buffer->read_index =3D next_read_location; > + > + return 0; > +} > + > +/* > + * VMBus > + */ > + > +/* > + * Retrieve the raw packet on the specified channel > + */ > +static int > +hv_vmbus_channel_recv_packet_raw(struct hv_data *hv, void *buffer, > + uint32_t buffer_len, > + uint32_t *buffer_actual_len, > + uint64_t *request_id, > + int mode) > +{ > + int ret; > + uint32_t packetLen; > + struct hv_vm_packet_descriptor desc; > + > + *buffer_actual_len =3D 0; > + *request_id =3D 0; > + > + ret =3D hv_ring_buffer_peek(hv, &desc, > + sizeof(struct hv_vm_packet_descriptor)); > + > + if (ret !=3D 0) > + return 0; > + > + if ((desc.type =3D=3D > HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES > + && !(mode & 1)) || > + ((desc.type =3D=3D > HV_VMBUS_PACKET_TYPE_COMPLETION) && !(mode & 2))) { > + return -1; > + } > + > + packetLen =3D desc.length8 << 3; > + > + *buffer_actual_len =3D packetLen; > + > + if (unlikely(packetLen > buffer_len)) { > + PMD_PERROR_LOG(hv, DBG_RX, "The buffer desc is too big, > will drop it"); > + return -ENOMEM; > + } > + > + *request_id =3D desc.transaction_id; > + > + /* Copy over the entire packet to the user buffer */ > + ret =3D hv_ring_buffer_read(hv, buffer, packetLen, 0); > + > + return 0; > +} > + > +/* > + * Trigger an event notification on the specified channel > + */ > +static void > +vmbus_channel_set_event(struct hv_data *hv) > +{ > + /* Here we assume that channel->offer_msg.monitor_allocated =3D=3D > 1, > + * in another case our driver will not work */ > + /* Each uint32_t represents 32 channels */ > + __sync_or_and_fetch(((uint32_t *)hv->send_interrupt_page > + + ((hv->vmbus_device >> 5))), 1 << (hv->vmbus_device & > 31) > + ); > + __sync_or_and_fetch((uint32_t *)&hv->monitor_pages-> > + trigger_group[hv->monitor_group].u.pending, 1 << > hv->monitor_bit); > +} > + > +/** > + * @brief Send the specified buffer on the given channel > + */ > +static int > +hv_vmbus_channel_send_packet(struct hv_data *hv, void *buffer, > + uint32_t buffer_len, uint64_t request_id, > + enum hv_vmbus_packet_type type, > + uint32_t flags) > +{ > + struct hv_vmbus_sg_buffer_list buffer_list[3]; > + struct hv_vm_packet_descriptor desc; > + uint32_t packet_len_aligned; > + uint64_t aligned_data; > + uint32_t packet_len; > + int ret =3D 0; > + uint32_t old_write =3D hv->out->write_index; > + > + packet_len =3D sizeof(struct hv_vm_packet_descriptor) + buffer_len; > + packet_len_aligned =3D HV_ALIGN_UP(packet_len, sizeof(uint64_t)); > + aligned_data =3D 0; > + > + /* Setup the descriptor */ > + desc.type =3D type; /* HV_VMBUS_PACKET_TYPE_DATA_IN_BAND; > */ > + desc.flags =3D flags; /* > HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED */ > + /* in 8-bytes granularity */ > + desc.data_offset8 =3D sizeof(struct hv_vm_packet_descriptor) >> 3; > + desc.length8 =3D (uint16_t) (packet_len_aligned >> 3); > + desc.transaction_id =3D request_id; > + > + buffer_list[0].data =3D &desc; > + buffer_list[0].length =3D sizeof(struct hv_vm_packet_descriptor); > + > + buffer_list[1].data =3D buffer; > + buffer_list[1].length =3D buffer_len; > + > + buffer_list[2].data =3D &aligned_data; > + buffer_list[2].length =3D packet_len_aligned - packet_len; > + > + ret =3D hv_ring_buffer_write(hv, buffer_list, 3); > + > + rte_mb(); > + if (!ret && !hv->out->interrupt_mask && hv->out->read_index =3D=3D > old_write) > + vmbus_channel_set_event(hv); > + > + return ret; > +} > + > +/* > + * Send a range of single-page buffer packets using > + * a GPADL Direct packet type > + */ > +static int > +hv_vmbus_channel_send_packet_pagebuffer( > + struct hv_data *hv, > + struct hv_vmbus_page_buffer page_buffers[], > + uint32_t page_count, > + void *buffer, > + uint32_t buffer_len, > + uint64_t request_id) > +{ > + > + int ret =3D 0; > + uint32_t packet_len, packetLen_aligned, descSize, i =3D 0; > + struct hv_vmbus_sg_buffer_list buffer_list[3]; > + struct hv_vmbus_channel_packet_page_buffer desc; > + uint64_t alignedData =3D 0; > + uint32_t old_write =3D hv->out->write_index; > + > + if (page_count > HV_MAX_PAGE_BUFFER_COUNT) { > + PMD_PERROR_LOG(hv, DBG_VMBUS, "page_count %u goes > out of the limit", > + page_count); > + return -EINVAL; > + } > + > + /* > + * Adjust the size down since > hv_vmbus_channel_packet_page_buffer > + * is the largest size we support > + */ > + descSize =3D sizeof(struct hv_vmbus_channel_packet_page_buffer) - > + ((HV_MAX_PAGE_BUFFER_COUNT - page_count) * > + sizeof(struct hv_vmbus_page_buffer)); > + packet_len =3D descSize + buffer_len; > + packetLen_aligned =3D HV_ALIGN_UP(packet_len, sizeof(uint64_t)); > + > + /* Setup the descriptor */ > + desc.type =3D HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT; > + desc.flags =3D > HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; > + desc.data_offset8 =3D descSize >> 3; /* in 8-bytes granularity */ > + desc.length8 =3D (uint16_t) (packetLen_aligned >> 3); > + desc.transaction_id =3D request_id; > + desc.range_count =3D page_count; > + > + for (i =3D 0; i < page_count; i++) { > + desc.range[i].length =3D page_buffers[i].length; > + desc.range[i].offset =3D page_buffers[i].offset; > + desc.range[i].pfn =3D page_buffers[i].pfn; > + } > + > + buffer_list[0].data =3D &desc; > + buffer_list[0].length =3D descSize; > + > + buffer_list[1].data =3D buffer; > + buffer_list[1].length =3D buffer_len; > + > + buffer_list[2].data =3D &alignedData; > + buffer_list[2].length =3D packetLen_aligned - packet_len; > + > + ret =3D hv_ring_buffer_write(hv, buffer_list, 3); > + if (likely(ret =3D=3D 0)) > + ++hv->num_outstanding_sends; > + > + rte_mb(); > + if (!ret && !hv->out->interrupt_mask && > + hv->out->read_index =3D=3D old_write) > + vmbus_channel_set_event(hv); > + > + return ret; > +} > + > +/* > + * NetVSC > + */ > + > +/* > + * Net VSC on send > + * Sends a packet on the specified Hyper-V device. > + * Returns 0 on success, non-zero on failure. > + */ > +static int > +hv_nv_on_send(struct hv_data *hv, struct netvsc_packet *pkt) > +{ > + struct nvsp_msg send_msg; > + int ret; > + > + send_msg.msg_type =3D nvsp_msg_1_type_send_rndis_pkt; > + if (pkt->is_data_pkt) { > + /* 0 is RMC_DATA */ > + send_msg.msgs.send_rndis_pkt.chan_type =3D 0; > + } else { > + /* 1 is RMC_CONTROL */ > + send_msg.msgs.send_rndis_pkt.chan_type =3D 1; > + } > + > + /* Not using send buffer section */ > + send_msg.msgs.send_rndis_pkt.send_buf_section_idx =3D > + 0xFFFFFFFF; > + send_msg.msgs.send_rndis_pkt.send_buf_section_size =3D 0; > + > + if (likely(pkt->page_buf_count)) { > + ret =3D hv_vmbus_channel_send_packet_pagebuffer(hv, > + pkt->page_buffers, pkt->page_buf_count, > + &send_msg, sizeof(struct nvsp_msg), > + (uint64_t)pkt->is_data_pkt ? (hv->txq- > >tx_tail + 1) : 0); > + } else { > + PMD_PERROR_LOG(hv, DBG_TX, "pkt->page_buf_count > value can't be zero"); > + ret =3D -1; > + } > + > + return ret; > +} > + > +/* > + * Net VSC on receive > + * > + * This function deals exclusively with virtual addresses. > + */ > +static void > +hv_nv_on_receive(struct hv_data *hv, struct hv_vm_packet_descriptor > *pkt) > +{ > + struct hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; > + struct nvsp_msg *nvsp_msg_pkt; > + struct netvsc_packet *net_vsc_pkt =3D NULL; > + unsigned long start; > + int count, i; > + > + nvsp_msg_pkt =3D (struct nvsp_msg *)((unsigned long)pkt > + + (pkt->data_offset8 << 3)); > + > + /* Make sure this is a valid nvsp packet */ > + if (unlikely(nvsp_msg_pkt->msg_type !=3D > nvsp_msg_1_type_send_rndis_pkt)) { > + PMD_PERROR_LOG(hv, DBG_RX, "NVSP packet is not valid"); > + return; > + } > + > + vm_xfer_page_pkt =3D (struct hv_vm_transfer_page_packet_header > *)pkt; > + > + if (unlikely(vm_xfer_page_pkt->transfer_page_set_id > + !=3D NETVSC_RECEIVE_BUFFER_ID)) { > + PMD_PERROR_LOG(hv, DBG_RX, "transfer_page_set_id is > not valid"); > + return; > + } > + > + count =3D vm_xfer_page_pkt->range_count; > + > + /* > + * Initialize the netvsc packet > + */ > + for (i =3D 0; i < count; ++i) { > + net_vsc_pkt =3D hv->netvsc_packet; > + > + net_vsc_pkt->tot_data_buf_len =3D > + vm_xfer_page_pkt->ranges[i].byte_count; > + net_vsc_pkt->page_buf_count =3D 1; > + > + net_vsc_pkt->page_buffers[0].length =3D > + vm_xfer_page_pkt->ranges[i].byte_count; > + > + /* The virtual address of the packet in the receive buffer */ > + start =3D ((unsigned long)hv->recv_buf + > + vm_xfer_page_pkt->ranges[i].byte_offset); > + > + /* Page number of the virtual page containing packet start */ > + net_vsc_pkt->page_buffers[0].pfn =3D start >> PAGE_SHIFT; > + > + /* Calculate the page relative offset */ > + net_vsc_pkt->page_buffers[0].offset =3D > + vm_xfer_page_pkt->ranges[i].byte_offset & > (PAGE_SIZE - 1); > + > + /* > + * In this implementation, we are dealing with virtual > + * addresses exclusively. Since we aren't using physical > + * addresses at all, we don't care if a packet crosses a > + * page boundary. For this reason, the original code to > + * check for and handle page crossings has been removed. > + */ > + > + /* > + * Pass it to the upper layer. The receive completion call > + * has been moved into this function. > + */ > + hv_rf_on_receive(hv, net_vsc_pkt); > + } > + /* Send a receive completion packet to RNDIS device (ie NetVsp) */ > + hv_vmbus_channel_send_packet(hv, hv->rx_comp_msg, > sizeof(struct nvsp_msg), > + vm_xfer_page_pkt->d.transaction_id, > + HV_VMBUS_PACKET_TYPE_COMPLETION, 0); > +} > + > +/* > + * Net VSC on send completion > + */ > +static void > +hv_nv_on_send_completion(struct hv_data *hv, struct > hv_vm_packet_descriptor *pkt) > +{ > + struct nvsp_msg *nvsp_msg_pkt; > + > + nvsp_msg_pkt =3D > + (struct nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << > 3)); > + > + if (likely(nvsp_msg_pkt->msg_type =3D=3D > + > nvsp_msg_1_type_send_rndis_pkt_complete)) { > + > + if (unlikely(hv->hlt_req_pending)) > + hv->hlt_req_sent =3D 1; > + else > + if (pkt->transaction_id) > + ++hv->txq->tx_free; > + --hv->num_outstanding_sends; > + return; > + } > + PMD_PINFO_LOG(hv, DBG_TX, "unhandled completion (for kernel > req or so)"); > +} > + > +/* > + * Analogue of bsd hv_nv_on_channel_callback > + */ > +static void > +hv_nv_complete_request(struct hv_data *hv, struct rndis_request > *request) > +{ > + uint32_t bytes_rxed, cnt =3D 0; > + uint64_t request_id; > + struct hv_vm_packet_descriptor *desc; > + uint8_t *buffer; > + int bufferlen =3D NETVSC_PACKET_SIZE; > + int ret =3D 0; > + > + PMD_INIT_FUNC_TRACE(); > + > + hv->req =3D request; > + > + buffer =3D rte_malloc(NULL, bufferlen, RTE_CACHE_LINE_SIZE); > + if (!buffer) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "failed to allocate > packet"); > + return; > + } > + > + do { > + rte_delay_us(1); > + ret =3D hv_vmbus_channel_recv_packet_raw(hv, > + buffer, bufferlen, &bytes_rxed, > &request_id, 3); > + if (ret =3D=3D 0) { > + if (bytes_rxed > 0) { > + desc =3D (struct hv_vm_packet_descriptor > *)buffer; > + > + switch (desc->type) { > + case > HV_VMBUS_PACKET_TYPE_COMPLETION: > + hv_nv_on_send_completion(hv, > desc); > + break; > + case > HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: > + hv_nv_on_receive(hv, desc); > + break; > + default: > + break; > + } > + PMD_PDEBUG_LOG(hv, DBG_LOAD, > + "Did %d attempts until non-empty > data was receieved", > + cnt); > + cnt =3D 0; > + } else { > + cnt++; > + } > + } else if (ret =3D=3D -ENOMEM) { > + /* Handle large packet */ > + PMD_PDEBUG_LOG(hv, DBG_LOAD, > + "recv_packet_raw returned -ENOMEM"); > + rte_free(buffer); > + buffer =3D rte_malloc(NULL, bytes_rxed, > RTE_CACHE_LINE_SIZE); > + if (buffer =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "failed > to allocate buffer"); > + break; > + } > + bufferlen =3D bytes_rxed; > + } else { > + PMD_PERROR_LOG(hv, DBG_LOAD, "Unexpected > return code (%d)", ret); > + } > + if (!hv->req) { > + PMD_PINFO_LOG(hv, DBG_LOAD, "Single request > processed"); > + break; > + } > + if (cnt >=3D LOOP_CNT) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "Emergency > break from the loop"); > + break; > + } > + if (hv->hlt_req_sent) { > + PMD_PINFO_LOG(hv, DBG_LOAD, "Halt request > processed"); > + break; > + } > + /* The field hv->req->response_msg.ndis_msg_type > + * should be set to non-zero value when response received > + */ > + } while (!hv->req->response_msg.ndis_msg_type); > + > + rte_free(buffer); > +} > + > +/* > + * RNDIS > + */ > + > +/* > + * Create new RNDIS request > + */ > +static inline struct rndis_request * > +hv_rndis_request(struct hv_data *hv, uint32_t message_type, > + uint32_t message_length) > +{ > + struct rndis_request *request; > + struct rndis_msg *rndis_mesg; > + struct rndis_set_request *set; > + char mz_name[RTE_MEMZONE_NAMESIZE]; > + uint32_t size; > + > + PMD_INIT_FUNC_TRACE(); > + > + request =3D rte_zmalloc("rndis_req", sizeof(struct rndis_request), > + RTE_CACHE_LINE_SIZE); > + > + if (!request) > + return NULL; > + > + sprintf(mz_name, "hv_%d_%u_%d_%p", hv->vmbus_device, > message_type, > + hv->new_request_id, request); > + > + size =3D MAX(message_length, sizeof(struct rndis_msg)); > + > + request->request_msg_memzone =3D > rte_memzone_reserve_aligned(mz_name, > + size, rte_lcore_to_socket_id(rte_lcore_id()), 0, > PAGE_SIZE); > + if (!request->request_msg_memzone) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "memzone_reserve > failed"); > + rte_free(request); > + return NULL; > + } > + request->request_msg =3D request->request_msg_memzone->addr; > + rndis_mesg =3D request->request_msg; > + rndis_mesg->ndis_msg_type =3D message_type; > + rndis_mesg->msg_len =3D message_length; > + > + /* > + * Set the request id. This field is always after the rndis header > + * for request/response packet types so we just use the set_request > + * as a template. > + */ > + set =3D &rndis_mesg->msg.set_request; > + hv->new_request_id++; > + set->request_id =3D hv->new_request_id; > + > + return request; > +} > + > +/* > + * RNDIS filter > + */ > + > +static void > +hv_rf_receive_response( > + struct hv_data *hv, > + struct rndis_msg *response) > +{ > + struct rndis_request *request =3D hv->req; > + > + PMD_INIT_FUNC_TRACE(); > + > + if (response->msg_len <=3D sizeof(struct rndis_msg)) { > + rte_memcpy(&request->response_msg, response, > + response->msg_len); > + } else { > + if (response->ndis_msg_type =3D=3D > REMOTE_NDIS_INITIALIZE_CMPLT) { > + request->response_msg.msg.init_complete.status =3D > + STATUS_BUFFER_OVERFLOW; > + } > + PMD_PERROR_LOG(hv, DBG_LOAD, "response buffer > overflow\n"); > + } > +} > + > +/* > + * RNDIS filter receive indicate status > + */ > +static void > +hv_rf_receive_indicate_status(struct hv_data *hv, struct rndis_msg > *response) > +{ > + struct rndis_indicate_status *indicate =3D &response- > >msg.indicate_status; > + > + PMD_INIT_FUNC_TRACE(); > + > + if (indicate->status =3D=3D RNDIS_STATUS_MEDIA_CONNECT) > + hv->link_status =3D 1; > + else if (indicate->status =3D=3D RNDIS_STATUS_MEDIA_DISCONNECT) > + hv->link_status =3D 0; > + else if (indicate->status =3D=3D RNDIS_STATUS_INVALID_DATA) > + PMD_PERROR_LOG(hv, DBG_RX, "Invalid data in RNDIS > message"); > + else > + PMD_PERROR_LOG(hv, DBG_RX, "Unsupported status: %u", > indicate->status); > +} > + > +/* > + * RNDIS filter receive data > + */ > +static void > +hv_rf_receive_data(struct hv_data *hv, struct rndis_msg *msg, > + struct netvsc_packet *pkt) > +{ > + struct rte_mbuf *m_new; > + struct hv_rx_queue *rxq =3D hv->rxq; > + struct rndis_packet *rndis_pkt; > + uint32_t data_offset; > + > + if (unlikely(hv->closed)) > + return; > + > + rndis_pkt =3D &msg->msg.packet; > + > + if (unlikely(hv->max_rx_pkt_len < rndis_pkt->data_length)) { > + PMD_PWARN_LOG(hv, DBG_RX, "Packet is too large (%db), > dropping.", > + rndis_pkt->data_length); > + ++hv->stats.ierrors; > + return; > + } > + > + /* Remove rndis header, then pass data packet up the stack */ > + data_offset =3D RNDIS_HEADER_SIZE + rndis_pkt->data_offset; > + > + /* L2 frame length, with L2 header, not including CRC */ > + pkt->tot_data_buf_len =3D rndis_pkt->data_length; > + pkt->page_buffers[0].offset +=3D data_offset; > + /* Buffer length now L2 frame length plus trailing junk */ > + pkt->page_buffers[0].length -=3D data_offset; > + > + pkt->vlan_tci =3D 0; > + > + /* > + * Just put data into appropriate mbuf, all further work will be done > + * by the upper layer (mbuf replacement, index adjustment, etc) > + */ > + m_new =3D rxq->sw_ring[rxq->rx_tail]; > + if (++rxq->rx_tail =3D=3D rxq->nb_rx_desc) > + rxq->rx_tail =3D 0; > + > + /* > + * Copy the received packet to mbuf. > + * The copy is required since the memory pointed to by > netvsc_packet > + * cannot be reallocated > + */ > + uint8_t *vaddr =3D (uint8_t *) > + (pkt->page_buffers[0].pfn << PAGE_SHIFT) > + + pkt->page_buffers[0].offset; > + > + m_new->nb_segs =3D 1; > + m_new->pkt_len =3D m_new->data_len =3D pkt->tot_data_buf_len; > + rte_memcpy(rte_pktmbuf_mtod(m_new, void *), vaddr, m_new- > >data_len); > + > + if (pkt->vlan_tci) { > + m_new->vlan_tci =3D pkt->vlan_tci; > + m_new->ol_flags |=3D PKT_RX_VLAN_PKT; > + } > + > + hv->pkt_rxed =3D 1; > +} > + > +/* > + * RNDIS filter receive data, jumbo frames support > + */ > +static void > +hv_rf_receive_data_sg(struct hv_data *hv, struct rndis_msg *msg, > + struct netvsc_packet *pkt) > +{ > + struct rte_mbuf *m_new; > + struct hv_rx_queue *rxq =3D hv->rxq; > + struct rndis_packet *rndis_pkt; > + uint32_t data_offset; > + > + if (unlikely(hv->closed)) > + return; > + > + rndis_pkt =3D &msg->msg.packet; > + > + /* Remove rndis header, then pass data packet up the stack */ > + data_offset =3D RNDIS_HEADER_SIZE + rndis_pkt->data_offset; > + > + /* L2 frame length, with L2 header, not including CRC */ > + pkt->tot_data_buf_len =3D rndis_pkt->data_length; > + pkt->page_buffers[0].offset +=3D data_offset; > + /* Buffer length now L2 frame length plus trailing junk */ > + pkt->page_buffers[0].length -=3D data_offset; > + > + pkt->vlan_tci =3D 0; > + > + /* > + * Just put data into appropriate mbuf, all further work will be done > + * by the upper layer (mbuf replacement, index adjustment, etc) > + */ > + m_new =3D rxq->sw_ring[rxq->rx_tail]; > + if (++rxq->rx_tail =3D=3D rxq->nb_rx_desc) > + rxq->rx_tail =3D 0; > + > + /* > + * Copy the received packet to mbuf. > + * The copy is required since the memory pointed to by > netvsc_packet > + * cannot be reallocated > + */ > + uint8_t *vaddr =3D (uint8_t *) > + (pkt->page_buffers[0].pfn << PAGE_SHIFT) > + + pkt->page_buffers[0].offset; > + > + /* Scatter-gather emulation */ > + uint32_t carry_len =3D pkt->tot_data_buf_len; > + struct rte_mbuf *m_next; > + > + m_new->pkt_len =3D carry_len; > + m_new->nb_segs =3D (carry_len - 1) / hv->max_rx_pkt_len + 1; > + > + while (1) { > + m_new->data_len =3D MIN(carry_len, hv->max_rx_pkt_len); > + rte_memcpy(rte_pktmbuf_mtod(m_new, void *), > + vaddr, m_new->data_len); > + vaddr +=3D m_new->data_len; > + > + if (carry_len <=3D hv->max_rx_pkt_len) > + break; > + > + carry_len -=3D hv->max_rx_pkt_len; > + m_next =3D rxq->sw_ring[rxq->rx_tail]; > + if (++rxq->rx_tail =3D=3D rxq->nb_rx_desc) > + rxq->rx_tail =3D 0; > + m_new->next =3D m_next; > + m_new =3D m_next; > + } > + > + if (pkt->vlan_tci) { > + m_new->vlan_tci =3D pkt->vlan_tci; > + m_new->ol_flags |=3D PKT_RX_VLAN_PKT; > + } > + > + hv->pkt_rxed =3D 1; > +} > + > +static int > +hv_rf_send_request(struct hv_data *hv, struct rndis_request *request) > +{ > + struct netvsc_packet *packet; > + > + PMD_INIT_FUNC_TRACE(); > + /* Set up the packet to send it */ > + packet =3D &request->pkt; > + > + packet->is_data_pkt =3D 0; > + packet->tot_data_buf_len =3D request->request_msg->msg_len; > + packet->page_buf_count =3D 1; > + > + packet->page_buffers[0].pfn =3D > + (request->request_msg_memzone->phys_addr) >> > PAGE_SHIFT; > + packet->page_buffers[0].length =3D request->request_msg->msg_len; > + packet->page_buffers[0].offset =3D > + (unsigned long)request->request_msg & (PAGE_SIZE - 1); > + > + return hv_nv_on_send(hv, packet); > +} > + > +static void u8_to_u16(const char *src, int len, char *dst) > +{ > + int i; > + > + for (i =3D 0; i < len; ++i) { > + dst[2 * i] =3D src[i]; > + dst[2 * i + 1] =3D 0; > + } > +} > + > +int > +hv_rf_set_device_mac(struct hv_data *hv, uint8_t *macaddr) > +{ > + struct rndis_request *request; > + struct rndis_set_request *set_request; > + struct rndis_config_parameter_info *info; > + struct rndis_set_complete *set_complete; > + char mac_str[2*ETHER_ADDR_LEN+1]; > + wchar_t *param_value, *param_name; > + uint32_t status; > + uint32_t message_len =3D sizeof(struct rndis_config_parameter_info) > + > + 2 * MAC_STRLEN + 4 * ETHER_ADDR_LEN; > + int ret, i; > + > + request =3D hv_rndis_request(hv, REMOTE_NDIS_SET_MSG, > + RNDIS_MESSAGE_SIZE(struct rndis_set_request) + > message_len); > + if (!request) > + return -ENOMEM; > + > + set_request =3D &request->request_msg->msg.set_request; > + set_request->oid =3D RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER; > + set_request->device_vc_handle =3D 0; > + set_request->info_buffer_offset =3D sizeof(struct rndis_set_request); > + set_request->info_buffer_length =3D message_len; > + > + info =3D (struct rndis_config_parameter_info *)((ulong)set_request + > + set_request->info_buffer_offset); > + info->parameter_type =3D RNDIS_CONFIG_PARAM_TYPE_STRING; > + info->parameter_name_offset =3D > + sizeof(struct rndis_config_parameter_info); > + info->parameter_name_length =3D 2 * MAC_STRLEN; > + info->parameter_value_offset =3D > + info->parameter_name_offset + info- > >parameter_name_length; > + /* Multiply by 2 because of string representation and by 2 > + * because of utf16 representation > + */ > + info->parameter_value_length =3D 4 * ETHER_ADDR_LEN; > + param_name =3D (wchar_t *)((ulong)info + info- > >parameter_name_offset); > + param_value =3D (wchar_t *)((ulong)info + info- > >parameter_value_offset); > + > + u8_to_u16(MAC_PARAM_STR, MAC_STRLEN, (char *)param_name); > + for (i =3D 0; i < ETHER_ADDR_LEN; ++i) { > + mac_str[2*i] =3D high(macaddr[i]); > + mac_str[2*i+1] =3D low(macaddr[i]); > + } > + > + u8_to_u16((const char *)mac_str, 2 * ETHER_ADDR_LEN, (char > *)param_value); > + > + ret =3D hv_rf_send_request(hv, request); > + if (ret) > + goto cleanup; > + > + request->response_msg.msg.set_complete.status =3D 0xFFFF; > + hv_nv_complete_request(hv, request); > + set_complete =3D &request->response_msg.msg.set_complete; > + if (set_complete->status =3D=3D 0xFFFF) { > + /* Host is not responding, we can't free request in this case > */ > + ret =3D -1; > + PMD_PERROR_LOG(hv, DBG_LOAD, "Host is not > responding"); > + goto exit; > + } > + /* Response received, check status */ > + status =3D set_complete->status; > + if (status) { > + /* Bad response status, return error */ > + PMD_PERROR_LOG(hv, DBG_LOAD, "set_complete->status > =3D %u\n", status); > + ret =3D -EINVAL; > + } > + > +cleanup: > + rte_free(request); > +exit: > + return ret; > +} > + > +/* > + * RNDIS filter on receive > + */ > +static int > +hv_rf_on_receive(struct hv_data *hv, struct netvsc_packet *pkt) > +{ > + struct rndis_msg rndis_mesg; > + struct rndis_msg *rndis_hdr; > + > + /* Shift virtual page number to form virtual page address */ > + rndis_hdr =3D (struct rndis_msg *)(pkt->page_buffers[0].pfn << > PAGE_SHIFT); > + > + rndis_hdr =3D (void *)((unsigned long)rndis_hdr > + + pkt->page_buffers[0].offset); > + > + /* > + * Make sure we got a valid rndis message > + * Fixme: There seems to be a bug in set completion msg where > + * its msg_len is 16 bytes but the byte_count field in the > + * xfer page range shows 52 bytes > + */ > + if (unlikely(pkt->tot_data_buf_len !=3D rndis_hdr->msg_len)) { > + ++hv->stats.ierrors; > + PMD_PERROR_LOG(hv, DBG_RX, > + "invalid rndis message? (expected %u " > + "bytes got %u)... dropping this message", > + rndis_hdr->msg_len, pkt->tot_data_buf_len); > + return -1; > + } > + > + rte_memcpy(&rndis_mesg, rndis_hdr, > + (rndis_hdr->msg_len > sizeof(struct rndis_msg)) ? > + sizeof(struct rndis_msg) : rndis_hdr->msg_len); > + > + switch (rndis_mesg.ndis_msg_type) { > + > + /* data message */ > + case REMOTE_NDIS_PACKET_MSG: > + hv->receive_callback(hv, &rndis_mesg, pkt); > + break; > + /* completion messages */ > + case REMOTE_NDIS_INITIALIZE_CMPLT: > + case REMOTE_NDIS_QUERY_CMPLT: > + case REMOTE_NDIS_SET_CMPLT: > + case REMOTE_NDIS_RESET_CMPLT: > + case REMOTE_NDIS_KEEPALIVE_CMPLT: > + hv_rf_receive_response(hv, &rndis_mesg); > + break; > + /* notification message */ > + case REMOTE_NDIS_INDICATE_STATUS_MSG: > + hv_rf_receive_indicate_status(hv, &rndis_mesg); > + break; > + default: > + PMD_PERROR_LOG(hv, DBG_RX, "hv_rf_on_receive(): > Unknown msg_type 0x%x", > + rndis_mesg.ndis_msg_type); > + break; > + } > + > + return 0; > +} > + > +/* > + * RNDIS filter on send > + */ > +int > +hv_rf_on_send(struct hv_data *hv, struct netvsc_packet *pkt) > +{ > + struct rndis_msg *rndis_mesg; > + struct rndis_packet *rndis_pkt; > + uint32_t rndis_msg_size; > + > + /* Add the rndis header */ > + rndis_mesg =3D (struct rndis_msg *)pkt->extension; > + > + memset(rndis_mesg, 0, sizeof(struct rndis_msg)); > + > + rndis_msg_size =3D RNDIS_MESSAGE_SIZE(struct rndis_packet); > + > + rndis_mesg->ndis_msg_type =3D REMOTE_NDIS_PACKET_MSG; > + rndis_mesg->msg_len =3D pkt->tot_data_buf_len + rndis_msg_size; > + > + rndis_pkt =3D &rndis_mesg->msg.packet; > + rndis_pkt->data_offset =3D sizeof(struct rndis_packet); > + rndis_pkt->data_length =3D pkt->tot_data_buf_len; > + > + pkt->is_data_pkt =3D 1; > + > + /* > + * Invoke netvsc send. If return status is bad, the caller now > + * resets the context pointers before retrying. > + */ > + return hv_nv_on_send(hv, pkt); > +} > + > +static int > +hv_rf_init_device(struct hv_data *hv) > +{ > + struct rndis_request *request; > + struct rndis_initialize_request *init; > + struct rndis_initialize_complete *init_complete; > + uint32_t status; > + int ret; > + > + PMD_INIT_FUNC_TRACE(); > + > + request =3D hv_rndis_request(hv, REMOTE_NDIS_INITIALIZE_MSG, > + RNDIS_MESSAGE_SIZE(struct rndis_initialize_request)); > + if (!request) { > + ret =3D -1; > + goto cleanup; > + } > + > + /* Set up the rndis set */ > + init =3D &request->request_msg->msg.init_request; > + init->major_version =3D RNDIS_MAJOR_VERSION; > + init->minor_version =3D RNDIS_MINOR_VERSION; > + /* > + * Per the RNDIS document, this should be set to the max MTU > + * plus the header size. However, 2048 works fine, so leaving > + * it as is. > + */ > + init->max_xfer_size =3D 2048; > + > + hv->rndis_dev_state =3D RNDIS_DEV_INITIALIZING; > + > + ret =3D hv_rf_send_request(hv, request); > + if (ret !=3D 0) { > + hv->rndis_dev_state =3D RNDIS_DEV_UNINITIALIZED; > + goto cleanup; > + } > + > + /* Putting -1 here to ensure that HyperV really answered us */ > + request->response_msg.msg.init_complete.status =3D -1; > + hv_nv_complete_request(hv, request); > + > + init_complete =3D &request->response_msg.msg.init_complete; > + status =3D init_complete->status; > + if (status =3D=3D 0) { > + PMD_PINFO_LOG(hv, DBG_LOAD, "Remote NDIS device is > initialized"); > + hv->rndis_dev_state =3D RNDIS_DEV_INITIALIZED; > + ret =3D 0; > + } else { > + PMD_PINFO_LOG(hv, DBG_LOAD, "Remote NDIS device left > uninitialized"); > + hv->rndis_dev_state =3D RNDIS_DEV_UNINITIALIZED; > + ret =3D -1; > + } > + > +cleanup: > + rte_free(request); > + > + return ret; > +} > + > +/* > + * RNDIS filter query device > + */ > +static int > +hv_rf_query_device(struct hv_data *hv, uint32_t oid, void *result, > + uint32_t result_size) > +{ > + struct rndis_request *request; > + struct rndis_query_request *query; > + struct rndis_query_complete *query_complete; > + int ret =3D 0; > + > + PMD_INIT_FUNC_TRACE(); > + > + request =3D hv_rndis_request(hv, REMOTE_NDIS_QUERY_MSG, > + RNDIS_MESSAGE_SIZE(struct rndis_query_request)); > + if (request =3D=3D NULL) { > + ret =3D -1; > + goto cleanup; > + } > + > + /* Set up the rndis query */ > + query =3D &request->request_msg->msg.query_request; > + query->oid =3D oid; > + query->info_buffer_offset =3D sizeof(struct rndis_query_request); > + query->info_buffer_length =3D 0; > + query->device_vc_handle =3D 0; > + > + ret =3D hv_rf_send_request(hv, request); > + if (ret !=3D 0) { > + PMD_PERROR_LOG(hv, DBG_TX, "RNDISFILTER request > failed to Send!"); > + goto cleanup; > + } > + > + hv_nv_complete_request(hv, request); > + > + /* Copy the response back */ > + query_complete =3D &request->response_msg.msg.query_complete; > + > + if (query_complete->info_buffer_length > result_size) { > + ret =3D -EINVAL; > + goto cleanup; > + } > + > + rte_memcpy(result, (void *)((unsigned long)query_complete + > + query_complete->info_buffer_offset), > + query_complete->info_buffer_length); > + > +cleanup: > + rte_free(request); > + > + return ret; > +} > + > +/* > + * RNDIS filter query device MAC address > + */ > +static inline int > +hv_rf_query_device_mac(struct hv_data *hv) > +{ > + uint32_t size =3D HW_MACADDR_LEN; > + > + int ret =3D hv_rf_query_device(hv, > RNDIS_OID_802_3_PERMANENT_ADDRESS, > + &hv->hw_mac_addr, size); > + PMD_PDEBUG_LOG(hv, DBG_TX, "MAC: > %02x:%02x:%02x:%02x:%02x:%02x, ret =3D %d", > + hv->hw_mac_addr[0], hv->hw_mac_addr[1], hv- > >hw_mac_addr[2], > + hv->hw_mac_addr[3], hv->hw_mac_addr[4], hv- > >hw_mac_addr[5], > + ret); > + return ret; > +} > + > +/* > + * RNDIS filter query device link status > + */ > +static inline int > +hv_rf_query_device_link_status(struct hv_data *hv) > +{ > + uint32_t size =3D sizeof(uint32_t); > + /* Set all bits to 1, it's to ensure that the response is actual */ > + uint32_t status =3D -1; > + > + int ret =3D hv_rf_query_device(hv, > RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, > + &status, size); > + hv->link_status =3D status ? 0 : 1; > + PMD_PDEBUG_LOG(hv, DBG_TX, "Link Status: %s", > + hv->link_status ? "Up" : "Down"); > + return ret; > +} > + > +int > +hv_rf_on_device_add(struct hv_data *hv) > +{ > + int ret; > + > + PMD_INIT_FUNC_TRACE(); > + > + hv->closed =3D 0; > + hv->rb_data_size =3D hv->rb_size - sizeof(struct > hv_vmbus_ring_buffer); > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "hv->rb_data_size =3D %u", hv- > >rb_data_size); > + > + if (unlikely(hv->in->interrupt_mask =3D=3D 0)) { > + PMD_PINFO_LOG(hv, DBG_LOAD, "Disabling interrupts from > host"); > + hv->in->interrupt_mask =3D 1; > + rte_mb(); > + } > + > + hv->netvsc_packet =3D rte_zmalloc("", sizeof(struct netvsc_packet), > + RTE_CACHE_LINE_SIZE); > + if (hv->netvsc_packet =3D=3D NULL) > + return -ENOMEM; > + hv->netvsc_packet->is_data_pkt =3D 1; > + > + hv->rx_comp_msg =3D rte_zmalloc("", sizeof(struct nvsp_msg), > + RTE_CACHE_LINE_SIZE); > + if (hv->rx_comp_msg =3D=3D NULL) > + return -ENOMEM; > + > + hv->rx_comp_msg->msg_type =3D > nvsp_msg_1_type_send_rndis_pkt_complete; > + hv->rx_comp_msg->msgs.send_rndis_pkt_complete.status =3D > + nvsp_status_success; > + > + memset(&hv->stats, 0, sizeof(struct hv_stats)); > + > + hv->receive_callback =3D hv_rf_receive_data; > + > + /* It's for completion of requests which were sent from kernel-space > part */ > + hv_nv_complete_request(hv, NULL); > + hv_nv_complete_request(hv, NULL); > + > + hv->rndis_dev_state =3D RNDIS_DEV_UNINITIALIZED; > + > + /* Send the rndis initialization message */ > + ret =3D hv_rf_init_device(hv); > + if (ret !=3D 0) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "rndis init failed!"); > + hv_rf_on_device_remove(hv); > + return ret; > + } > + > + /* Get the mac address */ > + ret =3D hv_rf_query_device_mac(hv); > + if (ret !=3D 0) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "rndis query mac > failed!"); > + hv_rf_on_device_remove(hv); > + return ret; > + } > + > + return ret; > +} > + > +#define HALT_COMPLETION_WAIT_COUNT 25 > + > +/* > + * RNDIS filter halt device > + */ > +static int > +hv_rf_halt_device(struct hv_data *hv) > +{ > + struct rndis_request *request; > + struct rndis_halt_request *halt; > + int i, ret; > + > + PMD_INIT_FUNC_TRACE(); > + > + /* Attempt to do a rndis device halt */ > + request =3D hv_rndis_request(hv, REMOTE_NDIS_HALT_MSG, > + RNDIS_MESSAGE_SIZE(struct rndis_halt_request)); > + if (!request) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "Unable to create > RNDIS_HALT request"); > + return -1; > + } > + > + /* initialize "poor man's semaphore" */ > + hv->hlt_req_sent =3D 0; > + > + /* Set up the rndis set */ > + halt =3D &request->request_msg->msg.halt_request; > + hv->new_request_id++; > + halt->request_id =3D hv->new_request_id; > + > + ret =3D hv_rf_send_request(hv, request); > + if (ret) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "Failed to send > RNDIS_HALT request: %d", > + ret); > + return ret; > + } > + > + /* > + * Wait for halt response from halt callback. We must wait for > + * the transaction response before freeing the request and other > + * resources. > + */ > + for (i =3D HALT_COMPLETION_WAIT_COUNT; i > 0; i--) { > + hv_nv_complete_request(hv, request); > + if (hv->hlt_req_sent !=3D 0) { > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "Completed > HALT request at %d try", > + HALT_COMPLETION_WAIT_COUNT - i > + 1); > + break; > + } > + } > + hv->hlt_req_sent =3D 0; > + if (i =3D=3D 0) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "RNDIS_HALT request > was not completed!"); > + rte_free(request); > + return -1; > + } > + > + hv->rndis_dev_state =3D RNDIS_DEV_UNINITIALIZED; > + > + rte_free(request); > + > + return 0; > +} > + > +#define HV_TX_DRAIN_TRIES 50 > +static inline int > +hyperv_tx_drain(struct hv_data *hv) > +{ > + int i =3D HV_TX_DRAIN_TRIES; > + > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "Waiting for TXs to be > completed..."); > + while (hv->num_outstanding_sends > 0 && --i) { > + hv_nv_complete_request(hv, NULL); > + rte_delay_ms(100); > + } > + > + return hv->num_outstanding_sends; > +} > + > +/* > + * RNDIS filter on device remove > + */ > +int > +hv_rf_on_device_remove(struct hv_data *hv) > +{ > + int ret; > + > + PMD_INIT_FUNC_TRACE(); > + hv->closed =3D 1; > + if (hyperv_tx_drain(hv) > 0) { > + /* Hypervisor is not responding, exit with error here */ > + PMD_PWARN_LOG(hv, DBG_LOAD, "Can't drain TX queue: > no response"); > + return -EAGAIN; > + } > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "TX queue is empty, can halt > the device"); > + > + /* Halt and release the rndis device */ > + hv->hlt_req_pending =3D 1; > + ret =3D hv_rf_halt_device(hv); > + hv->hlt_req_pending =3D 0; > + > + rte_free(hv->netvsc_packet); > + > + return ret; > +} > + > +/* > + * RNDIS filter set packet filter > + * Sends an rndis request with the new filter, then waits for a response > + * from the host. > + * Returns zero on success, non-zero on failure. > + */ > +static int > +hv_rf_set_packet_filter(struct hv_data *hv, uint32_t new_filter) > +{ > + struct rndis_request *request; > + struct rndis_set_request *set; > + struct rndis_set_complete *set_complete; > + uint32_t status; > + int ret; > + > + PMD_INIT_FUNC_TRACE(); > + > + request =3D hv_rndis_request(hv, REMOTE_NDIS_SET_MSG, > + RNDIS_MESSAGE_SIZE(struct rndis_set_request) + > sizeof(uint32_t)); > + if (!request) { > + ret =3D -1; > + goto cleanup; > + } > + > + /* Set up the rndis set */ > + set =3D &request->request_msg->msg.set_request; > + set->oid =3D RNDIS_OID_GEN_CURRENT_PACKET_FILTER; > + set->info_buffer_length =3D sizeof(uint32_t); > + set->info_buffer_offset =3D sizeof(struct rndis_set_request); > + > + rte_memcpy((void *)((unsigned long)set + sizeof(struct > rndis_set_request)), > + &new_filter, sizeof(uint32_t)); > + > + ret =3D hv_rf_send_request(hv, request); > + if (ret) > + goto cleanup; > + > + /* > + * Wait for the response from the host. > + */ > + request->response_msg.msg.set_complete.status =3D 0xFFFF; > + hv_nv_complete_request(hv, request); > + > + set_complete =3D &request->response_msg.msg.set_complete; > + if (set_complete->status =3D=3D 0xFFFF) { > + /* Host is not responding, we can't free request in this case > */ > + ret =3D -1; > + goto exit; > + } > + /* Response received, check status */ > + status =3D set_complete->status; > + if (status) > + /* Bad response status, return error */ > + ret =3D -2; > + > +cleanup: > + rte_free(request); > +exit: > + return ret; > +} > + > +/* > + * RNDIS filter open device > + */ > +int > +hv_rf_on_open(struct hv_data *hv) > +{ > + int ret; > + > + if (hv->closed) > + return 0; > + > + if (hv->jumbo_frame_support) > + hv->receive_callback =3D hv_rf_receive_data_sg; > + > + ret =3D hyperv_set_rx_mode(hv, 1, 0); > + if (!ret) { > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "RNDIS device > opened"); > + hv->rndis_dev_state =3D RNDIS_DEV_DATAINITIALIZED; > + } else > + PMD_PERROR_LOG(hv, DBG_LOAD, "RNDIS device is left > unopened"); > + > + return ret; > +} > + > +/* > + * RNDIS filter on close > + */ > +int > +hv_rf_on_close(struct hv_data *hv) > +{ > + int ret; > + > + PMD_INIT_FUNC_TRACE(); > + > + if (hv->closed) > + return 0; > + > + if (hv->rndis_dev_state !=3D RNDIS_DEV_DATAINITIALIZED) { > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "RNDIS device state > should be" > + " RNDIS_DEV_DATAINITIALIZED, but now it is > %u", > + hv->rndis_dev_state); > + return 0; > + } > + > + ret =3D hv_rf_set_packet_filter(hv, 0); > + if (!ret) { > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "RNDIS device closed"); > + hv->rndis_dev_state =3D RNDIS_DEV_INITIALIZED; > + } else > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "RNDIS device is left > unclosed"); > + > + return ret; > +} > + > +/* > + * RX Flow > + */ > +int > +hyperv_get_buffer(struct hv_data *hv, void *buffer, uint32_t bufferlen) > +{ > + uint32_t bytes_rxed; > + uint64_t request_id; > + struct hv_vm_packet_descriptor *desc; > + > + int ret =3D hv_vmbus_channel_recv_packet_raw(hv, buffer, bufferlen, > + &bytes_rxed, &request_id, 1); > + if (likely(ret =3D=3D 0)) { > + if (bytes_rxed) { > + desc =3D (struct hv_vm_packet_descriptor *)buffer; > + > + if (likely(desc->type =3D=3D > + > HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES)) { > + hv->pkt_rxed =3D 0; > + hv_nv_on_receive(hv, desc); > + return hv->pkt_rxed; > + } > + } > + } > + > + return 0; > +} > + > +/* > + * TX completions handler > + */ > +void > +hyperv_scan_comps(struct hv_data *hv, int allow_rx_drop) > +{ > + uint32_t bytes_rxed; > + uint64_t request_id; > + > + while (1) { > + int ret =3D hv_vmbus_channel_recv_packet_raw(hv, hv->desc, > PAGE_SIZE, > + &bytes_rxed, &request_id, 2 | allow_rx_drop); > + > + if (ret !=3D 0 || !bytes_rxed) > + break; > + > + if (likely(hv->desc->type =3D=3D > HV_VMBUS_PACKET_TYPE_COMPLETION)) > + hv_nv_on_send_completion(hv, hv->desc); > + } > +} > + > +/* > + * Get link status > + */ > +uint8_t > +hyperv_get_link_status(struct hv_data *hv) > +{ > + if (hv_rf_query_device_link_status(hv)) > + return 2; > + return hv->link_status; > +} > + > +/* > + * Set/Reset RX mode > + */ > +int > +hyperv_set_rx_mode(struct hv_data *hv, uint8_t promisc, uint8_t mcast) > +{ > + PMD_INIT_FUNC_TRACE(); > + > + if (!promisc) { > + return hv_rf_set_packet_filter(hv, > + NDIS_PACKET_TYPE_BROADCAST | > + (mcast ? > NDIS_PACKET_TYPE_ALL_MULTICAST : 0) | > + NDIS_PACKET_TYPE_DIRECTED); > + } > + > + return hv_rf_set_packet_filter(hv, > NDIS_PACKET_TYPE_PROMISCUOUS); > +} > diff --git a/lib/librte_pmd_hyperv/hyperv_drv.h > b/lib/librte_pmd_hyperv/hyperv_drv.h > new file mode 100644 > index 0000000..22acad5 > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv_drv.h > @@ -0,0 +1,558 @@ > +/*- > + * Copyright (c) 2009-2012 Microsoft Corp. > + * Copyright (c) 2010-2012 Citrix Inc. > + * Copyright (c) 2012 NetApp Inc. > + * Copyright (c) 2013-2015 Brocade Communications Systems, Inc. > + * 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 th= e > + * documentation and/or other materials provided with the distributio= n. > + * > + * 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. > + * > + */ > + > +#ifndef _HYPERV_DRV_H_ > +#define _HYPERV_DRV_H_ > + > +/* > + * Definitions from hyperv.h > + */ > +#define HW_MACADDR_LEN 6 > +#define HV_MAX_PAGE_BUFFER_COUNT 19 > + > +#define HV_ALIGN_UP(value, align) \ > + (((value) & (align-1)) ? \ > + (((value) + (align-1)) & ~(align-1)) : (value)) > + > +/* > + * Connection identifier type > + */ > +union hv_vmbus_connection_id { > + uint32_t as_uint32_t; > + struct { > + uint32_t id:24; > + uint32_t reserved:8; > + } u; > + > +} __attribute__((packed)); > + > +union hv_vmbus_monitor_trigger_state { > + uint32_t as_uint32_t; > + struct { > + uint32_t group_enable:4; > + uint32_t rsvd_z:28; > + } u; > +}; > + > +union hv_vmbus_monitor_trigger_group { > + uint64_t as_uint64_t; > + struct { > + uint32_t pending; > + uint32_t armed; > + } u; > +}; > + > +struct hv_vmbus_monitor_parameter { > + union hv_vmbus_connection_id connection_id; > + uint16_t flag_number; > + uint16_t rsvd_z; > +}; > + > +/* > + * hv_vmbus_monitor_page Layout > + * ------------------------------------------------------ > + * | 0 | trigger_state (4 bytes) | Rsvd1 (4 bytes) | > + * | 8 | trigger_group[0] | > + * | 10 | trigger_group[1] | > + * | 18 | trigger_group[2] | > + * | 20 | trigger_group[3] | > + * | 28 | Rsvd2[0] | > + * | 30 | Rsvd2[1] | > + * | 38 | Rsvd2[2] | > + * | 40 | next_check_time[0][0] | next_check_time[0][1] | > + * | ... | > + * | 240 | latency[0][0..3] | > + * | 340 | Rsvz3[0] | > + * | 440 | parameter[0][0] | > + * | 448 | parameter[0][1] | > + * | ... | > + * | 840 | Rsvd4[0] | > + * ------------------------------------------------------ > + */ > + > +struct hv_vmbus_monitor_page { > + union hv_vmbus_monitor_trigger_state trigger_state; > + uint32_t rsvd_z1; > + > + union hv_vmbus_monitor_trigger_group trigger_group[4]; > + uint64_t rsvd_z2[3]; > + > + int32_t next_check_time[4][32]; > + > + uint16_t latency[4][32]; > + uint64_t rsvd_z3[32]; > + > + struct hv_vmbus_monitor_parameter parameter[4][32]; > + > + uint8_t rsvd_z4[1984]; > +}; > + > +enum hv_vmbus_packet_type { > + HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES > =3D 0x7, > + HV_VMBUS_PACKET_TYPE_DATA_USING_GPA_DIRECT > =3D 0x9, > + HV_VMBUS_PACKET_TYPE_COMPLETION > =3D 0xb, > +}; > + > +#define HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED 1 > + > +struct hv_vm_packet_descriptor { > + uint16_t type; > + uint16_t data_offset8; > + uint16_t length8; > + uint16_t flags; > + uint64_t transaction_id; > +} __attribute__((packed)); > + > +struct hv_vm_transfer_page { > + uint32_t byte_count; > + uint32_t byte_offset; > +} __attribute__((packed)); > + > +struct hv_vm_transfer_page_packet_header { > + struct hv_vm_packet_descriptor d; > + uint16_t transfer_page_set_id; > + uint8_t sender_owns_set; > + uint8_t reserved; > + uint32_t range_count; > + struct hv_vm_transfer_page ranges[1]; > +} __attribute__((packed)); > + > +struct hv_vmbus_ring_buffer { > + volatile uint32_t write_index; > + volatile uint32_t read_index; > + /* > + * NOTE: The interrupt_mask field is used only for channels, but > + * vmbus connection also uses this data structure > + */ > + volatile uint32_t interrupt_mask; > + /* pad it to PAGE_SIZE so that data starts on a page */ > + uint8_t reserved[4084]; > + > + /* > + * WARNING: Ring data starts here + ring_data_start_offset > + * !!! DO NOT place any fields below this !!! > + */ > + uint8_t buffer[0]; /* doubles as interrupt mask > */ > +} __attribute__((packed)); > + > +struct hv_vmbus_page_buffer { > + uint32_t length; > + uint32_t offset; > + uint64_t pfn; > +} __attribute__((packed)); > + > +/* > + * Definitions from hv_vmbus_priv.h > + */ > +struct hv_vmbus_sg_buffer_list { > + void *data; > + uint32_t length; > +}; > + > +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; > + struct hv_vmbus_page_buffer > range[HV_MAX_PAGE_BUFFER_COUNT]; > +} __attribute__((packed)); > + > +/* > + * Definitions from hv_net_vsc.h > + */ > +#define NETVSC_PACKET_MAXPAGE 16 > +#define NETVSC_PACKET_SIZE 256 > + > +/* > + * This message is used by both the VSP and the VSC to complete > + * a RNDIS message to the opposite channel endpoint. At this > + * point, the initiator of this message cannot use any resources > + * associated with the original RNDIS packet. > + */ > +enum nvsp_status_ { > + nvsp_status_none =3D 0, > + nvsp_status_success, > + nvsp_status_failure, > +}; > + > +struct nvsp_1_msg_send_rndis_pkt_complete { > + uint32_t status; > +} __attribute__((packed)); > + > +enum nvsp_msg_type { > + /* > + * Version 1 Messages > + */ > + nvsp_msg_1_type_send_ndis_vers =3D 100, > + > + nvsp_msg_1_type_send_rx_buf, > + nvsp_msg_1_type_send_rx_buf_complete, > + nvsp_msg_1_type_revoke_rx_buf, > + > + nvsp_msg_1_type_send_send_buf, > + nvsp_msg_1_type_send_send_buf_complete, > + nvsp_msg_1_type_revoke_send_buf, > + > + nvsp_msg_1_type_send_rndis_pkt, > + nvsp_msg_1_type_send_rndis_pkt_complete, > +}; > + > +struct nvsp_1_msg_send_rndis_pkt { > + /* > + * This field is specified by RNDIS. They assume there's > + * two different channels of communication. However, > + * the Network VSP only has one. Therefore, the channel > + * travels with the RNDIS packet. > + */ > + uint32_t chan_type; > + > + /* > + * This field is used to send part or all of the data > + * through a send buffer. This value specifies an > + * index into the send buffer. If the index is > + * 0xFFFFFFFF, then the send buffer is not being used > + * and all of the data was sent through other VMBus > + * mechanisms. > + */ > + uint32_t send_buf_section_idx; > + uint32_t send_buf_section_size; > +} __attribute__((packed)); > + > +/* > + * ALL Messages > + */ > +struct nvsp_msg { > + uint32_t msg_type; > + union { > + struct nvsp_1_msg_send_rndis_pkt send_rndis_pkt; > + struct nvsp_1_msg_send_rndis_pkt_complete > send_rndis_pkt_complete; > + /* size is set like in linux kernel driver */ > + uint8_t raw[24]; > + } msgs; > +} __attribute__((packed)); > + > +#define NETVSC_RECEIVE_BUFFER_ID 0xcafe > + > +struct netvsc_packet { > + uint8_t is_data_pkt; /* One byte */ > + uint8_t ext_pages; > + uint16_t vlan_tci; > + > + void *extension; > + uint64_t extension_phys_addr; > + uint32_t tot_data_buf_len; > + uint32_t page_buf_count; > + struct hv_vmbus_page_buffer > page_buffers[NETVSC_PACKET_MAXPAGE]; > +}; > + > +/* > + * Definitions from hv_rndis.h > + */ > +#define RNDIS_MAJOR_VERSION 0x00000001 > +#define RNDIS_MINOR_VERSION 0x00000000 > + > +#define STATUS_BUFFER_OVERFLOW (0x80000005L) > + > +/* > + * Remote NDIS message types > + */ > +#define REMOTE_NDIS_PACKET_MSG 0x00000001 > +#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002 > +#define REMOTE_NDIS_HALT_MSG 0x00000003 > +#define REMOTE_NDIS_QUERY_MSG 0x00000004 > +#define REMOTE_NDIS_SET_MSG 0x00000005 > +#define REMOTE_NDIS_RESET_MSG 0x00000006 > +#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007 > +#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008 > +/* > + * Remote NDIS message completion types > + */ > +#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002 > +#define REMOTE_NDIS_QUERY_CMPLT 0x80000004 > +#define REMOTE_NDIS_SET_CMPLT 0x80000005 > +#define REMOTE_NDIS_RESET_CMPLT 0x80000006 > +#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008 > + > +#define RNDIS_OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 > +#define RNDIS_OID_GEN_CURRENT_PACKET_FILTER 0x0001010E > +#define RNDIS_OID_802_3_PERMANENT_ADDRESS 0x01010101 > +#define RNDIS_OID_802_3_CURRENT_ADDRESS 0x01010102 > +#define RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B > + > +#define RNDIS_CONFIG_PARAM_TYPE_STRING 2 > +/* extended info after the RNDIS request message */ > +#define RNDIS_EXT_LEN 100 > +/* > + * Packet extension field contents associated with a Data message. > + */ > +struct rndis_per_packet_info { > + uint32_t size; > + uint32_t type; > + uint32_t per_packet_info_offset; > +}; > + > +#define ieee_8021q_info 6 > + > +struct ndis_8021q_info { > + union { > + struct { > + uint32_t user_pri:3; /* User Priority */ > + uint32_t cfi:1; /* Canonical Format ID */ > + uint32_t vlan_id:12; > + uint32_t reserved:16; > + } s1; > + uint32_t value; > + } u1; > +}; > + > +/* Format of Information buffer passed in a SetRequest for the OID */ > +/* OID_GEN_RNDIS_CONFIG_PARAMETER. */ > +struct rndis_config_parameter_info { > + uint32_t parameter_name_offset; > + uint32_t parameter_name_length; > + uint32_t parameter_type; > + uint32_t parameter_value_offset; > + uint32_t parameter_value_length; > +}; > + > +/* > + * NdisInitialize message > + */ > +struct rndis_initialize_request { > + /* RNDIS request ID */ > + uint32_t request_id; > + uint32_t major_version; > + uint32_t minor_version; > + uint32_t max_xfer_size; > +}; > + > +/* > + * Response to NdisInitialize > + */ > +struct rndis_initialize_complete { > + /* RNDIS request ID */ > + uint32_t request_id; > + /* RNDIS status */ > + uint32_t status; > + uint32_t major_version; > + uint32_t minor_version; > + uint32_t device_flags; > + /* RNDIS medium */ > + uint32_t medium; > + uint32_t max_pkts_per_msg; > + uint32_t max_xfer_size; > + uint32_t pkt_align_factor; > + uint32_t af_list_offset; > + uint32_t af_list_size; > +}; > + > +/* > + * NdisSetRequest message > + */ > +struct rndis_set_request { > + /* RNDIS request ID */ > + uint32_t request_id; > + /* RNDIS OID */ > + uint32_t oid; > + uint32_t info_buffer_length; > + uint32_t info_buffer_offset; > + /* RNDIS handle */ > + uint32_t device_vc_handle; > +}; > + > +/* > + * Response to NdisSetRequest > + */ > +struct rndis_set_complete { > + /* RNDIS request ID */ > + uint32_t request_id; > + /* RNDIS status */ > + uint32_t status; > +}; > + > +/* > + * NdisQueryRequest message > + */ > +struct rndis_query_request { > + /* RNDIS request ID */ > + uint32_t request_id; > + /* RNDIS OID */ > + uint32_t oid; > + uint32_t info_buffer_length; > + uint32_t info_buffer_offset; > + /* RNDIS handle */ > + uint32_t device_vc_handle; > +}; > + > +/* > + * Response to NdisQueryRequest > + */ > +struct rndis_query_complete { > + /* RNDIS request ID */ > + uint32_t request_id; > + /* RNDIS status */ > + uint32_t status; > + uint32_t info_buffer_length; > + uint32_t info_buffer_offset; > +}; > + > +/* > + * Data message. All offset fields contain byte offsets from the beginni= ng > + * of the rndis_packet structure. All length fields are in bytes. > + * VcHandle is set to 0 for connectionless data, otherwise it > + * contains the VC handle. > + */ > +struct rndis_packet { > + uint32_t data_offset; > + uint32_t data_length; > + uint32_t oob_data_offset; > + uint32_t oob_data_length; > + uint32_t num_oob_data_elements; > + uint32_t per_pkt_info_offset; > + uint32_t per_pkt_info_length; > + /* RNDIS handle */ > + uint32_t vc_handle; > + uint32_t reserved; > +}; > + > +/* > + * NdisHalt message > + */ > +struct rndis_halt_request { > + /* RNDIS request ID */ > + uint32_t request_id; > +}; > + > +/* > + * NdisMIndicateStatus message > + */ > +struct rndis_indicate_status { > + /* RNDIS status */ > + uint32_t status; > + uint32_t status_buf_length; > + uint32_t status_buf_offset; > +}; > + > +#define RNDIS_STATUS_MEDIA_CONNECT (0x4001000BL) > +#define RNDIS_STATUS_MEDIA_DISCONNECT (0x4001000CL) > +#define RNDIS_STATUS_INVALID_DATA (0xC0010015L) > + > +/* > + * union with all of the RNDIS messages > + */ > +union rndis_msg_container { > + struct rndis_initialize_request init_request; > + struct rndis_initialize_complete init_complete; > + struct rndis_set_request set_request; > + struct rndis_set_complete set_complete; > + struct rndis_query_request query_request; > + struct rndis_query_complete query_complete; > + struct rndis_packet packet; > + struct rndis_halt_request halt_request; > + struct rndis_indicate_status indicate_status; > +#if 0 > + rndis_keepalive_request keepalive_request; > + rndis_reset_request reset_request; > + rndis_reset_complete reset_complete; > + rndis_keepalive_complete keepalive_complete; > + rcondis_mp_create_vc co_miniport_create_vc; > + rcondis_mp_delete_vc co_miniport_delete_vc; > + rcondis_indicate_status co_miniport_status; > + rcondis_mp_activate_vc_request co_miniport_activate_vc; > + rcondis_mp_deactivate_vc_request co_miniport_deactivate_vc; > + rcondis_mp_create_vc_complete > co_miniport_create_vc_complete; > + rcondis_mp_delete_vc_complete > co_miniport_delete_vc_complete; > + rcondis_mp_activate_vc_complete > co_miniport_activate_vc_complete; > + rcondis_mp_deactivate_vc_complete > co_miniport_deactivate_vc_complete; > +#endif > + uint32_t packet_ex[16]; /* to pad the union size */ > +}; > + > +struct rndis_msg { > + uint32_t ndis_msg_type; > + > + /* > + * Total length of this message, from the beginning > + * of the rndis_msg struct, in bytes. > + */ > + uint32_t msg_len; > + > + /* Actual message */ > + union rndis_msg_container msg; > +}; > + > +#define RNDIS_HEADER_SIZE (sizeof(struct rndis_msg) - sizeof(union > rndis_msg_container)) > + > +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 > +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 > +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 > +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 > +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 > +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 > + > +/* > + * get the size of an RNDIS message. Pass in the message type, > + * rndis_set_request, rndis_packet for example > + */ > +#define RNDIS_MESSAGE_SIZE(message) \ > + (sizeof(message) + (sizeof(struct rndis_msg) - sizeof(union > rndis_msg_container))) > + > + > +/* > + * Definitions from hv_rndis_filter.h > + */ > +enum { > + RNDIS_DEV_UNINITIALIZED =3D 0, > + RNDIS_DEV_INITIALIZING, > + RNDIS_DEV_INITIALIZED, > + RNDIS_DEV_DATAINITIALIZED, > +}; > + > +struct rndis_request { > + /* assumed a fixed size response here. */ > + struct rndis_msg response_msg; > + > + /* Simplify allocation by having a netvsc packet inline */ > + struct netvsc_packet pkt; > + /* set additional buffer since packet can cross page boundary */ > + struct hv_vmbus_page_buffer buffer; > + /* assumed a fixed size request here. */ > + struct rndis_msg *request_msg; > + const struct rte_memzone *request_msg_memzone; > +}; > + > +struct rndis_filter_packet { > + struct rndis_msg message; > +}; > + > +#endif /* _HYPERV_DRV_H_ */ > diff --git a/lib/librte_pmd_hyperv/hyperv_ethdev.c > b/lib/librte_pmd_hyperv/hyperv_ethdev.c > new file mode 100644 > index 0000000..7b909db > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv_ethdev.c > @@ -0,0 +1,332 @@ > +/*- > + * Copyright (c) 2013-2015 Brocade Communications Systems, Inc. > + * All rights reserved. > + */ > + > +#include > +#include > +#include "hyperv.h" > + > +static struct rte_vmbus_id vmbus_id_hyperv_map[] =3D { > + { > + .device_id =3D 0x0, > + }, > +}; > + > +static void > +hyperv_dev_info_get(__rte_unused struct rte_eth_dev *dev, > + struct rte_eth_dev_info *dev_info) > +{ > + PMD_INIT_FUNC_TRACE(); > + dev_info->max_rx_queues =3D HV_MAX_RX_QUEUES; > + dev_info->max_tx_queues =3D HV_MAX_TX_QUEUES; > + dev_info->min_rx_bufsize =3D HV_MIN_RX_BUF_SIZE; > + dev_info->max_rx_pktlen =3D HV_MAX_RX_PKT_LEN; > + dev_info->max_mac_addrs =3D HV_MAX_MAC_ADDRS; > +} > + > +inline int > +rte_hv_dev_atomic_write_link_status(struct rte_eth_dev *dev, > + struct rte_eth_link *link) > +{ > + struct rte_eth_link *dst =3D &(dev->data->dev_link); > + struct rte_eth_link *src =3D link; > + > + if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst, > + *(uint64_t *)src) =3D=3D 0) > + return -1; > + > + return 0; > +} > + > +inline int > +rte_hv_dev_atomic_read_link_status(struct rte_eth_dev *dev, > + struct rte_eth_link *link) > +{ > + struct rte_eth_link *dst =3D link; > + struct rte_eth_link *src =3D &(dev->data->dev_link); > + > + if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst, > + *(uint64_t *)src) =3D=3D 0) > + return -1; > + > + return 0; > +} > + > +/* return 0 means link status changed, -1 means not changed */ > +static int > +hyperv_dev_link_update(struct rte_eth_dev *dev, > + __rte_unused int wait_to_complete) > +{ > + uint8_t ret; > + struct rte_eth_link old, link; > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + memset(&old, 0, sizeof(old)); > + memset(&link, 0, sizeof(link)); > + rte_hv_dev_atomic_read_link_status(dev, &old); > + if (!hv->link_status && (hv->link_req_cnt =3D=3D HV_MAX_LINK_REQ)) { > + ret =3D hyperv_get_link_status(hv); > + if (ret > 1) > + return -1; > + hv->link_req_cnt =3D 0; > + } > + link.link_duplex =3D ETH_LINK_FULL_DUPLEX; > + link.link_speed =3D ETH_LINK_SPEED_10000; > + link.link_status =3D hv->link_status; > + hv->link_req_cnt++; > + rte_hv_dev_atomic_write_link_status(dev, &link); > + > + return (old.link_status =3D=3D link.link_status) ? -1 : 0; > +} > + > +static int > +hyperv_dev_configure(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + const struct rte_eth_rxmode *rxmode =3D &dev->data- > >dev_conf.rxmode; > + > + PMD_INIT_FUNC_TRACE(); > + > + rte_memcpy(dev->data->mac_addrs->addr_bytes, hv- > >hw_mac_addr, > + ETHER_ADDR_LEN); > + hv->jumbo_frame_support =3D rxmode->jumbo_frame; > + > + return 0; > +} > + > +static int > +hyperv_init(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + struct rte_vmbus_device *vmbus_dev; > + > + vmbus_dev =3D dev->vmbus_dev; > + hv->uio_fd =3D vmbus_dev->uio_fd; > + hv->kernel_initialized =3D 1; > + hv->vmbus_device =3D vmbus_dev->id.device_id; > + hv->monitor_bit =3D (uint8_t)(vmbus_dev->vmbus_monitor_id % 32); > + hv->monitor_group =3D (uint8_t)(vmbus_dev->vmbus_monitor_id / > 32); > + PMD_PDEBUG_LOG(hv, DBG_LOAD, "hyperv_init for vmbus device > %d", > + vmbus_dev->id.device_id); > + > + /* get the memory mappings */ > + hv->ring_pages =3D vmbus_dev- > >mem_resource[TXRX_RING_MAP].addr; > + hv->int_page =3D vmbus_dev->mem_resource[INT_PAGE_MAP].addr; > + hv->monitor_pages =3D > + (struct hv_vmbus_monitor_page *) > + vmbus_dev->mem_resource[MON_PAGE_MAP].addr; > + hv->recv_buf =3D vmbus_dev- > >mem_resource[RECV_BUF_MAP].addr; > + assert(hv->ring_pages); > + assert(hv->int_page); > + assert(hv->monitor_pages); > + assert(hv->recv_buf); > + > + /* separate send/recv int_pages */ > + hv->recv_interrupt_page =3D hv->int_page; > + > + hv->send_interrupt_page =3D > + ((uint8_t *) hv->int_page + (PAGE_SIZE >> 1)); > + > + /* retrieve in/out ring_buffers */ > + hv->out =3D hv->ring_pages; > + hv->in =3D (void *)((uint64_t)hv->out + > + (vmbus_dev->mem_resource[TXRX_RING_MAP].len > / 2)); > + hv->rb_size =3D (vmbus_dev->mem_resource[TXRX_RING_MAP].len / > 2); > + > + dev->rx_pkt_burst =3D hyperv_recv_pkts; > + dev->tx_pkt_burst =3D hyperv_xmit_pkts; > + > + return hv_rf_on_device_add(hv); > +} > + > +#define HV_DEV_ID (hv->vmbus_device << 1) > +#define HV_MTU (dev->data->dev_conf.rxmode.max_rx_pkt_len << 9) > + > +static int > +hyperv_dev_start(struct rte_eth_dev *dev) > +{ > + int ret; > + uint32_t cmd; > + size_t bytes; > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + if (!hv->kernel_initialized) { > + cmd =3D HV_DEV_ID | HV_MTU; > + bytes =3D write(hv->uio_fd, &cmd, sizeof(uint32_t)); > + if (bytes < sizeof(uint32_t)) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "write on uio_fd > %d failed", > + hv->uio_fd); > + return -1; > + } > + ret =3D vmbus_uio_map_resource(dev->vmbus_dev); > + if (ret < 0) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "Failed to map > resources"); > + return ret; > + } > + ret =3D hyperv_init(dev); > + if (ret) > + return ret; > + } > + ret =3D hv_rf_on_open(hv); > + if (ret) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "hv_rf_on_open > failed"); > + return ret; > + } > + hv->link_req_cnt =3D HV_MAX_LINK_REQ; > + > + return ret; > +} > + > +static void > +hyperv_dev_stop(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + uint32_t cmd; > + size_t bytes; > + > + PMD_INIT_FUNC_TRACE(); > + if (!hv->closed) { > + hv_rf_on_close(hv); > + hv_rf_on_device_remove(hv); > + if (hv->kernel_initialized) { > + cmd =3D 1 | HV_DEV_ID; > + bytes =3D write(hv->uio_fd, &cmd, sizeof(uint32_t)); > + if (bytes) > + hv->kernel_initialized =3D 0; > + else > + PMD_PWARN_LOG(hv, DBG_LOAD, "write to > uio_fd %d failed: (%zu)b", > + hv->uio_fd, bytes); > + } > + hv->link_status =3D 0; > + } > +} > + > +static void > +hyperv_dev_close(struct rte_eth_dev *dev) > +{ > + PMD_INIT_FUNC_TRACE(); > + hyperv_dev_stop(dev); > +} > + > +static void > +hyperv_dev_promisc_enable(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + hyperv_set_rx_mode(hv, 1, dev->data->all_multicast); > +} > + > +static void > +hyperv_dev_promisc_disable(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + hyperv_set_rx_mode(hv, 0, dev->data->all_multicast); > +} > + > +static void > +hyperv_dev_allmulticast_enable(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + hyperv_set_rx_mode(hv, dev->data->promiscuous, 1); > +} > + > +static void > +hyperv_dev_allmulticast_disable(struct rte_eth_dev *dev) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + hyperv_set_rx_mode(hv, dev->data->promiscuous, 0); > +} > + > +static void > +hyperv_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats > *stats) > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + struct hv_stats *st =3D &hv->stats; > + > + PMD_INIT_FUNC_TRACE(); > + > + memset(stats, 0, sizeof(struct rte_eth_stats)); > + > + stats->opackets =3D st->opkts; > + stats->obytes =3D st->obytes; > + stats->oerrors =3D st->oerrors; > + stats->ipackets =3D st->ipkts; > + stats->ibytes =3D st->ibytes; > + stats->ierrors =3D st->ierrors; > + stats->rx_nombuf =3D st->rx_nombuf; > +} > + > +static struct eth_dev_ops hyperv_eth_dev_ops =3D { > + .dev_configure =3D hyperv_dev_configure, > + .dev_start =3D hyperv_dev_start, > + .dev_stop =3D hyperv_dev_stop, > + .dev_infos_get =3D hyperv_dev_info_get, > + .rx_queue_release =3D hyperv_dev_rx_queue_release, > + .tx_queue_release =3D hyperv_dev_tx_queue_release, > + .rx_queue_setup =3D hyperv_dev_rx_queue_setup, > + .tx_queue_setup =3D hyperv_dev_tx_queue_setup, > + .dev_close =3D hyperv_dev_close, > + .promiscuous_enable =3D hyperv_dev_promisc_enable, > + .promiscuous_disable =3D hyperv_dev_promisc_disable, > + .allmulticast_enable =3D hyperv_dev_allmulticast_enable, > + .allmulticast_disable =3D hyperv_dev_allmulticast_disable, > + .link_update =3D hyperv_dev_link_update, > + .stats_get =3D hyperv_dev_stats_get, > +}; > + > +static int > +eth_hyperv_dev_init(struct rte_eth_dev *eth_dev) > +{ > + int ret; > + > + PMD_INIT_FUNC_TRACE(); > + > + eth_dev->dev_ops =3D &hyperv_eth_dev_ops; > + eth_dev->data->mac_addrs =3D rte_malloc("mac_addrs", > + sizeof(struct ether_addr), > + RTE_CACHE_LINE_SIZE); > + if (!eth_dev->data->mac_addrs) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "unable to allocate > memory for mac addrs"); > + return -1; > + } > + > + ret =3D hyperv_init(eth_dev); > + > + return ret; > +} > + > +static struct eth_driver rte_hyperv_pmd =3D { > + .vmbus_drv =3D { > + .name =3D "rte_hyperv_pmd", > + .module_name =3D "hv_uio", > + .id_table =3D vmbus_id_hyperv_map, > + }, > + .bus_type =3D RTE_BUS_VMBUS, > + .eth_dev_init =3D eth_hyperv_dev_init, > + .dev_private_size =3D sizeof(struct hv_data), > +}; > + > +static int > +rte_hyperv_pmd_init(const char *name __rte_unused, > + const char *param __rte_unused) > +{ > + rte_eth_driver_register(&rte_hyperv_pmd); > + return 0; > +} > + > +static struct rte_driver rte_hyperv_driver =3D { > + .type =3D PMD_PDEV, > + .init =3D rte_hyperv_pmd_init, > +}; > + > +PMD_REGISTER_DRIVER(rte_hyperv_driver); > diff --git a/lib/librte_pmd_hyperv/hyperv_logs.h > b/lib/librte_pmd_hyperv/hyperv_logs.h > new file mode 100644 > index 0000000..1b96468 > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv_logs.h > @@ -0,0 +1,69 @@ > +/*- > + * Copyright(c) 2013-2015 Brocade Communications Systems, Inc. > + * All rights reserved. > + */ > + > +#ifndef _HYPERV_LOGS_H_ > +#define _HYPERV_LOGS_H_ > + > +#ifdef RTE_LIBRTE_HV_DEBUG_INIT > +#define PMD_INIT_LOG(level, fmt, args...) \ > + RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args) > +#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>") > +#else > +#define PMD_INIT_LOG(level, fmt, args...) do { } while (0) > +#define PMD_INIT_FUNC_TRACE() do { } while (0) > +#endif > + > +#ifdef RTE_LIBRTE_HV_DEBUG > + > +#define RTE_DBG_LOAD INIT > +#define RTE_DBG_STATS STATS > +#define RTE_DBG_TX TX > +#define RTE_DBG_RX RX > +#define RTE_DBG_MBUF MBUF > +#define RTE_DBG_ASSERT ASRT > +#define RTE_DBG_RB RB > +#define RTE_DBG_VMBUS VMBUS > +#define RTE_DBG_ALL ALL > + > +#define STR(x) #x > + > +#define HV_RTE_LOG(hv, codepath, level, fmt, args...) \ > + RTE_LOG(level, PMD, "[%d]: %-6s: %s: " fmt "\n", \ > + hv->vmbus_device, STR(codepath), __func__, ## args) > + > +#define PMD_PDEBUG_LOG(hv, codepath, fmt, args...) \ > +do { \ > + if (unlikely(hv->debug & (codepath))) \ > + HV_RTE_LOG(hv, RTE_##codepath, DEBUG, fmt, ## args) \ > +} while (0) > + > +#define PMD_PINFO_LOG(hv, codepath, fmt, args...) \ > +do { \ > + if (unlikely(hv->debug & (codepath))) \ > + HV_RTE_LOG(hv, RTE_##codepath, INFO, fmt, ## args) \ > +} while (0) > + > +#define PMD_PWARN_LOG(hv, codepath, fmt, args...) \ > +do { \ > + if (unlikely(hv->debug & (codepath))) \ > + HV_RTE_LOG(hv, RTE_##codepath, WARNING, fmt, ## args) > \ > +} while (0) > + > +#define PMD_PERROR_LOG(hv, codepath, fmt, args...) \ > +do { \ > + if (unlikely(hv->debug & (codepath))) \ > + HV_RTE_LOG(hv, RTE_##codepath, ERR, fmt, ## args) \ > +} while (0) > +#else > +#define HV_RTE_LOG(level, fmt, args...) do { } while (0) > +#define PMD_PDEBUG_LOG(fmt, args...) do { } while (0) > +#define PMD_PINFO_LOG(fmt, args...) do { } while (0) > +#define PMD_PWARN_LOG(fmt, args...) do { } while (0) > +#define PMD_PERROR_LOG(fmt, args...) do { } while (0) > +#undef RTE_LIBRTE_HV_DEBUG_TX > +#undef RTE_LIBRTE_HV_DEBUG_RX > +#endif > + > +#endif /* _HYPERV_LOGS_H_ */ > diff --git a/lib/librte_pmd_hyperv/hyperv_rxtx.c > b/lib/librte_pmd_hyperv/hyperv_rxtx.c > new file mode 100644 > index 0000000..9e423d0 > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv_rxtx.c > @@ -0,0 +1,403 @@ > +/*- > + * Copyright(c) 2013-2015 Brocade Communications Systems, Inc. > + * All rights reserved. > + */ > + > +#include "hyperv.h" > +#include "hyperv_rxtx.h" > +#include "hyperv_drv.h" > + > +#define RTE_MBUF_DATA_DMA_ADDR(mb) \ > + ((uint64_t)((mb)->buf_physaddr + (mb)->data_off)) > + > +#define RPPI_SIZE (sizeof(struct rndis_per_packet_info)\ > + + sizeof(struct ndis_8021q_info)) > +#define RNDIS_OFF (sizeof(struct netvsc_packet) + RPPI_SIZE) > +#define TX_PKT_SIZE (RNDIS_OFF + sizeof(struct rndis_filter_packet) * 2) > + > +static inline struct rte_mbuf * > +hv_rxmbuf_alloc(struct rte_mempool *mp) > +{ > + return __rte_mbuf_raw_alloc(mp); > +} > + > +static inline int > +hyperv_has_rx_work(struct hv_data *hv) > +{ > + return hv->in->read_index !=3D hv->in->write_index; > +} > + > +#ifndef DEFAULT_TX_FREE_THRESHOLD > +#define DEFAULT_TX_FREE_THRESHOLD 32 > +#endif > + > +int > +hyperv_dev_tx_queue_setup(struct rte_eth_dev *dev, > + uint16_t queue_idx, > + uint16_t nb_desc, > + unsigned int socket_id, > + const struct rte_eth_txconf *tx_conf) > + > +{ > + struct hv_data *hv =3D dev->data->dev_private; > + const struct rte_memzone *tz; > + struct hv_tx_queue *txq; > + char tz_name[RTE_MEMZONE_NAMESIZE]; > + uint32_t i, delta =3D 0, new_delta; > + struct netvsc_packet *pkt; > + > + PMD_INIT_FUNC_TRACE(); > + > + txq =3D rte_zmalloc_socket("ethdev TX queue", sizeof(struct > hv_tx_queue), > + RTE_CACHE_LINE_SIZE, socket_id); > + if (txq =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "rte_zmalloc for > tx_queue failed"); > + return -ENOMEM; > + } > + > + if (tx_conf->tx_free_thresh >=3D nb_desc) { > + PMD_PERROR_LOG(hv, DBG_LOAD, > + "tx_free_thresh should be less then nb_desc"); > + return -EINVAL; > + } > + txq->tx_free_thresh =3D (tx_conf->tx_free_thresh ? tx_conf- > >tx_free_thresh : > + DEFAULT_TX_FREE_THRESHOLD); > + txq->pkts =3D rte_calloc_socket("TX pkts", sizeof(void*), nb_desc, > + RTE_CACHE_LINE_SIZE, socket_id); > + if (txq->pkts =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "rte_zmalloc for pkts > failed"); > + return -ENOMEM; > + } > + sprintf(tz_name, "hv_%d_%u_%u", hv->vmbus_device, queue_idx, > socket_id); > + tz =3D rte_memzone_reserve_aligned(tz_name, > + (uint32_t)nb_desc * TX_PKT_SIZE, > + > rte_lcore_to_socket_id(rte_lcore_id()), > + 0, PAGE_SIZE); > + if (tz =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "netvsc packet ring alloc > fail"); > + return -ENOMEM; > + } > + for (i =3D 0; i < nb_desc; i++) { > + pkt =3D txq->pkts[i] =3D (struct netvsc_packet *)((uint8_t *)tz- > >addr + > + i * TX_PKT_SIZE + > delta); > + pkt->extension =3D (uint8_t *)tz->addr + i * TX_PKT_SIZE + > RNDIS_OFF + delta; > + if (!pkt->extension) { > + PMD_PERROR_LOG(hv, DBG_TX, > + "pkt->extension is NULL for %d-th pkt", i); > + return -EINVAL; > + } > + pkt->extension_phys_addr =3D > + tz->phys_addr + i * TX_PKT_SIZE + RNDIS_OFF + > delta; > + pkt->ext_pages =3D 1; > + pkt->page_buffers[0].pfn =3D pkt->extension_phys_addr >> > PAGE_SHIFT; > + pkt->page_buffers[0].offset =3D > + (unsigned long)pkt->extension & (PAGE_SIZE - 1); > + pkt->page_buffers[0].length =3D RNDIS_MESSAGE_SIZE(struct > rndis_packet); > + if (pkt->page_buffers[0].offset + pkt- > >page_buffers[0].length > + > PAGE_SIZE) { > + new_delta =3D PAGE_SIZE - pkt- > >page_buffers[0].offset; > + pkt->page_buffers[0].pfn++; > + delta +=3D new_delta; > + pkt->page_buffers[0].offset =3D 0; > + pkt->extension =3D (uint8_t *)pkt->extension + > new_delta; > + pkt->extension_phys_addr +=3D new_delta; > + } > + } > + txq->sw_ring =3D rte_calloc_socket("txq_sw_ring", > + sizeof(struct rte_mbuf *), nb_desc, > + RTE_CACHE_LINE_SIZE, socket_id); > + if (txq->sw_ring =3D=3D NULL) { > + hyperv_dev_tx_queue_release(txq); > + return -ENOMEM; > + } > + txq->port_id =3D dev->data->port_id; > + txq->nb_tx_desc =3D txq->tx_avail =3D nb_desc; > + txq->tx_free_thresh =3D tx_conf->tx_free_thresh; > + txq->hv =3D hv; > + dev->data->tx_queues[queue_idx] =3D txq; > + hv->txq =3D txq; > + > + return 0; > +} > + > +void > +hyperv_dev_tx_queue_release(void *ptxq) > +{ > + struct hv_tx_queue *txq =3D ptxq; > + > + PMD_INIT_FUNC_TRACE(); > + if (txq =3D=3D NULL) > + return; > + rte_free(txq->sw_ring); > + rte_free(txq->pkts); > + rte_free(txq); > +} > + > +int > +hyperv_dev_rx_queue_setup(struct rte_eth_dev *dev, > + uint16_t queue_idx, > + uint16_t nb_desc, > + unsigned int socket_id, > + const struct rte_eth_rxconf *rx_conf, > + struct rte_mempool *mp) > +{ > + uint16_t i; > + struct hv_rx_queue *rxq; > + struct rte_mbuf *mbuf; > + struct hv_data *hv =3D dev->data->dev_private; > + > + PMD_INIT_FUNC_TRACE(); > + > + rxq =3D rte_zmalloc_socket("ethdev RX queue", sizeof(struct > hv_rx_queue), > + RTE_CACHE_LINE_SIZE, socket_id); > + if (rxq =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, > + "rte_zmalloc for rx_queue failed!"); > + return -ENOMEM; > + } > + hv->desc =3D rxq->desc =3D rte_zmalloc_socket(NULL, PAGE_SIZE, > + RTE_CACHE_LINE_SIZE, > socket_id); > + if (rxq->desc =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, > + "rte_zmalloc for vmbus_desc failed!"); > + hyperv_dev_rx_queue_release(rxq); > + return -ENOMEM; > + } > + rxq->sw_ring =3D rte_calloc_socket("rxq->sw_ring", > + sizeof(struct mbuf *), nb_desc, > + RTE_CACHE_LINE_SIZE, socket_id); > + if (rxq->sw_ring =3D=3D NULL) { > + hyperv_dev_rx_queue_release(rxq); > + return -ENOMEM; > + } > + > + for (i =3D 0; i < nb_desc; i++) { > + mbuf =3D hv_rxmbuf_alloc(mp); > + if (mbuf =3D=3D NULL) { > + PMD_PERROR_LOG(hv, DBG_LOAD, "RX mbuf alloc > failed"); > + return -ENOMEM; > + } > + > + mbuf->nb_segs =3D 1; > + mbuf->next =3D NULL; > + mbuf->port =3D rxq->port_id; > + rxq->sw_ring[i] =3D mbuf; > + } > + > + rxq->mb_pool =3D mp; > + rxq->nb_rx_desc =3D nb_desc; > + rxq->rx_head =3D 0; > + rxq->rx_tail =3D 0; > + rxq->rx_free_thresh =3D rx_conf->rx_free_thresh; > + rxq->port_id =3D dev->data->port_id; > + rxq->hv =3D hv; > + dev->data->rx_queues[queue_idx] =3D rxq; > + hv->rxq =3D rxq; > + hv->max_rx_pkt_len =3D mp->elt_size - > + (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM); > + > + return 0; > +} > + > +void > +hyperv_dev_rx_queue_release(void *prxq) > +{ > + struct hv_rx_queue *rxq =3D prxq; > + > + PMD_INIT_FUNC_TRACE(); > + if (rxq =3D=3D NULL) > + return; > + rte_free(rxq->sw_ring); > + rte_free(rxq->desc); > + rte_free(rxq); > +} > + > +uint16_t > +hyperv_recv_pkts(void *prxq, struct rte_mbuf **rx_pkts, uint16_t > nb_pkts) > +{ > + struct hv_rx_queue *rxq =3D prxq; > + struct hv_data *hv =3D rxq->hv; > + struct rte_mbuf *new_mb, *rx_mbuf, *first_mbuf; > + uint16_t nb_rx =3D 0; > + uint16_t segs, i; > + > + if (unlikely(hv->closed)) > + return 0; > + > + nb_pkts =3D MIN(nb_pkts, HV_MAX_PKT_BURST); > + hyperv_scan_comps(hv, 0); > + > + while (nb_rx < nb_pkts) { > + /* > + * if there are no mbufs in sw_ring, > + * we need to trigger receive procedure > + */ > + if (rxq->rx_head =3D=3D rxq->rx_tail) { > + if (!hyperv_has_rx_work(hv)) > + break; > + > + if (unlikely(!hyperv_get_buffer(hv, rxq->desc, > PAGE_SIZE))) { > + hyperv_scan_comps(hv, 0); > + continue; > + } > + } > + > + /* > + * Now the received data is in sw_ring of our rxq > + * we need to extract it and replace in sw_ring with new > mbuf > + */ > + rx_mbuf =3D first_mbuf =3D rxq->sw_ring[rxq->rx_head]; > + segs =3D first_mbuf->nb_segs; > + for (i =3D 0; i < segs; ++i) { > + new_mb =3D hv_rxmbuf_alloc(rxq->mb_pool); > + if (unlikely(!new_mb)) { > + PMD_PERROR_LOG(hv, DBG_RX, "mbuf alloc > fail"); > + ++hv->stats.rx_nombuf; > + return nb_rx; > + } > + > + rx_mbuf =3D rxq->sw_ring[rxq->rx_head]; > + rxq->sw_ring[rxq->rx_head] =3D new_mb; > + > + if (++rxq->rx_head =3D=3D rxq->nb_rx_desc) > + rxq->rx_head =3D 0; > + > + rx_mbuf->ol_flags |=3D PKT_RX_IPV4_HDR; > + rx_mbuf->port =3D rxq->port_id; > + } > + rx_mbuf->next =3D NULL; > + > + rx_pkts[nb_rx++] =3D first_mbuf; > + ++hv->stats.ipkts; > + hv->stats.ibytes +=3D first_mbuf->pkt_len; > + } > + > + return nb_rx; > +} > + > +static void hyperv_txeof(struct hv_tx_queue *txq) > +{ > + struct rte_mbuf *mb, *mb_next; > + > + txq->tx_avail +=3D txq->tx_free; > + while (txq->tx_free) { > + --txq->tx_free; > + mb =3D txq->sw_ring[txq->tx_head]; > + while (mb) { > + mb_next =3D mb->next; > + rte_mempool_put(mb->pool, mb); > + mb =3D mb_next; > + } > + if (++txq->tx_head =3D=3D txq->nb_tx_desc) > + txq->tx_head =3D 0; > + } > +} > + > +uint16_t > +hyperv_xmit_pkts(void *ptxq, struct rte_mbuf **tx_pkts, uint16_t > nb_pkts) > +{ > + struct hv_tx_queue *txq =3D ptxq; > + struct hv_data *hv =3D txq->hv; > + struct netvsc_packet *packet; > + struct rte_mbuf *m; > + uint32_t data_pages; > + uint64_t first_data_page; > + uint32_t total_len; > + uint32_t len; > + uint16_t i, nb_tx; > + uint8_t rndis_pages; > + int ret; > + > + if (unlikely(hv->closed)) > + return 0; > + > + for (nb_tx =3D 0; nb_tx < nb_pkts; ++nb_tx) { > + hyperv_scan_comps(hv, 0); > + /* Determine if the descriptor ring needs to be cleaned. */ > + if (txq->tx_free > txq->tx_free_thresh) > + hyperv_txeof(txq); > + > + if (!txq->tx_avail) { > + hyperv_scan_comps(hv, 1); > + hyperv_txeof(txq); > + if (!txq->tx_avail) { > + PMD_PWARN_LOG(hv, DBG_TX, "No TX > mbuf available"); > + break; > + } > + } > + m =3D tx_pkts[nb_tx]; > + len =3D m->data_len; > + total_len =3D m->pkt_len; > + first_data_page =3D RTE_MBUF_DATA_DMA_ADDR(m) >> > PAGE_SHIFT; > + data_pages =3D ((RTE_MBUF_DATA_DMA_ADDR(m) + len - 1) > >> PAGE_SHIFT) - > + first_data_page + 1; > + > + packet =3D txq->pkts[txq->tx_tail]; > + rndis_pages =3D packet->ext_pages; > + > + txq->sw_ring[txq->tx_tail] =3D m; > + packet->tot_data_buf_len =3D total_len; > + packet->page_buffers[rndis_pages].pfn =3D > + RTE_MBUF_DATA_DMA_ADDR(m) >> PAGE_SHIFT; > + packet->page_buffers[rndis_pages].offset =3D > + RTE_MBUF_DATA_DMA_ADDR(m) & (PAGE_SIZE - > 1); > + if (data_pages =3D=3D 1) > + packet->page_buffers[rndis_pages].length =3D len; > + else > + packet->page_buffers[rndis_pages].length =3D > PAGE_SIZE - > + packet->page_buffers[rndis_pages].offset; > + > + for (i =3D 1; i < data_pages; ++i) { > + packet->page_buffers[rndis_pages + i].pfn =3D > first_data_page + i; > + packet->page_buffers[rndis_pages + i].offset =3D 0; > + packet->page_buffers[rndis_pages + i].length =3D > PAGE_SIZE; > + } > + if (data_pages > 1) > + packet->page_buffers[rndis_pages - 1 + > data_pages].length =3D > + ((rte_pktmbuf_mtod(m, unsigned long) + len > - 1) > + & (PAGE_SIZE - 1)) + 1; > + > + uint16_t index =3D data_pages + rndis_pages; > + > + for (i =3D 1; i < m->nb_segs; ++i) { > + m =3D m->next; > + len =3D m->data_len; > + first_data_page =3D RTE_MBUF_DATA_DMA_ADDR(m) > >> PAGE_SHIFT; > + data_pages =3D ((RTE_MBUF_DATA_DMA_ADDR(m) + > len - 1) >> PAGE_SHIFT) - > + first_data_page + 1; > + packet->page_buffers[index].pfn =3D > + RTE_MBUF_DATA_DMA_ADDR(m) >> > PAGE_SHIFT; > + packet->page_buffers[index].offset =3D > + rte_pktmbuf_mtod(m, unsigned long) > + & (PAGE_SIZE - 1); > + packet->page_buffers[index].length =3D m->data_len; > + if (data_pages > 1) { > + /* It can be 2 in case of usual mbuf_size=3D2048 > */ > + packet->page_buffers[index].length =3D > PAGE_SIZE - > + packet->page_buffers[index].offset; > + packet->page_buffers[++index].offset =3D 0; > + packet->page_buffers[index].pfn =3D > + packet->page_buffers[index - 1].pfn > + 1; > + packet->page_buffers[index].length =3D > + m->data_len > + - packet->page_buffers[index - > 1].length; > + } > + ++index; > + } > + packet->page_buf_count =3D index; > + > + ret =3D hv_rf_on_send(hv, packet); > + if (likely(ret =3D=3D 0)) { > + ++hv->stats.opkts; > + hv->stats.obytes +=3D total_len; > + if (++txq->tx_tail =3D=3D txq->nb_tx_desc) > + txq->tx_tail =3D 0; > + --txq->tx_avail; > + } else { > + ++hv->stats.oerrors; > + PMD_PERROR_LOG(hv, DBG_TX, "TX ring buffer is > busy"); > + } > + } > + > + return nb_tx; > +} > diff --git a/lib/librte_pmd_hyperv/hyperv_rxtx.h > b/lib/librte_pmd_hyperv/hyperv_rxtx.h > new file mode 100644 > index 0000000..c45a704 > --- /dev/null > +++ b/lib/librte_pmd_hyperv/hyperv_rxtx.h > @@ -0,0 +1,35 @@ > +/*- > + * Copyright(c) 2013-2015 Brocade Communications Systems, Inc. > + * All rights reserved. > + */ > + > +/** > + * Structure associated with each TX queue. > + */ > +struct hv_tx_queue { > + struct netvsc_packet **pkts; > + struct rte_mbuf **sw_ring; > + uint16_t nb_tx_desc; > + uint16_t tx_avail; > + uint16_t tx_head; > + uint16_t tx_tail; > + uint16_t tx_free_thresh; > + uint16_t tx_free; > + uint8_t port_id; > + struct hv_data *hv; > +} __rte_cache_aligned; > + > +/** > + * Structure associated with each RX queue. > + */ > +struct hv_rx_queue { > + struct rte_mempool *mb_pool; > + struct rte_mbuf **sw_ring; > + uint16_t nb_rx_desc; > + uint16_t rx_head; > + uint16_t rx_tail; > + uint16_t rx_free_thresh; > + uint8_t port_id; > + struct hv_data *hv; > + struct hv_vm_packet_descriptor *desc; > +} __rte_cache_aligned; > diff --git a/mk/rte.app.mk b/mk/rte.app.mk > index 62a76ae..e0416d1 100644 > --- a/mk/rte.app.mk > +++ b/mk/rte.app.mk > @@ -133,6 +133,10 @@ LDLIBS +=3D -lm > LDLIBS +=3D -lrt > endif >=20 > +ifeq ($(CONFIG_RTE_LIBRTE_HV_PMD),y) > +LDLIBS +=3D -lrte_pmd_hyperv > +endif > + > ifeq ($(CONFIG_RTE_LIBRTE_VHOST), y) > LDLIBS +=3D -lrte_vhost > endif > -- > 2.1.4