net/ixgbe: fix intr callback unregister by adding retry
[dpdk.git] / drivers / net / ixgbe / ixgbe_ethdev.c
index 4339347..4df5c75 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
- *   All rights reserved.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of Intel Corporation nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2017 Intel Corporation
  */
 
 #include <sys/queue.h>
 #include <rte_log.h>
 #include <rte_debug.h>
 #include <rte_pci.h>
-#include <rte_atomic.h>
+#include <rte_bus_pci.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>
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
 #include <rte_ethdev_pci.h>
 #include <rte_malloc.h>
 #include <rte_random.h>
 #include <rte_dev.h>
 #include <rte_hash_crc.h>
+#ifdef RTE_LIBRTE_SECURITY
 #include <rte_security_driver.h>
+#endif
 
 #include "ixgbe_logs.h"
 #include "base/ixgbe_api.h"
@@ -93,6 +65,9 @@
 /* Timer value included in XOFF frames. */
 #define IXGBE_FC_PAUSE 0x680
 
+/*Default value of Max Rx Queue*/
+#define IXGBE_MAX_RX_QUEUE_NUM 128
+
 #define IXGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */
 #define IXGBE_LINK_UP_CHECK_TIMEOUT   1000 /* ms */
 #define IXGBE_VMDQ_NUM_UC_MAC         4096 /* Maximum nb. of UC MAC addr. */
@@ -425,6 +400,9 @@ static void ixgbe_l2_tunnel_conf(struct rte_eth_dev *dev);
                (r) = (h)->bitmap[idx] >> bit & 1;\
        } while (0)
 
+int ixgbe_logtype_init;
+int ixgbe_logtype_driver;
+
 /*
  * The set of PCI devices this driver supports
  */
@@ -808,58 +786,6 @@ static const struct rte_ixgbe_xstats_name_off rte_ixgbevf_stats_strings[] = {
 #define IXGBEVF_NB_XSTATS (sizeof(rte_ixgbevf_stats_strings) / \
                sizeof(rte_ixgbevf_stats_strings[0]))
 
-/**
- * Atomically reads the link status information from global
- * structure rte_eth_dev.
- *
- * @param dev
- *   - Pointer to the structure rte_eth_dev to read from.
- *   - Pointer to the buffer to be saved with the link status.
- *
- * @return
- *   - On success, zero.
- *   - On failure, negative value.
- */
-static inline int
-rte_ixgbe_dev_atomic_read_link_status(struct rte_eth_dev *dev,
-                               struct rte_eth_link *link)
-{
-       struct rte_eth_link *dst = link;
-       struct rte_eth_link *src = &(dev->data->dev_link);
-
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                                       *(uint64_t *)src) == 0)
-               return -1;
-
-       return 0;
-}
-
-/**
- * Atomically writes the link status information into global
- * structure rte_eth_dev.
- *
- * @param dev
- *   - Pointer to the structure rte_eth_dev to read from.
- *   - Pointer to the buffer to be saved with the link status.
- *
- * @return
- *   - On success, zero.
- *   - On failure, negative value.
- */
-static inline int
-rte_ixgbe_dev_atomic_write_link_status(struct rte_eth_dev *dev,
-                               struct rte_eth_link *link)
-{
-       struct rte_eth_link *dst = &(dev->data->dev_link);
-       struct rte_eth_link *src = link;
-
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                                       *(uint64_t *)src) == 0)
-               return -1;
-
-       return 0;
-}
-
 /*
  * This function is the same as ixgbe_is_sfp() in base/ixgbe.h.
  */
@@ -1168,11 +1094,6 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
                return 0;
        }
 
-       /* Initialize security_ctx only for primary process*/
-       eth_dev->security_ctx = ixgbe_ipsec_ctx_create(eth_dev);
-       if (eth_dev->security_ctx == NULL)
-               return -ENOMEM;
-
        rte_eth_copy_pci_info(eth_dev, pci_dev);
 
        /* Vendor and Device ID need to be set before init of shared code */
@@ -1199,6 +1120,12 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
        /* Unlock any pending hardware semaphore */
        ixgbe_swfw_lock_reset(hw);
 
