net/i40e/base: support LLDP agent
[dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index 76cd9f5..1b361c0 100644 (file)
@@ -400,6 +400,15 @@ static void i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev);
 
 int i40e_logtype_init;
 int i40e_logtype_driver;
+#ifdef RTE_LIBRTE_I40E_DEBUG_RX
+int i40e_logtype_rx;
+#endif
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX
+int i40e_logtype_tx;
+#endif
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX_FREE
+int i40e_logtype_tx_free;
+#endif
 
 static const char *const valid_keys[] = {
        ETH_I40E_FLOATING_VEB_ARG,
@@ -493,6 +502,8 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
        .filter_ctrl                  = i40e_dev_filter_ctrl,
        .rxq_info_get                 = i40e_rxq_info_get,
        .txq_info_get                 = i40e_txq_info_get,
+       .rx_burst_mode_get            = i40e_rx_burst_mode_get,
+       .tx_burst_mode_get            = i40e_tx_burst_mode_get,
        .mirror_rule_set              = i40e_mirror_rule_set,
        .mirror_rule_reset            = i40e_mirror_rule_reset,
        .timesync_enable              = i40e_timesync_enable,
@@ -687,13 +698,14 @@ static int eth_i40e_pci_remove(struct rte_pci_device *pci_dev)
 
        ethdev = rte_eth_dev_allocated(pci_dev->device.name);
        if (!ethdev)
-               return -ENODEV;
-
+               return 0;
 
        if (ethdev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR)
-               return rte_eth_dev_destroy(ethdev, i40e_vf_representor_uninit);
+               return rte_eth_dev_pci_generic_remove(pci_dev,
+                                       i40e_vf_representor_uninit);
        else
-               return rte_eth_dev_destroy(ethdev, eth_i40e_dev_uninit);
+               return rte_eth_dev_pci_generic_remove(pci_dev,
+                                               eth_i40e_dev_uninit);
 }
 
 static struct rte_pci_driver rte_i40e_pmd = {
@@ -1381,6 +1393,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
        hw->adapter_stopped = 0;
        hw->adapter_closed = 0;
 
+       /* Init switch device pointer */
+       hw->switch_dev = NULL;
+
        /*
         * Switch Tag value should not be identical to either the First Tag
         * or Second Tag values. So set something other than common Ethertype
@@ -1590,6 +1605,11 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
        rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.perm_addr,
                                        &dev->data->mac_addrs[0]);
 
+       /* Pass the information to the rte_eth_dev_close() that it should also
+        * release the private port resources.
+        */
+       dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
+
        /* Init dcb to sw mode by default */
        ret = i40e_dcb_init_configure(dev, TRUE);
        if (ret != I40E_SUCCESS) {
@@ -1759,85 +1779,18 @@ void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)
 static int
 eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 {
-       struct i40e_pf *pf;
-       struct rte_pci_device *pci_dev;
-       struct rte_intr_handle *intr_handle;
        struct i40e_hw *hw;
-       struct i40e_filter_control_settings settings;
-       struct rte_flow *p_flow;
-       int ret;
-       uint8_t aq_fail = 0;
-       int retries = 0;
 
        PMD_INIT_FUNC_TRACE();
 
        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
                return 0;
 
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       pci_dev = RTE_ETH_DEV_TO_PCI(dev);
-       intr_handle = &pci_dev->intr_handle;
-
-       ret = rte_eth_switch_domain_free(pf->switch_domain_id);
-       if (ret)
-               PMD_INIT_LOG(WARNING, "failed to free switch domain: %d", ret);
 
        if (hw->adapter_closed == 0)
                i40e_dev_close(dev);
 
-       dev->dev_ops = NULL;
-       dev->rx_pkt_burst = NULL;
-       dev->tx_pkt_burst = NULL;
-
-       /* Clear PXE mode */
-       i40e_clear_pxe_mode(hw);
-
-       /* Unconfigure filter control */
-       memset(&settings, 0, sizeof(settings));
-       ret = i40e_set_filter_control(hw, &settings);
-       if (ret)
-               PMD_INIT_LOG(WARNING, "setup_pf_filter_control failed: %d",
-                                       ret);
-
-       /* Disable flow control */
-       hw->fc.requested_mode = I40E_FC_NONE;
-       i40e_set_fc(hw, &aq_fail, TRUE);
-
-       /* uninitialize pf host driver */
-       i40e_pf_host_uninit(dev);
-
-       /* disable uio intr before callback unregister */
-       rte_intr_disable(intr_handle);
-
-       /* unregister callback func to eal lib */
-       do {
-               ret = rte_intr_callback_unregister(intr_handle,
-                               i40e_dev_interrupt_handler, dev);
-               if (ret >= 0) {
-                       break;
-               } else if (ret != -EAGAIN) {
-                       PMD_INIT_LOG(ERR,
-                                "intr callback unregister failed: %d",
-                                ret);
-                       return ret;
-               }
-               i40e_msec_delay(500);
-       } while (retries++ < 5);
-
-       i40e_rm_ethtype_filter_list(pf);
-       i40e_rm_tunnel_filter_list(pf);
-       i40e_rm_fdir_filter_list(pf);
-
-       /* Remove all flows */
-       while ((p_flow = TAILQ_FIRST(&pf->flow_list))) {
-               TAILQ_REMOVE(&pf->flow_list, p_flow, node);
-               rte_free(p_flow);
-       }
-
-       /* Remove all Traffic Manager configuration */
-       i40e_tm_conf_uninit(dev);
-
        return 0;
 }
 
@@ -1863,6 +1816,9 @@ i40e_dev_configure(struct rte_eth_dev *dev)
        ad->tx_simple_allowed = true;
        ad->tx_vec_allowed = true;
 
+       if (dev->data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG)
+               dev->data->dev_conf.rxmode.offloads |= DEV_RX_OFFLOAD_RSS_HASH;
+
        /* Only legacy filter API needs the following fdir config. So when the
         * legacy filter API is deprecated, the following codes should also be
         * removed.
@@ -2285,6 +2241,9 @@ i40e_apply_link_speed(struct rte_eth_dev *dev)
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct rte_eth_conf *conf = &dev->data->dev_conf;
 
+       abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK |
+                    I40E_AQ_PHY_LINK_ENABLED;
+
        if (conf->link_speeds == ETH_LINK_SPEED_AUTONEG) {
                conf->link_speeds = ETH_LINK_SPEED_40G |
                                    ETH_LINK_SPEED_25G |
@@ -2292,11 +2251,12 @@ i40e_apply_link_speed(struct rte_eth_dev *dev)
                                    ETH_LINK_SPEED_10G |
                                    ETH_LINK_SPEED_1G |
                                    ETH_LINK_SPEED_100M;
+
+               abilities |= I40E_AQ_PHY_AN_ENABLED;
+       } else {
+               abilities &= ~I40E_AQ_PHY_AN_ENABLED;
        }
        speed = i40e_parse_link_speeds(conf->link_speeds);
-       abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK |
-                    I40E_AQ_PHY_AN_ENABLED |
-                    I40E_AQ_PHY_LINK_ENABLED;
 
        return i40e_phy_conf_link(hw, abilities, speed, true);
 }
@@ -2315,13 +2275,6 @@ i40e_dev_start(struct rte_eth_dev *dev)
 
        hw->adapter_stopped = 0;
 
-       if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
-               PMD_INIT_LOG(ERR,
-               "Invalid link_speeds for port %u, autonegotiation disabled",
-                             dev->data->port_id);
-               return -EINVAL;
-       }
-
        rte_intr_disable(intr_handle);
 
        if ((rte_intr_cap_multiple(intr_handle) ||
@@ -2535,12 +2488,21 @@ i40e_dev_close(struct rte_eth_dev *dev)
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_mirror_rule *p_mirror;
+       struct i40e_filter_control_settings settings;
+       struct rte_flow *p_flow;
        uint32_t reg;
        int i;
        int ret;
+       uint8_t aq_fail = 0;
+       int retries = 0;
 
        PMD_INIT_FUNC_TRACE();
 
+       ret = rte_eth_switch_domain_free(pf->switch_domain_id);
+       if (ret)
+               PMD_INIT_LOG(WARNING, "failed to free switch domain: %d", ret);
+
+
        i40e_dev_stop(dev);
 
        /* Remove all mirror rules */
@@ -2605,6 +2567,53 @@ i40e_dev_close(struct rte_eth_dev *dev)
                        (reg | I40E_PFGEN_CTRL_PFSWR_MASK));
        I40E_WRITE_FLUSH(hw);
 
