net/hns3: fix DCB reconfiguration
[dpdk.git] / drivers / net / nfp / nfp_net.c
index 470caff..2ee88fb 100644 (file)
@@ -59,6 +59,7 @@ static int nfp_net_infos_get(struct rte_eth_dev *dev,
                             struct rte_eth_dev_info *dev_info);
 static int nfp_net_init(struct rte_eth_dev *eth_dev);
 static int nfp_pf_init(struct rte_eth_dev *eth_dev);
+static int nfp_pci_uninit(struct rte_eth_dev *eth_dev);
 static int nfp_init_phyports(struct nfp_pf_dev *pf_dev);
 static int nfp_net_link_update(struct rte_eth_dev *dev, int wait_to_complete);
 static int nfp_net_promisc_enable(struct rte_eth_dev *dev);
@@ -768,10 +769,10 @@ nfp_net_start(struct rte_eth_dev *dev)
        if (hw->is_phyport) {
                if (rte_eal_process_type() == RTE_PROC_PRIMARY)
                        /* Configure the physical port up */
-                       nfp_eth_set_configured(hw->cpp, hw->idx, 1);
+                       nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 1);
                else
                        nfp_eth_set_configured(dev->process_private,
-                                              hw->idx, 1);
+                                              hw->nfp_idx, 1);
        }
 
        hw->ctrl = new_ctrl;
@@ -824,10 +825,10 @@ nfp_net_stop(struct rte_eth_dev *dev)
        if (hw->is_phyport) {
                if (rte_eal_process_type() == RTE_PROC_PRIMARY)
                        /* Configure the physical port down */
-                       nfp_eth_set_configured(hw->cpp, hw->idx, 0);
+                       nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 0);
                else
                        nfp_eth_set_configured(dev->process_private,
-                                              hw->idx, 0);
+                                              hw->nfp_idx, 0);
        }
 
        return 0;
@@ -848,10 +849,10 @@ nfp_net_set_link_up(struct rte_eth_dev *dev)
 
        if (rte_eal_process_type() == RTE_PROC_PRIMARY)
                /* Configure the physical port down */
-               return nfp_eth_set_configured(hw->cpp, hw->idx, 1);
+               return nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 1);
        else
                return nfp_eth_set_configured(dev->process_private,
-                                             hw->idx, 1);
+                                             hw->nfp_idx, 1);
 }
 
 /* Set the link down. */
@@ -869,10 +870,10 @@ nfp_net_set_link_down(struct rte_eth_dev *dev)
 
        if (rte_eal_process_type() == RTE_PROC_PRIMARY)
                /* Configure the physical port down */
-               return nfp_eth_set_configured(hw->cpp, hw->idx, 0);
+               return nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 0);
        else
                return nfp_eth_set_configured(dev->process_private,
-                                             hw->idx, 0);
+                                             hw->nfp_idx, 0);
 }
 
 /* Reset and stop device. The device can not be restarted. */
@@ -909,8 +910,34 @@ nfp_net_close(struct rte_eth_dev *dev)
                        (struct nfp_net_rxq *)dev->data->rx_queues[i]);
        }
 
+       /* Only free PF resources after all physical ports have been closed */
+       if (pci_dev->id.device_id == PCI_DEVICE_ID_NFP4000_PF_NIC ||
+           pci_dev->id.device_id == PCI_DEVICE_ID_NFP6000_PF_NIC) {
+               struct nfp_pf_dev *pf_dev;
+               pf_dev = NFP_NET_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+               /* Mark this port as unused and free device priv resources*/
+               nn_cfg_writeb(hw, NFP_NET_CFG_LSC, 0xff);
+               pf_dev->ports[hw->idx] = NULL;
+               rte_eth_dev_release_port(dev);
+
+               for (i = 0; i < pf_dev->total_phyports; i++) {
+                       /* Check to see if ports are still in use */
+                       if (pf_dev->ports[i])
+                               return 0;
+               }
+
+               /* Now it is safe to free all PF resources */
+               PMD_INIT_LOG(INFO, "Freeing PF resources");
+               nfp_cpp_area_free(pf_dev->ctrl_area);
+               nfp_cpp_area_free(pf_dev->hwqueues_area);
+               free(pf_dev->hwinfo);
+               free(pf_dev->sym_tbl);
+               nfp_cpp_free(pf_dev->cpp);
+               rte_free(pf_dev);
+       }
+
        rte_intr_disable(&pci_dev->intr_handle);