+#ifdef RTE_LIBRTE_SECURITY
+       /* Initialize security_ctx only for primary process*/
+       if (ixgbe_ipsec_ctx_create(eth_dev))
+               return -ENOMEM;
+#endif
+
        /* Initialize DCB configuration*/
        memset(dcb_config, 0, sizeof(struct ixgbe_dcb_config));
        ixgbe_dcb_init(hw, dcb_config);
@@ -1359,6 +1286,8 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct ixgbe_hw *hw;
+       int retries = 0;
+       int ret;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -1379,8 +1308,20 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
 
        /* disable uio intr before callback unregister */
        rte_intr_disable(intr_handle);
-       rte_intr_callback_unregister(intr_handle,
-                                    ixgbe_dev_interrupt_handler, eth_dev);
+
+       do {
+               ret = rte_intr_callback_unregister(intr_handle,
+                               ixgbe_dev_interrupt_handler, eth_dev);
+               if (ret >= 0) {
+                       break;
+               } else if (ret != -EAGAIN) {
+                       PMD_INIT_LOG(ERR,
+                               "intr callback unregister failed: %d",
+                               ret);
+                       return ret;
+               }
+               rte_delay_ms(100);
+       } while (retries++ < (10 + IXGBE_LINK_UP_TIME));
 
        /* uninitialize PF if max_vfs not zero */
        ixgbe_pf_host_uninit(eth_dev);
@@ -1406,7 +1347,9 @@ eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev)
        /* Remove all Traffic Manager configuration */
        ixgbe_tm_conf_uninit(eth_dev);
 
+#ifdef RTE_LIBRTE_SECURITY
        rte_free(eth_dev->security_ctx);
+#endif
 
        return 0;
 }
@@ -2188,9 +2131,10 @@ ixgbe_check_vf_rss_rxq_num(struct rte_eth_dev *dev, uint16_t nb_rx_q)
                return -EINVAL;
        }
 
-       RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool = nb_rx_q;
-       RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx = pci_dev->max_vfs * nb_rx_q;
-
+       RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool =
+               IXGBE_MAX_RX_QUEUE_NUM / RTE_ETH_DEV_SRIOV(dev).active;
+       RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx =
+               pci_dev->max_vfs * RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool;
        return 0;
 }
 
@@ -2230,8 +2174,6 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev)
                case ETH_MQ_RX_NONE:
                        /* if nothing mq mode configure, use default scheme */
                        dev->data->dev_conf.rxmode.mq_mode = ETH_MQ_RX_VMDQ_ONLY;
-                       if (RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool > 1)
-                               RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool = 1;
                        break;
                default: /* ETH_MQ_RX_DCB, ETH_MQ_RX_DCB_RSS or ETH_MQ_TX_DCB*/
                        /* SRIOV only works in VMDq enable mode */
@@ -2776,7 +2718,7 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
 
        /* Clear recorded link status */
        memset(&link, 0, sizeof(link));
-       rte_ixgbe_dev_atomic_write_link_status(dev, &link);
+       rte_eth_linkstatus_set(dev, &link);
 
        if (!rte_intr_allow_others(intr_handle))
                /* resume to the default handler */
@@ -3670,7 +3612,8 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                DEV_RX_OFFLOAD_VLAN_STRIP |
                DEV_RX_OFFLOAD_IPV4_CKSUM |
                DEV_RX_OFFLOAD_UDP_CKSUM  |
