ethdev: return diagnostic when setting MAC address
[dpdk.git] / drivers / net / e1000 / igb_ethdev.c
index e4f7a9f..9b808a9 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2016 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-2016 Intel Corporation
  */
 
 #include <sys/queue.h>
 #include <rte_log.h>
 #include <rte_debug.h>
 #include <rte_pci.h>
+#include <rte_bus_pci.h>
 #include <rte_ether.h>
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
 #include <rte_ethdev_pci.h>
 #include <rte_memory.h>
-#include <rte_memzone.h>
 #include <rte_eal.h>
-#include <rte_atomic.h>
 #include <rte_malloc.h>
 #include <rte_dev.h>
 
@@ -112,7 +82,7 @@ static void eth_igb_allmulticast_enable(struct rte_eth_dev *dev);
 static void eth_igb_allmulticast_disable(struct rte_eth_dev *dev);
 static int  eth_igb_link_update(struct rte_eth_dev *dev,
                                int wait_to_complete);
-static void eth_igb_stats_get(struct rte_eth_dev *dev,
+static int eth_igb_stats_get(struct rte_eth_dev *dev,
                                struct rte_eth_stats *rte_stats);
 static int eth_igb_xstats_get(struct rte_eth_dev *dev,
                              struct rte_eth_xstat *xstats, unsigned n);
@@ -157,7 +127,7 @@ static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev,
 static int eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
                                 enum rte_vlan_type vlan_type,
                                 uint16_t tpid_id);
-static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void igb_vlan_hw_filter_disable(struct rte_eth_dev *dev);
@@ -175,7 +145,7 @@ static int eth_igb_rar_set(struct rte_eth_dev *dev,
                           struct ether_addr *mac_addr,
                           uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
-static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+static int eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
                struct ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
@@ -188,7 +158,7 @@ static void igbvf_promiscuous_disable(struct rte_eth_dev *dev);
 static void igbvf_allmulticast_enable(struct rte_eth_dev *dev);
 static void igbvf_allmulticast_disable(struct rte_eth_dev *dev);
 static int eth_igbvf_link_update(struct e1000_hw *hw);
-static void eth_igbvf_stats_get(struct rte_eth_dev *dev,
+static int eth_igbvf_stats_get(struct rte_eth_dev *dev,
                                struct rte_eth_stats *rte_stats);
 static int eth_igbvf_xstats_get(struct rte_eth_dev *dev,
                                struct rte_eth_xstat *xstats, unsigned n);
@@ -200,7 +170,7 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
                uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
-static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+static int igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
                struct ether_addr *addr);
 static int igbvf_get_reg_length(struct rte_eth_dev *dev);
 static int igbvf_get_regs(struct rte_eth_dev *dev,
@@ -334,6 +304,8 @@ static const struct rte_pci_id pci_id_igb_map[] = {
        { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_FIBER) },
        { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_SERDES) },
        { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_SGMII) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_COPPER_FLASHLESS) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_SERDES_FLASHLESS) },
        { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I211_COPPER) },
        { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I354_BACKPLANE_1GBPS) },
        { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I354_SGMII) },
@@ -549,57 +521,6 @@ static const struct rte_igb_xstats_name_off rte_igbvf_stats_strings[] = {
 #define IGBVF_NB_XSTATS (sizeof(rte_igbvf_stats_strings) / \
                sizeof(rte_igbvf_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_igb_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_igb_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;
-}
 
 static inline void
 igb_intr_enable(struct rte_eth_dev *dev)
@@ -816,7 +737,6 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
        }
 
        rte_eth_copy_pci_info(eth_dev, pci_dev);
-       eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
 
        hw->hw_addr= (void *)pci_dev->mem_resource[0].addr;
 
@@ -947,6 +867,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
        TAILQ_INIT(&igb_filter_ethertype_list);
        TAILQ_INIT(&igb_filter_syn_list);
        TAILQ_INIT(&igb_filter_flex_list);
