i40evf: fix write back with virtual channel 1.1
[dpdk.git] / drivers / net / i40e / i40e_ethdev_vf.c
index f7332e7..1324281 100644 (file)
 #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;
@@ -298,8 +301,8 @@ i40evf_wait_cmd_done(struct rte_eth_dev *dev,
        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);
@@ -361,6 +364,7 @@ i40evf_execute_vf_cmd(struct rte_eth_dev *dev, struct vf_cmd_info *args)
                     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;
        }
 
@@ -368,8 +372,10 @@ i40evf_execute_vf_cmd(struct rte_eth_dev *dev, struct vf_cmd_info *args)
        /* 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);
@@ -409,7 +415,7 @@ i40evf_check_api_version(struct rte_eth_dev *dev)
        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)",
@@ -429,14 +435,23 @@ i40evf_get_vf_resource(struct rte_eth_dev *dev)
        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 *)&caps;
+               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) {
@@ -700,11 +715,14 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
        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;
@@ -794,7 +812,7 @@ i40evf_stop_queues(struct rte_eth_dev *dev)
        /* 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;
                }
        }
@@ -802,7 +820,7 @@ i40evf_stop_queues(struct rte_eth_dev *dev)
        /* 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;
                }
        }
@@ -1145,6 +1163,22 @@ err:
        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)
 {
@@ -1175,6 +1209,7 @@ 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");
@@ -1195,6 +1230,28 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
        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
  */
@@ -1202,10 +1259,11 @@ 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),
 };
 
 /*
@@ -1391,7 +1449,7 @@ i40evf_dev_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
                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;
                }
@@ -1481,6 +1539,8 @@ i40evf_rx_init(struct rte_eth_dev *dev)
 
        i40evf_config_rss(vf);
        for (i = 0; i < dev->data->nb_rx_queues; i++) {
+               if (!rxq[i] || !rxq[i]->q_set)
+                       continue;
                if (i40evf_rxq_init(dev, rxq[i]) < 0)
                        return -EFAULT;
        }
@@ -1501,18 +1561,36 @@ i40evf_tx_init(struct rte_eth_dev *dev)
 }
 
 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
@@ -1524,6 +1602,8 @@ i40evf_dev_start(struct rte_eth_dev *dev)
 
        PMD_INIT_FUNC_TRACE();
 
+       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);
@@ -1557,7 +1637,7 @@ i40evf_dev_start(struct rte_eth_dev *dev)
                goto err_mac;
        }
 
-       i40evf_enable_queues_intr(hw);
+       i40evf_enable_queues_intr(dev);
        return 0;
 
 err_mac:
@@ -1569,12 +1649,11 @@ err_queue:
 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
@@ -1670,8 +1749,22 @@ i40evf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        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 = {
@@ -1709,6 +1802,8 @@ i40evf_dev_close(struct rte_eth_dev *dev)
        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);
 }
@@ -1843,6 +1938,7 @@ i40evf_config_rss(struct i40e_vf *vf)
        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);
@@ -1850,9 +1946,10 @@ i40evf_config_rss(struct i40e_vf *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)