#include "i40e_rxtx.h"
#include "i40e_ethdev.h"
#include "i40e_pf.h"
-#define I40EVF_VSI_DEFAULT_MSIX_INTR 1
+#define I40EVF_VSI_DEFAULT_MSIX_INTR 1
+#define I40EVF_VSI_DEFAULT_MSIX_INTR_LNX 0
/* busy wait delay in msec */
#define I40EVF_BUSY_WAIT_DELAY 10
#define I40EVF_BUSY_WAIT_COUNT 50
#define MAX_RESET_WAIT_CNT 20
+/*ITR index for NOITR*/
+#define I40E_QINT_RQCTL_MSIX_INDX_NOITR 3
struct i40evf_arq_msg_info {
enum i40e_virtchnl_ops ops;
int i = 0;
enum i40evf_aq_result ret;
-#define MAX_TRY_TIMES 10
-#define ASQ_DELAY_MS 50
+#define MAX_TRY_TIMES 20
+#define ASQ_DELAY_MS 100
do {
/* Delay some time first */
rte_delay_ms(ASQ_DELAY_MS);
args->in_args, args->in_args_size, NULL);
if (err) {
PMD_DRV_LOG(ERR, "fail to send cmd %d", args->ops);
+ _clear_cmd(vf);
return err;
}
/* read message and it's expected one */
if (!err && args->ops == info.ops)
_clear_cmd(vf);
- else if (err)
+ else if (err) {
PMD_DRV_LOG(ERR, "Failed to read message from AdminQ");
+ _clear_cmd(vf);
+ }
else if (args->ops != info.ops)
PMD_DRV_LOG(ERR, "command mismatch, expect %u, get %u",
args->ops, info.ops);
if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
PMD_DRV_LOG(INFO, "Peer is DPDK PF host");
else if ((vf->version_major == I40E_VIRTCHNL_VERSION_MAJOR) &&
- (vf->version_minor == I40E_VIRTCHNL_VERSION_MINOR))
+ (vf->version_minor <= I40E_VIRTCHNL_VERSION_MINOR))
PMD_DRV_LOG(INFO, "Peer is Linux PF host");
else {
PMD_INIT_LOG(ERR, "PF/VF API version mismatch:(%u.%u)-(%u.%u)",
struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
int err;
struct vf_cmd_info args;
- uint32_t len;
+ uint32_t caps, len;
args.ops = I40E_VIRTCHNL_OP_GET_VF_RESOURCES;
- args.in_args = NULL;
- args.in_args_size = 0;
args.out_buffer = cmd_result_buffer;
args.out_size = I40E_AQ_BUF_SZ;
-
+ if (PF_IS_V11(vf)) {
+ caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 |
+ I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ |
+ I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
+ I40E_VIRTCHNL_VF_OFFLOAD_VLAN |
+ I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING;
+ args.in_args = (uint8_t *)∩︀
+ args.in_args_size = sizeof(caps);
+ } else {
+ args.in_args = NULL;
+ args.in_args_size = 0;
+ }
err = i40evf_execute_vf_cmd(dev, &args);
if (err) {
int i, err;
map_info = (struct i40e_virtchnl_irq_map_info *)cmd_buffer;
map_info->num_vectors = 1;
- map_info->vecmap[0].rxitr_idx = RTE_LIBRTE_I40E_ITR_INTERVAL / 2;
- map_info->vecmap[0].txitr_idx = RTE_LIBRTE_I40E_ITR_INTERVAL / 2;
+ map_info->vecmap[0].rxitr_idx = I40E_QINT_RQCTL_MSIX_INDX_NOITR;
map_info->vecmap[0].vsi_id = vf->vsi_res->vsi_id;
/* Alway use default dynamic MSIX interrupt */
- map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
+ map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+ else
+ map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
+
/* Don't map any tx queue */
map_info->vecmap[0].txq_map = 0;
map_info->vecmap[0].rxq_map = 0;
/* Stop TX queues first */
for (i = 0; i < dev->data->nb_tx_queues; i++) {
if (i40evf_dev_tx_queue_stop(dev, i) != 0) {
- PMD_DRV_LOG(ERR, "Fail to start queue %u", i);
+ PMD_DRV_LOG(ERR, "Fail to stop queue %u", i);
return -1;
}
}
/* Then stop RX queues */
for (i = 0; i < dev->data->nb_rx_queues; i++) {
if (i40evf_dev_rx_queue_stop(dev, i) != 0) {
- PMD_DRV_LOG(ERR, "Fail to start queue %u", i);
+ PMD_DRV_LOG(ERR, "Fail to stop queue %u", i);
return -1;
}
}
return -1;
}
+static int
+i40evf_uninit_vf(struct rte_eth_dev *dev)
+{
+ struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (hw->adapter_stopped == 0)
+ i40evf_dev_close(dev);
+ rte_free(vf->vf_res);
+ vf->vf_res = NULL;
+
+ return 0;
+}
+
static int
i40evf_dev_init(struct rte_eth_dev *eth_dev)
{
hw->bus.device = eth_dev->pci_dev->addr.devid;
hw->bus.func = eth_dev->pci_dev->addr.function;
hw->hw_addr = (void *)eth_dev->pci_dev->mem_resource[0].addr;
+ hw->adapter_stopped = 0;
if(i40evf_init_vf(eth_dev) != 0) {
PMD_INIT_LOG(ERR, "Init vf failed");
return 0;
}
+static int
+i40evf_dev_uninit(struct rte_eth_dev *eth_dev)
+{
+ PMD_INIT_FUNC_TRACE();
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ return -EPERM;
+
+ eth_dev->dev_ops = NULL;
+ eth_dev->rx_pkt_burst = NULL;
+ eth_dev->tx_pkt_burst = NULL;
+
+ if (i40evf_uninit_vf(eth_dev) != 0) {
+ PMD_INIT_LOG(ERR, "i40evf_uninit_vf failed");
+ return -1;
+ }
+
+ rte_free(eth_dev->data->mac_addrs);
+ eth_dev->data->mac_addrs = NULL;
+
+ return 0;
+}
/*
* virtual function driver struct
*/
static struct eth_driver rte_i40evf_pmd = {
- {
+ .pci_drv = {
.name = "rte_i40evf_pmd",
.id_table = pci_id_i40evf_map,
- .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+ .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
},
.eth_dev_init = i40evf_dev_init,
- .dev_private_size = sizeof(struct i40e_vf),
+ .eth_dev_uninit = i40evf_dev_uninit,
+ .dev_private_size = sizeof(struct i40e_adapter),
};
/*
err = i40evf_switch_queue(dev, FALSE, tx_queue_id, FALSE);
if (err) {
- PMD_DRV_LOG(ERR, "Failed to switch TX queue %u of",
+ PMD_DRV_LOG(ERR, "Failed to switch TX queue %u off",
tx_queue_id);
return err;
}
return ret;
}
+static int
+i40evf_rxq_init(struct rte_eth_dev *dev, struct i40e_rx_queue *rxq)
+{
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct rte_eth_dev_data *dev_data = dev->data;
+ struct rte_pktmbuf_pool_private *mbp_priv;
+ uint16_t buf_size, len;
+
+ rxq->qrx_tail = hw->hw_addr + I40E_QRX_TAIL1(rxq->queue_id);
+ I40E_PCI_REG_WRITE(rxq->qrx_tail, rxq->nb_rx_desc - 1);
+ I40EVF_WRITE_FLUSH(hw);
+
+ /* Calculate the maximum packet length allowed */
+ mbp_priv = rte_mempool_get_priv(rxq->mp);
+ buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+ RTE_PKTMBUF_HEADROOM);
+ rxq->hs_mode = i40e_header_split_none;
+ rxq->rx_hdr_len = 0;
+ rxq->rx_buf_len = RTE_ALIGN(buf_size, (1 << I40E_RXQ_CTX_DBUFF_SHIFT));
+ len = rxq->rx_buf_len * I40E_MAX_CHAINED_RX_BUFFERS;
+ rxq->max_pkt_len = RTE_MIN(len,
+ dev_data->dev_conf.rxmode.max_rx_pkt_len);
+
+ /**
+ * Check if the jumbo frame and maximum packet length are set correctly
+ */
+ if (dev_data->dev_conf.rxmode.jumbo_frame == 1) {
+ if (rxq->max_pkt_len <= ETHER_MAX_LEN ||
+ rxq->max_pkt_len > I40E_FRAME_SIZE_MAX) {
+ PMD_DRV_LOG(ERR, "maximum packet length must be "
+ "larger than %u and smaller than %u, as jumbo "
+ "frame is enabled", (uint32_t)ETHER_MAX_LEN,
+ (uint32_t)I40E_FRAME_SIZE_MAX);
+ return I40E_ERR_CONFIG;
+ }
+ } else {
+ if (rxq->max_pkt_len < ETHER_MIN_LEN ||
+ rxq->max_pkt_len > ETHER_MAX_LEN) {
+ PMD_DRV_LOG(ERR, "maximum packet length must be "
+ "larger than %u and smaller than %u, as jumbo "
+ "frame is disabled", (uint32_t)ETHER_MIN_LEN,
+ (uint32_t)ETHER_MAX_LEN);
+ return I40E_ERR_CONFIG;
+ }
+ }
+
+ if (dev_data->dev_conf.rxmode.enable_scatter ||
+ (rxq->max_pkt_len + 2 * I40E_VLAN_TAG_SIZE) > buf_size) {
+ dev_data->scattered_rx = 1;
+ dev->rx_pkt_burst = i40e_recv_scattered_pkts;
+ }
+
+ return 0;
+}
+
static int
i40evf_rx_init(struct rte_eth_dev *dev)
{
uint16_t i;
struct i40e_rx_queue **rxq =
(struct i40e_rx_queue **)dev->data->rx_queues;
- struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
i40evf_config_rss(vf);
for (i = 0; i < dev->data->nb_rx_queues; i++) {
- rxq[i]->qrx_tail = hw->hw_addr + I40E_QRX_TAIL1(i);
- I40E_PCI_REG_WRITE(rxq[i]->qrx_tail, rxq[i]->nb_rx_desc - 1);
+ if (!rxq[i] || !rxq[i]->q_set)
+ continue;
+ if (i40evf_rxq_init(dev, rxq[i]) < 0)
+ return -EFAULT;
}
- /* Flush the operation to write registers */
- I40EVF_WRITE_FLUSH(hw);
-
return 0;
}
}
static inline void
-i40evf_enable_queues_intr(struct i40e_hw *hw)
+i40evf_enable_queues_intr(struct rte_eth_dev *dev)
{
- I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
+ struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
+ /* To support DPDK PF host */
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
I40E_VFINT_DYN_CTLN1_INTENA_MASK |
I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
+ else
+ /* To support Linux PF host */
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01,
+ I40E_VFINT_DYN_CTL01_INTENA_MASK |
+ I40E_VFINT_DYN_CTL01_CLEARPBA_MASK);
}
static inline void
-i40evf_disable_queues_intr(struct i40e_hw *hw)
+i40evf_disable_queues_intr(struct rte_eth_dev *dev)
{
- I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
+ struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+ if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
+ I40E_WRITE_REG(hw,
+ I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
0);
+ else
+ I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTL01, 0);
}
static int
PMD_INIT_FUNC_TRACE();
- vf->max_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
- if (dev->data->dev_conf.rxmode.jumbo_frame == 1) {
- if (vf->max_pkt_len <= ETHER_MAX_LEN ||
- vf->max_pkt_len > I40E_FRAME_SIZE_MAX) {
- PMD_DRV_LOG(ERR, "maximum packet length must "
- "be larger than %u and smaller than %u,"
- "as jumbo frame is enabled",
- (uint32_t)ETHER_MAX_LEN,
- (uint32_t)I40E_FRAME_SIZE_MAX);
- return I40E_ERR_CONFIG;
- }
- } else {
- if (vf->max_pkt_len < ETHER_MIN_LEN ||
- vf->max_pkt_len > ETHER_MAX_LEN) {
- PMD_DRV_LOG(ERR, "maximum packet length must be "
- "larger than %u and smaller than %u, "
- "as jumbo frame is disabled",
- (uint32_t)ETHER_MIN_LEN,
- (uint32_t)ETHER_MAX_LEN);
- return I40E_ERR_CONFIG;
- }
- }
+ hw->adapter_stopped = 0;
+ vf->max_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
vf->num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
dev->data->nb_tx_queues);
goto err_mac;
}
- i40evf_enable_queues_intr(hw);
+ i40evf_enable_queues_intr(dev);
return 0;
err_mac:
static void
i40evf_dev_stop(struct rte_eth_dev *dev)
{
- struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
PMD_INIT_FUNC_TRACE();
- i40evf_disable_queues_intr(hw);
+ i40evf_disable_queues_intr(dev);
i40evf_stop_queues(dev);
+ i40e_dev_clear_queues(dev);
}
static int
dev_info->max_tx_queues = vf->vsi_res->num_queue_pairs;
dev_info->min_rx_bufsize = I40E_BUF_SIZE_MIN;
dev_info->max_rx_pktlen = I40E_FRAME_SIZE_MAX;
+ dev_info->hash_key_size = (I40E_VFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t);
dev_info->reta_size = ETH_RSS_RETA_SIZE_64;
dev_info->flow_type_rss_offloads = I40E_RSS_OFFLOAD_ALL;
+ dev_info->rx_offload_capa =
+ DEV_RX_OFFLOAD_VLAN_STRIP |
+ DEV_RX_OFFLOAD_QINQ_STRIP |
+ DEV_RX_OFFLOAD_IPV4_CKSUM |
+ DEV_RX_OFFLOAD_UDP_CKSUM |
+ DEV_RX_OFFLOAD_TCP_CKSUM;
+ dev_info->tx_offload_capa =
+ DEV_TX_OFFLOAD_VLAN_INSERT |
+ DEV_TX_OFFLOAD_QINQ_INSERT |
+ DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM;
dev_info->default_rxconf = (struct rte_eth_rxconf) {
.rx_thresh = {
struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
i40evf_dev_stop(dev);
+ hw->adapter_stopped = 1;
+ i40e_dev_free_queues(dev);
i40evf_reset_vf(hw);
i40e_shutdown_adminq(hw);
}
struct i40e_hw *hw = I40E_VF_TO_HW(vf);
struct rte_eth_rss_conf rss_conf;
uint32_t i, j, lut = 0, nb_q = (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4;
+ uint16_t num;
if (vf->dev_data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
i40evf_disable_rss(vf);
return 0;
}
+ num = i40e_align_floor(vf->dev_data->nb_rx_queues);
/* Fill out the look up table */
for (i = 0, j = 0; i < nb_q; i++, j++) {
- if (j >= vf->num_queue_pairs)
+ if (j >= num)
j = 0;
lut = (lut << 8) | j;
if ((i & 3) == 3)