+       TAILQ_INIT(&igb_filter_rss_list);
        TAILQ_INIT(&igb_flow_list);
 
        return 0;
@@ -1006,6 +927,10 @@ eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
        memset(filter_info->ethertype_filters, 0,
                E1000_MAX_ETQF_FILTERS * sizeof(struct igb_ethertype_filter));
 
+       /* clear the rss filter info */
+       memset(&filter_info->rss_info, 0,
+               sizeof(struct igb_rte_flow_rss_conf));
+
        /* remove all ntuple filters of the device */
        igb_ntuple_filter_uninit(eth_dev);
 
@@ -1051,7 +976,6 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 
        pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        rte_eth_copy_pci_info(eth_dev, pci_dev);
-       eth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
 
        hw->device_id = pci_dev->id.device_id;
        hw->vendor_id = pci_dev->id.vendor_id;
@@ -1166,7 +1090,8 @@ static int eth_igb_pci_remove(struct rte_pci_device *pci_dev)
 
 static struct rte_pci_driver rte_igb_pmd = {
        .id_table = pci_id_igb_map,
-       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
+                    RTE_PCI_DRV_IOVA_AS_VA,
        .probe = eth_igb_pci_probe,
        .remove = eth_igb_pci_remove,
 };
@@ -1189,7 +1114,7 @@ static int eth_igbvf_pci_remove(struct rte_pci_device *pci_dev)
  */
 static struct rte_pci_driver rte_igbvf_pmd = {
        .id_table = pci_id_igbvf_map,
-       .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_IOVA_AS_VA,
        .probe = eth_igbvf_pci_probe,
        .remove = eth_igbvf_pci_remove,
 };
@@ -1211,7 +1136,7 @@ igb_check_mq_mode(struct rte_eth_dev *dev)
        enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
        enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
        uint16_t nb_rx_q = dev->data->nb_rx_queues;
-       uint16_t nb_tx_q = dev->data->nb_rx_queues;
+       uint16_t nb_tx_q = dev->data->nb_tx_queues;
 
        if ((rx_mq_mode & ETH_MQ_RX_DCB_FLAG) ||
            tx_mq_mode == ETH_MQ_TX_DCB ||
@@ -1300,6 +1225,31 @@ eth_igb_configure(struct rte_eth_dev *dev)
        return 0;
 }
 
+static void
+eth_igb_rxtx_control(struct rte_eth_dev *dev,
+                    bool enable)
+{
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t tctl, rctl;
+
+       tctl = E1000_READ_REG(hw, E1000_TCTL);
+       rctl = E1000_READ_REG(hw, E1000_RCTL);
+
+       if (enable) {
+               /* enable Tx/Rx */
+               tctl |= E1000_TCTL_EN;
+               rctl |= E1000_RCTL_EN;
+       } else {
+               /* disable Tx/Rx */
+               tctl &= ~E1000_TCTL_EN;
+               rctl &= ~E1000_RCTL_EN;
+       }
+       E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+       E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+       E1000_WRITE_FLUSH(hw);
+}
+
 static int
 eth_igb_start(struct rte_eth_dev *dev)
 {
@@ -1400,7 +1350,12 @@ eth_igb_start(struct rte_eth_dev *dev)
         */
        mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
                        ETH_VLAN_EXTEND_MASK;
-       eth_igb_vlan_offload_set(dev, mask);
+       ret = eth_igb_vlan_offload_set(dev, mask);
+       if (ret) {
+               PMD_INIT_LOG(ERR, "Unable to set vlan offload");
+               igb_dev_clear_queues(dev);
+               return ret;
+       }
 
        if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
                /* Enable VLAN filter since VMDq always use VLAN filter */
@@ -1498,6 +1453,9 @@ eth_igb_start(struct rte_eth_dev *dev)
        /* restore all types filter */
        igb_filter_restore(dev);
 
+       eth_igb_rxtx_control(dev, true);
+       eth_igb_link_update(dev, 0);
+
        PMD_INIT_LOG(DEBUG, "<<");
 
        return 0;
@@ -1523,6 +1481,8 @@ eth_igb_stop(struct rte_eth_dev *dev)
        struct rte_eth_link link;
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
+       eth_igb_rxtx_control(dev, false);
+
        igb_intr_disable(hw);
 
        /* disable intr eventfd mapping */
@@ -1547,7 +1507,7 @@ eth_igb_stop(struct rte_eth_dev *dev)
 
        /* clear the recorded link status */
        memset(&link, 0, sizeof(link));
-       rte_igb_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 */
@@ -1623,7 +1583,7 @@ eth_igb_close(struct rte_eth_dev *dev)
        }
 
        memset(&link, 0, sizeof(link));
