net/i40e: release port upon close
[dpdk.git] / drivers / net / i40e / i40e_ethdev_vf.c
index 63dbe14..7ffb111 100644 (file)
@@ -75,8 +75,8 @@ enum i40evf_aq_result {
 static int i40evf_dev_configure(struct rte_eth_dev *dev);
 static int i40evf_dev_start(struct rte_eth_dev *dev);
 static void i40evf_dev_stop(struct rte_eth_dev *dev);
-static void i40evf_dev_info_get(struct rte_eth_dev *dev,
-                               struct rte_eth_dev_info *dev_info);
+static int 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 int i40evf_dev_stats_get(struct rte_eth_dev *dev,
@@ -86,16 +86,16 @@ static int i40evf_dev_xstats_get(struct rte_eth_dev *dev,
 static int i40evf_dev_xstats_get_names(struct rte_eth_dev *dev,
                                       struct rte_eth_xstat_name *xstats_names,
                                       unsigned limit);
-static void i40evf_dev_xstats_reset(struct rte_eth_dev *dev);
+static int 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 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);
-static void i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev);
-static void i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev);
-static void i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev);
+static int i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev);
+static int i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev);
+static int i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev);
+static int i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev);
 static int i40evf_init_vlan(struct rte_eth_dev *dev);
 static int i40evf_dev_rx_queue_start(struct rte_eth_dev *dev,
                                     uint16_t rx_queue_id);
@@ -140,6 +140,8 @@ static int
 i40evf_set_mc_addr_list(struct rte_eth_dev *dev,
                        struct rte_ether_addr *mc_addr_set,
                        uint32_t nb_mc_addr);
+static void
+i40evf_dev_alarm_handler(void *param);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
@@ -573,7 +575,7 @@ i40evf_fill_virtchnl_vsi_txq_info(struct virtchnl_txq_info *txq_info,
 {
        txq_info->vsi_id = vsi_id;
        txq_info->queue_id = queue_id;
-       if (queue_id < nb_txq) {
+       if (queue_id < nb_txq && txq) {
                txq_info->ring_len = txq->nb_tx_desc;
                txq_info->dma_ring_addr = txq->tx_ring_phys_addr;
        }
@@ -590,7 +592,7 @@ i40evf_fill_virtchnl_vsi_rxq_info(struct virtchnl_rxq_info *rxq_info,
        rxq_info->vsi_id = vsi_id;
        rxq_info->queue_id = queue_id;
        rxq_info->max_pkt_size = max_pkt_size;
-       if (queue_id < nb_rxq) {
+       if (queue_id < nb_rxq && rxq) {
                rxq_info->ring_len = rxq->nb_rx_desc;
                rxq_info->dma_ring_addr = rxq->rx_ring_phys_addr;
                rxq_info->databuffer_size =
@@ -623,10 +625,11 @@ i40evf_configure_vsi_queues(struct rte_eth_dev *dev)
 
        for (i = 0, vc_qpi = vc_vqci->qpair; i < nb_qp; i++, vc_qpi++) {
                i40evf_fill_virtchnl_vsi_txq_info(&vc_qpi->txq,
-                       vc_vqci->vsi_id, i, dev->data->nb_tx_queues, txq[i]);
+                       vc_vqci->vsi_id, i, dev->data->nb_tx_queues,
+                       txq ? txq[i] : NULL);
                i40evf_fill_virtchnl_vsi_rxq_info(&vc_qpi->rxq,
                        vc_vqci->vsi_id, i, dev->data->nb_rx_queues,
-                                       vf->max_pkt_len, rxq[i]);
+                       vf->max_pkt_len, rxq ? rxq[i] : NULL);
        }
        memset(&args, 0, sizeof(args));
        args.ops = VIRTCHNL_OP_CONFIG_VSI_QUEUES;
@@ -947,7 +950,7 @@ i40evf_update_stats(struct i40e_vsi *vsi,
        i40evf_stat_update_32(&oes->tx_discards, &nes->tx_discards);
 }
 
-static void
+static int
 i40evf_dev_xstats_reset(struct rte_eth_dev *dev)
 {
        int ret;
@@ -960,6 +963,8 @@ i40evf_dev_xstats_reset(struct rte_eth_dev *dev)
        /* set stats offset base on current values */
        if (ret == 0)
                vf->vsi.eth_stats_offset = *pstats;
+
+       return ret;
 }
 
 static int i40evf_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
@@ -1050,10 +1055,14 @@ i40evf_request_queues(struct rte_eth_dev *dev, uint16_t num)
        args.in_args_size = sizeof(vfres);
        args.out_buffer = vf->aq_resp;
        args.out_size = I40E_AQ_BUF_SZ;
+
+       rte_eal_alarm_cancel(i40evf_dev_alarm_handler, dev);
        err = i40evf_execute_vf_cmd(dev, &args);
        if (err)
                PMD_DRV_LOG(ERR, "fail to execute command OP_REQUEST_QUEUES");
 
+       rte_eal_alarm_set(I40EVF_ALARM_INTERVAL,
+                         i40evf_dev_alarm_handler, dev);
        return err;
 }
 
@@ -1303,17 +1312,12 @@ err:
 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_closed == 0)
                i40evf_dev_close(dev);
-       rte_free(vf->vf_res);
-       vf->vf_res = NULL;
-       rte_free(vf->aq_resp);
-       vf->aq_resp = NULL;
 
        return 0;
 }
@@ -1404,7 +1408,7 @@ i40evf_handle_aq_msg(struct rte_eth_dev *dev)
                        }
                        break;
                default:
