From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:42244) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S65ql-0000hz-TP for qemu-devel@nongnu.org; Fri, 09 Mar 2012 14:51:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S65qi-0008Vl-8p for qemu-devel@nongnu.org; Fri, 09 Mar 2012 14:51:39 -0500 Received: from e33.co.us.ibm.com ([32.97.110.151]:33076) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S65qh-0008VP-TN for qemu-devel@nongnu.org; Fri, 09 Mar 2012 14:51:36 -0500 Received: from /spool/local by e33.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 9 Mar 2012 12:51:29 -0700 Received: from d03relay05.boulder.ibm.com (d03relay05.boulder.ibm.com [9.17.195.107]) by d03dlp01.boulder.ibm.com (Postfix) with ESMTP id 01D481FF004A for ; Fri, 9 Mar 2012 12:51:08 -0700 (MST) Received: from d03av06.boulder.ibm.com (d03av06.boulder.ibm.com [9.17.195.245]) by d03relay05.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q29Jp2nF018938 for ; Fri, 9 Mar 2012 12:51:02 -0700 Received: from d03av06.boulder.ibm.com (loopback [127.0.0.1]) by d03av06.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q29JpI2M005841 for ; Fri, 9 Mar 2012 12:51:18 -0700 Message-ID: <4F5A5F23.6030108@us.ibm.com> Date: Fri, 09 Mar 2012 13:50:59 -0600 From: Anthony Liguori MIME-Version: 1.0 References: <1331134726-6634-1-git-send-email-dmitry.fleytman@ravellosystems.com> <1331134726-6634-2-git-send-email-dmitry.fleytman@ravellosystems.com> In-Reply-To: <1331134726-6634-2-git-send-email-dmitry.fleytman@ravellosystems.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH v3] VMXNET3 paravirtual NIC device implementation List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Dmitry Fleytman Cc: Alex Fishman , "Michael S. Tsirkin" , Izik Eidus , qemu-devel@nongnu.org, Yan Vugenfirer , Gerhard Wiesinger On 03/07/2012 09:38 AM, Dmitry Fleytman wrote: > Implementation of VMWare VMXNET3 paravirtual NIC device. > Supports of all the device features including offload capabilties, > VLANs and etc. > The device is tested on different OSes: > Fedora 15 > Ubuntu 10.4 > Centos 6.2 > Windows 2008R2 > Windows 2008 64bit > Windows 2008 32bit > Windows 2003 64bit > Windows 2003 32bit > Currently live migration is not supported. > > Signed-off-by: Dmitry Fleytman > Signed-off-by: Yan Vugenfirer > --- > Makefile.objs | 1 + > default-configs/pci.mak | 1 + > hw/pci.c | 2 + > hw/pci.h | 1 + > hw/virtio-net.h | 13 +- Why is this patch touching virtio-net? > hw/vmware_utils.h | 131 +++ > hw/vmxnet3.c | 2744 +++++++++++++++++++++++++++++++++++++++++++++++ > hw/vmxnet3.h | 727 +++++++++++++ > hw/vmxnet3_debug.h | 104 ++ > hw/vmxnet_utils.c | 202 ++++ > hw/vmxnet_utils.h | 263 +++++ > iov.c | 27 + > iov.h | 3 + > net.c | 2 +- > net/checksum.h | 7 + You should split out the common code changes into independent patches. > 15 files changed, 4221 insertions(+), 7 deletions(-) > create mode 100644 hw/vmware_utils.h > create mode 100644 hw/vmxnet3.c > create mode 100644 hw/vmxnet3.h > create mode 100644 hw/vmxnet3_debug.h > create mode 100644 hw/vmxnet_utils.c > create mode 100644 hw/vmxnet_utils.h > > diff --git a/Makefile.objs b/Makefile.objs > index 808de6a..3f846a6 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -264,6 +264,7 @@ hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o > hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o > hw-obj-$(CONFIG_E1000_PCI) += e1000.o > hw-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o > +hw-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o vmxnet_utils.o > > hw-obj-$(CONFIG_SMC91C111) += smc91c111.o > hw-obj-$(CONFIG_LAN9118) += lan9118.o > diff --git a/default-configs/pci.mak b/default-configs/pci.mak > index 21e4ccf..f8e6ee1 100644 > --- a/default-configs/pci.mak > +++ b/default-configs/pci.mak > @@ -13,6 +13,7 @@ CONFIG_PCNET_COMMON=y > CONFIG_LSI_SCSI_PCI=y > CONFIG_RTL8139_PCI=y > CONFIG_E1000_PCI=y > +CONFIG_VMXNET3_PCI=y > CONFIG_IDE_CORE=y > CONFIG_IDE_QDEV=y > CONFIG_IDE_PCI=y > diff --git a/hw/pci.c b/hw/pci.c > index bf046bf..f0fb1ee 100644 > --- a/hw/pci.c > +++ b/hw/pci.c > @@ -1350,6 +1350,7 @@ static const char * const pci_nic_models[] = { > "e1000", > "pcnet", > "virtio", > + "vmxnet3", > NULL > }; > > @@ -1362,6 +1363,7 @@ static const char * const pci_nic_names[] = { > "e1000", > "pcnet", > "virtio-net-pci", > + "vmxnet3", > NULL > }; > > diff --git a/hw/pci.h b/hw/pci.h > index 4f19fdb..fee8250 100644 > --- a/hw/pci.h > +++ b/hw/pci.h > @@ -60,6 +60,7 @@ > #define PCI_DEVICE_ID_VMWARE_NET 0x0720 > #define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 > #define PCI_DEVICE_ID_VMWARE_IDE 0x1729 > +#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 > > /* Intel (0x8086) */ > #define PCI_DEVICE_ID_INTEL_82551IT 0x1209 > diff --git a/hw/virtio-net.h b/hw/virtio-net.h > index 4468741..fa3c17b 100644 > --- a/hw/virtio-net.h > +++ b/hw/virtio-net.h > @@ -78,13 +78,14 @@ struct virtio_net_config > * specify GSO or CSUM features, you can simply ignore the header. */ > struct virtio_net_hdr > { > -#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset > +#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */ > +#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ > uint8_t flags; > -#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame > -#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO) > -#define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO) > -#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP > -#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set > +#define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */ > +#define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */ > +#define VIRTIO_NET_HDR_GSO_UDP 3 /* GSO frame, IPv4 UDP (UFO) */ > +#define VIRTIO_NET_HDR_GSO_TCPV6 4 /* GSO frame, IPv6 TCP */ > +#define VIRTIO_NET_HDR_GSO_ECN 0x80 /* TCP has ECN set */ > uint8_t gso_type; > uint16_t hdr_len; > uint16_t gso_size; > diff --git a/hw/vmware_utils.h b/hw/vmware_utils.h > new file mode 100644 > index 0000000..304bb48 > --- /dev/null > +++ b/hw/vmware_utils.h > @@ -0,0 +1,131 @@ > +/* > + * QEMU VMWARE paravirtual devices - auxiliary code > + * > + * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) > + * > + * Developed by Daynix Computing LTD (http://www.daynix.com) > + * > + * Authors: > + * Dmitry Fleytman > + * Yan Vugenfirer > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + * > + */ > + > +/* Shared memory access functions with byte swap support */ > +static inline void > +vmw_shmem_read(target_phys_addr_t addr, void *buf, int len) > +{ > + DSHPRINTF("SHMEM r: %" PRIx64 ", len: %d to %p", > + (uint64_t) addr, len, buf); > + cpu_physical_memory_read(addr, buf, len); > +} > + > +static inline void > +vmw_shmem_write(target_phys_addr_t addr, void *buf, int len) > +{ > + DSHPRINTF("SHMEM w: %" PRIx64 ", len: %d to %p", > + (uint64_t) addr, len, buf); > + cpu_physical_memory_write(addr, buf, len); > +} > + > +static inline void > +vmw_shmem_rw(target_phys_addr_t addr, void *buf, int len, int is_write) > +{ > + DSHPRINTF("SHMEM r/w: %" PRIx64 ", len: %d (to %p), is write: %d", > + (uint64_t) addr, len, buf, is_write); > + > + cpu_physical_memory_rw(addr, buf, len, is_write); > +} > + > +static inline void > +vmw_shmem_set(target_phys_addr_t addr, uint8 val, int len) > +{ > + int i; > + DSHPRINTF("SHMEM set: %" PRIx64 ", len: %d (value 0x%X)", > + (uint64_t) addr, len, val); > + > + for (i = 0; i< len; i++) { > + cpu_physical_memory_write(addr + i,&val, 1); > + } > +} > + > +static inline uint32_t > +vmw_shmem_ld8(target_phys_addr_t addr) > +{ > + uint8_t res = ldub_phys(addr); > + DSHPRINTF("SHMEM load8: %" PRIx64 " (value 0x%X)", > + (uint64_t) addr, res); > + return res; > +} > + > +static inline void > +vmw_shmem_st8(target_phys_addr_t addr, uint8_t value) > +{ > + DSHPRINTF("SHMEM store8: %" PRIx64 " (value 0x%X)", > + (uint64_t) addr, value); > + stb_phys(addr, value); > +} > + > +static inline uint32_t > +vmw_shmem_ld16(target_phys_addr_t addr) > +{ > + uint16_t res = lduw_le_phys(addr); > + DSHPRINTF("SHMEM load16: %" PRIx64 " (value 0x%X)", > + (uint64_t) addr, res); > + return res; > +} > + > +static inline void > +vmw_shmem_st16(target_phys_addr_t addr, uint16_t value) > +{ > + DSHPRINTF("SHMEM store16: %" PRIx64 " (value 0x%X)", > + (uint64_t) addr, value); > + stw_le_phys(addr, value); > +} > + > +static inline uint32_t > +vmw_shmem_ld32(target_phys_addr_t addr) > +{ > + uint32_t res = ldl_le_phys(addr); > + DSHPRINTF("SHMEM load32: %" PRIx64 " (value 0x%X)", > + (uint64_t) addr, res); > + return res; > +} > + > +static inline void > +vmw_shmem_st32(target_phys_addr_t addr, uint32_t value) > +{ > + DSHPRINTF("SHMEM store32: %" PRIx64 " (value 0x%X)", > + (uint64_t) addr, value); > + stl_le_phys(addr, value); > +} > + > +static inline uint64_t > +vmw_shmem_ld64(target_phys_addr_t addr) > +{ > + uint64_t res = ldq_le_phys(addr); > + DSHPRINTF("SHMEM load64: %" PRIx64 " (value %" PRIx64 ")", > + (uint64_t) addr, res); > + return res; > +} > + > +static inline void > +vmw_shmem_st64(target_phys_addr_t addr, uint64_t value) > +{ > + DSHPRINTF("SHMEM store64: %" PRIx64 " (value %" PRIx64 ")", > + (uint64_t) addr, value); > + stq_le_phys(addr, value); > +} > + > +/* MACROS for simplification of operations on array-style registers */ > +#define IS_MULTIREG_ADDR(addr, base, cnt, regsize) \ > + (((addr)>= (base))&& ((addr)< (base) + (cnt) * (regsize))) > + > +#define MULTIREG_IDX_BY_ADDR(addr, base, regsize) \ > + (((addr) - (base)) / (regsize)) > + > +/* Bitfields */ > +#define FLAG_IS_SET(field, flag) (((field)& (flag)) == (flag)) > diff --git a/hw/vmxnet3.c b/hw/vmxnet3.c > new file mode 100644 > index 0000000..05daeed > --- /dev/null > +++ b/hw/vmxnet3.c > @@ -0,0 +1,2744 @@ > +/* > + * QEMU VMWARE VMXNET3 paravirtual NIC > + * > + * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) > + * > + * Developed by Daynix Computing LTD (http://www.daynix.com) > + * > + * Authors: > + * Dmitry Fleytman > + * Yan Vugenfirer > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + * > + */ > + > +#define VMXNET3_ENABLE_MSIX > +#define VMXNET3_ENABLE_MSI > + > +/* Define this constant to non-zero to enable IP4 */ > +/* fragmentation feature */ > + > +/* #define VMXNET_MAX_IP_PLOAD_LEN ETH_MAX_IP_PLOAD_LEN */ > +#define VMXNET3_MAX_IP_PLOAD_LEN 0 > + > +#include "hw.h" > +#include "pci.h" > +#include "net.h" > +#include "virtio-net.h" > +#include "net/tap.h" > +#include "net/checksum.h" > +#include "sysemu.h" > +#include "iov.h" > +#include "bswap.h" > +#ifdef VMXNET3_ENABLE_MSIX > +#include "msix.h" > +#endif > +#ifdef VMXNET3_ENABLE_MSI > +#include "msi.h" > +#endif > + > +#include "vmxnet3_debug.h" > +#include "vmxnet3.h" > +#include "vmware_utils.h" > +#include "vmxnet_utils.h" > + > +#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1 > +#define VMXNET3_MSIX_BAR_SIZE 0x2000 > + > +#define VMXNET3_BAR0_IDX (0) > +#define VMXNET3_BAR1_IDX (1) > +#define VMXNET3_MSIX_BAR_IDX (2) > + > +/* Link speed in Mbps should be shifted by 16 */ > +#define VMXNET3_LINK_SPEED (1000<< 16) > + > +/* Link status: 1 - up, 0 - down. */ > +#define VMXNET3_LINK_STATUS_UP 0x1 > + > +/* Least significant bit should be set for revision and version */ > +#define VMXNET3_DEVICE_VERSION 0x1 > +#define VMXNET3_DEVICE_REVISION 0x1 > + > +/* Macros for rings descriptors access */ > +#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \ > + (vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) > + > +#define VMXNET3_WRITE_TX_QUEUE_DESCR8(dpa, field, value) \ > + (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value))) > + > +#define VMXNET3_READ_TX_QUEUE_DESCR32(dpa, field) \ > + (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) > + > +#define VMXNET3_WRITE_TX_QUEUE_DESCR32(dpa, field, value) \ > + (vmw_shmem_st32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) > + > +#define VMXNET3_READ_TX_QUEUE_DESCR64(dpa, field) \ > + (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) > + > +#define VMXNET3_WRITE_TX_QUEUE_DESCR64(dpa, field, value) \ > + (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) > + > +#define VMXNET3_READ_RX_QUEUE_DESCR64(dpa, field) \ > + (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) > + > +#define VMXNET3_READ_RX_QUEUE_DESCR32(dpa, field) \ > + (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) > + > +#define VMXNET3_WRITE_RX_QUEUE_DESCR64(dpa, field, value) \ > + (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) > + > +#define VMXNET3_WRITE_RX_QUEUE_DESCR8(dpa, field, value) \ > + (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) > + > +/* Macros for guest driver shared area access */ > +#define VMXNET3_READ_DRV_SHARED64(shpa, field) \ > + (vmw_shmem_ld64(shpa + offsetof(struct Vmxnet3_DriverShared, field))) > + > +#define VMXNET3_READ_DRV_SHARED32(shpa, field) \ > + (vmw_shmem_ld32(shpa + offsetof(struct Vmxnet3_DriverShared, field))) > + > +#define VMXNET3_WRITE_DRV_SHARED32(shpa, field, val) \ > + (vmw_shmem_st32(shpa + offsetof(struct Vmxnet3_DriverShared, field), val)) > + > +#define VMXNET3_READ_DRV_SHARED16(shpa, field) \ > + (vmw_shmem_ld16(shpa + offsetof(struct Vmxnet3_DriverShared, field))) > + > +#define VMXNET3_READ_DRV_SHARED8(shpa, field) \ > + (vmw_shmem_ld8(shpa + offsetof(struct Vmxnet3_DriverShared, field))) > + > +#define VMXNET3_READ_DRV_SHARED(shpa, field, b, l) \ > + (vmw_shmem_read(shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l)) > + > +/* TX/RX packets abstractions */ > +typedef struct Vmxnet3_TxPktMdata { > + uint32_t offload_mode; > + uint32_t cso_or_gso_size; > + uint32_t hdr_length; > + eth_pkt_types_e packet_type; > +} Vmxnet3_TxPktMdata; > + > +typedef struct _Vmxnet3_RxPktMdata { > + uint32_t tot_len; > + uint16_t vlan_tag; > + bool vlan_stripped; > + bool vhdr_valid; > + eth_pkt_types_e packet_type; > +} Vmxnet3_RxPktMdata; > + > +#define VMXNET3_TXPKT_REBUILT_HDR_LEN (1024) > + > +typedef struct _Vmxnet3_TxPkt { > + Vmxnet3_TxPktMdata mdata; > + struct virtio_net_hdr virt_hdr; > + bool has_virt_hdr; > + > + struct iovec *vec; > + > + uint8_t __l2_hdr[ETH_MAX_L2_HDR_LEN]; > + uint8_t __l3_hdr[ETH_MAX_L3_HDR_LEN]; Please avoid using underscores as prefixes. > + > + uint32_t payload_len; > + uint32_t max_payload_len; > + > + uint32_t payload_frags; > + uint32_t max_payload_frags; > + > + struct { > + uint32_t offset; > + bool more_frags; > + bool orig_more_frags; > + } fragmentation; > +} Vmxnet3_TxPkt; > + > +#define VMXNET3_TXPKT_VHDR_FRAG (0) > +#define VMXNET3_TXPKT_L2HDR_FRAG (1) > +#define VMXNET3_TXPKT_L3HDR_FRAG (2) > +#define VMXNET3_TXPKT_NUM_NETHDR_FRAGS (2) > +#define VMXNET3_TXPKT_PL_START_FRAG (3) > + > +#define vmxnet3_txpkt_get_mdata(p) (&((p)->mdata)) > +#define vmxnet3_txpkt_get_vhdr(p) (&((p)->virt_hdr)) > + > +#define vmxnet3_txpkt_get_l2hdr(p) \ > + ((p)->vec[VMXNET3_TXPKT_L2HDR_FRAG].iov_base) > +#define vmxnet3_txpkt_get_l2hdr_len(p) \ > + ((p)->vec[VMXNET3_TXPKT_L2HDR_FRAG].iov_len) > +#define vmxnet3_txpkt_set_l2hdr_len(p, l) \ > + ((p)->vec[VMXNET3_TXPKT_L2HDR_FRAG].iov_len = l) > +#define vmxnet3_txpkt_get_l3hdr(p) \ > + ((p)->vec[VMXNET3_TXPKT_L3HDR_FRAG].iov_base) > +#define vmxnet3_txpkt_get_l3hdr_len(p) \ > + ((p)->vec[VMXNET3_TXPKT_L3HDR_FRAG].iov_len) > +#define vmxnet3_txpkt_set_l3hdr_len(p, l) \ > + ((p)->vec[VMXNET3_TXPKT_L3HDR_FRAG].iov_len = l) > +#define vmxnet3_txpkt_get_payload_len(p) \ > + ((p)->payload_len) > + > +#define vmxnet3_txpkt_set_more_frags(p, mf) \ > + ((p)->fragmentation.more_frags = mf) > +#define vmxnet3_txpkt_get_more_frags(p) \ > + ((p)->fragmentation.more_frags | \ > + (p)->fragmentation.orig_more_frags) > +#define vmxnet3_txpkt_set_frag_off(p, off) \ > + ((p)->fragmentation.offset = off) > +#define vmxnet3_txpkt_get_frag_off(p) \ > + ((p)->fragmentation.offset) > +#define vmxnet3_txpkt_advance_frag_off(p, off) \ > + ((p)->fragmentation.offset += off) I'd prefer most of these macros to be static functions. Static functions are much easier to debug and the compiler is very good at inlining as appropriate. I don't see any benefit to using macros here. > +static inline size_t > +vmxnet3_txpkt_get_total_len(const Vmxnet3_TxPkt *p) > +{ > + return vmxnet3_txpkt_get_l2hdr_len(p) + > + vmxnet3_txpkt_get_l3hdr_len(p) + > + vmxnet3_txpkt_get_payload_len(p); > +} > + > +static inline struct iovec* > +vmxnet3_txpkt_get_payload_frag(Vmxnet3_TxPkt *p, uint32_t num) > +{ > + assert(num< p->max_payload_frags); > + return&p->vec[num + VMXNET3_TXPKT_PL_START_FRAG]; > +} > + > +static inline void > +vmxnet3_txpkt_set_num_pl_frags(Vmxnet3_TxPkt *p, uint32_t num) > +{ > + assert(num<= p->max_payload_frags); > + p->payload_frags = num; > +} > + > +static inline uint32_t > +vmxnet3_txpkt_get_num_pl_frags(Vmxnet3_TxPkt *p) > +{ > + return p->payload_frags; > +} > + > +static inline void > +vmxnet3_txpkt_reset_payload(Vmxnet3_TxPkt *p) > +{ > + p->payload_len = 0; > +} > + > +static void vmxnet3_txpkt_reset(Vmxnet3_TxPkt *p) > +{ > + memset(&p->mdata, 0, sizeof(p->mdata)); > + vmxnet3_txpkt_set_num_pl_frags(p, 0); > + vmxnet3_txpkt_reset_payload(p); > + vmxnet3_txpkt_set_more_frags(p, 0); > + vmxnet3_txpkt_set_frag_off(p, 0); > + p->max_payload_len = 0; > + > + if (NULL != p->vec) { > + p->vec[VMXNET3_TXPKT_L2HDR_FRAG].iov_len = 0; > + p->vec[VMXNET3_TXPKT_L3HDR_FRAG].iov_len = 0; > + } > +} > + > +static bool > +vmxnet3_txpkt_prealloc(Vmxnet3_TxPkt *p, uint32_t max_frags, bool has_virt_hdr) > +{ > + if (NULL != p->vec) { > + g_free(p->vec); > + } > + > + p->vec = > + g_malloc(sizeof(*p->vec) * (max_frags + VMXNET3_TXPKT_PL_START_FRAG)); > + if (NULL == p->vec) { > + return false; > + } > + > + p->max_payload_frags = max_frags; > + p->has_virt_hdr = has_virt_hdr; > + p->vec[VMXNET3_TXPKT_VHDR_FRAG].iov_base =&p->virt_hdr; > + p->vec[VMXNET3_TXPKT_VHDR_FRAG].iov_len = > + p->has_virt_hdr ? sizeof(p->virt_hdr) : 0; > + p->vec[VMXNET3_TXPKT_L2HDR_FRAG].iov_base =&p->__l2_hdr; > + p->vec[VMXNET3_TXPKT_L3HDR_FRAG].iov_base =&p->__l3_hdr; > + vmxnet3_txpkt_reset(p); > + return true; > +} > + > +static void vmxnet3_txpkt_init(Vmxnet3_TxPkt *p) > +{ > + p->vec = NULL; > +} > + > +static void vmxnet3_txpkt_cleanup(Vmxnet3_TxPkt *p) > +{ > + g_free(p->vec); > +} > + > +static void vmxnet3_txpkt_unmap(Vmxnet3_TxPkt *p, bool is_write) > +{ > + int i; > + > + for (i = VMXNET3_TXPKT_PL_START_FRAG; > + i< p->payload_frags + VMXNET3_TXPKT_PL_START_FRAG; i++) { > + cpu_physical_memory_unmap(p->vec[i].iov_base, p->vec[i].iov_len, > + is_write, p->vec[i].iov_len); > + } > +} > + > +static void* > +vmxnet3_txpkt_map(Vmxnet3_TxPkt *p, uint32_t *mapped_fragments, bool is_write) > +{ > + int i; > + > + for (i = VMXNET3_TXPKT_PL_START_FRAG; > + i< p->payload_frags + VMXNET3_TXPKT_PL_START_FRAG; i++) { > + target_phys_addr_t mapped_len = p->vec[i].iov_len; > + size_t orig_len = p->vec[i].iov_len; > + p->vec[i].iov_base = > + cpu_physical_memory_map((uint64_t) p->vec[i].iov_base, > +&mapped_len, is_write); > + p->vec[i].iov_len = mapped_len; > + > + if ((NULL == p->vec[i].iov_base) || (orig_len != mapped_len)) { > + p->payload_frags = i + !!p->vec[i].iov_base; > + vmxnet3_txpkt_unmap(p, is_write); > + return NULL; > + } > + } > + > + *mapped_fragments = VMXNET3_TXPKT_PL_START_FRAG + p->payload_frags; > + return p->vec; > +} > + > +static inline void > +vmxnet3_txpkt_dump(Vmxnet3_TxPkt *p) > +{ > +#ifdef DEBUG_VMXNET3_PACKETS > + Vmxnet3_TxPktMdata *m = vmxnet3_txpkt_get_mdata(p); > +#endif > + > + DPKPRINTF("TXPKT MDATA: om: %d, cso/gso_size: %d, hdr_len: %d, " > + "pkt_type: 0x%X, l2hdr_len: %lu l3hdr_len: %lu, payload_len: %u", > + m->offload_mode, m->cso_or_gso_size, > + m->hdr_length, m->packet_type, > + vmxnet3_txpkt_get_l2hdr_len(p), > + vmxnet3_txpkt_get_l3hdr_len(p), > + vmxnet3_txpkt_get_payload_len(p)); > +}; > + > +/* RX packet may contain up to 2 fragments - rebuilt eth header */ > +/* in case of VLAN tag stripping */ > +/* and payload received from QEMU - in any case */ > +#define VMXNET3_MAX_RX_PACKET_FRAGMENTS (2) > + > +typedef struct _Vmxnet3_RxPkt { > + Vmxnet3_RxPktMdata mdata; > + struct virtio_net_hdr virt_hdr; > + struct eth_header eth_hdr; > + struct iovec vec[VMXNET3_MAX_RX_PACKET_FRAGMENTS]; > + uint16 vec_len; > +} Vmxnet3_RxPkt; > + > +#define vmxnet3_rxpkt_get_mdata(p) (&((p)->mdata)) > +#define vmxnet3_rxpkt_get_ehdr(p) (&((p)->eth_hdr)) > +#define vmxnet3_rxpkt_get_vhdr(p) (&((p)->virt_hdr)) > +#define vmxnet3_rxpkt_get_frag(p, n) (&((p)->vec[(n)])) > +#define vmxnet3_rxpkt_set_num_frags(p, n) ((p)->vec_len = (n)) > +#define vmxnet3_rxpkt_get_num_frags(p) ((p)->vec_len) > + > +static inline void vmxnet3_rxpkt_attach_ehdr(Vmxnet3_RxPkt *p) > +{ > + vmxnet3_rxpkt_get_frag(p, 0)->iov_base =&p->eth_hdr; > + vmxnet3_rxpkt_get_frag(p, 0)->iov_len = sizeof(p->eth_hdr); > +} > + > +static inline void vmxnet3_rxpkt_reset(Vmxnet3_RxPkt *p) > +{ > + memset(&p->mdata, 0, sizeof(p->mdata)); > + memset(&p->virt_hdr, 0, sizeof(p->virt_hdr)); > + vmxnet3_rxpkt_set_num_frags(p, 0); > +} > + > +static void vmxnet3_rxpkt_init(Vmxnet3_RxPkt *p) > +{ > + vmxnet3_rxpkt_reset(p); > +} > + > +static inline void > +vmxnet3_rxpkt_dump(Vmxnet3_RxPkt *p) > +{ > +#ifdef DEBUG_VMXNET3_PACKETS > + Vmxnet3_RxPktMdata *m = vmxnet3_rxpkt_get_mdata(p); > +#endif > + > + DPKPRINTF("RXPKT MDATA: tot_len: %d, pkt_type: 0x%X, " > + "vlan_stripped: %d, vlan_tag: %d, vhdr_valid: %d", > + m->tot_len, m->packet_type, > + m->vlan_stripped, m->vlan_tag, m->vhdr_valid); > +}; > + > +/* Cyclic ring abstraction */ > +typedef struct _Vmxnet3_Ring { > + target_phys_addr_t pa; > + size_t size; > + size_t cell_size; > + size_t next; > + uint8_t gen; > +} Vmxnet3_Ring; Watch the underscores and move the types all to the top of the file please. Please split this up to make it more reviewable. > + > +static void vmxnet3_class_init(ObjectClass *class, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(class); > + PCIDeviceClass *c = PCI_DEVICE_CLASS(class); > + > + c->init = vmxnet3_pci_init; > + c->exit = vmxnet3_pci_uninit; > + c->romfile = "pxe-e1000.rom"; I assume this is a mistake. > + c->vendor_id = PCI_VENDOR_ID_VMWARE; > + c->device_id = PCI_DEVICE_ID_VMWARE_VMXNET3; > + c->revision = PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION; > + c->class_id = PCI_CLASS_NETWORK_ETHERNET; > + c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; > + c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; > +#if defined(VMXNET3_ENABLE_MSI) || defined(VMXNET3_ENABLE_MSIX) > + c->config_write = vmxnet3_write_config, > +#endif > + dc->desc = "VMWare Paravirtualized Ethernet v3"; > + dc->reset = vmxnet3_qdev_reset; > + dc->vmsd =&vmstate_vmxnet3; > + dc->props = vmxnet3_properties; > +} > + > +static TypeInfo vmxnet3_info = { > + .name = "vmxnet3", > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(VMXNET3_State), > + .class_init = vmxnet3_class_init, > +}; > + > +static void vmxnet3_register_types(void) > +{ > + DCBPRINTF("vmxnet3_register_types called..."); > + type_register_static(&vmxnet3_info); > +} > + > +type_init(vmxnet3_register_types) > diff --git a/hw/vmxnet3.h b/hw/vmxnet3.h > new file mode 100644 > index 0000000..6ec3fd5 > --- /dev/null > +++ b/hw/vmxnet3.h > @@ -0,0 +1,727 @@ > +/* > + * QEMU VMWARE VMXNET3 paravirtual NIC > + * > + * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) > + * > + * Developed by Daynix Computing LTD (http://www.daynix.com) > + * > + * Authors: > + * Dmitry Fleytman > + * Yan Vugenfirer > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + * > + */ > + > +#ifndef _QEMU_VMXNET3_H > +#define _QEMU_VMXNET3_H > + > +#define VMXNET3_DEVICE_MAX_TX_QUEUES 8 > +#define VMXNET3_DEVICE_MAX_RX_QUEUES 8 /* Keep this value as a power of 2 */ > + > +/* Defines needed to integrate VMWARE headers */ > +#define u64 uint64_t > +#define u32 uint32_t > +#define u16 uint16_t > +#define u8 uint8_t > +#define __le16 uint16_t > +#define __le32 uint32_t > +#define __le64 uint64_t > +#define __packed QEMU_PACKED > + > +#if defined(HOST_WORDS_BIGENDIAN) > +#define const_cpu_to_le64(x) bswap_64(x) > +#define __BIG_ENDIAN_BITFIELD > +#else > +#define const_cpu_to_le64(x) (x) > +#endif > + > +/* Following is an interface definition for */ > +/* VMXNET3 device as provided by VMWARE */ > +/* Original file and copyright is available */ > +/* in Linux kernel v3.2.8 at */ > +/* drivers/net/vmxnet3/vmxnet3_defs.h */ You need to include the original VMware copyrights in this file. Ideally, we'd just import the original header directly. Regards, Anthony Liguori