-       nn_cfg_writeb(hw, NFP_NET_CFG_LSC, 0xff);
 
        /* unregister callback func from eal lib */
        rte_intr_callback_unregister(&pci_dev->intr_handle,
@@ -1230,9 +1257,6 @@ nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                                             DEV_RX_OFFLOAD_UDP_CKSUM |
                                             DEV_RX_OFFLOAD_TCP_CKSUM;
 
-       dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_JUMBO_FRAME |
-                                    DEV_RX_OFFLOAD_RSS_HASH;
-
        if (hw->cap & NFP_NET_CFG_CTRL_TXVLAN)
                dev_info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT;
 
@@ -1281,15 +1305,22 @@ nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                .nb_mtu_seg_max = NFP_TX_MAX_MTU_SEG,
        };
 
-       dev_info->flow_type_rss_offloads = ETH_RSS_IPV4 |
-                                          ETH_RSS_NONFRAG_IPV4_TCP |
-                                          ETH_RSS_NONFRAG_IPV4_UDP |
-                                          ETH_RSS_IPV6 |
-                                          ETH_RSS_NONFRAG_IPV6_TCP |
-                                          ETH_RSS_NONFRAG_IPV6_UDP;
+       /* All NFP devices support jumbo frames */
+       dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_JUMBO_FRAME;
+
+       if (hw->cap & NFP_NET_CFG_CTRL_RSS) {
+               dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_RSS_HASH;
 
-       dev_info->reta_size = NFP_NET_CFG_RSS_ITBL_SZ;
-       dev_info->hash_key_size = NFP_NET_CFG_RSS_KEY_SZ;
+               dev_info->flow_type_rss_offloads = ETH_RSS_IPV4 |
+                                                  ETH_RSS_NONFRAG_IPV4_TCP |
+                                                  ETH_RSS_NONFRAG_IPV4_UDP |
+                                                  ETH_RSS_IPV6 |
+                                                  ETH_RSS_NONFRAG_IPV6_TCP |
+                                                  ETH_RSS_NONFRAG_IPV6_UDP;
+
+               dev_info->reta_size = NFP_NET_CFG_RSS_ITBL_SZ;
+               dev_info->hash_key_size = NFP_NET_CFG_RSS_KEY_SZ;
+       }
 
        dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G |
                               ETH_LINK_SPEED_25G | ETH_LINK_SPEED_40G |
@@ -2779,15 +2810,15 @@ nfp_net_init(struct rte_eth_dev *eth_dev)
                        return -ENODEV;
                }
 
-               /* This points to the specific port private data */
-               PMD_INIT_LOG(DEBUG, "Working with physical port number %d",
-                                   port);
-
                /* Use PF array of physical ports to get pointer to
                 * this specific port
                 */
                hw = pf_dev->ports[port];
 
+               PMD_INIT_LOG(DEBUG, "Working with physical port number: %d, "
+                                   "NFP internal port number: %d",
+                                   port, hw->nfp_idx);
+
        } else {
                hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
        }