-       rte_igb_dev_atomic_write_link_status(dev, &link);
+       rte_eth_linkstatus_set(dev, &link);
 }
 
 static int
@@ -1828,7 +1788,7 @@ igb_read_stats_registers(struct e1000_hw *hw, struct e1000_hw_stats *stats)
        stats->tsctfc += E1000_READ_REG(hw, E1000_TSCTFC);
 }
 
-static void
+static int
 eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -1838,7 +1798,7 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        igb_read_stats_registers(hw, stats);
 
        if (rte_stats == NULL)
-               return;
+               return -EINVAL;
 
        /* Rx Errors */
        rte_stats->imissed = stats->mpc;
@@ -1853,6 +1813,7 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        rte_stats->opackets = stats->gptc;
        rte_stats->ibytes   = stats->gorc;
        rte_stats->obytes   = stats->gotc;
+       return 0;
 }
 
 static void
@@ -2093,7 +2054,7 @@ eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
        return IGBVF_NB_XSTATS;
 }
 
-static void
+static int
 eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -2103,12 +2064,13 @@ eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        igbvf_read_stats_registers(hw, hw_stats);
 
        if (rte_stats == NULL)
-               return;
+               return -EINVAL;
 
        rte_stats->ipackets = hw_stats->gprc;
        rte_stats->ibytes = hw_stats->gorc;
        rte_stats->opackets = hw_stats->gptc;
        rte_stats->obytes = hw_stats->gotc;
+       return 0;
 }
 
 static void
@@ -2182,22 +2144,15 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       dev_info->pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */
        dev_info->max_rx_pktlen  = 0x3FFF; /* See RLPML register. */
        dev_info->max_mac_addrs = hw->mac.rar_entry_count;
-       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_info->tx_offload_capa =
-               DEV_TX_OFFLOAD_VLAN_INSERT |
-               DEV_TX_OFFLOAD_IPV4_CKSUM  |
-               DEV_TX_OFFLOAD_UDP_CKSUM   |
-               DEV_TX_OFFLOAD_TCP_CKSUM   |
-               DEV_TX_OFFLOAD_SCTP_CKSUM  |
-               DEV_TX_OFFLOAD_TCP_TSO;
+       dev_info->rx_queue_offload_capa = igb_get_rx_queue_offloads_capa(dev);
+       dev_info->rx_offload_capa = igb_get_rx_port_offloads_capa(dev) |
+                                   dev_info->rx_queue_offload_capa;
+       dev_info->tx_queue_offload_capa = igb_get_tx_queue_offloads_capa(dev);
+       dev_info->tx_offload_capa = igb_get_tx_port_offloads_capa(dev) |
+                                   dev_info->tx_queue_offload_capa;
 
        switch (hw->mac.type) {
        case e1000_82575:
@@ -2260,6 +2215,7 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                },
                .rx_free_thresh = IGB_DEFAULT_RX_FREE_THRESH,
                .rx_drop_en = 0,
+               .offloads = 0,
        };
 
        dev_info->default_txconf = (struct rte_eth_txconf) {
@@ -2269,6 +2225,7 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                        .wthresh = IGB_DEFAULT_TX_WTHRESH,
                },
                .txq_flags = 0,
+               .offloads = 0,
        };
 
        dev_info->rx_desc_lim = rx_desc_lim;