+       dev->dev_ops = NULL;
+       dev->rx_pkt_burst = NULL;
+       dev->tx_pkt_burst = NULL;
+
+       /* Clear PXE mode */
+       i40e_clear_pxe_mode(hw);
+
+       /* Unconfigure filter control */
+       memset(&settings, 0, sizeof(settings));
+       ret = i40e_set_filter_control(hw, &settings);
+       if (ret)
+               PMD_INIT_LOG(WARNING, "setup_pf_filter_control failed: %d",
+                                       ret);
+
+       /* Disable flow control */
+       hw->fc.requested_mode = I40E_FC_NONE;
+       i40e_set_fc(hw, &aq_fail, TRUE);
+
+       /* uninitialize pf host driver */
+       i40e_pf_host_uninit(dev);
+
+       do {
+               ret = rte_intr_callback_unregister(intr_handle,
+                               i40e_dev_interrupt_handler, dev);
+               if (ret >= 0 || ret == -ENOENT) {
+                       break;
+               } else if (ret != -EAGAIN) {
+                       PMD_INIT_LOG(ERR,
+                                "intr callback unregister failed: %d",
+                                ret);
+               }
+               i40e_msec_delay(500);
+       } while (retries++ < 5);
+
+       i40e_rm_ethtype_filter_list(pf);
+       i40e_rm_tunnel_filter_list(pf);
+       i40e_rm_fdir_filter_list(pf);
+
+       /* Remove all flows */
+       while ((p_flow = TAILQ_FIRST(&pf->flow_list))) {
+               TAILQ_REMOVE(&pf->flow_list, p_flow, node);
+               rte_free(p_flow);
+       }
+
+       /* Remove all Traffic Manager configuration */
+       i40e_tm_conf_uninit(dev);
+
        hw->adapter_closed = 1;
 }
 
