| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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 <dmitry@daynix.com> | 
					
						
							|  |  |  |  * Tamir Shomer <tamirs@daynix.com> | 
					
						
							|  |  |  |  * Yan Vugenfirer <yan@daynix.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This work is licensed under the terms of the GNU GPL, version 2. | 
					
						
							|  |  |  |  * See the COPYING file in the top-level directory. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:11 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-05 17:06:20 +01:00
										 |  |  | #include "hw/hw.h"
 | 
					
						
							|  |  |  | #include "hw/pci/pci.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:51 +02:00
										 |  |  | #include "hw/qdev-properties.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | #include "net/tap.h"
 | 
					
						
							|  |  |  | #include "net/checksum.h"
 | 
					
						
							|  |  |  | #include "sysemu/sysemu.h"
 | 
					
						
							|  |  |  | #include "qemu/bswap.h"
 | 
					
						
							| 
									
										
										
										
											2021-07-15 12:37:55 +02:00
										 |  |  | #include "qemu/log.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-23 16:35:07 +02:00
										 |  |  | #include "qemu/module.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-05 17:06:20 +01:00
										 |  |  | #include "hw/pci/msix.h"
 | 
					
						
							|  |  |  | #include "hw/pci/msi.h"
 | 
					
						
							| 
									
										
										
										
											2017-04-24 13:42:55 +02:00
										 |  |  | #include "migration/register.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:45 +02:00
										 |  |  | #include "migration/vmstate.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "vmxnet3.h"
 | 
					
						
							| 
									
										
										
										
											2018-12-21 16:40:26 +02:00
										 |  |  | #include "vmxnet3_defs.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | #include "vmxnet_debug.h"
 | 
					
						
							|  |  |  | #include "vmware_utils.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  | #include "net_tx_pkt.h"
 | 
					
						
							|  |  |  | #include "net_rx_pkt.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | #include "qom/object.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
 | 
					
						
							|  |  |  | #define VMXNET3_MSIX_BAR_SIZE 0x2000
 | 
					
						
							| 
									
										
										
										
											2014-08-20 13:27:14 +01:00
										 |  |  | #define MIN_BUF_SIZE 60
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-23 15:59:57 +01:00
										 |  |  | /* Compatibility flags for migration */ | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:35 +02:00
										 |  |  | #define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT 0
 | 
					
						
							|  |  |  | #define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS \
 | 
					
						
							|  |  |  |     (1 << VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT) | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:39 +02:00
										 |  |  | #define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1
 | 
					
						
							|  |  |  | #define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \
 | 
					
						
							|  |  |  |     (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT) | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:39 +02:00
										 |  |  | #define VMXNET3_EXP_EP_OFFSET (0x48)
 | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:35 +02:00
										 |  |  | #define VMXNET3_MSI_OFFSET(s) \
 | 
					
						
							|  |  |  |     ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x50 : 0x84) | 
					
						
							|  |  |  | #define VMXNET3_MSIX_OFFSET(s) \
 | 
					
						
							|  |  |  |     ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0 : 0x9c) | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:41 +02:00
										 |  |  | #define VMXNET3_DSN_OFFSET     (0x100)
 | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | #define VMXNET3_BAR0_IDX      (0)
 | 
					
						
							|  |  |  | #define VMXNET3_BAR1_IDX      (1)
 | 
					
						
							|  |  |  | #define VMXNET3_MSIX_BAR_IDX  (2)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define VMXNET3_OFF_MSIX_TABLE (0x000)
 | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:36 +02:00
										 |  |  | #define VMXNET3_OFF_MSIX_PBA(s) \
 | 
					
						
							|  |  |  |     ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x800 : 0x1000) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* 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 */ | 
					
						
							| 
									
										
										
										
											2015-12-22 22:06:11 -08:00
										 |  |  | #define VMXNET3_UPT_REVISION      0x1
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | #define VMXNET3_DEVICE_REVISION   0x1
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:19 +03:00
										 |  |  | /* Number of interrupt vectors for non-MSIx modes */ | 
					
						
							|  |  |  | #define VMXNET3_MAX_NMSIX_INTRS   (1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | /* Macros for rings descriptors access */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_TX_QUEUE_DESCR8(_d, dpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld8(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_WRITE_TX_QUEUE_DESCR8(_d, dpa, field, value) \
 | 
					
						
							|  |  |  |     (vmw_shmem_st8(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_TX_QUEUE_DESCR32(_d, dpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld32(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_WRITE_TX_QUEUE_DESCR32(_d, dpa, field, value) \
 | 
					
						
							|  |  |  |     (vmw_shmem_st32(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_TX_QUEUE_DESCR64(_d, dpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld64(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_WRITE_TX_QUEUE_DESCR64(_d, dpa, field, value) \
 | 
					
						
							|  |  |  |     (vmw_shmem_st64(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_RX_QUEUE_DESCR64(_d, dpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld64(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_RX_QUEUE_DESCR32(_d, dpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld32(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_WRITE_RX_QUEUE_DESCR64(_d, dpa, field, value) \
 | 
					
						
							|  |  |  |     (vmw_shmem_st64(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_WRITE_RX_QUEUE_DESCR8(_d, dpa, field, value) \
 | 
					
						
							|  |  |  |     (vmw_shmem_st8(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Macros for guest driver shared area access */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_DRV_SHARED64(_d, shpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld64(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_DRV_SHARED32(_d, shpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld32(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_WRITE_DRV_SHARED32(_d, shpa, field, val) \
 | 
					
						
							|  |  |  |     (vmw_shmem_st32(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field), val)) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_DRV_SHARED16(_d, shpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld16(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_DRV_SHARED8(_d, shpa, field) \
 | 
					
						
							|  |  |  |     (vmw_shmem_ld8(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | #define VMXNET3_READ_DRV_SHARED(_d, shpa, field, b, l) \
 | 
					
						
							|  |  |  |     (vmw_shmem_read(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l)) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define VMXNET_FLAG_IS_SET(field, flag) (((field) & (flag)) == (flag))
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | struct VMXNET3Class { | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:38 +02:00
										 |  |  |     PCIDeviceClass parent_class; | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:39 +02:00
										 |  |  |     DeviceRealize parent_dc_realize; | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | typedef struct VMXNET3Class VMXNET3Class; | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-31 17:07:33 -04:00
										 |  |  | DECLARE_CLASS_CHECKERS(VMXNET3Class, VMXNET3_DEVICE, | 
					
						
							|  |  |  |                        TYPE_VMXNET3) | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | static inline void vmxnet3_ring_init(PCIDevice *d, | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |                                      Vmxnet3Ring *ring, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                      hwaddr pa, | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:08 +00:00
										 |  |  |                                      uint32_t size, | 
					
						
							|  |  |  |                                      uint32_t cell_size, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                      bool zero_region) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ring->pa = pa; | 
					
						
							|  |  |  |     ring->size = size; | 
					
						
							|  |  |  |     ring->cell_size = cell_size; | 
					
						
							|  |  |  |     ring->gen = VMXNET3_INIT_GEN; | 
					
						
							|  |  |  |     ring->next = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (zero_region) { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         vmw_shmem_set(d, pa, 0, size * cell_size); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define VMXNET3_RING_DUMP(macro, ring_name, ridx, r)                         \
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:08 +00:00
										 |  |  |     macro("%s#%d: base %" PRIx64 " size %u cell_size %u gen %d next %u",  \ | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |           (ring_name), (ridx),                                               \ | 
					
						
							|  |  |  |           (r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void vmxnet3_ring_inc(Vmxnet3Ring *ring) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (++ring->next >= ring->size) { | 
					
						
							|  |  |  |         ring->next = 0; | 
					
						
							|  |  |  |         ring->gen ^= 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void vmxnet3_ring_dec(Vmxnet3Ring *ring) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (ring->next-- == 0) { | 
					
						
							|  |  |  |         ring->next = ring->size - 1; | 
					
						
							|  |  |  |         ring->gen ^= 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline hwaddr vmxnet3_ring_curr_cell_pa(Vmxnet3Ring *ring) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return ring->pa + ring->next * ring->cell_size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | static inline void vmxnet3_ring_read_curr_cell(PCIDevice *d, Vmxnet3Ring *ring, | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |                                                void *buff) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     vmw_shmem_read(d, vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | static inline void vmxnet3_ring_write_curr_cell(PCIDevice *d, Vmxnet3Ring *ring, | 
					
						
							| 
									
										
										
										
											2018-12-13 23:37:37 +01:00
										 |  |  |                                                 void *buff) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     vmw_shmem_write(d, vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline size_t vmxnet3_ring_curr_cell_idx(Vmxnet3Ring *ring) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return ring->next; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline uint8_t vmxnet3_ring_curr_gen(Vmxnet3Ring *ring) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return ring->gen; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Debug trace-related functions */ | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_dump_tx_descr(struct Vmxnet3_TxDesc *descr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMW_PKPRN("TX DESCR: " | 
					
						
							|  |  |  |               "addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, " | 
					
						
							|  |  |  |               "dtype: %d, ext1: %d, msscof: %d, hlen: %d, om: %d, " | 
					
						
							|  |  |  |               "eop: %d, cq: %d, ext2: %d, ti: %d, tci: %d", | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |               descr->addr, descr->len, descr->gen, descr->rsvd, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |               descr->dtype, descr->ext1, descr->msscof, descr->hlen, descr->om, | 
					
						
							|  |  |  |               descr->eop, descr->cq, descr->ext2, descr->ti, descr->tci); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_dump_virt_hdr(struct virtio_net_hdr *vhdr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMW_PKPRN("VHDR: flags 0x%x, gso_type: 0x%x, hdr_len: %d, gso_size: %d, " | 
					
						
							|  |  |  |               "csum_start: %d, csum_offset: %d", | 
					
						
							|  |  |  |               vhdr->flags, vhdr->gso_type, vhdr->hdr_len, vhdr->gso_size, | 
					
						
							|  |  |  |               vhdr->csum_start, vhdr->csum_offset); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_dump_rx_descr(struct Vmxnet3_RxDesc *descr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMW_PKPRN("RX DESCR: addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, " | 
					
						
							|  |  |  |               "dtype: %d, ext1: %d, btype: %d", | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |               descr->addr, descr->len, descr->gen, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |               descr->rsvd, descr->dtype, descr->ext1, descr->btype); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Interrupt management */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2016-06-10 17:54:23 +08:00
										 |  |  |  * This function returns sign whether interrupt line is in asserted state | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |  * This depends on the type of interrupt used. For INTX interrupt line will | 
					
						
							|  |  |  |  * be asserted until explicit deassertion, for MSI(X) interrupt line will | 
					
						
							|  |  |  |  * be deasserted automatically due to notification semantics of the MSI(X) | 
					
						
							|  |  |  |  * interrupts | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static bool _vmxnet3_assert_interrupt_line(VMXNET3State *s, uint32_t int_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->msix_used && msix_enabled(d)) { | 
					
						
							|  |  |  |         VMW_IRPRN("Sending MSI-X notification for vector %u", int_idx); | 
					
						
							|  |  |  |         msix_notify(d, int_idx); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:42 +08:00
										 |  |  |     if (msi_enabled(d)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMW_IRPRN("Sending MSI notification for vector %u", int_idx); | 
					
						
							|  |  |  |         msi_notify(d, int_idx); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_IRPRN("Asserting line for interrupt %u", int_idx); | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  |     pci_irq_assert(d); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void _vmxnet3_deassert_interrupt_line(VMXNET3State *s, int lidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * This function should never be called for MSI(X) interrupts | 
					
						
							|  |  |  |      * because deassertion never required for message interrupts | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     assert(!s->msix_used || !msix_enabled(d)); | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * This function should never be called for MSI(X) interrupts | 
					
						
							|  |  |  |      * because deassertion never required for message interrupts | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:42 +08:00
										 |  |  |     assert(!msi_enabled(d)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     VMW_IRPRN("Deasserting line for interrupt %u", lidx); | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  |     pci_irq_deassert(d); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_update_interrupt_line_state(VMXNET3State *s, int lidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!s->interrupt_states[lidx].is_pending && | 
					
						
							|  |  |  |        s->interrupt_states[lidx].is_asserted) { | 
					
						
							|  |  |  |         VMW_IRPRN("New interrupt line state for index %d is DOWN", lidx); | 
					
						
							|  |  |  |         _vmxnet3_deassert_interrupt_line(s, lidx); | 
					
						
							|  |  |  |         s->interrupt_states[lidx].is_asserted = false; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->interrupt_states[lidx].is_pending && | 
					
						
							|  |  |  |        !s->interrupt_states[lidx].is_masked && | 
					
						
							|  |  |  |        !s->interrupt_states[lidx].is_asserted) { | 
					
						
							|  |  |  |         VMW_IRPRN("New interrupt line state for index %d is UP", lidx); | 
					
						
							|  |  |  |         s->interrupt_states[lidx].is_asserted = | 
					
						
							|  |  |  |             _vmxnet3_assert_interrupt_line(s, lidx); | 
					
						
							|  |  |  |         s->interrupt_states[lidx].is_pending = false; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_trigger_interrupt(VMXNET3State *s, int lidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  |     s->interrupt_states[lidx].is_pending = true; | 
					
						
							|  |  |  |     vmxnet3_update_interrupt_line_state(s, lidx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->msix_used && msix_enabled(d) && s->auto_int_masking) { | 
					
						
							|  |  |  |         goto do_automask; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:42 +08:00
										 |  |  |     if (msi_enabled(d) && s->auto_int_masking) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         goto do_automask; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | do_automask: | 
					
						
							|  |  |  |     s->interrupt_states[lidx].is_masked = true; | 
					
						
							|  |  |  |     vmxnet3_update_interrupt_line_state(s, lidx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool vmxnet3_interrupt_asserted(VMXNET3State *s, int lidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return s->interrupt_states[lidx].is_asserted; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_clear_interrupt(VMXNET3State *s, int int_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->interrupt_states[int_idx].is_pending = false; | 
					
						
							|  |  |  |     if (s->auto_int_masking) { | 
					
						
							|  |  |  |         s->interrupt_states[int_idx].is_masked = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     vmxnet3_update_interrupt_line_state(s, int_idx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_on_interrupt_mask_changed(VMXNET3State *s, int lidx, bool is_masked) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->interrupt_states[lidx].is_masked = is_masked; | 
					
						
							|  |  |  |     vmxnet3_update_interrupt_line_state(s, lidx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  | static bool vmxnet3_verify_driver_magic(PCIDevice *d, hwaddr dshmem) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     return (VMXNET3_READ_DRV_SHARED32(d, dshmem, magic) == VMXNET3_REV1_MAGIC); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define VMXNET3_GET_BYTE(x, byte_num) (((x) >> (byte_num)*8) & 0xFF)
 | 
					
						
							|  |  |  | #define VMXNET3_MAKE_BYTE(byte_num, val) \
 | 
					
						
							|  |  |  |     (((uint32_t)((val) & 0xFF)) << (byte_num)*8) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_set_variable_mac(VMXNET3State *s, uint32_t h, uint32_t l) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->conf.macaddr.a[0] = VMXNET3_GET_BYTE(l,  0); | 
					
						
							|  |  |  |     s->conf.macaddr.a[1] = VMXNET3_GET_BYTE(l,  1); | 
					
						
							|  |  |  |     s->conf.macaddr.a[2] = VMXNET3_GET_BYTE(l,  2); | 
					
						
							|  |  |  |     s->conf.macaddr.a[3] = VMXNET3_GET_BYTE(l,  3); | 
					
						
							|  |  |  |     s->conf.macaddr.a[4] = VMXNET3_GET_BYTE(h, 0); | 
					
						
							|  |  |  |     s->conf.macaddr.a[5] = VMXNET3_GET_BYTE(h, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:38 +03:00
										 |  |  |     VMW_CFPRN("Variable MAC: " MAC_FMT, MAC_ARG(s->conf.macaddr.a)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t vmxnet3_get_mac_low(MACAddr *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return VMXNET3_MAKE_BYTE(0, addr->a[0]) | | 
					
						
							|  |  |  |            VMXNET3_MAKE_BYTE(1, addr->a[1]) | | 
					
						
							|  |  |  |            VMXNET3_MAKE_BYTE(2, addr->a[2]) | | 
					
						
							|  |  |  |            VMXNET3_MAKE_BYTE(3, addr->a[3]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t vmxnet3_get_mac_high(MACAddr *addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return VMXNET3_MAKE_BYTE(0, addr->a[4]) | | 
					
						
							|  |  |  |            VMXNET3_MAKE_BYTE(1, addr->a[5]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_inc_tx_consumption_counter(VMXNET3State *s, int qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_ring_inc(&s->txq_descr[qidx].tx_ring); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_inc_rx_consumption_counter(VMXNET3State *s, int qidx, int ridx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_ring_inc(&s->rxq_descr[qidx].rx_ring[ridx]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_inc_tx_completion_counter(VMXNET3State *s, int qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_ring_inc(&s->txq_descr[qidx].comp_ring); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_inc_rx_completion_counter(VMXNET3State *s, int qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_ring_inc(&s->rxq_descr[qidx].comp_ring); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_dec_rx_completion_counter(VMXNET3State *s, int qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_ring_dec(&s->rxq_descr[qidx].comp_ring); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-22 15:09:21 +00:00
										 |  |  | static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     struct Vmxnet3_TxCompDesc txcq_descr; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 00:42:20 +05:30
										 |  |  |     memset(&txcq_descr, 0, sizeof(txcq_descr)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     txcq_descr.txdIdx = tx_ridx; | 
					
						
							|  |  |  |     txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring); | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |     txcq_descr.val1 = cpu_to_le32(txcq_descr.val1); | 
					
						
							|  |  |  |     txcq_descr.val2 = cpu_to_le32(txcq_descr.val2); | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     vmxnet3_ring_write_curr_cell(d, &s->txq_descr[qidx].comp_ring, &txcq_descr); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Flush changes in TX descriptor before changing the counter value */ | 
					
						
							|  |  |  |     smp_wmb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_inc_tx_completion_counter(s, qidx); | 
					
						
							|  |  |  |     vmxnet3_trigger_interrupt(s, s->txq_descr[qidx].intr_idx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_setup_tx_offloads(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (s->offload_mode) { | 
					
						
							|  |  |  |     case VMXNET3_OM_NONE: | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_tx_pkt_build_vheader(s->tx_pkt, false, false, 0); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_OM_CSUM: | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_tx_pkt_build_vheader(s->tx_pkt, false, true, 0); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMW_PKPRN("L4 CSO requested\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_OM_TSO: | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_tx_pkt_build_vheader(s->tx_pkt, true, true, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             s->cso_or_gso_size); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_tx_pkt_update_ip_checksums(s->tx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMW_PKPRN("GSO offload requested."); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |         g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_tx_retrieve_metadata(VMXNET3State *s, | 
					
						
							|  |  |  |                              const struct Vmxnet3_TxDesc *txd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->offload_mode = txd->om; | 
					
						
							|  |  |  |     s->cso_or_gso_size = txd->msscof; | 
					
						
							|  |  |  |     s->tci = txd->tci; | 
					
						
							|  |  |  |     s->needs_vlan = txd->ti; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef enum { | 
					
						
							|  |  |  |     VMXNET3_PKT_STATUS_OK, | 
					
						
							|  |  |  |     VMXNET3_PKT_STATUS_ERROR, | 
					
						
							|  |  |  |     VMXNET3_PKT_STATUS_DISCARD,/* only for tx */ | 
					
						
							|  |  |  |     VMXNET3_PKT_STATUS_OUT_OF_BUF /* only for rx */ | 
					
						
							|  |  |  | } Vmxnet3PktStatus; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx, | 
					
						
							|  |  |  |     Vmxnet3PktStatus status) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     size_t tot_len = net_tx_pkt_get_total_len(s->tx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     struct UPT1_TxStats *stats = &s->txq_descr[qidx].txq_stats; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (status) { | 
					
						
							|  |  |  |     case VMXNET3_PKT_STATUS_OK: | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         switch (net_tx_pkt_get_packet_type(s->tx_pkt)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         case ETH_PKT_BCAST: | 
					
						
							|  |  |  |             stats->bcastPktsTxOK++; | 
					
						
							|  |  |  |             stats->bcastBytesTxOK += tot_len; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case ETH_PKT_MCAST: | 
					
						
							|  |  |  |             stats->mcastPktsTxOK++; | 
					
						
							|  |  |  |             stats->mcastBytesTxOK += tot_len; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case ETH_PKT_UCAST: | 
					
						
							|  |  |  |             stats->ucastPktsTxOK++; | 
					
						
							|  |  |  |             stats->ucastBytesTxOK += tot_len; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |             g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (s->offload_mode == VMXNET3_OM_TSO) { | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * According to VMWARE headers this statistic is a number | 
					
						
							|  |  |  |              * of packets after segmentation but since we don't have | 
					
						
							|  |  |  |              * this information in QEMU model, the best we can do is to | 
					
						
							|  |  |  |              * provide number of non-segmented packets | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             stats->TSOPktsTxOK++; | 
					
						
							|  |  |  |             stats->TSOBytesTxOK += tot_len; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_PKT_STATUS_DISCARD: | 
					
						
							|  |  |  |         stats->pktsTxDiscard++; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_PKT_STATUS_ERROR: | 
					
						
							|  |  |  |         stats->pktsTxError++; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |         g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_on_rx_done_update_stats(VMXNET3State *s, | 
					
						
							|  |  |  |                                 int qidx, | 
					
						
							|  |  |  |                                 Vmxnet3PktStatus status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct UPT1_RxStats *stats = &s->rxq_descr[qidx].rxq_stats; | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     size_t tot_len = net_rx_pkt_get_total_len(s->rx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (status) { | 
					
						
							|  |  |  |     case VMXNET3_PKT_STATUS_OUT_OF_BUF: | 
					
						
							|  |  |  |         stats->pktsRxOutOfBuf++; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_PKT_STATUS_ERROR: | 
					
						
							|  |  |  |         stats->pktsRxError++; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case VMXNET3_PKT_STATUS_OK: | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         switch (net_rx_pkt_get_packet_type(s->rx_pkt)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         case ETH_PKT_BCAST: | 
					
						
							|  |  |  |             stats->bcastPktsRxOK++; | 
					
						
							|  |  |  |             stats->bcastBytesRxOK += tot_len; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case ETH_PKT_MCAST: | 
					
						
							|  |  |  |             stats->mcastPktsRxOK++; | 
					
						
							|  |  |  |             stats->mcastBytesRxOK += tot_len; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case ETH_PKT_UCAST: | 
					
						
							|  |  |  |             stats->ucastPktsRxOK++; | 
					
						
							|  |  |  |             stats->ucastBytesRxOK += tot_len; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |             g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (tot_len > s->mtu) { | 
					
						
							|  |  |  |             stats->LROPktsRxOK++; | 
					
						
							|  |  |  |             stats->LROBytesRxOK += tot_len; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |         g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_ring_read_curr_txdesc(PCIDevice *pcidev, Vmxnet3Ring *ring, | 
					
						
							|  |  |  |                               struct Vmxnet3_TxDesc *txd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_ring_read_curr_cell(pcidev, ring, txd); | 
					
						
							|  |  |  |     txd->addr = le64_to_cpu(txd->addr); | 
					
						
							|  |  |  |     txd->val1 = le32_to_cpu(txd->val1); | 
					
						
							|  |  |  |     txd->val2 = le32_to_cpu(txd->val2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | static inline bool | 
					
						
							|  |  |  | vmxnet3_pop_next_tx_descr(VMXNET3State *s, | 
					
						
							|  |  |  |                           int qidx, | 
					
						
							|  |  |  |                           struct Vmxnet3_TxDesc *txd, | 
					
						
							|  |  |  |                           uint32_t *descr_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |     vmxnet3_ring_read_curr_txdesc(d, ring, txd); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     if (txd->gen == vmxnet3_ring_curr_gen(ring)) { | 
					
						
							|  |  |  |         /* Only read after generation field verification */ | 
					
						
							|  |  |  |         smp_rmb(); | 
					
						
							|  |  |  |         /* Re-read to be sure we got the latest version */ | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |         vmxnet3_ring_read_curr_txdesc(d, ring, txd); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring); | 
					
						
							|  |  |  |         *descr_idx = vmxnet3_ring_curr_cell_idx(ring); | 
					
						
							|  |  |  |         vmxnet3_inc_tx_consumption_counter(s, qidx); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_send_packet(VMXNET3State *s, uint32_t qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Vmxnet3PktStatus status = VMXNET3_PKT_STATUS_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!vmxnet3_setup_tx_offloads(s)) { | 
					
						
							|  |  |  |         status = VMXNET3_PKT_STATUS_ERROR; | 
					
						
							|  |  |  |         goto func_exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* debug prints */ | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     vmxnet3_dump_virt_hdr(net_tx_pkt_get_vhdr(s->tx_pkt)); | 
					
						
							|  |  |  |     net_tx_pkt_dump(s->tx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     if (!net_tx_pkt_send(s->tx_pkt, qemu_get_queue(s->nic))) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         status = VMXNET3_PKT_STATUS_DISCARD; | 
					
						
							|  |  |  |         goto func_exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func_exit: | 
					
						
							|  |  |  |     vmxnet3_on_tx_done_update_stats(s, qidx, status); | 
					
						
							|  |  |  |     return (status == VMXNET3_PKT_STATUS_OK); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct Vmxnet3_TxDesc txd; | 
					
						
							|  |  |  |     uint32_t txd_idx; | 
					
						
							|  |  |  |     uint32_t data_len; | 
					
						
							|  |  |  |     hwaddr data_pa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							|  |  |  |         if (!vmxnet3_pop_next_tx_descr(s, qidx, &txd, &txd_idx)) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vmxnet3_dump_tx_descr(&txd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!s->skip_current_tx_pkt) { | 
					
						
							|  |  |  |             data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE; | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |             data_pa = txd.addr; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |             if (!net_tx_pkt_add_raw_fragment(s->tx_pkt, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                                 data_pa, | 
					
						
							|  |  |  |                                                 data_len)) { | 
					
						
							|  |  |  |                 s->skip_current_tx_pkt = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (s->tx_sop) { | 
					
						
							|  |  |  |             vmxnet3_tx_retrieve_metadata(s, &txd); | 
					
						
							|  |  |  |             s->tx_sop = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (txd.eop) { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |             if (!s->skip_current_tx_pkt && net_tx_pkt_parse(s->tx_pkt)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                 if (s->needs_vlan) { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |                     net_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 vmxnet3_send_packet(s, qidx); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 vmxnet3_on_tx_done_update_stats(s, qidx, | 
					
						
							|  |  |  |                                                 VMXNET3_PKT_STATUS_ERROR); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             vmxnet3_complete_packet(s, qidx, txd_idx); | 
					
						
							|  |  |  |             s->tx_sop = true; | 
					
						
							|  |  |  |             s->skip_current_tx_pkt = false; | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |             net_tx_pkt_reset(s->tx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_read_next_rx_descr(VMXNET3State *s, int qidx, int ridx, | 
					
						
							|  |  |  |                            struct Vmxnet3_RxDesc *dbuf, uint32_t *didx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     Vmxnet3Ring *ring = &s->rxq_descr[qidx].rx_ring[ridx]; | 
					
						
							|  |  |  |     *didx = vmxnet3_ring_curr_cell_idx(ring); | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     vmxnet3_ring_read_curr_cell(d, ring, dbuf); | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |     dbuf->addr = le64_to_cpu(dbuf->addr); | 
					
						
							|  |  |  |     dbuf->val1 = le32_to_cpu(dbuf->val1); | 
					
						
							|  |  |  |     dbuf->ext1 = le32_to_cpu(dbuf->ext1); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline uint8_t | 
					
						
							|  |  |  | vmxnet3_get_rx_ring_gen(VMXNET3State *s, int qidx, int ridx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return s->rxq_descr[qidx].rx_ring[ridx].gen; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline hwaddr | 
					
						
							|  |  |  | vmxnet3_pop_rxc_descr(VMXNET3State *s, int qidx, uint32_t *descr_gen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t ring_gen; | 
					
						
							|  |  |  |     struct Vmxnet3_RxCompDesc rxcd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hwaddr daddr = | 
					
						
							|  |  |  |         vmxnet3_ring_curr_cell_pa(&s->rxq_descr[qidx].comp_ring); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     pci_dma_read(PCI_DEVICE(s), | 
					
						
							|  |  |  |                  daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc)); | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |     rxcd.val1 = le32_to_cpu(rxcd.val1); | 
					
						
							|  |  |  |     rxcd.val2 = le32_to_cpu(rxcd.val2); | 
					
						
							|  |  |  |     rxcd.val3 = le32_to_cpu(rxcd.val3); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     ring_gen = vmxnet3_ring_curr_gen(&s->rxq_descr[qidx].comp_ring); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (rxcd.gen != ring_gen) { | 
					
						
							|  |  |  |         *descr_gen = ring_gen; | 
					
						
							|  |  |  |         vmxnet3_inc_rx_completion_counter(s, qidx); | 
					
						
							|  |  |  |         return daddr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | vmxnet3_revert_rxc_descr(VMXNET3State *s, int qidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_dec_rx_completion_counter(s, qidx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RXQ_IDX      (0)
 | 
					
						
							|  |  |  | #define RX_HEAD_BODY_RING (0)
 | 
					
						
							|  |  |  | #define RX_BODY_ONLY_RING (1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_get_next_head_rx_descr(VMXNET3State *s, | 
					
						
							|  |  |  |                                struct Vmxnet3_RxDesc *descr_buf, | 
					
						
							|  |  |  |                                uint32_t *descr_idx, | 
					
						
							|  |  |  |                                uint32_t *ridx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							|  |  |  |         uint32_t ring_gen; | 
					
						
							|  |  |  |         vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, | 
					
						
							|  |  |  |                                    descr_buf, descr_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* If no more free descriptors - return */ | 
					
						
							|  |  |  |         ring_gen = vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING); | 
					
						
							|  |  |  |         if (descr_buf->gen != ring_gen) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Only read after generation field verification */ | 
					
						
							|  |  |  |         smp_rmb(); | 
					
						
							|  |  |  |         /* Re-read to be sure we got the latest version */ | 
					
						
							|  |  |  |         vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, | 
					
						
							|  |  |  |                                    descr_buf, descr_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Mark current descriptor as used/skipped */ | 
					
						
							|  |  |  |         vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* If this is what we are looking for - return */ | 
					
						
							|  |  |  |         if (descr_buf->btype == VMXNET3_RXD_BTYPE_HEAD) { | 
					
						
							|  |  |  |             *ridx = RX_HEAD_BODY_RING; | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_get_next_body_rx_descr(VMXNET3State *s, | 
					
						
							|  |  |  |                                struct Vmxnet3_RxDesc *d, | 
					
						
							|  |  |  |                                uint32_t *didx, | 
					
						
							|  |  |  |                                uint32_t *ridx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Try to find corresponding descriptor in head/body ring */ | 
					
						
							|  |  |  |     if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING)) { | 
					
						
							|  |  |  |         /* Only read after generation field verification */ | 
					
						
							|  |  |  |         smp_rmb(); | 
					
						
							|  |  |  |         /* Re-read to be sure we got the latest version */ | 
					
						
							|  |  |  |         vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx); | 
					
						
							|  |  |  |         if (d->btype == VMXNET3_RXD_BTYPE_BODY) { | 
					
						
							|  |  |  |             vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING); | 
					
						
							|  |  |  |             *ridx = RX_HEAD_BODY_RING; | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If there is no free descriptors on head/body ring or next free | 
					
						
							|  |  |  |      * descriptor is a head descriptor switch to body only ring | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* If no more free descriptors - return */ | 
					
						
							|  |  |  |     if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_BODY_ONLY_RING)) { | 
					
						
							|  |  |  |         /* Only read after generation field verification */ | 
					
						
							|  |  |  |         smp_rmb(); | 
					
						
							|  |  |  |         /* Re-read to be sure we got the latest version */ | 
					
						
							|  |  |  |         vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx); | 
					
						
							|  |  |  |         assert(d->btype == VMXNET3_RXD_BTYPE_BODY); | 
					
						
							|  |  |  |         *ridx = RX_BODY_ONLY_RING; | 
					
						
							|  |  |  |         vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_BODY_ONLY_RING); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool | 
					
						
							|  |  |  | vmxnet3_get_next_rx_descr(VMXNET3State *s, bool is_head, | 
					
						
							|  |  |  |                           struct Vmxnet3_RxDesc *descr_buf, | 
					
						
							|  |  |  |                           uint32_t *descr_idx, | 
					
						
							|  |  |  |                           uint32_t *ridx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_head || !s->rx_packets_compound) { | 
					
						
							|  |  |  |         return vmxnet3_get_next_head_rx_descr(s, descr_buf, descr_idx, ridx); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return vmxnet3_get_next_body_rx_descr(s, descr_buf, descr_idx, ridx); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  | /* In case packet was csum offloaded (either NEEDS_CSUM or DATA_VALID),
 | 
					
						
							|  |  |  |  * the implementation always passes an RxCompDesc with a "Checksum | 
					
						
							|  |  |  |  * calculated and found correct" to the OS (cnc=0 and tuc=1, see | 
					
						
							|  |  |  |  * vmxnet3_rx_update_descr). This emulates the observed ESXi behavior. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Therefore, if packet has the NEEDS_CSUM set, we must calculate | 
					
						
							|  |  |  |  * and place a fully computed checksum into the tcp/udp header. | 
					
						
							|  |  |  |  * Otherwise, the OS driver will receive a checksum-correct indication | 
					
						
							|  |  |  |  * (CHECKSUM_UNNECESSARY), but with the actual tcp/udp checksum field | 
					
						
							|  |  |  |  * having just the pseudo header csum value. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * While this is not a problem if packet is destined for local delivery, | 
					
						
							|  |  |  |  * in the case the host OS performs forwarding, it will forward an | 
					
						
							|  |  |  |  * incorrectly checksummed packet. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  | static void vmxnet3_rx_need_csum_calculate(struct NetRxPkt *pkt, | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |                                            const void *pkt_data, | 
					
						
							|  |  |  |                                            size_t pkt_len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct virtio_net_hdr *vhdr; | 
					
						
							|  |  |  |     bool isip4, isip6, istcp, isudp; | 
					
						
							|  |  |  |     uint8_t *data; | 
					
						
							|  |  |  |     int len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     if (!net_rx_pkt_has_virt_hdr(pkt)) { | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     vhdr = net_rx_pkt_get_vhdr(pkt); | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |     if (!VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |     if (!(isip4 || isip6) || !(istcp || isudp)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_dump_virt_hdr(vhdr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Validate packet len: csum_start + scum_offset + length of csum field */ | 
					
						
							|  |  |  |     if (pkt_len < (vhdr->csum_start + vhdr->csum_offset + 2)) { | 
					
						
							| 
									
										
										
										
											2015-12-07 21:28:31 -08:00
										 |  |  |         VMW_PKPRN("packet len:%zu < csum_start(%d) + csum_offset(%d) + 2, " | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |                   "cannot calculate checksum", | 
					
						
							| 
									
										
										
										
											2015-07-28 21:44:50 +03:00
										 |  |  |                   pkt_len, vhdr->csum_start, vhdr->csum_offset); | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = (uint8_t *)pkt_data + vhdr->csum_start; | 
					
						
							|  |  |  |     len = pkt_len - vhdr->csum_start; | 
					
						
							|  |  |  |     /* Put the checksum obtained into the packet */ | 
					
						
							| 
									
										
										
										
											2017-11-16 06:06:06 -08:00
										 |  |  |     stw_be_p(data + vhdr->csum_offset, | 
					
						
							|  |  |  |              net_checksum_finish_nozero(net_checksum_add(len, data))); | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     vhdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM; | 
					
						
							|  |  |  |     vhdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  | static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     struct Vmxnet3_RxCompDesc *rxcd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int csum_ok, is_gso; | 
					
						
							|  |  |  |     bool isip4, isip6, istcp, isudp; | 
					
						
							|  |  |  |     struct virtio_net_hdr *vhdr; | 
					
						
							|  |  |  |     uint8_t offload_type; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     if (net_rx_pkt_is_vlan_stripped(pkt)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         rxcd->ts = 1; | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         rxcd->tci = net_rx_pkt_get_vlan_tag(pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     if (!net_rx_pkt_has_virt_hdr(pkt)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         goto nocsum; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     vhdr = net_rx_pkt_get_vhdr(pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     /*
 | 
					
						
							|  |  |  |      * Checksum is valid when lower level tell so or when lower level | 
					
						
							|  |  |  |      * requires checksum offload telling that packet produced/bridged | 
					
						
							|  |  |  |      * locally and did travel over network after last checksum calculation | 
					
						
							|  |  |  |      * or production | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     csum_ok = VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_DATA_VALID) || | 
					
						
							|  |  |  |               VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     offload_type = vhdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN; | 
					
						
							|  |  |  |     is_gso = (offload_type != VIRTIO_NET_HDR_GSO_NONE) ? 1 : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!csum_ok && !is_gso) { | 
					
						
							|  |  |  |         goto nocsum; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     if ((!istcp && !isudp) || (!isip4 && !isip6)) { | 
					
						
							|  |  |  |         goto nocsum; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rxcd->cnc = 0; | 
					
						
							|  |  |  |     rxcd->v4 = isip4 ? 1 : 0; | 
					
						
							|  |  |  |     rxcd->v6 = isip6 ? 1 : 0; | 
					
						
							|  |  |  |     rxcd->tcp = istcp ? 1 : 0; | 
					
						
							|  |  |  |     rxcd->udp = isudp ? 1 : 0; | 
					
						
							|  |  |  |     rxcd->fcs = rxcd->tuc = rxcd->ipc = 1; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | nocsum: | 
					
						
							|  |  |  |     rxcd->cnc = 1; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  | vmxnet3_pci_dma_writev(PCIDevice *pci_dev, | 
					
						
							|  |  |  |                        const struct iovec *iov, | 
					
						
							|  |  |  |                        size_t start_iov_off, | 
					
						
							|  |  |  |                        hwaddr target_addr, | 
					
						
							|  |  |  |                        size_t bytes_to_copy) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     size_t curr_off = 0; | 
					
						
							|  |  |  |     size_t copied = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (bytes_to_copy) { | 
					
						
							|  |  |  |         if (start_iov_off < (curr_off + iov->iov_len)) { | 
					
						
							|  |  |  |             size_t chunk_len = | 
					
						
							|  |  |  |                 MIN((curr_off + iov->iov_len) - start_iov_off, bytes_to_copy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  |             pci_dma_write(pci_dev, target_addr + copied, | 
					
						
							|  |  |  |                           iov->iov_base + start_iov_off - curr_off, | 
					
						
							|  |  |  |                           chunk_len); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             copied += chunk_len; | 
					
						
							|  |  |  |             start_iov_off += chunk_len; | 
					
						
							|  |  |  |             curr_off = start_iov_off; | 
					
						
							|  |  |  |             bytes_to_copy -= chunk_len; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             curr_off += iov->iov_len; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         iov++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  | static void | 
					
						
							|  |  |  | vmxnet3_pci_dma_write_rxcd(PCIDevice *pcidev, dma_addr_t pa, | 
					
						
							|  |  |  |                            struct Vmxnet3_RxCompDesc *rxcd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     rxcd->val1 = cpu_to_le32(rxcd->val1); | 
					
						
							|  |  |  |     rxcd->val2 = cpu_to_le32(rxcd->val2); | 
					
						
							|  |  |  |     rxcd->val3 = cpu_to_le32(rxcd->val3); | 
					
						
							|  |  |  |     pci_dma_write(pcidev, pa, rxcd, sizeof(*rxcd)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_indicate_packet(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct Vmxnet3_RxDesc rxd; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     bool is_head = true; | 
					
						
							|  |  |  |     uint32_t rxd_idx; | 
					
						
							| 
									
										
										
										
											2013-03-26 10:24:06 +08:00
										 |  |  |     uint32_t rx_ridx = 0; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     struct Vmxnet3_RxCompDesc rxcd; | 
					
						
							|  |  |  |     uint32_t new_rxcd_gen = VMXNET3_INIT_GEN; | 
					
						
							|  |  |  |     hwaddr new_rxcd_pa = 0; | 
					
						
							|  |  |  |     hwaddr ready_rxcd_pa = 0; | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     struct iovec *data = net_rx_pkt_get_iovec(s->rx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     size_t bytes_copied = 0; | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     size_t bytes_left = net_rx_pkt_get_total_len(s->rx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     uint16_t num_frags = 0; | 
					
						
							|  |  |  |     size_t chunk_size; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     net_rx_pkt_dump(s->rx_pkt); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     while (bytes_left > 0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* cannot add more frags to packet */ | 
					
						
							|  |  |  |         if (num_frags == s->max_rx_frags) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         new_rxcd_pa = vmxnet3_pop_rxc_descr(s, RXQ_IDX, &new_rxcd_gen); | 
					
						
							|  |  |  |         if (!new_rxcd_pa) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!vmxnet3_get_next_rx_descr(s, is_head, &rxd, &rxd_idx, &rx_ridx)) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         chunk_size = MIN(bytes_left, rxd.len); | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |         vmxnet3_pci_dma_writev(d, data, bytes_copied, rxd.addr, chunk_size); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         bytes_copied += chunk_size; | 
					
						
							|  |  |  |         bytes_left -= chunk_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vmxnet3_dump_rx_descr(&rxd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |         if (ready_rxcd_pa != 0) { | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |             vmxnet3_pci_dma_write_rxcd(d, ready_rxcd_pa, &rxcd); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         memset(&rxcd, 0, sizeof(struct Vmxnet3_RxCompDesc)); | 
					
						
							|  |  |  |         rxcd.rxdIdx = rxd_idx; | 
					
						
							|  |  |  |         rxcd.len = chunk_size; | 
					
						
							|  |  |  |         rxcd.sop = is_head; | 
					
						
							|  |  |  |         rxcd.gen = new_rxcd_gen; | 
					
						
							|  |  |  |         rxcd.rqID = RXQ_IDX + rx_ridx * s->rxq_num; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |         if (bytes_left == 0) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             vmxnet3_rx_update_descr(s->rx_pkt, &rxcd); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         VMW_RIPRN("RX Completion descriptor: rxRing: %lu rxIdx %lu len %lu " | 
					
						
							|  |  |  |                   "sop %d csum_correct %lu", | 
					
						
							|  |  |  |                   (unsigned long) rx_ridx, | 
					
						
							|  |  |  |                   (unsigned long) rxcd.rxdIdx, | 
					
						
							|  |  |  |                   (unsigned long) rxcd.len, | 
					
						
							|  |  |  |                   (int) rxcd.sop, | 
					
						
							|  |  |  |                   (unsigned long) rxcd.tuc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         is_head = false; | 
					
						
							|  |  |  |         ready_rxcd_pa = new_rxcd_pa; | 
					
						
							|  |  |  |         new_rxcd_pa = 0; | 
					
						
							| 
									
										
										
										
											2013-03-28 10:53:29 +02:00
										 |  |  |         num_frags++; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |     if (ready_rxcd_pa != 0) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         rxcd.eop = 1; | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |         rxcd.err = (bytes_left != 0); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-14 12:20:24 +01:00
										 |  |  |         vmxnet3_pci_dma_write_rxcd(d, ready_rxcd_pa, &rxcd); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         /* Flush RX descriptor changes */ | 
					
						
							|  |  |  |         smp_wmb(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |     if (new_rxcd_pa != 0) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         vmxnet3_revert_rxc_descr(s, RXQ_IDX); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_trigger_interrupt(s, s->rxq_descr[RXQ_IDX].intr_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (bytes_left == 0) { | 
					
						
							|  |  |  |         vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_OK); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } else if (num_frags == s->max_rx_frags) { | 
					
						
							|  |  |  |         vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_ERROR); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, | 
					
						
							|  |  |  |                                         VMXNET3_PKT_STATUS_OUT_OF_BUF); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_io_bar0_write(void *opaque, hwaddr addr, | 
					
						
							|  |  |  |                       uint64_t val, unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-08 18:08:31 +05:30
										 |  |  |     if (!s->device_active) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_TXPROD, | 
					
						
							|  |  |  |                         VMXNET3_DEVICE_MAX_TX_QUEUES, VMXNET3_REG_ALIGN)) { | 
					
						
							|  |  |  |         int tx_queue_idx = | 
					
						
							|  |  |  |             VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_TXPROD, | 
					
						
							|  |  |  |                                      VMXNET3_REG_ALIGN); | 
					
						
							| 
									
										
										
										
											2021-07-15 12:37:55 +02:00
										 |  |  |         if (tx_queue_idx <= s->txq_num) { | 
					
						
							|  |  |  |             vmxnet3_process_tx_queue(s, tx_queue_idx); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Illegal TX queue %d/%d\n", | 
					
						
							|  |  |  |                           tx_queue_idx, s->txq_num); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR, | 
					
						
							|  |  |  |                         VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) { | 
					
						
							|  |  |  |         int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR, | 
					
						
							|  |  |  |                                          VMXNET3_REG_ALIGN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         VMW_CBPRN("Interrupt mask for line %d written: 0x%" PRIx64, l, val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         vmxnet3_on_interrupt_mask_changed(s, l, val); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD, | 
					
						
							|  |  |  |                         VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN) || | 
					
						
							|  |  |  |        VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD2, | 
					
						
							|  |  |  |                         VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_WRPRN("BAR0 unknown write [%" PRIx64 "] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |               (uint64_t) addr, val, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t | 
					
						
							|  |  |  | vmxnet3_io_bar0_read(void *opaque, hwaddr addr, unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-09-21 17:09:02 +03:00
										 |  |  |     VMXNET3State *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR, | 
					
						
							|  |  |  |                         VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) { | 
					
						
							| 
									
										
										
										
											2015-09-21 17:09:02 +03:00
										 |  |  |         int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR, | 
					
						
							|  |  |  |                                          VMXNET3_REG_ALIGN); | 
					
						
							|  |  |  |         return s->interrupt_states[l].is_masked; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("BAR0 unknown read [%" PRIx64 "], size %d", addr, size); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_reset_interrupt_states(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     for (i = 0; i < ARRAY_SIZE(s->interrupt_states); i++) { | 
					
						
							|  |  |  |         s->interrupt_states[i].is_asserted = false; | 
					
						
							|  |  |  |         s->interrupt_states[i].is_pending = false; | 
					
						
							|  |  |  |         s->interrupt_states[i].is_masked = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_reset_mac(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memcpy(&s->conf.macaddr.a, &s->perm_mac.a, sizeof(s->perm_mac.a)); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:38 +03:00
										 |  |  |     VMW_CFPRN("MAC address set to: " MAC_FMT, MAC_ARG(s->conf.macaddr.a)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_deactivate_device(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-12-15 12:27:54 +05:30
										 |  |  |     if (s->device_active) { | 
					
						
							|  |  |  |         VMW_CBPRN("Deactivating vmxnet3..."); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_tx_pkt_reset(s->tx_pkt); | 
					
						
							|  |  |  |         net_tx_pkt_uninit(s->tx_pkt); | 
					
						
							|  |  |  |         net_rx_pkt_uninit(s->rx_pkt); | 
					
						
							| 
									
										
										
										
											2015-12-15 12:27:54 +05:30
										 |  |  |         s->device_active = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_reset(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMW_CBPRN("Resetting vmxnet3..."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_deactivate_device(s); | 
					
						
							|  |  |  |     vmxnet3_reset_interrupt_states(s); | 
					
						
							|  |  |  |     s->drv_shmem = 0; | 
					
						
							|  |  |  |     s->tx_sop = true; | 
					
						
							|  |  |  |     s->skip_current_tx_pkt = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_update_rx_mode(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->rx_mode = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                            devRead.rxFilterConf.rxMode); | 
					
						
							|  |  |  |     VMW_CFPRN("RX mode: 0x%08X", s->rx_mode); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_update_vlan_filters(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Copy configuration from shared memory */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     VMXNET3_READ_DRV_SHARED(d, s->drv_shmem, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                             devRead.rxFilterConf.vfTable, | 
					
						
							|  |  |  |                             s->vlan_table, | 
					
						
							|  |  |  |                             sizeof(s->vlan_table)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Invert byte order when needed */ | 
					
						
							|  |  |  |     for (i = 0; i < ARRAY_SIZE(s->vlan_table); i++) { | 
					
						
							|  |  |  |         s->vlan_table[i] = le32_to_cpu(s->vlan_table[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Dump configuration for debugging purposes */ | 
					
						
							|  |  |  |     VMW_CFPRN("Configured VLANs:"); | 
					
						
							|  |  |  |     for (i = 0; i < sizeof(s->vlan_table) * 8; i++) { | 
					
						
							|  |  |  |         if (VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, i)) { | 
					
						
							|  |  |  |             VMW_CFPRN("\tVLAN %d is present", i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_update_mcast_filters(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     uint16_t list_bytes = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED16(d, s->drv_shmem, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                   devRead.rxFilterConf.mfTableLen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->mcast_list_len = list_bytes / sizeof(s->mcast_list[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->mcast_list = g_realloc(s->mcast_list, list_bytes); | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |     if (!s->mcast_list) { | 
					
						
							|  |  |  |         if (s->mcast_list_len == 0) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             VMW_CFPRN("Current multicast list is empty"); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             VMW_ERPRN("Failed to allocate multicast list of %d elements", | 
					
						
							|  |  |  |                       s->mcast_list_len); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         s->mcast_list_len = 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         int i; | 
					
						
							|  |  |  |         hwaddr mcast_list_pa = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |             VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                       devRead.rxFilterConf.mfTablePA); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         pci_dma_read(d, mcast_list_pa, s->mcast_list, list_bytes); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMW_CFPRN("Current multicast list len is %d:", s->mcast_list_len); | 
					
						
							|  |  |  |         for (i = 0; i < s->mcast_list_len; i++) { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:38 +03:00
										 |  |  |             VMW_CFPRN("\t" MAC_FMT, MAC_ARG(s->mcast_list[i].a)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_setup_rx_filtering(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vmxnet3_update_rx_mode(s); | 
					
						
							|  |  |  |     vmxnet3_update_vlan_filters(s); | 
					
						
							|  |  |  |     vmxnet3_update_mcast_filters(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t interrupt_mode = VMXNET3_IT_AUTO | (VMXNET3_IMM_AUTO << 2); | 
					
						
							|  |  |  |     VMW_CFPRN("Interrupt config is 0x%X", interrupt_mode); | 
					
						
							|  |  |  |     return interrupt_mode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_fill_stats(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2015-10-15 13:54:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!s->device_active) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     for (i = 0; i < s->txq_num; i++) { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         pci_dma_write(d, | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  |                       s->txq_descr[i].tx_stats_pa, | 
					
						
							|  |  |  |                       &s->txq_descr[i].txq_stats, | 
					
						
							|  |  |  |                       sizeof(s->txq_descr[i].txq_stats)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < s->rxq_num; i++) { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         pci_dma_write(d, | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  |                       s->rxq_descr[i].rx_stats_pa, | 
					
						
							|  |  |  |                       &s->rxq_descr[i].rxq_stats, | 
					
						
							|  |  |  |                       sizeof(s->rxq_descr[i].rxq_stats)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_adjust_by_guest_type(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct Vmxnet3_GOSInfo gos; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     VMXNET3_READ_DRV_SHARED(d, s->drv_shmem, devRead.misc.driverInfo.gos, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                             &gos, sizeof(gos)); | 
					
						
							|  |  |  |     s->rx_packets_compound = | 
					
						
							|  |  |  |         (gos.gosType == VMXNET3_GOS_TYPE_WIN) ? false : true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CFPRN("Guest type specifics: RXCOMPOUND: %d", s->rx_packets_compound); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_dump_conf_descr(const char *name, | 
					
						
							|  |  |  |                         struct Vmxnet3_VariableLenConfDesc *pm_descr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMW_CFPRN("%s descriptor dump: Version %u, Length %u", | 
					
						
							|  |  |  |               name, pm_descr->confVer, pm_descr->confLen); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_update_pm_state(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct Vmxnet3_VariableLenConfDesc pm_descr; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     pm_descr.confLen = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.pmConfDesc.confLen); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     pm_descr.confVer = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.pmConfDesc.confVer); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     pm_descr.confPA = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, devRead.pmConfDesc.confPA); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_dump_conf_descr("PM State", &pm_descr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_update_features(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t guest_features; | 
					
						
							|  |  |  |     int rxcso_supported; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     guest_features = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                                devRead.misc.uptFeatures); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM); | 
					
						
							|  |  |  |     s->rx_vlan_stripping = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXVLAN); | 
					
						
							|  |  |  |     s->lro_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_LRO); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CFPRN("Features configuration: LRO: %d, RXCSUM: %d, VLANSTRIP: %d", | 
					
						
							|  |  |  |               s->lro_supported, rxcso_supported, | 
					
						
							|  |  |  |               s->rx_vlan_stripping); | 
					
						
							|  |  |  |     if (s->peer_has_vhdr) { | 
					
						
							| 
									
										
										
										
											2014-02-20 12:14:07 +01:00
										 |  |  |         qemu_set_offload(qemu_get_queue(s->nic)->peer, | 
					
						
							|  |  |  |                          rxcso_supported, | 
					
						
							|  |  |  |                          s->lro_supported, | 
					
						
							|  |  |  |                          s->lro_supported, | 
					
						
							|  |  |  |                          0, | 
					
						
							|  |  |  |                          0); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  | static bool vmxnet3_verify_intx(VMXNET3State *s, int intx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:42 +08:00
										 |  |  |     return s->msix_used || msi_enabled(PCI_DEVICE(s)) | 
					
						
							|  |  |  |         || intx == pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1; | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:19 +03:00
										 |  |  | static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS; | 
					
						
							|  |  |  |     if (idx >= max_ints) { | 
					
						
							|  |  |  |         hw_error("Bad interrupt index: %d\n", idx); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_validate_interrupts(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx); | 
					
						
							|  |  |  |     vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < s->txq_num; i++) { | 
					
						
							|  |  |  |         int idx = s->txq_descr[i].intr_idx; | 
					
						
							|  |  |  |         VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx); | 
					
						
							|  |  |  |         vmxnet3_validate_interrupt_idx(s->msix_used, idx); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < s->rxq_num; i++) { | 
					
						
							|  |  |  |         int idx = s->rxq_descr[i].intr_idx; | 
					
						
							|  |  |  |         VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx); | 
					
						
							|  |  |  |         vmxnet3_validate_interrupt_idx(s->msix_used, idx); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-21 16:15:59 +02:00
										 |  |  | static bool vmxnet3_validate_queues(VMXNET3State *s) | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:20 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |     * txq_num and rxq_num are total number of queues | 
					
						
							|  |  |  |     * configured by guest. These numbers must not | 
					
						
							|  |  |  |     * exceed corresponding maximal values. | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->txq_num > VMXNET3_DEVICE_MAX_TX_QUEUES) { | 
					
						
							| 
									
										
										
										
											2021-07-21 16:15:59 +02:00
										 |  |  |         qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Bad TX queues number: %d\n", | 
					
						
							|  |  |  |                       s->txq_num); | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:20 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->rxq_num > VMXNET3_DEVICE_MAX_RX_QUEUES) { | 
					
						
							| 
									
										
										
										
											2021-07-21 16:15:59 +02:00
										 |  |  |         qemu_log_mask(LOG_GUEST_ERROR, "vmxnet3: Bad RX queues number: %d\n", | 
					
						
							|  |  |  |                       s->rxq_num); | 
					
						
							|  |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:20 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-21 16:15:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:20 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | static void vmxnet3_activate_device(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     static const uint32_t VMXNET3_DEF_TX_THRESHOLD = 1; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     hwaddr qdescr_table_pa; | 
					
						
							|  |  |  |     uint64_t pa; | 
					
						
							|  |  |  |     uint32_t size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Verify configuration consistency */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     if (!vmxnet3_verify_driver_magic(d, s->drv_shmem)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMW_ERPRN("Device configuration received from driver is invalid"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 12:27:54 +05:30
										 |  |  |     /* Verify if device is active */ | 
					
						
							|  |  |  |     if (s->device_active) { | 
					
						
							|  |  |  |         VMW_CFPRN("Vmxnet3 device is active"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-21 16:15:59 +02:00
										 |  |  |     s->txq_num = | 
					
						
							|  |  |  |         VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numTxQueues); | 
					
						
							|  |  |  |     s->rxq_num = | 
					
						
							|  |  |  |         VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numRxQueues); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num); | 
					
						
							|  |  |  |     if (!vmxnet3_validate_queues(s)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     vmxnet3_adjust_by_guest_type(s); | 
					
						
							|  |  |  |     vmxnet3_update_features(s); | 
					
						
							|  |  |  |     vmxnet3_update_pm_state(s); | 
					
						
							|  |  |  |     vmxnet3_setup_rx_filtering(s); | 
					
						
							|  |  |  |     /* Cache fields from shared memory */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     VMW_CFPRN("MTU is %u", s->mtu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->max_rx_frags = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED16(d, s->drv_shmem, devRead.misc.maxNumRxSG); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-28 10:53:29 +02:00
										 |  |  |     if (s->max_rx_frags == 0) { | 
					
						
							|  |  |  |         s->max_rx_frags = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     VMW_CFPRN("Max RX fragments is %u", s->max_rx_frags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->event_int_idx = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.intrConf.eventIntrIdx); | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  |     assert(vmxnet3_verify_intx(s, s->event_int_idx)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     VMW_CFPRN("Events interrupt line is %u", s->event_int_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->auto_int_masking = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.intrConf.autoMask); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     VMW_CFPRN("Automatic interrupt masking is %d", (int)s->auto_int_masking); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     qdescr_table_pa = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, devRead.misc.queueDescPA); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     VMW_CFPRN("TX queues descriptors table is at 0x%" PRIx64, qdescr_table_pa); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Worst-case scenario is a packet that holds all TX rings space so | 
					
						
							|  |  |  |      * we calculate total size of all TX rings for max TX fragments number | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     s->max_tx_frags = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* TX queues */ | 
					
						
							|  |  |  |     for (i = 0; i < s->txq_num; i++) { | 
					
						
							|  |  |  |         hwaddr qdescr_pa = | 
					
						
							|  |  |  |             qdescr_table_pa + i * sizeof(struct Vmxnet3_TxQueueDesc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Read interrupt number for this TX queue */ | 
					
						
							|  |  |  |         s->txq_descr[i].intr_idx = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |             VMXNET3_READ_TX_QUEUE_DESCR8(d, qdescr_pa, conf.intrIdx); | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  |         assert(vmxnet3_verify_intx(s, s->txq_descr[i].intr_idx)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         VMW_CFPRN("TX Queue %d interrupt: %d", i, s->txq_descr[i].intr_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Read rings memory locations for TX queues */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA); | 
					
						
							|  |  |  |         size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                           sizeof(struct Vmxnet3_TxDesc), false); | 
					
						
							|  |  |  |         VMXNET3_RING_DUMP(VMW_CFPRN, "TX", i, &s->txq_descr[i].tx_ring); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         s->max_tx_frags += size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* TXC ring */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA); | 
					
						
							|  |  |  |         size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize); | 
					
						
							|  |  |  |         vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                           sizeof(struct Vmxnet3_TxCompDesc), true); | 
					
						
							|  |  |  |         VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         s->txq_descr[i].tx_stats_pa = | 
					
						
							|  |  |  |             qdescr_pa + offsetof(struct Vmxnet3_TxQueueDesc, stats); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         memset(&s->txq_descr[i].txq_stats, 0, | 
					
						
							|  |  |  |                sizeof(s->txq_descr[i].txq_stats)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Fill device-managed parameters for queues */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         VMXNET3_WRITE_TX_QUEUE_DESCR32(d, qdescr_pa, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                                        ctrl.txThreshold, | 
					
						
							|  |  |  |                                        VMXNET3_DEF_TX_THRESHOLD); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Preallocate TX packet wrapper */ | 
					
						
							|  |  |  |     VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  |     net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), | 
					
						
							|  |  |  |                     s->max_tx_frags, s->peer_has_vhdr); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Read rings memory locations for RX queues */ | 
					
						
							|  |  |  |     for (i = 0; i < s->rxq_num; i++) { | 
					
						
							|  |  |  |         int j; | 
					
						
							|  |  |  |         hwaddr qd_pa = | 
					
						
							|  |  |  |             qdescr_table_pa + s->txq_num * sizeof(struct Vmxnet3_TxQueueDesc) + | 
					
						
							|  |  |  |             i * sizeof(struct Vmxnet3_RxQueueDesc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Read interrupt number for this RX queue */ | 
					
						
							|  |  |  |         s->rxq_descr[i].intr_idx = | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |             VMXNET3_READ_TX_QUEUE_DESCR8(d, qd_pa, conf.intrIdx); | 
					
						
							| 
									
										
										
										
											2013-10-07 10:36:37 +03:00
										 |  |  |         assert(vmxnet3_verify_intx(s, s->rxq_descr[i].intr_idx)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         VMW_CFPRN("RX Queue %d interrupt: %d", i, s->rxq_descr[i].intr_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Read rings memory locations */ | 
					
						
							|  |  |  |         for (j = 0; j < VMXNET3_RX_RINGS_PER_QUEUE; j++) { | 
					
						
							|  |  |  |             /* RX rings */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |             pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]); | 
					
						
							|  |  |  |             size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]); | 
					
						
							|  |  |  |             vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                               sizeof(struct Vmxnet3_RxDesc), false); | 
					
						
							|  |  |  |             VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d", | 
					
						
							|  |  |  |                       i, j, pa, size); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* RXC ring */ | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |         pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA); | 
					
						
							|  |  |  |         size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize); | 
					
						
							|  |  |  |         vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                           sizeof(struct Vmxnet3_RxCompDesc), true); | 
					
						
							|  |  |  |         VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         s->rxq_descr[i].rx_stats_pa = | 
					
						
							|  |  |  |             qd_pa + offsetof(struct Vmxnet3_RxQueueDesc, stats); | 
					
						
							|  |  |  |         memset(&s->rxq_descr[i].rxq_stats, 0, | 
					
						
							|  |  |  |                sizeof(s->rxq_descr[i].rxq_stats)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:19 +03:00
										 |  |  |     vmxnet3_validate_interrupts(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     /* Make sure everything is in place before device activation */ | 
					
						
							|  |  |  |     smp_wmb(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_reset_mac(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->device_active = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     s->last_command = cmd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (cmd) { | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_PERM_MAC_HI: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get upper part of permanent MAC"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_PERM_MAC_LO: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get lower part of permanent MAC"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_STATS: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get device statistics"); | 
					
						
							|  |  |  |         vmxnet3_fill_stats(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_ACTIVATE_DEV: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Activating vmxnet3 device"); | 
					
						
							|  |  |  |         vmxnet3_activate_device(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_UPDATE_RX_MODE: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Update rx mode"); | 
					
						
							|  |  |  |         vmxnet3_update_rx_mode(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_UPDATE_VLAN_FILTERS: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Update VLAN filters"); | 
					
						
							|  |  |  |         vmxnet3_update_vlan_filters(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_UPDATE_MAC_FILTERS: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Update MAC filters"); | 
					
						
							|  |  |  |         vmxnet3_update_mcast_filters(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_UPDATE_FEATURE: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Update features"); | 
					
						
							|  |  |  |         vmxnet3_update_features(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_UPDATE_PMCFG: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Update power management config"); | 
					
						
							|  |  |  |         vmxnet3_update_pm_state(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_LINK: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get link"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_RESET_DEV: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Reset device"); | 
					
						
							|  |  |  |         vmxnet3_reset(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_QUIESCE_DEV: | 
					
						
							| 
									
										
										
										
											2015-12-15 12:27:54 +05:30
										 |  |  |         VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - deactivate the device"); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         vmxnet3_deactivate_device(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_CONF_INTR: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: VMXNET3_CMD_GET_CONF_INTR - interrupt configuration"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 08:55:04 +03:00
										 |  |  |     case VMXNET3_CMD_GET_ADAPTIVE_RING_INFO: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: VMXNET3_CMD_GET_ADAPTIVE_RING_INFO - " | 
					
						
							|  |  |  |                   "adaptive ring info flags"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												net/vmxnet3: return correct value for VMXNET3_CMD_GET_DID_* command
VMXNET3_CMD_GET_DID_LO should return PCI ID of the device
and VMXNET3_CMD_GET_DID_HI should return vmxnet3 revision ID.
This behavior can be observed by the following steps:
1) run a Linux distro on esxi server (5.x+)
2) modify vmxnet3 Linux driver to read DID_HI and DID_LO:
  VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DID_LO);
  lo =  VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
  VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DID_HI);
  high =  VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
  pr_info("vmxnet3 DID lo: 0x%x, high: 0x%x\n", lo, high);
The kernel log will have something like the following message:
  [ 7005.111170] vmxnet3 DID lo: 0x7b0, high: 0x1
Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Dmitry Fleytman <dmitry@daynix.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
											
										 
											2015-12-22 22:06:08 -08:00
										 |  |  |     case VMXNET3_CMD_GET_DID_LO: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get lower part of device ID"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_DID_HI: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get upper part of device ID"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-22 22:06:09 -08:00
										 |  |  |     case VMXNET3_CMD_GET_DEV_EXTRA_INFO: | 
					
						
							|  |  |  |         VMW_CBPRN("Set: Get device extra info"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         VMW_CBPRN("Received unknown command: %" PRIx64, cmd); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t vmxnet3_get_command_status(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint64_t ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (s->last_command) { | 
					
						
							|  |  |  |     case VMXNET3_CMD_ACTIVATE_DEV: | 
					
						
							| 
									
										
										
										
											2015-12-22 22:06:07 -08:00
										 |  |  |         ret = (s->device_active) ? 0 : 1; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         VMW_CFPRN("Device active: %" PRIx64, ret); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-28 10:53:29 +02:00
										 |  |  |     case VMXNET3_CMD_RESET_DEV: | 
					
						
							|  |  |  |     case VMXNET3_CMD_QUIESCE_DEV: | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_QUEUE_STATUS: | 
					
						
							| 
									
										
										
										
											2015-12-22 22:06:09 -08:00
										 |  |  |     case VMXNET3_CMD_GET_DEV_EXTRA_INFO: | 
					
						
							| 
									
										
										
										
											2013-03-28 10:53:29 +02:00
										 |  |  |         ret = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     case VMXNET3_CMD_GET_LINK: | 
					
						
							|  |  |  |         ret = s->link_status_and_speed; | 
					
						
							|  |  |  |         VMW_CFPRN("Link and speed: %" PRIx64, ret); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_PERM_MAC_LO: | 
					
						
							|  |  |  |         ret = vmxnet3_get_mac_low(&s->perm_mac); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_PERM_MAC_HI: | 
					
						
							|  |  |  |         ret = vmxnet3_get_mac_high(&s->perm_mac); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_CONF_INTR: | 
					
						
							|  |  |  |         ret = vmxnet3_get_interrupt_config(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-18 08:55:04 +03:00
										 |  |  |     case VMXNET3_CMD_GET_ADAPTIVE_RING_INFO: | 
					
						
							|  |  |  |         ret = VMXNET3_DISABLE_ADAPTIVE_RING; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												net/vmxnet3: return correct value for VMXNET3_CMD_GET_DID_* command
VMXNET3_CMD_GET_DID_LO should return PCI ID of the device
and VMXNET3_CMD_GET_DID_HI should return vmxnet3 revision ID.
This behavior can be observed by the following steps:
1) run a Linux distro on esxi server (5.x+)
2) modify vmxnet3 Linux driver to read DID_HI and DID_LO:
  VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DID_LO);
  lo =  VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
  VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DID_HI);
  high =  VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
  pr_info("vmxnet3 DID lo: 0x%x, high: 0x%x\n", lo, high);
The kernel log will have something like the following message:
  [ 7005.111170] vmxnet3 DID lo: 0x7b0, high: 0x1
Signed-off-by: Miao Yan <yanmiaobest@gmail.com>
Reviewed-by: Dmitry Fleytman <dmitry@daynix.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
											
										 
											2015-12-22 22:06:08 -08:00
										 |  |  |     case VMXNET3_CMD_GET_DID_LO: | 
					
						
							|  |  |  |         ret = PCI_DEVICE_ID_VMWARE_VMXNET3; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case VMXNET3_CMD_GET_DID_HI: | 
					
						
							|  |  |  |         ret = VMXNET3_DEVICE_REVISION; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     default: | 
					
						
							|  |  |  |         VMW_WRPRN("Received request for unknown command: %x", s->last_command); | 
					
						
							| 
									
										
										
										
											2015-12-22 22:06:10 -08:00
										 |  |  |         ret = 0; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_set_events(VMXNET3State *s, uint32_t val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint32_t events; | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("Setting events: 0x%x", val); | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     events = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, ecr) | val; | 
					
						
							|  |  |  |     VMXNET3_WRITE_DRV_SHARED32(d, s->drv_shmem, ecr, events); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_ack_events(VMXNET3State *s, uint32_t val) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     uint32_t events; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("Clearing events: 0x%x", val); | 
					
						
							| 
									
										
										
										
											2016-06-20 15:50:40 +02:00
										 |  |  |     events = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, ecr) & ~val; | 
					
						
							|  |  |  |     VMXNET3_WRITE_DRV_SHARED32(d, s->drv_shmem, ecr, events); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_io_bar1_write(void *opaque, | 
					
						
							|  |  |  |                       hwaddr addr, | 
					
						
							|  |  |  |                       uint64_t val, | 
					
						
							|  |  |  |                       unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							|  |  |  |     /* Vmxnet3 Revision Report Selection */ | 
					
						
							|  |  |  |     case VMXNET3_REG_VRRS: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_VRRS] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* UPT Version Report Selection */ | 
					
						
							|  |  |  |     case VMXNET3_REG_UVRS: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_UVRS] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Driver Shared Address Low */ | 
					
						
							|  |  |  |     case VMXNET3_REG_DSAL: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAL] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Guest driver will first write the low part of the shared | 
					
						
							|  |  |  |          * memory address. We save it to temp variable and set the | 
					
						
							|  |  |  |          * shared address only after we get the high part | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2014-08-11 21:00:58 +08:00
										 |  |  |         if (val == 0) { | 
					
						
							| 
									
										
										
										
											2015-12-15 12:27:54 +05:30
										 |  |  |             vmxnet3_deactivate_device(s); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         s->temp_shared_guest_driver_memory = val; | 
					
						
							|  |  |  |         s->drv_shmem = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Driver Shared Address High */ | 
					
						
							|  |  |  |     case VMXNET3_REG_DSAH: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAH] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Set the shared memory between guest driver and device. | 
					
						
							|  |  |  |          * We already should have low address part. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         s->drv_shmem = s->temp_shared_guest_driver_memory | (val << 32); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Command */ | 
					
						
							|  |  |  |     case VMXNET3_REG_CMD: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_CMD] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         vmxnet3_handle_command(s, val); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MAC Address Low */ | 
					
						
							|  |  |  |     case VMXNET3_REG_MACL: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACL] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         s->temp_mac = val; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MAC Address High */ | 
					
						
							|  |  |  |     case VMXNET3_REG_MACH: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACH] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         vmxnet3_set_variable_mac(s, val, s->temp_mac); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Interrupt Cause Register */ | 
					
						
							|  |  |  |     case VMXNET3_REG_ICR: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |         g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Event Cause Register */ | 
					
						
							|  |  |  |     case VMXNET3_REG_ECR: | 
					
						
							|  |  |  |         VMW_CBPRN("Write BAR1 [VMXNET3_REG_ECR] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   val, size); | 
					
						
							|  |  |  |         vmxnet3_ack_events(s, val); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         VMW_CBPRN("Unknown Write to BAR1 [%" PRIx64 "] = %" PRIx64 ", size %d", | 
					
						
							|  |  |  |                   addr, val, size); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t | 
					
						
							|  |  |  | vmxnet3_io_bar1_read(void *opaque, hwaddr addr, unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |         VMXNET3State *s = opaque; | 
					
						
							|  |  |  |         uint64_t ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (addr) { | 
					
						
							|  |  |  |         /* Vmxnet3 Revision Report Selection */ | 
					
						
							|  |  |  |         case VMXNET3_REG_VRRS: | 
					
						
							|  |  |  |             VMW_CBPRN("Read BAR1 [VMXNET3_REG_VRRS], size %d", size); | 
					
						
							|  |  |  |             ret = VMXNET3_DEVICE_REVISION; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* UPT Version Report Selection */ | 
					
						
							|  |  |  |         case VMXNET3_REG_UVRS: | 
					
						
							|  |  |  |             VMW_CBPRN("Read BAR1 [VMXNET3_REG_UVRS], size %d", size); | 
					
						
							| 
									
										
										
										
											2015-12-22 22:06:11 -08:00
										 |  |  |             ret = VMXNET3_UPT_REVISION; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Command */ | 
					
						
							|  |  |  |         case VMXNET3_REG_CMD: | 
					
						
							|  |  |  |             VMW_CBPRN("Read BAR1 [VMXNET3_REG_CMD], size %d", size); | 
					
						
							|  |  |  |             ret = vmxnet3_get_command_status(s); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* MAC Address Low */ | 
					
						
							|  |  |  |         case VMXNET3_REG_MACL: | 
					
						
							|  |  |  |             VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACL], size %d", size); | 
					
						
							|  |  |  |             ret = vmxnet3_get_mac_low(&s->conf.macaddr); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* MAC Address High */ | 
					
						
							|  |  |  |         case VMXNET3_REG_MACH: | 
					
						
							|  |  |  |             VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACH], size %d", size); | 
					
						
							|  |  |  |             ret = vmxnet3_get_mac_high(&s->conf.macaddr); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Interrupt Cause Register | 
					
						
							|  |  |  |          * Used for legacy interrupts only so interrupt index always 0 | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         case VMXNET3_REG_ICR: | 
					
						
							|  |  |  |             VMW_CBPRN("Read BAR1 [VMXNET3_REG_ICR], size %d", size); | 
					
						
							|  |  |  |             if (vmxnet3_interrupt_asserted(s, 0)) { | 
					
						
							|  |  |  |                 vmxnet3_clear_interrupt(s, 0); | 
					
						
							|  |  |  |                 ret = true; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 ret = false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             VMW_CBPRN("Unknow read BAR1[%" PRIx64 "], %d bytes", addr, size); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | vmxnet3_can_receive(NetClientState *nc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = qemu_get_nic_opaque(nc); | 
					
						
							|  |  |  |     return s->device_active && | 
					
						
							|  |  |  |            VMXNET_FLAG_IS_SET(s->link_status_and_speed, VMXNET3_LINK_STATUS_UP); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool | 
					
						
							|  |  |  | vmxnet3_is_registered_vlan(VMXNET3State *s, const void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint16_t vlan_tag = eth_get_pkt_tci(data) & VLAN_VID_MASK; | 
					
						
							|  |  |  |     if (IS_SPECIAL_VLAN_ID(vlan_tag)) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, vlan_tag); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_is_allowed_mcast_group(VMXNET3State *s, const uint8_t *group_mac) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     for (i = 0; i < s->mcast_list_len; i++) { | 
					
						
							|  |  |  |         if (!memcmp(group_mac, s->mcast_list[i].a, sizeof(s->mcast_list[i]))) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const void *data, | 
					
						
							|  |  |  |     size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     struct eth_header *ehdr = PKT_GET_ETH_HDR(data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_PROMISC)) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!vmxnet3_is_registered_vlan(s, data)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     switch (net_rx_pkt_get_packet_type(s->rx_pkt)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     case ETH_PKT_UCAST: | 
					
						
							|  |  |  |         if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_UCAST)) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (memcmp(s->conf.macaddr.a, ehdr->h_dest, ETH_ALEN)) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case ETH_PKT_BCAST: | 
					
						
							|  |  |  |         if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_BCAST)) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case ETH_PKT_MCAST: | 
					
						
							|  |  |  |         if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_ALL_MULTI)) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_MCAST)) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!vmxnet3_is_allowed_mcast_group(s, ehdr->h_dest)) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2013-07-25 18:21:28 +02:00
										 |  |  |         g_assert_not_reached(); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t | 
					
						
							|  |  |  | vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = qemu_get_nic_opaque(nc); | 
					
						
							|  |  |  |     size_t bytes_indicated; | 
					
						
							| 
									
										
										
										
											2014-08-20 13:27:14 +01:00
										 |  |  |     uint8_t min_buf[MIN_BUF_SIZE]; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!vmxnet3_can_receive(nc)) { | 
					
						
							|  |  |  |         VMW_PKPRN("Cannot receive now"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 11:49:25 -04:00
										 |  |  |     if (s->peer_has_vhdr) { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf); | 
					
						
							| 
									
										
										
										
											2015-06-23 11:49:25 -04:00
										 |  |  |         buf += sizeof(struct virtio_net_hdr); | 
					
						
							|  |  |  |         size -= sizeof(struct virtio_net_hdr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-20 13:27:14 +01:00
										 |  |  |     /* Pad to minimum Ethernet frame length */ | 
					
						
							|  |  |  |     if (size < sizeof(min_buf)) { | 
					
						
							|  |  |  |         memcpy(min_buf, buf, size); | 
					
						
							|  |  |  |         memset(&min_buf[size], 0, sizeof(min_buf) - size); | 
					
						
							|  |  |  |         buf = min_buf; | 
					
						
							|  |  |  |         size = sizeof(min_buf); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     net_rx_pkt_set_packet_type(s->rx_pkt, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         get_eth_packet_type(PKT_GET_ETH_HDR(buf))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (vmxnet3_rx_filter_may_indicate(s, buf, size)) { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_rx_pkt_set_protocols(s->rx_pkt, buf, size); | 
					
						
							| 
									
										
										
										
											2015-07-14 11:55:16 +03:00
										 |  |  |         vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |         net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1; | 
					
						
							|  |  |  |         if (bytes_indicated < size) { | 
					
						
							| 
									
										
										
										
											2015-12-07 21:28:31 -08:00
										 |  |  |             VMW_PKPRN("RX: %zu of %zu bytes indicated", bytes_indicated, size); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         VMW_PKPRN("Packet dropped by RX filter"); | 
					
						
							|  |  |  |         bytes_indicated = size; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert(size > 0); | 
					
						
							|  |  |  |     assert(bytes_indicated != 0); | 
					
						
							|  |  |  |     return bytes_indicated; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_set_link_status(NetClientState *nc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = qemu_get_nic_opaque(nc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (nc->link_down) { | 
					
						
							|  |  |  |         s->link_status_and_speed &= ~VMXNET3_LINK_STATUS_UP; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         s->link_status_and_speed |= VMXNET3_LINK_STATUS_UP; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_set_events(s, VMXNET3_ECR_LINK); | 
					
						
							|  |  |  |     vmxnet3_trigger_interrupt(s, s->event_int_idx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static NetClientInfo net_vmxnet3_info = { | 
					
						
							| 
									
										
											  
											
												qapi: Change Netdev into a flat union
This is a mostly-mechanical conversion that creates a new flat
union 'Netdev' QAPI type that covers all the branches of the
former 'NetClientOptions' simple union, where the branches are
now listed in a new 'NetClientDriver' enum rather than generated
from the simple union.  The existence of a flat union has no
change to the command line syntax accepted for new code, and
will make it possible for a future patch to switch the QMP
command to parse a boxed union for no change to valid QMP; but
it does have some ripple effect on the C code when dealing with
the new types.
While making the conversion, note that the 'NetLegacy' type
remains unchanged: it applies only to legacy command line options,
and will not be ported to QMP, so it should remain a wrapper
around a simple union; to avoid confusion, the type named
'NetClientOptions' is now gone, and we introduce 'NetLegacyOptions'
in its place.  Then, in the C code, we convert from NetLegacy to
Netdev as soon as possible, so that the bulk of the net stack
only has to deal with one QAPI type, not two.  Note that since
the old legacy code always rejected 'hubport', we can just omit
that branch from the new 'NetLegacyOptions' simple union.
Based on an idea originally by Zoltán Kővágó <DirtY.iCE.hu@gmail.com>:
Message-Id: <01a527fbf1a5de880091f98cf011616a78adeeee.1441627176.git.DirtY.iCE.hu@gmail.com>
although the sed script in that patch no longer applies due to
other changes in the tree since then, and I also did some manual
cleanups (such as fixing whitespace to keep checkpatch happy).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1468468228-27827-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Fixup from Eric squashed in]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
											
										 
											2016-07-13 21:50:23 -06:00
										 |  |  |         .type = NET_CLIENT_DRIVER_NIC, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         .size = sizeof(NICState), | 
					
						
							|  |  |  |         .receive = vmxnet3_receive, | 
					
						
							|  |  |  |         .link_status_changed = vmxnet3_set_link_status, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-02-06 17:02:18 +01:00
										 |  |  |     NetClientState *nc = qemu_get_queue(s->nic); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 12:14:07 +01:00
										 |  |  |     if (qemu_has_vnet_hdr(nc->peer)) { | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_net_uninit(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     g_free(s->mcast_list); | 
					
						
							| 
									
										
										
										
											2015-12-15 12:27:54 +05:30
										 |  |  |     vmxnet3_deactivate_device(s); | 
					
						
							| 
									
										
										
										
											2013-06-04 14:47:26 +02:00
										 |  |  |     qemu_del_nic(s->nic); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_net_init(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     DeviceState *d = DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("vmxnet3_net_init called..."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     qemu_macaddr_default_if_unset(&s->conf.macaddr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Windows guest will query the address that was set on init */ | 
					
						
							|  |  |  |     memcpy(&s->perm_mac.a, &s->conf.macaddr.a, sizeof(s->perm_mac.a)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->mcast_list = NULL; | 
					
						
							|  |  |  |     s->mcast_list_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->link_status_and_speed = VMXNET3_LINK_SPEED | VMXNET3_LINK_STATUS_UP; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:38 +03:00
										 |  |  |     VMW_CFPRN("Permanent MAC: " MAC_FMT, MAC_ARG(s->perm_mac.a)); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf, | 
					
						
							|  |  |  |                           object_get_typename(OBJECT(s)), | 
					
						
							|  |  |  |                           d->id, s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->peer_has_vhdr = vmxnet3_peer_has_vnet_hdr(s); | 
					
						
							|  |  |  |     s->tx_sop = true; | 
					
						
							|  |  |  |     s->skip_current_tx_pkt = false; | 
					
						
							|  |  |  |     s->tx_pkt = NULL; | 
					
						
							|  |  |  |     s->rx_pkt = NULL; | 
					
						
							|  |  |  |     s->rx_vlan_stripping = false; | 
					
						
							|  |  |  |     s->lro_supported = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->peer_has_vhdr) { | 
					
						
							| 
									
										
										
										
											2014-02-20 12:14:07 +01:00
										 |  |  |         qemu_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             sizeof(struct virtio_net_hdr)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 12:14:07 +01:00
										 |  |  |         qemu_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_unuse_msix_vectors(VMXNET3State *s, int num_vectors) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     for (i = 0; i < num_vectors; i++) { | 
					
						
							|  |  |  |         msix_vector_unuse(d, i); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_use_msix_vectors(VMXNET3State *s, int num_vectors) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     for (i = 0; i < num_vectors; i++) { | 
					
						
							|  |  |  |         int res = msix_vector_use(d, i); | 
					
						
							|  |  |  |         if (0 > res) { | 
					
						
							|  |  |  |             VMW_WRPRN("Failed to use MSI-X vector %d, error %d", i, res); | 
					
						
							|  |  |  |             vmxnet3_unuse_msix_vectors(s, i); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | vmxnet3_init_msix(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  |     int res = msix_init(d, VMXNET3_MAX_INTRS, | 
					
						
							|  |  |  |                         &s->msix_bar, | 
					
						
							|  |  |  |                         VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE, | 
					
						
							|  |  |  |                         &s->msix_bar, | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:36 +02:00
										 |  |  |                         VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s), | 
					
						
							| 
									
										
										
										
											2017-01-17 14:18:48 +08:00
										 |  |  |                         VMXNET3_MSIX_OFFSET(s), NULL); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (0 > res) { | 
					
						
							|  |  |  |         VMW_WRPRN("Failed to initialize MSI-X, error %d", res); | 
					
						
							|  |  |  |         s->msix_used = false; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) { | 
					
						
							|  |  |  |             VMW_WRPRN("Failed to use MSI-X vectors, error %d", res); | 
					
						
							|  |  |  |             msix_uninit(d, &s->msix_bar, &s->msix_bar); | 
					
						
							|  |  |  |             s->msix_used = false; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             s->msix_used = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return s->msix_used; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_cleanup_msix(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->msix_used) { | 
					
						
							| 
									
										
										
										
											2014-05-19 15:47:16 +02:00
										 |  |  |         vmxnet3_unuse_msix_vectors(s, VMXNET3_MAX_INTRS); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |         msix_uninit(d, &s->msix_bar, &s->msix_bar); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | vmxnet3_cleanup_msi(VMXNET3State *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:42 +08:00
										 |  |  |     msi_uninit(d); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const MemoryRegionOps b0_ops = { | 
					
						
							|  |  |  |     .read = vmxnet3_io_bar0_read, | 
					
						
							|  |  |  |     .write = vmxnet3_io_bar0_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_LITTLE_ENDIAN, | 
					
						
							|  |  |  |     .impl = { | 
					
						
							|  |  |  |             .min_access_size = 4, | 
					
						
							|  |  |  |             .max_access_size = 4, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const MemoryRegionOps b1_ops = { | 
					
						
							|  |  |  |     .read = vmxnet3_io_bar1_read, | 
					
						
							|  |  |  |     .write = vmxnet3_io_bar1_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_LITTLE_ENDIAN, | 
					
						
							|  |  |  |     .impl = { | 
					
						
							|  |  |  |             .min_access_size = 4, | 
					
						
							|  |  |  |             .max_access_size = 4, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:35 +03:00
										 |  |  | static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:41 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:35 +03:00
										 |  |  |     uint64_t dsn_payload; | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:41 +02:00
										 |  |  |     uint8_t *dsnp = (uint8_t *)&dsn_payload; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dsnp[0] = 0xfe; | 
					
						
							|  |  |  |     dsnp[1] = s->conf.macaddr.a[3]; | 
					
						
							|  |  |  |     dsnp[2] = s->conf.macaddr.a[4]; | 
					
						
							|  |  |  |     dsnp[3] = s->conf.macaddr.a[5]; | 
					
						
							|  |  |  |     dsnp[4] = s->conf.macaddr.a[0]; | 
					
						
							|  |  |  |     dsnp[5] = s->conf.macaddr.a[1]; | 
					
						
							|  |  |  |     dsnp[6] = s->conf.macaddr.a[2]; | 
					
						
							|  |  |  |     dsnp[7] = 0xff; | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:35 +03:00
										 |  |  |     return dsn_payload; | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:41 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define VMXNET3_USE_64BIT         (true)
 | 
					
						
							|  |  |  | #define VMXNET3_PER_VECTOR_MASK   (false)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-19 15:52:30 +01:00
										 |  |  | static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = VMXNET3(pci_dev); | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:39 +08:00
										 |  |  |     int ret; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("Starting init..."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 21:25:08 -04:00
										 |  |  |     memory_region_init_io(&s->bar0, OBJECT(s), &b0_ops, s, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                           "vmxnet3-b0", VMXNET3_PT_REG_SIZE); | 
					
						
							|  |  |  |     pci_register_bar(pci_dev, VMXNET3_BAR0_IDX, | 
					
						
							|  |  |  |                      PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 21:25:08 -04:00
										 |  |  |     memory_region_init_io(&s->bar1, OBJECT(s), &b1_ops, s, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                           "vmxnet3-b1", VMXNET3_VD_REG_SIZE); | 
					
						
							|  |  |  |     pci_register_bar(pci_dev, VMXNET3_BAR1_IDX, | 
					
						
							|  |  |  |                      PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 21:25:08 -04:00
										 |  |  |     memory_region_init(&s->msix_bar, OBJECT(s), "vmxnet3-msix-bar", | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                        VMXNET3_MSIX_BAR_SIZE); | 
					
						
							|  |  |  |     pci_register_bar(pci_dev, VMXNET3_MSIX_BAR_IDX, | 
					
						
							|  |  |  |                      PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix_bar); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_reset_interrupt_states(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Interrupt pin A */ | 
					
						
							|  |  |  |     pci_dev->config[PCI_INTERRUPT_PIN] = 0x01; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 14:13:39 +08:00
										 |  |  |     ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS, | 
					
						
							|  |  |  |                    VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL); | 
					
						
							|  |  |  |     /* Any error other than -ENOTSUP(board's MSI support is broken)
 | 
					
						
							|  |  |  |      * is a programming error. Fall back to INTx silently on -ENOTSUP */ | 
					
						
							|  |  |  |     assert(!ret || ret == -ENOTSUP); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     if (!vmxnet3_init_msix(s)) { | 
					
						
							|  |  |  |         VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent."); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_net_init(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:41 +02:00
										 |  |  |     if (pci_is_express(pci_dev)) { | 
					
						
							| 
									
										
										
										
											2017-11-29 19:46:27 +11:00
										 |  |  |         if (pci_bus_is_express(pci_get_bus(pci_dev))) { | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:41 +02:00
										 |  |  |             pcie_endpoint_cap_init(pci_dev, VMXNET3_EXP_EP_OFFSET); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:35 +03:00
										 |  |  |         pcie_dev_ser_num_init(pci_dev, VMXNET3_DSN_OFFSET, | 
					
						
							|  |  |  |                               vmxnet3_device_serial_num(s)); | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:39 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-07 16:00:19 +08:00
										 |  |  | static void vmxnet3_instance_init(Object *obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = VMXNET3(obj); | 
					
						
							|  |  |  |     device_add_bootindex_property(obj, &s->conf.bootindex, | 
					
						
							|  |  |  |                                   "bootindex", "/ethernet-phy@0", | 
					
						
							| 
									
										
										
										
											2020-05-05 17:29:23 +02:00
										 |  |  |                                   DEVICE(obj)); | 
					
						
							| 
									
										
										
										
											2014-10-07 16:00:19 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_pci_uninit(PCIDevice *pci_dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = VMXNET3(pci_dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("Starting uninit..."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_net_uninit(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_cleanup_msix(s); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vmxnet3_cleanup_msi(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_qdev_reset(DeviceState *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(dev); | 
					
						
							|  |  |  |     VMXNET3State *s = VMXNET3(d); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VMW_CBPRN("Starting QDEV reset..."); | 
					
						
							|  |  |  |     vmxnet3_reset(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool vmxnet3_mc_list_needed(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int vmxnet3_mcast_list_pre_load(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->mcast_list = g_malloc(s->mcast_list_buff_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 12:29:12 +01:00
										 |  |  | static int vmxnet3_pre_save(void *opaque) | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s->mcast_list_buff_size = s->mcast_list_len * sizeof(MACAddr); | 
					
						
							| 
									
										
										
										
											2017-09-25 12:29:12 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const VMStateDescription vmxstate_vmxnet3_mcast_list = { | 
					
						
							|  |  |  |     .name = "vmxnet3/mcast_list", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .pre_load = vmxnet3_mcast_list_pre_load, | 
					
						
							| 
									
										
										
										
											2014-09-23 14:09:54 +02:00
										 |  |  |     .needed = vmxnet3_mc_list_needed, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2017-02-03 18:52:17 +01:00
										 |  |  |         VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             mcast_list_buff_size), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | static const VMStateDescription vmstate_vmxnet3_ring = { | 
					
						
							|  |  |  |     .name = "vmxnet3-ring", | 
					
						
							|  |  |  |     .version_id = 0, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_UINT64(pa, Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_UINT32(size, Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_UINT32(cell_size, Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_UINT32(next, Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_UINT8(gen, Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | static const VMStateDescription vmstate_vmxnet3_tx_stats = { | 
					
						
							|  |  |  |     .name = "vmxnet3-tx-stats", | 
					
						
							|  |  |  |     .version_id = 0, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_UINT64(TSOPktsTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(TSOBytesTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(ucastPktsTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(ucastBytesTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(mcastPktsTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(mcastBytesTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(bcastPktsTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(bcastBytesTxOK, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(pktsTxError, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(pktsTxDiscard, struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | static const VMStateDescription vmstate_vmxnet3_txq_descr = { | 
					
						
							|  |  |  |     .name = "vmxnet3-txq-descr", | 
					
						
							|  |  |  |     .version_id = 0, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_STRUCT(tx_ring, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_ring, | 
					
						
							|  |  |  |                        Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_STRUCT(comp_ring, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_ring, | 
					
						
							|  |  |  |                        Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_UINT8(intr_idx, Vmxnet3TxqDescr), | 
					
						
							|  |  |  |         VMSTATE_UINT64(tx_stats_pa, Vmxnet3TxqDescr), | 
					
						
							|  |  |  |         VMSTATE_STRUCT(txq_stats, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_tx_stats, | 
					
						
							|  |  |  |                        struct UPT1_TxStats), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | static const VMStateDescription vmstate_vmxnet3_rx_stats = { | 
					
						
							|  |  |  |     .name = "vmxnet3-rx-stats", | 
					
						
							|  |  |  |     .version_id = 0, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_UINT64(LROPktsRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(LROBytesRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(ucastPktsRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(ucastBytesRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(mcastPktsRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(mcastBytesRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(bcastPktsRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(bcastBytesRxOK, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(pktsRxOutOfBuf, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_UINT64(pktsRxError, struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2017-01-19 11:00:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | static const VMStateDescription vmstate_vmxnet3_rxq_descr = { | 
					
						
							|  |  |  |     .name = "vmxnet3-rxq-descr", | 
					
						
							|  |  |  |     .version_id = 0, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_STRUCT_ARRAY(rx_ring, Vmxnet3RxqDescr, | 
					
						
							|  |  |  |                              VMXNET3_RX_RINGS_PER_QUEUE, 0, | 
					
						
							|  |  |  |                              vmstate_vmxnet3_ring, Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_STRUCT(comp_ring, Vmxnet3RxqDescr, 0, vmstate_vmxnet3_ring, | 
					
						
							|  |  |  |                        Vmxnet3Ring), | 
					
						
							|  |  |  |         VMSTATE_UINT8(intr_idx, Vmxnet3RxqDescr), | 
					
						
							|  |  |  |         VMSTATE_UINT64(rx_stats_pa, Vmxnet3RxqDescr), | 
					
						
							|  |  |  |         VMSTATE_STRUCT(rxq_stats, Vmxnet3RxqDescr, 0, vmstate_vmxnet3_rx_stats, | 
					
						
							|  |  |  |                        struct UPT1_RxStats), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int vmxnet3_post_load(void *opaque, int version_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3State *s = opaque; | 
					
						
							|  |  |  |     PCIDevice *d = PCI_DEVICE(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:42 +03:00
										 |  |  |     net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), | 
					
						
							|  |  |  |                     s->max_tx_frags, s->peer_has_vhdr); | 
					
						
							| 
									
										
										
										
											2016-06-01 11:23:39 +03:00
										 |  |  |     net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (s->msix_used) { | 
					
						
							|  |  |  |         if  (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) { | 
					
						
							|  |  |  |             VMW_WRPRN("Failed to re-use MSI-X vectors"); | 
					
						
							|  |  |  |             msix_uninit(d, &s->msix_bar, &s->msix_bar); | 
					
						
							|  |  |  |             s->msix_used = false; | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-21 16:15:59 +02:00
										 |  |  |     if (!vmxnet3_validate_queues(s)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-04-04 12:45:21 +03:00
										 |  |  |     vmxnet3_validate_interrupts(s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  | static const VMStateDescription vmstate_vmxnet3_int_state = { | 
					
						
							|  |  |  |     .name = "vmxnet3-int-state", | 
					
						
							|  |  |  |     .version_id = 0, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_BOOL(is_masked, Vmxnet3IntState), | 
					
						
							|  |  |  |         VMSTATE_BOOL(is_pending, Vmxnet3IntState), | 
					
						
							|  |  |  |         VMSTATE_BOOL(is_asserted, Vmxnet3IntState), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const VMStateDescription vmstate_vmxnet3 = { | 
					
						
							|  |  |  |     .name = "vmxnet3", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .pre_save = vmxnet3_pre_save, | 
					
						
							|  |  |  |     .post_load = vmxnet3_post_load, | 
					
						
							| 
									
										
										
										
											2014-04-16 15:32:32 +02:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							| 
									
										
										
										
											2019-07-05 04:07:11 +03:00
										 |  |  |             VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_MSIX(parent_obj, VMXNET3State), | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |             VMSTATE_BOOL(rx_packets_compound, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_BOOL(lro_supported, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(rx_mode, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(mcast_list_len, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(mcast_list_buff_size, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32_ARRAY(vlan_table, VMXNET3State, VMXNET3_VFT_SIZE), | 
					
						
							|  |  |  |             VMSTATE_UINT32(mtu, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT16(max_rx_frags, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(max_tx_frags, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT8(event_int_idx, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_BOOL(auto_int_masking, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT8(txq_num, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT8(rxq_num, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(device_active, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(last_command, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(link_status_and_speed, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT32(temp_mac, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT64(drv_shmem, VMXNET3State), | 
					
						
							|  |  |  |             VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  |             VMSTATE_STRUCT_ARRAY(txq_descr, VMXNET3State, | 
					
						
							|  |  |  |                 VMXNET3_DEVICE_MAX_TX_QUEUES, 0, vmstate_vmxnet3_txq_descr, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                 Vmxnet3TxqDescr), | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  |             VMSTATE_STRUCT_ARRAY(rxq_descr, VMXNET3State, | 
					
						
							|  |  |  |                 VMXNET3_DEVICE_MAX_RX_QUEUES, 0, vmstate_vmxnet3_rxq_descr, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |                 Vmxnet3RxqDescr), | 
					
						
							| 
									
										
										
										
											2016-12-15 20:05:09 +00:00
										 |  |  |             VMSTATE_STRUCT_ARRAY(interrupt_states, VMXNET3State, | 
					
						
							|  |  |  |                 VMXNET3_MAX_INTRS, 0, vmstate_vmxnet3_int_state, | 
					
						
							|  |  |  |                 Vmxnet3IntState), | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             VMSTATE_END_OF_LIST() | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2014-09-23 14:09:54 +02:00
										 |  |  |     .subsections = (const VMStateDescription*[]) { | 
					
						
							|  |  |  |         &vmxstate_vmxnet3_mcast_list, | 
					
						
							|  |  |  |         NULL | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Property vmxnet3_properties[] = { | 
					
						
							|  |  |  |     DEFINE_NIC_PROPERTIES(VMXNET3State, conf), | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:37 +02:00
										 |  |  |     DEFINE_PROP_BIT("x-old-msi-offsets", VMXNET3State, compat_flags, | 
					
						
							|  |  |  |                     VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT, false), | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:40 +02:00
										 |  |  |     DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags, | 
					
						
							|  |  |  |                     VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false), | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:39 +02:00
										 |  |  | static void vmxnet3_realize(DeviceState *qdev, Error **errp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMXNET3Class *vc = VMXNET3_DEVICE_GET_CLASS(qdev); | 
					
						
							|  |  |  |     PCIDevice *pci_dev = PCI_DEVICE(qdev); | 
					
						
							|  |  |  |     VMXNET3State *s = VMXNET3(qdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE)) { | 
					
						
							|  |  |  |         pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vc->parent_dc_realize(qdev, errp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | static void vmxnet3_class_init(ObjectClass *class, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     DeviceClass *dc = DEVICE_CLASS(class); | 
					
						
							|  |  |  |     PCIDeviceClass *c = PCI_DEVICE_CLASS(class); | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:39 +02:00
										 |  |  |     VMXNET3Class *vc = VMXNET3_DEVICE_CLASS(class); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-19 15:52:30 +01:00
										 |  |  |     c->realize = vmxnet3_pci_realize; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     c->exit = vmxnet3_pci_uninit; | 
					
						
							|  |  |  |     c->vendor_id = PCI_VENDOR_ID_VMWARE; | 
					
						
							|  |  |  |     c->device_id = PCI_DEVICE_ID_VMWARE_VMXNET3; | 
					
						
							|  |  |  |     c->revision = PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION; | 
					
						
							| 
									
										
										
										
											2016-06-24 14:11:31 +02:00
										 |  |  |     c->romfile = "efi-vmxnet3.rom"; | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     c->class_id = PCI_CLASS_NETWORK_ETHERNET; | 
					
						
							|  |  |  |     c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; | 
					
						
							|  |  |  |     c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; | 
					
						
							| 
									
										
										
										
											2018-01-13 23:04:12 -03:00
										 |  |  |     device_class_set_parent_realize(dc, vmxnet3_realize, | 
					
						
							|  |  |  |                                     &vc->parent_dc_realize); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     dc->desc = "VMWare Paravirtualized Ethernet v3"; | 
					
						
							|  |  |  |     dc->reset = vmxnet3_qdev_reset; | 
					
						
							|  |  |  |     dc->vmsd = &vmstate_vmxnet3; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:30:32 +04:00
										 |  |  |     device_class_set_props(dc, vmxnet3_properties); | 
					
						
							| 
									
										
										
										
											2013-07-29 17:17:45 +03:00
										 |  |  |     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const TypeInfo vmxnet3_info = { | 
					
						
							|  |  |  |     .name          = TYPE_VMXNET3, | 
					
						
							|  |  |  |     .parent        = TYPE_PCI_DEVICE, | 
					
						
							| 
									
										
										
										
											2015-12-24 09:17:38 +02:00
										 |  |  |     .class_size    = sizeof(VMXNET3Class), | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  |     .instance_size = sizeof(VMXNET3State), | 
					
						
							|  |  |  |     .class_init    = vmxnet3_class_init, | 
					
						
							| 
									
										
										
										
											2014-10-07 16:00:19 +08:00
										 |  |  |     .instance_init = vmxnet3_instance_init, | 
					
						
							| 
									
										
										
										
											2017-09-27 16:56:32 -03:00
										 |  |  |     .interfaces = (InterfaceInfo[]) { | 
					
						
							|  |  |  |         { INTERFACE_PCIE_DEVICE }, | 
					
						
							|  |  |  |         { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | 
					
						
							|  |  |  |         { } | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2013-03-09 11:21:06 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vmxnet3_register_types(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     VMW_CBPRN("vmxnet3_register_types called..."); | 
					
						
							|  |  |  |     type_register_static(&vmxnet3_info); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type_init(vmxnet3_register_types) |