@@ -2311,14 +2268,9 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       dev_info->pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */
        dev_info->max_rx_pktlen  = 0x3FFF; /* See RLPML register. */
        dev_info->max_mac_addrs = hw->mac.rar_entry_count;
-       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_info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT |
                                DEV_TX_OFFLOAD_IPV4_CKSUM  |
                                DEV_TX_OFFLOAD_UDP_CKSUM   |
@@ -2339,6 +2291,13 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                break;
        }
 
+       dev_info->rx_queue_offload_capa = igb_get_rx_queue_offloads_capa(dev);
+       dev_info->rx_offload_capa = igb_get_rx_port_offloads_capa(dev) |
+                                   dev_info->rx_queue_offload_capa;
+       dev_info->tx_queue_offload_capa = igb_get_tx_queue_offloads_capa(dev);
+       dev_info->tx_offload_capa = igb_get_tx_port_offloads_capa(dev) |
+                                   dev_info->tx_queue_offload_capa;
+
        dev_info->default_rxconf = (struct rte_eth_rxconf) {
                .rx_thresh = {
                        .pthresh = IGB_DEFAULT_RX_PTHRESH,
@@ -2347,6 +2306,7 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                },
                .rx_free_thresh = IGB_DEFAULT_RX_FREE_THRESH,
                .rx_drop_en = 0,
+               .offloads = 0,
        };
 
        dev_info->default_txconf = (struct rte_eth_txconf) {
@@ -2356,6 +2316,7 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                        .wthresh = IGB_DEFAULT_TX_WTHRESH,
                },
                .txq_flags = 0,
+               .offloads = 0,
        };
 
        dev_info->rx_desc_lim = rx_desc_lim;
@@ -2368,7 +2329,7 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct rte_eth_link link, old;
+       struct rte_eth_link link;
        int link_check, count;
 
        link_check = 0;
@@ -2409,8 +2370,6 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
                rte_delay_ms(IGB_LINK_UPDATE_CHECK_INTERVAL);
        }
        memset(&link, 0, sizeof(link));
-       rte_igb_dev_atomic_read_link_status(dev, &link);
-       old = link;
 
        /* Now we check if a transition has happened */
        if (link_check) {
@@ -2427,16 +2386,10 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
                link.link_speed = 0;
                link.link_duplex = ETH_LINK_HALF_DUPLEX;
                link.link_status = ETH_LINK_DOWN;
-               link.link_autoneg = ETH_LINK_SPEED_FIXED;
+               link.link_autoneg = ETH_LINK_FIXED;
        }
-       rte_igb_dev_atomic_write_link_status(dev, &link);
-
-       /* not changed */
-       if (old.link_status == link.link_status)
-               return -1;
 
-       /* changed */
-       return 0;
+       return rte_eth_linkstatus_set(dev, &link);
 }
 
 /*
@@ -2690,7 +2643,7 @@ igb_vlan_hw_extend_disable(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
 
        /* Update maximum packet length */
-       if (dev->data->dev_conf.rxmode.jumbo_frame == 1)
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
                E1000_WRITE_REG(hw, E1000_RLPML,
                        dev->data->dev_conf.rxmode.max_rx_pkt_len +
                                                VLAN_TAG_SIZE);
@@ -2709,35 +2662,40 @@ igb_vlan_hw_extend_enable(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
 
        /* Update maximum packet length */
-       if (dev->data->dev_conf.rxmode.jumbo_frame == 1)
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
                E1000_WRITE_REG(hw, E1000_RLPML,
                        dev->data->dev_conf.rxmode.max_rx_pkt_len +
                                                2 * VLAN_TAG_SIZE);
 }
 
-static void
+static int
 eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