-                       PMD_DRV_LOG(ERR, "Request %u is not supported yet",
+                       PMD_DRV_LOG(DEBUG, "Request %u is not supported yet",
                                    aq_opc);
                        break;
                }
@@ -1479,7 +1483,6 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
                return 0;
        }
        i40e_set_default_ptype_table(eth_dev);
-       i40e_set_default_pctype_table(eth_dev);
        rte_eth_copy_pci_info(eth_dev, pci_dev);
 
        hw->vendor_id = pci_dev->id.vendor_id;
@@ -1492,11 +1495,17 @@ i40evf_dev_init(struct rte_eth_dev *eth_dev)
        hw->adapter_stopped = 0;
        hw->adapter_closed = 0;
 
+       /* Pass the information to the rte_eth_dev_close() that it should also
+        * release the private port resources.
+        */
+       eth_dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
        if(i40evf_init_vf(eth_dev) != 0) {
                PMD_INIT_LOG(ERR, "Init vf failed");
                return -1;
        }
 
+       i40e_set_default_pctype_table(eth_dev);
        rte_eal_alarm_set(I40EVF_ALARM_INTERVAL,
                          i40evf_dev_alarm_handler, eth_dev);
 
@@ -1527,10 +1536,6 @@ i40evf_dev_uninit(struct rte_eth_dev *eth_dev)
        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;
@@ -1556,7 +1561,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 | RTE_PCI_DRV_IOVA_AS_VA,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
        .probe = eth_i40evf_pci_probe,
        .remove = eth_i40evf_pci_remove,
 };
@@ -2149,7 +2154,7 @@ i40evf_dev_link_update(struct rte_eth_dev *dev,
        return rte_eth_linkstatus_set(dev, &new_link);
 }
 
-static void
+static int
 i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev)
 {
        struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
@@ -2157,14 +2162,18 @@ i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev)
 
        /* If enabled, just return */
        if (vf->promisc_unicast_enabled)
-               return;
+               return 0;
 
        ret = i40evf_config_promisc(dev, 1, vf->promisc_multicast_enabled);
        if (ret == 0)
                vf->promisc_unicast_enabled = TRUE;
+       else
+               ret = -EAGAIN;
+
+       return ret;
 }
 
-static void
+static int
 i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev)
 {
        struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
@@ -2172,14 +2181,18 @@ i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev)
 
        /* If disabled, just return */
        if (!vf->promisc_unicast_enabled)
-               return;
+               return 0;
 
        ret = i40evf_config_promisc(dev, 0, vf->promisc_multicast_enabled);
        if (ret == 0)
                vf->promisc_unicast_enabled = FALSE;
+       else
+               ret = -EAGAIN;
+
+       return ret;
 }
 
-static void
+static int
 i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev)
 {
        struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
@@ -2187,14 +2200,18 @@ i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev)
 
        /* If enabled, just return */
        if (vf->promisc_multicast_enabled)