@@ -2838,7 +2847,7 @@ update_link_aq(struct i40e_hw *hw, struct rte_eth_link *link,
                status = i40e_aq_get_link_info(hw, enable_lse,
                                                &link_status, NULL);
                if (unlikely(status != I40E_SUCCESS)) {
-                       link->link_speed = ETH_SPEED_NUM_100M;
+                       link->link_speed = ETH_SPEED_NUM_NONE;
                        link->link_duplex = ETH_LINK_FULL_DUPLEX;
                        PMD_DRV_LOG(ERR, "Failed to get link info");
                        return;
@@ -2872,7 +2881,7 @@ update_link_aq(struct i40e_hw *hw, struct rte_eth_link *link,
                link->link_speed = ETH_SPEED_NUM_40G;
                break;
        default:
-               link->link_speed = ETH_SPEED_NUM_100M;
+               link->link_speed = ETH_SPEED_NUM_NONE;
                break;
        }
 }
@@ -2898,6 +2907,9 @@ i40e_dev_link_update(struct rte_eth_dev *dev,
        else
                update_link_aq(hw, &link, enable_lse, wait_to_complete);
 
+       if (hw->switch_dev)
+               rte_eth_linkstatus_get(hw->switch_dev, &link);
+
        ret = rte_eth_linkstatus_set(dev, &link);
        i40e_notify_all_vfs_link_status(dev);
 
@@ -3608,7 +3620,8 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                DEV_RX_OFFLOAD_SCATTER |
                DEV_RX_OFFLOAD_VLAN_EXTEND |
                DEV_RX_OFFLOAD_VLAN_FILTER |
-               DEV_RX_OFFLOAD_JUMBO_FRAME;
+               DEV_RX_OFFLOAD_JUMBO_FRAME |
+               DEV_RX_OFFLOAD_RSS_HASH;
 
        dev_info->tx_queue_offload_capa = DEV_TX_OFFLOAD_MBUF_FAST_FREE;
        dev_info->tx_offload_capa =
@@ -3842,6 +3855,11 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
        struct i40e_vsi *vsi = pf->main_vsi;
        struct rte_eth_rxmode *rxmode;
 
+       if (mask & ETH_QINQ_STRIP_MASK) {
+               PMD_DRV_LOG(ERR, "Strip qinq is not supported.");
+               return -ENOTSUP;
+       }
+
        rxmode = &dev->data->dev_conf.rxmode;
        if (mask & ETH_VLAN_FILTER_MASK) {
                if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
@@ -8475,7 +8493,7 @@ static int
 i40e_add_vxlan_port(struct i40e_pf *pf, uint16_t port, int udp_type)
 {
        int  idx, ret;
-       uint8_t filter_idx;
+       uint8_t filter_idx = 0;
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
 
        idx = i40e_get_vxlan_port_idx(pf, port);
@@ -11556,12 +11574,12 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
         */
        if (sw_dcb == TRUE) {
                if (i40e_need_stop_lldp(dev)) {
-                       ret = i40e_aq_stop_lldp(hw, TRUE, NULL);
+                       ret = i40e_aq_stop_lldp(hw, TRUE, TRUE, NULL);
                        if (ret != I40E_SUCCESS)
                                PMD_INIT_LOG(DEBUG, "Failed to stop lldp");
                }
 
-               ret = i40e_init_dcb(hw);
+               ret = i40e_init_dcb(hw, true);
                /* If lldp agent is stopped, the return value from
                 * i40e_init_dcb we expect is failure with I40E_AQ_RC_EPERM
                 * adminq status. Otherwise, it should return success.
@@ -11605,11 +11623,11 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
                        return -ENOTSUP;
                }
        } else {
-               ret = i40e_aq_start_lldp(hw, NULL);
+               ret = i40e_aq_start_lldp(hw, true, NULL);
                if (ret != I40E_SUCCESS)
                        PMD_INIT_LOG(DEBUG, "Failed to start lldp");
 
-               ret = i40e_init_dcb(hw);
+               ret = i40e_init_dcb(hw, true);
                if (!ret) {
                        if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
                                PMD_INIT_LOG(ERR,
@@ -12868,6 +12886,24 @@ RTE_INIT(i40e_init_log)
        i40e_logtype_driver = rte_log_register("pmd.net.i40e.driver");
        if (i40e_logtype_driver >= 0)
                rte_log_set_level(i40e_logtype_driver, RTE_LOG_NOTICE);
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_RX
+       i40e_logtype_rx = rte_log_register("pmd.net.i40e.rx");
+       if (i40e_logtype_rx >= 0)
+               rte_log_set_level(i40e_logtype_rx, RTE_LOG_DEBUG);
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX
+       i40e_logtype_tx = rte_log_register("pmd.net.i40e.tx");
+       if (i40e_logtype_tx >= 0)
+               rte_log_set_level(i40e_logtype_tx, RTE_LOG_DEBUG);
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX_FREE
+       i40e_logtype_tx_free = rte_log_register("pmd.net.i40e.tx_free");
+       if (i40e_logtype_tx_free >= 0)
+               rte_log_set_level(i40e_logtype_tx_free, RTE_LOG_DEBUG);
+#endif
 }
 
 RTE_PMD_REGISTER_PARAM_STRING(net_i40e,