net/i40e: fix VF cannot forward packets issue
[dpdk.git] / drivers / net / i40e / i40e_ethdev_vf.c
index 111ac39..91b5bb0 100644 (file)
 #include <rte_log.h>
 #include <rte_debug.h>
 #include <rte_pci.h>
+#include <rte_bus_pci.h>
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
 #include <rte_memory.h>
-#include <rte_memzone.h>
 #include <rte_eal.h>
 #include <rte_alarm.h>
 #include <rte_ether.h>
@@ -67,8 +67,6 @@
 #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_LNX 0
 
 /* busy wait delay in msec */
 #define I40EVF_BUSY_WAIT_DELAY 10
@@ -108,7 +106,7 @@ static void i40evf_dev_info_get(struct rte_eth_dev *dev,
                                struct rte_eth_dev_info *dev_info);
 static int i40evf_dev_link_update(struct rte_eth_dev *dev,
                                  int wait_to_complete);
-static void i40evf_dev_stats_get(struct rte_eth_dev *dev,
+static int i40evf_dev_stats_get(struct rte_eth_dev *dev,
                                struct rte_eth_stats *stats);
 static int i40evf_dev_xstats_get(struct rte_eth_dev *dev,
                                 struct rte_eth_xstat *xstats, unsigned n);
@@ -118,7 +116,7 @@ static int i40evf_dev_xstats_get_names(struct rte_eth_dev *dev,
 static void i40evf_dev_xstats_reset(struct rte_eth_dev *dev);
 static int i40evf_vlan_filter_set(struct rte_eth_dev *dev,
                                  uint16_t vlan_id, int on);
-static void i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void i40evf_dev_close(struct rte_eth_dev *dev);
 static int  i40evf_dev_reset(struct rte_eth_dev *dev);
 static void i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev);
@@ -652,8 +650,9 @@ i40evf_config_irq_map(struct rte_eth_dev *dev)
        uint32_t vector_id;
        int i, err;
 
-       if (rte_intr_allow_others(intr_handle))
-               vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR_LNX;
+       if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+           rte_intr_allow_others(intr_handle))
+               vector_id = I40E_RX_VEC_START;
        else
                vector_id = I40E_MISC_VEC_ID;
 
@@ -1111,10 +1110,30 @@ i40evf_enable_irq0(struct i40e_hw *hw)
 }
 
 static int