-               return;
+               return 0;
 
        ret = i40evf_config_promisc(dev, vf->promisc_unicast_enabled, 1);
        if (ret == 0)
                vf->promisc_multicast_enabled = TRUE;
+       else
+               ret = -EAGAIN;
+
+       return ret;
 }
 
-static void
+static int
 i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev)
 {
        struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
@@ -2202,14 +2219,18 @@ i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev)
 
        /* If enabled, just return */
        if (!vf->promisc_multicast_enabled)
-               return;
+               return 0;
 
        ret = i40evf_config_promisc(dev, vf->promisc_unicast_enabled, 0);
        if (ret == 0)
                vf->promisc_multicast_enabled = FALSE;
+       else
+               ret = -EAGAIN;
+
+       return ret;
 }
 
-static void
+static int
 i40evf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
        struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
@@ -2285,6 +2306,8 @@ i40evf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                .nb_min = I40E_MIN_RING_DESC,
                .nb_align = I40E_ALIGN_RING_DESC,
        };
+
+       return 0;
 }
 
 static int
@@ -2317,6 +2340,7 @@ static void
 i40evf_dev_close(struct rte_eth_dev *dev)
 {
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
        i40evf_dev_stop(dev);
        i40e_dev_free_queues(dev);
@@ -2332,6 +2356,16 @@ i40evf_dev_close(struct rte_eth_dev *dev)
        i40evf_reset_vf(dev);
        i40e_shutdown_adminq(hw);
        i40evf_disable_irq0(hw);
+
+       dev->dev_ops = NULL;
+       dev->rx_pkt_burst = NULL;
+       dev->tx_pkt_burst = NULL;
+
+       rte_free(vf->vf_res);
+       vf->vf_res = NULL;
+       rte_free(vf->aq_resp);
+       vf->aq_resp = NULL;
+
        hw->adapter_closed = 1;
 }
 
@@ -2591,7 +2625,10 @@ 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;
+       uint32_t rss_lut_size = (I40E_VFQF_HLUT1_MAX_INDEX + 1) * 4;
        uint16_t num;
+       uint8_t *lut_info;
+       int ret;
 
        if (vf->dev_data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
                i40evf_disable_rss(vf);
@@ -2601,12 +2638,29 @@ i40evf_config_rss(struct i40e_vf *vf)
 
        num = RTE_MIN(vf->dev_data->nb_rx_queues, I40E_MAX_QP_NUM_PER_VF);
        /* Fill out the look up table */
-       for (i = 0, j = 0; i < nb_q; i++, j++) {
-               if (j >= num)
-                       j = 0;
-               lut = (lut << 8) | j;
-               if ((i & 3) == 3)
-                       I40E_WRITE_REG(hw, I40E_VFQF_HLUT(i >> 2), lut);
+       if (!(vf->flags & I40E_FLAG_RSS_AQ_CAPABLE)) {
+               for (i = 0, j = 0; i < nb_q; i++, j++) {
+                       if (j >= num)
+                               j = 0;
+                       lut = (lut << 8) | j;
+                       if ((i & 3) == 3)
+                               I40E_WRITE_REG(hw, I40E_VFQF_HLUT(i >> 2), lut);
+               }
+       } else {
+               lut_info = rte_zmalloc("i40e_rss_lut", rss_lut_size, 0);
+               if (!lut_info) {
+                       PMD_DRV_LOG(ERR, "No memory can be allocated");
+                       return -ENOMEM;
+               }
+
+               for (i = 0; i < rss_lut_size; i++)
+                       lut_info[i] = i % vf->num_queue_pairs;
+
+               ret = i40evf_set_rss_lut(&vf->vsi, lut_info,
+                                        rss_lut_size);
+               rte_free(lut_info);
+               if (ret)
+                       return ret;
        }
 
        rss_conf = vf->dev_data->dev_conf.rx_adv_conf.rss_conf;
@@ -2808,3 +2862,9 @@ i40evf_set_mc_addr_list(struct rte_eth_dev *dev,
 
        return 0;
 }
+
+bool
+is_i40evf_supported(struct rte_eth_dev *dev)
+{
+       return is_device_supported(dev, &rte_i40evf_pmd);
+}