-               DEV_RX_OFFLOAD_TCP_CKSUM;
+               DEV_RX_OFFLOAD_TCP_CKSUM  |
+               DEV_RX_OFFLOAD_CRC_STRIP;
 
        /*
         * RSC is only supported by 82599 and x540 PF devices in a non-SR-IOV
@@ -3707,8 +3650,12 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
            hw->mac.type == ixgbe_mac_X550EM_a)
                dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
 
-       dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_SECURITY;
-       dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_SECURITY;
+#ifdef RTE_LIBRTE_SECURITY
+       if (dev->security_ctx) {
+               dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_SECURITY;
+               dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_SECURITY;
+       }
+#endif
 
        dev_info->default_rxconf = (struct rte_eth_rxconf) {
                .rx_thresh = {
@@ -3813,7 +3760,8 @@ ixgbevf_dev_info_get(struct rte_eth_dev *dev,
        dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP |
                                DEV_RX_OFFLOAD_IPV4_CKSUM |
                                DEV_RX_OFFLOAD_UDP_CKSUM  |
-                               DEV_RX_OFFLOAD_TCP_CKSUM;
+                               DEV_RX_OFFLOAD_TCP_CKSUM  |
+                               DEV_RX_OFFLOAD_CRC_STRIP;
        dev_info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT |
                                DEV_TX_OFFLOAD_IPV4_CKSUM  |
                                DEV_TX_OFFLOAD_UDP_CKSUM   |
@@ -3959,7 +3907,7 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
                            int wait_to_complete, int vf)
 {
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct rte_eth_link link, old;
+       struct rte_eth_link link;
        ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
        struct ixgbe_interrupt *intr =
                IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
@@ -3969,12 +3917,11 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
        int wait = 1;
        bool autoneg = false;
 
+       memset(&link, 0, sizeof(link));
        link.link_status = ETH_LINK_DOWN;
        link.link_speed = 0;
        link.link_duplex = ETH_LINK_HALF_DUPLEX;
        link.link_autoneg = ETH_LINK_AUTONEG;
-       memset(&old, 0, sizeof(old));
-       rte_ixgbe_dev_atomic_read_link_status(dev, &old);
 
        hw->mac.get_link_status = true;
 
@@ -3998,19 +3945,14 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
        if (diag != 0) {
                link.link_speed = ETH_SPEED_NUM_100M;
                link.link_duplex = ETH_LINK_FULL_DUPLEX;
-               rte_ixgbe_dev_atomic_write_link_status(dev, &link);
-               if (link.link_status == old.link_status)
-                       return -1;
-               return 0;
+               return rte_eth_linkstatus_set(dev, &link);
        }
 
        if (link_up == 0) {
-               rte_ixgbe_dev_atomic_write_link_status(dev, &link);
                intr->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
-               if (link.link_status == old.link_status)
-                       return -1;
-               return 0;
+               return rte_eth_linkstatus_set(dev, &link);
        }
+
        intr->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
        link.link_status = ETH_LINK_UP;
        link.link_duplex = ETH_LINK_FULL_DUPLEX;
@@ -4042,12 +3984,8 @@ ixgbe_dev_link_update_share(struct rte_eth_dev *dev,
                link.link_speed = ETH_SPEED_NUM_10G;
                break;
        }
-       rte_ixgbe_dev_atomic_write_link_status(dev, &link);
-
-       if (link.link_status == old.link_status)
-               return -1;
 
-       return 0;
+       return rte_eth_linkstatus_set(dev, &link);
 }
 
 static int
@@ -4246,8 +4184,8 @@ ixgbe_dev_link_status_print(struct rte_eth_dev *dev)
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_eth_link link;
 
-       memset(&link, 0, sizeof(link));
-       rte_ixgbe_dev_atomic_read_link_status(dev, &link);
+       rte_eth_linkstatus_get(dev, &link);
+
        if (link.link_status) {
                PMD_INIT_LOG(INFO, "Port %d: Link Up - speed %u Mbps - %s",
                                        (int)(dev->data->port_id),
@@ -4282,7 +4220,6 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev,
        struct ixgbe_interrupt *intr =
                IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
        int64_t timeout;
-       struct rte_eth_link link;
        struct ixgbe_hw *hw =
                IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -4299,9 +4236,10 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev,
        }
 
        if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
+               struct rte_eth_link link;
+
                /* get the link status before link update, for predicting later */
-               memset(&link, 0, sizeof(link));
-               rte_ixgbe_dev_atomic_read_link_status(dev, &link);
+               rte_eth_linkstatus_get(dev, &link);
 
                ixgbe_dev_link_update(dev, 0);
 
@@ -4375,12 +4313,12 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
                intr->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
                ixgbe_dev_link_status_print(dev);
                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
-                                             NULL, NULL);
+                                             NULL);
        }
 
        if (intr->flags & IXGBE_FLAG_MACSEC) {
                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_MACSEC,
-                                             NULL, NULL);
+                                             NULL);
                intr->flags &= ~IXGBE_FLAG_MACSEC;
        }
 
