/* * Stop device: disable rx and tx functions to allow for reconfiguring. */ static void vmxnet3_dev_stop(struct rte_eth_dev *dev) { struct rte_eth_link link; struct vmxnet3_hw *hw = dev->data->dev_private; PMD_INIT_FUNC_TRACE(); if (hw->adapter_stopped == 1) { PMD_INIT_LOG(DEBUG, "Device already closed."); return; } /* disable interrupts */ vmxnet3_disable_intr(hw); /* quiesce the device first */ VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV); VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_DSAL, 0); VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_DSAH, 0); /* reset the device */ VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV); PMD_INIT_LOG(DEBUG, "Device reset."); hw->adapter_stopped = 0; vmxnet3_dev_clear_queues(dev); /* Clear recorded link status */ memset(&link, 0, sizeof(link)); vmxnet3_dev_atomic_write_link_status(dev, &link); }
/* * Configure device link speed and setup link. * Must be called after eth_vmxnet3_dev_init. Other wise it might fail * It returns 0 on success. */ static int vmxnet3_dev_start(struct rte_eth_dev *dev) { int status, ret; struct vmxnet3_hw *hw = dev->data->dev_private; PMD_INIT_FUNC_TRACE(); ret = vmxnet3_setup_driver_shared(dev); if (ret != VMXNET3_SUCCESS) return ret; /* Exchange shared data with device */ VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_DSAL, VMXNET3_GET_ADDR_LO(hw->sharedPA)); VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_DSAH, VMXNET3_GET_ADDR_HI(hw->sharedPA)); /* Activate device by register write */ VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_ACTIVATE_DEV); status = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_CMD); if (status != 0) { PMD_INIT_LOG(ERR, "Device activation: UNSUCCESSFUL"); return -1; } /* Disable interrupts */ vmxnet3_disable_intr(hw); /* * Load RX queues with blank mbufs and update next2fill index for device * Update RxMode of the device */ ret = vmxnet3_dev_rxtx_init(dev); if (ret != VMXNET3_SUCCESS) { PMD_INIT_LOG(ERR, "Device receive init: UNSUCCESSFUL"); return ret; } /* Setting proper Rx Mode and issue Rx Mode Update command */ vmxnet3_dev_set_rxmode(hw, VMXNET3_RXM_UCAST | VMXNET3_RXM_BCAST, 1); /* * Don't need to handle events for now */ #if PROCESS_SYS_EVENTS == 1 events = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_ECR); PMD_INIT_LOG(DEBUG, "Reading events: 0x%X", events); vmxnet3_process_events(hw); #endif return status; }
static void vmxnet3_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *buf) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); u8 *base; int i; VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); /* this does assume each counter is 64-bit wide */ base = (u8 *)&adapter->tqd_start->stats; for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset); base = (u8 *)&adapter->tx_queue.stats; for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset); base = (u8 *)&adapter->rqd_start->stats; for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset); base = (u8 *)&adapter->rx_queue.stats; for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset); base = (u8 *)adapter; for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_global_stats[i].offset); }
static void vmxnet3_write_mac(struct vmxnet3_hw *hw, const uint8_t *addr) { uint32_t val; PMD_INIT_LOG(DEBUG, "Writing MAC Address : %02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); val = *(const uint32_t *)addr; VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_MACL, val); val = (addr[5] << 8) | addr[4]; VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_MACH, val); }
static int vmxnet3_set_rss_indir(struct net_device *netdev, const struct ethtool_rxfh_indir *p) { unsigned int i; unsigned long flags; struct vmxnet3_adapter *adapter = netdev_priv(netdev); struct UPT1_RSSConf *rssConf = adapter->rss_conf; if (p->size != rssConf->indTableSize) return -EINVAL; for (i = 0; i < rssConf->indTableSize; i++) { /* * Return with error code if any of the queue indices * is out of range */ if (p->ring_index[i] < 0 || p->ring_index[i] >= adapter->num_rx_queues) return -EINVAL; } for (i = 0; i < rssConf->indTableSize; i++) rssConf->indTable[i] = p->ring_index[i]; spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_RSSIDT); spin_unlock_irqrestore(&adapter->cmd_lock, flags); return 0; }
static int vmxnet3_set_flags(struct net_device *netdev, u32 data) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1; u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; unsigned long flags; if (data & ~ETH_FLAG_LRO) return -EOPNOTSUPP; if (lro_requested ^ lro_present) { /* toggle the LRO feature*/ netdev->features ^= NETIF_F_LRO; /* update harware LRO capability accordingly */ if (lro_requested) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_LRO; else adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_LRO; spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); spin_unlock_irqrestore(&adapter->cmd_lock, flags); } return 0; }
struct net_device_stats * vmxnet3_get_stats(struct net_device *netdev) { struct vmxnet3_adapter *adapter; struct vmxnet3_tq_driver_stats *drvTxStats; struct vmxnet3_rq_driver_stats *drvRxStats; struct UPT1_TxStats *devTxStats; struct UPT1_RxStats *devRxStats; struct net_device_stats *net_stats = &netdev->stats; unsigned long flags; int i; adapter = netdev_priv(netdev); /* Collect the dev stats into the shared area */ spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); spin_unlock_irqrestore(&adapter->cmd_lock, flags); memset(net_stats, 0, sizeof(*net_stats)); for (i = 0; i < adapter->num_tx_queues; i++) { devTxStats = &adapter->tqd_start[i].stats; drvTxStats = &adapter->tx_queue[i].stats; net_stats->tx_packets += devTxStats->ucastPktsTxOK + devTxStats->mcastPktsTxOK + devTxStats->bcastPktsTxOK; net_stats->tx_bytes += devTxStats->ucastBytesTxOK + devTxStats->mcastBytesTxOK + devTxStats->bcastBytesTxOK; net_stats->tx_errors += devTxStats->pktsTxError; net_stats->tx_dropped += drvTxStats->drop_total; } for (i = 0; i < adapter->num_rx_queues; i++) { devRxStats = &adapter->rqd_start[i].stats; drvRxStats = &adapter->rx_queue[i].stats; net_stats->rx_packets += devRxStats->ucastPktsRxOK + devRxStats->mcastPktsRxOK + devRxStats->bcastPktsRxOK; net_stats->rx_bytes += devRxStats->ucastBytesRxOK + devRxStats->mcastBytesRxOK + devRxStats->bcastBytesRxOK; net_stats->rx_errors += devRxStats->pktsRxError; net_stats->rx_dropped += drvRxStats->drop_total; net_stats->multicast += devRxStats->mcastPktsRxOK; } return net_stats; }
struct net_device_stats * vmxnet3_get_stats(struct net_device *netdev) { struct vmxnet3_adapter *adapter; struct vmxnet3_tq_driver_stats *drvTxStats; struct vmxnet3_rq_driver_stats *drvRxStats; struct UPT1_TxStats *devTxStats; struct UPT1_RxStats *devRxStats; struct net_device_stats *net_stats = &netdev->stats; adapter = netdev_priv(netdev); /* Collect the dev stats into the shared area */ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); /* Assuming that we have a single queue device */ devTxStats = &adapter->tqd_start->stats; devRxStats = &adapter->rqd_start->stats; /* Get access to the driver stats per queue */ drvTxStats = &adapter->tx_queue.stats; drvRxStats = &adapter->rx_queue.stats; memset(net_stats, 0, sizeof(*net_stats)); net_stats->rx_packets = devRxStats->ucastPktsRxOK + devRxStats->mcastPktsRxOK + devRxStats->bcastPktsRxOK; net_stats->tx_packets = devTxStats->ucastPktsTxOK + devTxStats->mcastPktsTxOK + devTxStats->bcastPktsTxOK; net_stats->rx_bytes = devRxStats->ucastBytesRxOK + devRxStats->mcastBytesRxOK + devRxStats->bcastBytesRxOK; net_stats->tx_bytes = devTxStats->ucastBytesTxOK + devTxStats->mcastBytesTxOK + devTxStats->bcastBytesTxOK; net_stats->rx_errors = devRxStats->pktsRxError; net_stats->tx_errors = devTxStats->pktsTxError; net_stats->rx_dropped = drvRxStats->drop_total; net_stats->tx_dropped = drvTxStats->drop_total; net_stats->multicast = devRxStats->mcastPktsRxOK; return net_stats; }
static void vmxnet3_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) { unsigned int i; struct vmxnet3_hw *hw = dev->data->dev_private; VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); RTE_BUILD_BUG_ON(RTE_ETHDEV_QUEUE_STAT_CNTRS < VMXNET3_MAX_TX_QUEUES); for (i = 0; i < hw->num_tx_queues; i++) { struct UPT1_TxStats *txStats = &hw->tqd_start[i].stats; stats->q_opackets[i] = txStats->ucastPktsTxOK + txStats->mcastPktsTxOK + txStats->bcastPktsTxOK; stats->q_obytes[i] = txStats->ucastBytesTxOK + txStats->mcastBytesTxOK + txStats->bcastBytesTxOK; stats->opackets += stats->q_opackets[i]; stats->obytes += stats->q_obytes[i]; stats->oerrors += txStats->pktsTxError + txStats->pktsTxDiscard; } RTE_BUILD_BUG_ON(RTE_ETHDEV_QUEUE_STAT_CNTRS < VMXNET3_MAX_RX_QUEUES); for (i = 0; i < hw->num_rx_queues; i++) { struct UPT1_RxStats *rxStats = &hw->rqd_start[i].stats; stats->q_ipackets[i] = rxStats->ucastPktsRxOK + rxStats->mcastPktsRxOK + rxStats->bcastPktsRxOK; stats->q_ibytes[i] = rxStats->ucastBytesRxOK + rxStats->mcastBytesRxOK + rxStats->bcastBytesRxOK; stats->ipackets += stats->q_ipackets[i]; stats->ibytes += stats->q_ibytes[i]; stats->q_errors[i] = rxStats->pktsRxError; stats->ierrors += rxStats->pktsRxError; stats->rx_nombuf += rxStats->pktsRxOutOfBuf; } }
static void vmxnet3_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *buf) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); unsigned long flags; u8 *base; int i; int j = 0; spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS); spin_unlock_irqrestore(&adapter->cmd_lock, flags); /* this does assume each counter is 64-bit wide */ for (j = 0; j < adapter->num_tx_queues; j++) { base = (u8 *)&adapter->tqd_start[j].stats; *buf++ = (u64)j; for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset); base = (u8 *)&adapter->tx_queue[j].stats; for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset); } for (j = 0; j < adapter->num_tx_queues; j++) { base = (u8 *)&adapter->rqd_start[j].stats; *buf++ = (u64) j; for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset); base = (u8 *)&adapter->rx_queue[j].stats; for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset); } base = (u8 *)adapter; for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) *buf++ = *(u64 *)(base + vmxnet3_global_stats[i].offset); }
static int vmxnet3_set_rx_csum(struct net_device *netdev, u32 val) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); if (adapter->rxcsum != val) { adapter->rxcsum = val; if (netif_running(netdev)) { if (val) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_RXCSUM; else adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_RXCSUM; VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); } } return 0; }
static int vmxnet3_set_flags(struct net_device *netdev, u32 data) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1; u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; if (lro_requested ^ lro_present) { /* toggle the LRO feature*/ netdev->features ^= NETIF_F_LRO; /* update harware LRO capability accordingly */ if (lro_requested) adapter->shared->devRead.misc.uptFeatures |= cpu_to_le64(UPT1_F_LRO); else adapter->shared->devRead.misc.uptFeatures &= cpu_to_le64(~UPT1_F_LRO); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); } return 0; }
static int vmxnet3_set_rx_csum(struct net_device *netdev, u32 val) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); unsigned long flags; if (adapter->rxcsum != val) { adapter->rxcsum = val; if (netif_running(netdev)) { if (val) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_RXCSUM; else adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_RXCSUM; spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_FEATURE); spin_unlock_irqrestore(&adapter->cmd_lock, flags); } } return 0; }
/* * It returns 0 on success. */ static int eth_vmxnet3_dev_init(struct rte_eth_dev *eth_dev) { struct rte_pci_device *pci_dev; struct vmxnet3_hw *hw = eth_dev->data->dev_private; uint32_t mac_hi, mac_lo, ver; PMD_INIT_FUNC_TRACE(); eth_dev->dev_ops = &vmxnet3_eth_dev_ops; eth_dev->rx_pkt_burst = &vmxnet3_recv_pkts; eth_dev->tx_pkt_burst = &vmxnet3_xmit_pkts; pci_dev = eth_dev->pci_dev; /* * for secondary processes, we don't initialize any further as primary * has already done this work. */ if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; rte_eth_copy_pci_info(eth_dev, pci_dev); /* Vendor and Device ID need to be set before init of shared code */ hw->device_id = pci_dev->id.device_id; hw->vendor_id = pci_dev->id.vendor_id; hw->hw_addr0 = (void *)pci_dev->mem_resource[0].addr; hw->hw_addr1 = (void *)pci_dev->mem_resource[1].addr; hw->num_rx_queues = 1; hw->num_tx_queues = 1; hw->bufs_per_pkt = 1; /* Check h/w version compatibility with driver. */ ver = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_VRRS); PMD_INIT_LOG(DEBUG, "Hardware version : %d", ver); if (ver & 0x1) VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_VRRS, 1); else { PMD_INIT_LOG(ERR, "Incompatible h/w version, should be 0x1"); return -EIO; } /* Check UPT version compatibility with driver. */ ver = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_UVRS); PMD_INIT_LOG(DEBUG, "UPT hardware version : %d", ver); if (ver & 0x1) VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_UVRS, 1); else { PMD_INIT_LOG(ERR, "Incompatible UPT version."); return -EIO; } /* Getting MAC Address */ mac_lo = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_MACL); mac_hi = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_MACH); memcpy(hw->perm_addr , &mac_lo, 4); memcpy(hw->perm_addr+4, &mac_hi, 2); /* Allocate memory for storing MAC addresses */ eth_dev->data->mac_addrs = rte_zmalloc("vmxnet3", ETHER_ADDR_LEN * VMXNET3_MAX_MAC_ADDRS, 0); if (eth_dev->data->mac_addrs == NULL) { PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to store MAC addresses", ETHER_ADDR_LEN * VMXNET3_MAX_MAC_ADDRS); return -ENOMEM; } /* Copy the permanent MAC address */ ether_addr_copy((struct ether_addr *) hw->perm_addr, ð_dev->data->mac_addrs[0]); PMD_INIT_LOG(DEBUG, "MAC Address : %02x:%02x:%02x:%02x:%02x:%02x", hw->perm_addr[0], hw->perm_addr[1], hw->perm_addr[2], hw->perm_addr[3], hw->perm_addr[4], hw->perm_addr[5]); /* Put device in Quiesce Mode */ VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV); /* allow untagged pkts */ VMXNET3_SET_VFTABLE_ENTRY(hw->shadow_vfta, 0); return 0; }