-i40evf_reset_vf(struct i40e_hw *hw)
+i40evf_check_vf_reset_done(struct i40e_hw *hw)
 {
        int i, reset;
 
+       for (i = 0; i < MAX_RESET_WAIT_CNT; i++) {
+               reset = I40E_READ_REG(hw, I40E_VFGEN_RSTAT) &
+                       I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+               reset = reset >> I40E_VFGEN_RSTAT_VFR_STATE_SHIFT;
+               if (reset == VIRTCHNL_VFR_VFACTIVE ||
+                   reset == VIRTCHNL_VFR_COMPLETED)
+                       break;
+               rte_delay_ms(50);
+       }
+
+       if (i >= MAX_RESET_WAIT_CNT)
+               return -1;
+
+       return 0;
+}
+static int
+i40evf_reset_vf(struct i40e_hw *hw)
+{
+       int ret;
+
        if (i40e_vf_reset(hw) != I40E_SUCCESS) {
                PMD_INIT_LOG(ERR, "Reset VF NIC failed");
                return -1;
@@ -1130,19 +1149,10 @@ i40evf_reset_vf(struct i40e_hw *hw)
          */
        rte_delay_ms(200);
 
-       for (i = 0; i < MAX_RESET_WAIT_CNT; i++) {
-               reset = rd32(hw, I40E_VFGEN_RSTAT) &
-                       I40E_VFGEN_RSTAT_VFR_STATE_MASK;
-               reset = reset >> I40E_VFGEN_RSTAT_VFR_STATE_SHIFT;
-               if (VIRTCHNL_VFR_COMPLETED == reset || VIRTCHNL_VFR_VFACTIVE == reset)
-                       break;
-               else
-                       rte_delay_ms(50);
-       }
-
-       if (i >= MAX_RESET_WAIT_CNT) {
-               PMD_INIT_LOG(ERR, "Reset VF NIC failed");
-               return -1;
+       ret = i40evf_check_vf_reset_done(hw);
+       if (ret) {
+               PMD_INIT_LOG(ERR, "VF is still resetting");
+               return ret;
        }
 
        return 0;
@@ -1165,6 +1175,10 @@ i40evf_init_vf(struct rte_eth_dev *dev)
                goto err;
        }
 
+       err = i40evf_check_vf_reset_done(hw);
+       if (err)
+               goto err;
+
        i40e_init_adminq_parameter(hw);
        err = i40e_init_adminq(hw);
        if (err) {
@@ -1189,6 +1203,7 @@ i40evf_init_vf(struct rte_eth_dev *dev)
                PMD_INIT_LOG(ERR, "init_adminq failed");
                goto err;
        }
+
        vf->aq_resp = rte_zmalloc("vf_aq_resp", I40E_AQ_BUF_SZ, 0);
        if (!vf->aq_resp) {
                PMD_INIT_LOG(ERR, "unable to allocate vf_aq_resp memory");
@@ -1416,7 +1431,6 @@ i40evf_dev_interrupt_handler(void *param)
 
 done:
        i40evf_enable_irq0(hw);
-       rte_intr_enable(dev->intr_handle);
 }
 
 static int
@@ -1445,7 +1459,6 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
        i40e_set_default_ptype_table(eth_dev);
        i40e_set_default_pctype_table(eth_dev);
        rte_eth_copy_pci_info(eth_dev, pci_dev);
-       eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
 
        hw->vendor_id = pci_dev->id.vendor_id;
        hw->device_id = pci_dev->id.device_id;
@@ -1527,7 +1540,7 @@ static int eth_i40evf_pci_remove(struct rte_pci_device *pci_dev)
  */
 static struct rte_pci_driver 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_IOVA_AS_VA,
        .probe = eth_i40evf_pci_probe,
        .remove = eth_i40evf_pci_remove,
 };
@@ -1572,12 +1585,10 @@ static int
 i40evf_init_vlan(struct rte_eth_dev *dev)
 {
        /* Apply vlan offload setting */
-       i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
-
-       return I40E_SUCCESS;
+       return i40evf_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
 }
 
-static void
+static int
 i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
        struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
@@ -1590,6 +1601,8 @@ i40evf_vlan_offload_set(struct rte_eth_dev *dev, int mask)
                else
                        i40evf_disable_vlan_strip(dev);
        }
+
+       return 0;
 }
 
 static int
@@ -2025,7 +2038,20 @@ i40evf_dev_start(struct rte_eth_dev *dev)
                goto err_mac;
        }
 
+       /* When a VF port is bound to VFIO-PCI, only miscellaneous interrupt
+        * is mapped to VFIO vector 0 in i40evf_dev_init( ).
+        * If previous VFIO interrupt mapping set in i40evf_dev_init( ) is
+        * not cleared, it will fail when rte_intr_enable( ) tries to map Rx
+        * queue interrupt to other VFIO vectors.
+        * So clear uio/vfio intr/evevnfd first to avoid failure.
+        */
+       if (dev->data->dev_conf.intr_conf.rxq != 0) {
+               rte_intr_disable(intr_handle);
+               rte_intr_enable(intr_handle);
+       }
+
        i40evf_enable_queues_intr(dev);
+
        return 0;
 
 err_mac:
@@ -2100,6 +2126,8 @@ i40evf_dev_link_update(struct rte_eth_dev *dev,
        new_link.link_duplex = ETH_LINK_FULL_DUPLEX;
        new_link.link_status = vf->link_up ? ETH_LINK_UP :
                                             ETH_LINK_DOWN;
+       new_link.link_autoneg =
+               dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED;
 
        i40evf_dev_atomic_write_link_status(dev, &new_link);
 
@@ -2230,7 +2258,7 @@ i40evf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        };
 }
 
-static void
+static int
 i40evf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
        int ret;
@@ -2253,6 +2281,7 @@ i40evf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
        } else {
                PMD_DRV_LOG(ERR, "Get statistics failed");
        }
+       return ret;
 }
 
 static void