@@ -5017,7 +4955,11 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
 
        PMD_INIT_FUNC_TRACE();
 
-       hw->mac.ops.reset_hw(hw);
+       err = hw->mac.ops.reset_hw(hw);
+       if (err) {
+               PMD_INIT_LOG(ERR, "Unable to reset vf hardware (%d)", err);
+               return err;
+       }
        hw->mac.get_link_status = true;
 
        /* negotiate mailbox API version to use with the PF. */
@@ -5049,7 +4991,8 @@ ixgbevf_dev_start(struct rte_eth_dev *dev)
        ixgbevf_dev_rxtx_start(dev);
 
        /* check and configure queue intr-vector mapping */
-       if (dev->data->dev_conf.intr_conf.rxq != 0) {
+       if (rte_intr_cap_multiple(intr_handle) &&
+           dev->data->dev_conf.intr_conf.rxq) {
                /* According to datasheet, only vector 0/1/2 can be used,
                 * now only one vector is used for Rx queue
                 */
@@ -6820,9 +6763,8 @@ ixgbe_start_timecounters(struct rte_eth_dev *dev)
        uint32_t shift = 0;
 
        /* Get current link speed. */
-       memset(&link, 0, sizeof(link));
        ixgbe_dev_link_update(dev, 1);
-       rte_ixgbe_dev_atomic_read_link_status(dev, &link);
+       rte_eth_linkstatus_get(dev, &link);
 
        switch (link.link_speed) {
        case ETH_SPEED_NUM_100M:
@@ -8157,13 +8099,17 @@ static void ixgbevf_mbx_process(struct rte_eth_dev *dev)
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        u32 in_msg = 0;
 
-       if (ixgbe_read_mbx(hw, &in_msg, 1, 0))
-               return;
+       /* peek the message first */
+       in_msg = IXGBE_READ_REG(hw, IXGBE_VFMBMEM);
 
        /* PF reset VF event */
-       if (in_msg == IXGBE_PF_CONTROL_MSG)
+       if (in_msg == IXGBE_PF_CONTROL_MSG) {
+               /* dummy mbx read to ack pf */
+               if (ixgbe_read_mbx(hw, &in_msg, 1, 0))
+                       return;
                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
-                                             NULL, NULL);
+                                             NULL);
+       }
 }
 
 static int
@@ -8331,6 +8277,18 @@ ixgbe_l2_tn_filter_restore(struct rte_eth_dev *dev)
        }
 }
 
+/* restore rss filter */
+static inline void
+ixgbe_rss_filter_restore(struct rte_eth_dev *dev)
+{
+       struct ixgbe_filter_info *filter_info =
+               IXGBE_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+
+       if (filter_info->rss_info.num)
+               ixgbe_config_rss_filter(dev,
+                       &filter_info->rss_info, TRUE);
+}
+
 static int
 ixgbe_filter_restore(struct rte_eth_dev *dev)
 {
@@ -8339,6 +8297,7 @@ ixgbe_filter_restore(struct rte_eth_dev *dev)
        ixgbe_syn_filter_restore(dev);
        ixgbe_fdir_filter_restore(dev);
        ixgbe_l2_tn_filter_restore(dev);
+       ixgbe_rss_filter_restore(dev);
 
        return 0;
 }
@@ -8436,3 +8395,15 @@ RTE_PMD_REGISTER_KMOD_DEP(net_ixgbe, "* igb_uio | uio_pci_generic | vfio-pci");
 RTE_PMD_REGISTER_PCI(net_ixgbe_vf, rte_ixgbevf_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_ixgbe_vf, pci_id_ixgbevf_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_ixgbe_vf, "* igb_uio | vfio-pci");
+
+RTE_INIT(ixgbe_init_log);
+static void
+ixgbe_init_log(void)
+{
+       ixgbe_logtype_init = rte_log_register("pmd.net.ixgbe.init");
+       if (ixgbe_logtype_init >= 0)
+               rte_log_set_level(ixgbe_logtype_init, RTE_LOG_NOTICE);
+       ixgbe_logtype_driver = rte_log_register("pmd.net.ixgbe.driver");
+       if (ixgbe_logtype_driver >= 0)
+               rte_log_set_level(ixgbe_logtype_driver, RTE_LOG_NOTICE);
+}