+       struct rte_eth_rxmode *rxmode;
+
+       rxmode = &dev->data->dev_conf.rxmode;
        if(mask & ETH_VLAN_STRIP_MASK){
-               if (dev->data->dev_conf.rxmode.hw_vlan_strip)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
                        igb_vlan_hw_strip_enable(dev);
                else
                        igb_vlan_hw_strip_disable(dev);
        }
 
        if(mask & ETH_VLAN_FILTER_MASK){
-               if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
                        igb_vlan_hw_filter_enable(dev);
                else
                        igb_vlan_hw_filter_disable(dev);
        }
 
        if(mask & ETH_VLAN_EXTEND_MASK){
-               if (dev->data->dev_conf.rxmode.hw_vlan_extend)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)
                        igb_vlan_hw_extend_enable(dev);
                else
                        igb_vlan_hw_extend_disable(dev);
        }
+
+       return 0;
 }
 
 
@@ -2849,7 +2807,6 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev,
        struct e1000_interrupt *intr =
                E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
-       uint32_t tctl, rctl;
        struct rte_eth_link link;
        int ret;
 
@@ -2872,8 +2829,7 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev,
                if (ret < 0)
                        return 0;
 
-               memset(&link, 0, sizeof(link));
-               rte_igb_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",
@@ -2891,22 +2847,8 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev,
                             pci_dev->addr.bus,
                             pci_dev->addr.devid,
                             pci_dev->addr.function);
-               tctl = E1000_READ_REG(hw, E1000_TCTL);
-               rctl = E1000_READ_REG(hw, E1000_RCTL);
-               if (link.link_status) {
-                       /* enable Tx/Rx */
-                       tctl |= E1000_TCTL_EN;
-                       rctl |= E1000_RCTL_EN;
-               } else {
-                       /* disable Tx/Rx */
-                       tctl &= ~E1000_TCTL_EN;
-                       rctl &= ~E1000_RCTL_EN;
-               }
-               E1000_WRITE_REG(hw, E1000_TCTL, tctl);
-               E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-               E1000_WRITE_FLUSH(hw);
                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
-                                             NULL, NULL);
+                                             NULL);
        }
 
        return 0;
@@ -2960,13 +2902,17 @@ void igbvf_mbx_process(struct rte_eth_dev *dev)
        struct e1000_mbx_info *mbx = &hw->mbx;
        u32 in_msg = 0;
 
-       if (mbx->ops.read(hw, &in_msg, 1, 0))
-               return;
+       /* peek the message first */
+       in_msg = E1000_READ_REG(hw, E1000_VMBMEM(0));
 
        /* PF reset VF event */
-       if (in_msg == E1000_PF_CONTROL_MSG)
+       if (in_msg == E1000_PF_CONTROL_MSG) {
+               /* dummy mbx read to ack pf */
+               if (mbx->ops.read(hw, &in_msg, 1, 0))
+                       return;
                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
-                                             NULL, NULL);
+                                             NULL);
+       }
 }
 
 static int
@@ -3141,13 +3087,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
        e1000_rar_set(hw, addr, index);
 }
 
-static void
+static int
 eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
                                struct ether_addr *addr)
 {
        eth_igb_rar_clear(dev, 0);
-
        eth_igb_rar_set(dev, (void *)addr, 0, 0);
+
+       return 0;
 }
 /*
  * Virtual Function operations
@@ -3245,14 +3192,14 @@ igbvf_dev_configure(struct rte_eth_dev *dev)
         * Keep the persistent behavior the same as Host PF
         */
 #ifndef RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC
-       if (!conf->rxmode.hw_strip_crc) {
+       if (!(conf->rxmode.offloads & DEV_RX_OFFLOAD_CRC_STRIP)) {
                PMD_INIT_LOG(NOTICE, "VF can't disable HW CRC Strip");
-               conf->rxmode.hw_strip_crc = 1;
+               conf->rxmode.offloads |= DEV_RX_OFFLOAD_CRC_STRIP;
        }
 #else
-       if (conf->rxmode.hw_strip_crc) {
+       if (conf->rxmode.offloads & DEV_RX_OFFLOAD_CRC_STRIP) {
                PMD_INIT_LOG(NOTICE, "VF can't enable HW CRC Strip");
-               conf->rxmode.hw_strip_crc = 0;
+               conf->rxmode.offloads &= ~DEV_RX_OFFLOAD_CRC_STRIP;
        }
 #endif
 
@@ -3290,7 +3237,8 @@ igbvf_dev_start(struct rte_eth_dev *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) {
                intr_vector = dev->data->nb_rx_queues;
                ret = rte_intr_efd_enable(intr_handle, intr_vector);
                if (ret)
@@ -3498,7 +3446,7 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
        return 0;
 }
 
-static void
+static int
 igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
 {
        struct e1000_hw *hw =
@@ -3506,6 +3454,7 @@ igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
 
        /* index is not used by rar_set() */
        hw->mac.ops.rar_set(hw, (void *)addr, 0);
+       return 0;
 }
 
 
@@ -4094,7 +4043,7 @@ eth_igb_get_flex_filter(struct rte_eth_dev *dev,
        flex_filter.filter_info.priority = filter->priority;
        memcpy(flex_filter.filter_info.dwords, filter->bytes, filter->len);
        memcpy(flex_filter.filter_info.mask, filter->mask,
-                       RTE_ALIGN(filter->len, sizeof(char)) / sizeof(char));
+                       RTE_ALIGN(filter->len, CHAR_BIT) / CHAR_BIT);
 
        it = eth_igb_flex_filter_lookup(&filter_info->flex_list,
                                &flex_filter.filter_info);
@@ -4493,10 +4442,12 @@ eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 
        /* switch to jumbo mode if needed */
        if (frame_size > ETHER_MAX_LEN) {
-               dev->data->dev_conf.rxmode.jumbo_frame = 1;
+               dev->data->dev_conf.rxmode.offloads |=
+                       DEV_RX_OFFLOAD_JUMBO_FRAME;
                rctl |= E1000_RCTL_LPE;
        } else {
-               dev->data->dev_conf.rxmode.jumbo_frame = 0;
+               dev->data->dev_conf.rxmode.offloads &=
+                       ~DEV_RX_OFFLOAD_JUMBO_FRAME;
                rctl &= ~E1000_RCTL_LPE;
        }
        E1000_WRITE_REG(hw, E1000_RCTL, rctl);
@@ -5382,7 +5333,14 @@ eth_igb_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint32_t mask = 1 << queue_id;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+       uint32_t vec = E1000_MISC_VEC_ID;
+
+       if (rte_intr_allow_others(intr_handle))
+               vec = E1000_RX_VEC_START;
+
+       uint32_t mask = 1 << (queue_id + vec);
 
        E1000_WRITE_REG(hw, E1000_EIMC, mask);
        E1000_WRITE_FLUSH(hw);
@@ -5397,7 +5355,12 @@ eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
-       uint32_t mask = 1 << queue_id;
+       uint32_t vec = E1000_MISC_VEC_ID;
+
+       if (rte_intr_allow_others(intr_handle))
+               vec = E1000_RX_VEC_START;
+
+       uint32_t mask = 1 << (queue_id + vec);
        uint32_t regval;
 
        regval = E1000_READ_REG(hw, E1000_EIMS);
@@ -5606,6 +5569,17 @@ igb_flex_filter_restore(struct rte_eth_dev *dev)
        }
 }
 
+/* restore rss filter */
+static inline void
+igb_rss_filter_restore(struct rte_eth_dev *dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+
+       if (filter_info->rss_info.num)
+               igb_config_rss_filter(dev, &filter_info->rss_info, TRUE);
+}
+
 /* restore all types filter */
 static int
 igb_filter_restore(struct rte_eth_dev *dev)
@@ -5614,6 +5588,7 @@ igb_filter_restore(struct rte_eth_dev *dev)
        igb_ethertype_filter_restore(dev);
        igb_syn_filter_restore(dev);
        igb_flex_filter_restore(dev);
+       igb_rss_filter_restore(dev);
 
        return 0;
 }