@@ -3466,9 +3497,17 @@ static int nfp_init_phyports(struct nfp_pf_dev *pf_dev)
 {
        struct nfp_net_hw *hw;
        struct rte_eth_dev *eth_dev;
+       struct nfp_eth_table *nfp_eth_table = NULL;
        int ret = 0;
        int i;
 
+       nfp_eth_table = nfp_eth_read_ports(pf_dev->cpp);
+       if (!nfp_eth_table) {
+               PMD_INIT_LOG(ERR, "Error reading NFP ethernet table");
+               ret = -EIO;
+               goto error;
+       }
+
        /* Loop through all physical ports on PF */
        for (i = 0; i < pf_dev->total_phyports; i++) {
                const unsigned int numa_node = rte_socket_id();
@@ -3524,6 +3563,7 @@ skip_dev_alloc:
                hw->cpp = pf_dev->cpp;
                hw->eth_dev = eth_dev;
                hw->idx = i;
+               hw->nfp_idx = nfp_eth_table->ports[i].index;
                hw->is_phyport = true;
 
 nfp_net_init:
@@ -3542,7 +3582,8 @@ nfp_net_init:
                rte_eth_dev_probing_finish(eth_dev);
 
        } /* End loop, all ports on this PF */
-       return 0;
+       ret = 0;
+       goto eth_table_cleanup;
 
 port_cleanup:
        for (i = 0; i < pf_dev->total_phyports; i++) {
@@ -3553,6 +3594,8 @@ port_cleanup:
                        pf_dev->ports[i] = NULL;
                }
        }
+eth_table_cleanup:
+       free(nfp_eth_table);
 error:
        return ret;
 }
@@ -3765,6 +3808,29 @@ static const struct rte_pci_id pci_id_nfp_vf_net_map[] = {
        },
 };
 
+static int nfp_pci_uninit(struct rte_eth_dev *eth_dev)
+{
+       struct rte_pci_device *pci_dev;
+       uint16_t port_id;
+
+       pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+
+       if (pci_dev->id.device_id == PCI_DEVICE_ID_NFP4000_PF_NIC ||
+           pci_dev->id.device_id == PCI_DEVICE_ID_NFP6000_PF_NIC) {
+               /* Free up all physical ports under PF */
+               RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device)
+                       rte_eth_dev_close(port_id);
+               /*
+                * Ports can be closed and freed but hotplugging is not
+                * currently supported
+                */
+               return -ENOTSUP;
+       }
+
+       /* VF cleanup, just free private port data */
+       return nfp_net_close(eth_dev);
+}
+
 static int eth_nfp_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
        struct rte_pci_device *pci_dev)
 {
@@ -3774,16 +3840,7 @@ static int eth_nfp_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 static int eth_nfp_pci_remove(struct rte_pci_device *pci_dev)
 {
-       struct rte_eth_dev *eth_dev;
-
-       eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
-       if (eth_dev == NULL)
-               return 0; /* port already released */
-       if ((pci_dev->id.device_id == PCI_DEVICE_ID_NFP4000_PF_NIC) ||
-           (pci_dev->id.device_id == PCI_DEVICE_ID_NFP6000_PF_NIC))
-               return -ENOTSUP;
-
-       return rte_eth_dev_pci_generic_remove(pci_dev, NULL);
+       return rte_eth_dev_pci_generic_remove(pci_dev, nfp_pci_uninit);
 }
 
 static struct rte_pci_driver rte_nfp_net_pf_pmd = {
@@ -3806,8 +3863,8 @@ RTE_PMD_REGISTER_PCI_TABLE(net_nfp_pf, pci_id_nfp_pf_net_map);
 RTE_PMD_REGISTER_PCI_TABLE(net_nfp_vf, pci_id_nfp_vf_net_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_nfp_pf, "* igb_uio | uio_pci_generic | vfio");
 RTE_PMD_REGISTER_KMOD_DEP(net_nfp_vf, "* igb_uio | uio_pci_generic | vfio");
-RTE_LOG_REGISTER(nfp_logtype_init, pmd.net.nfp.init, NOTICE);
-RTE_LOG_REGISTER(nfp_logtype_driver, pmd.net.nfp.driver, NOTICE);
+RTE_LOG_REGISTER_SUFFIX(nfp_logtype_init, init, NOTICE);
+RTE_LOG_REGISTER_SUFFIX(nfp_logtype_driver, driver, NOTICE);
 /*
  * Local variables:
  * c-file-style: "Linux"