doc: whitespace changes in licenses
[dpdk.git] / lib / librte_pmd_ixgbe / ixgbe_ethdev.c
index bdba7b0..e0350d6 100644 (file)
@@ -4,32 +4,31 @@
  *   Copyright(c) 2010-2013 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 
+ *   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 
+ *     * 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 
+ *     * 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 
+ *     * 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 
+ *   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.
- * 
  */
 
 #include <sys/queue.h>
@@ -85,6 +84,8 @@
 #define IXGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */
 #define IXGBE_LINK_UP_CHECK_TIMEOUT   1000 /* ms */
 
+#define IXGBEVF_PMD_NAME "rte_ixgbevf_pmd" /* PMD name */
+
 #define IXGBE_QUEUE_STAT_COUNTERS (sizeof(hw_stats->qprc) / sizeof(hw_stats->qprc[0]))
 
 static int eth_ixgbe_dev_init(struct eth_driver *eth_drv,
@@ -116,10 +117,6 @@ static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
 static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue,
                int on);
 static void ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask);
-static void ixgbe_vlan_hw_filter_enable(struct rte_eth_dev *dev);
-static void ixgbe_vlan_hw_filter_disable(struct rte_eth_dev *dev);
-static void ixgbe_vlan_hw_strip_enable_all(struct rte_eth_dev *dev);
-static void ixgbe_vlan_hw_strip_disable_all(struct rte_eth_dev *dev);
 static void ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue);
 static void ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev);
@@ -131,8 +128,12 @@ static int  ixgbe_flow_ctrl_set(struct rte_eth_dev *dev,
                struct rte_eth_fc_conf *fc_conf);
 static int ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev,
                struct rte_eth_pfc_conf *pfc_conf);
+static int ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
+               struct rte_eth_rss_reta *reta_conf);
+static int ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev,
+               struct rte_eth_rss_reta *reta_conf);    
 static void ixgbe_dev_link_status_print(struct rte_eth_dev *dev);
-static int ixgbe_dev_interrupt_setup(struct rte_eth_dev *dev);
+static int ixgbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev);
 static int ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev);
 static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev);
 static void ixgbe_dev_interrupt_handler(struct rte_intr_handle *handle,
@@ -161,7 +162,6 @@ static void ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev,
 static void ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on);
 
-
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
  */
@@ -242,6 +242,8 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = {
        .vlan_strip_queue_set = ixgbe_vlan_strip_queue_set,
        .rx_queue_setup       = ixgbe_dev_rx_queue_setup,
        .rx_queue_release     = ixgbe_dev_rx_queue_release,
+       .rx_queue_count       = ixgbe_dev_rx_queue_count,
+       .rx_descriptor_done   = ixgbe_dev_rx_descriptor_done,
        .tx_queue_setup       = ixgbe_dev_tx_queue_setup,
        .tx_queue_release     = ixgbe_dev_tx_queue_release,
        .dev_led_on           = ixgbe_dev_led_on,
@@ -258,6 +260,8 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = {
        .fdir_update_perfect_filter   = ixgbe_fdir_update_perfect_filter,
        .fdir_remove_perfect_filter   = ixgbe_fdir_remove_perfect_filter,
        .fdir_set_masks               = ixgbe_fdir_set_masks,
+       .reta_update          = ixgbe_dev_rss_reta_update,
+       .reta_query           = ixgbe_dev_rss_reta_query,
 };
 
 /*
@@ -354,6 +358,35 @@ ixgbe_is_sfp(struct ixgbe_hw *hw)
        }
 }
 
+static inline int32_t
+ixgbe_pf_reset_hw(struct ixgbe_hw *hw)
+{
+       uint32_t ctrl_ext;
+       int32_t status;
+
+       status = ixgbe_reset_hw(hw);
+
+       ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+       /* Set PF Reset Done bit so PF/VF Mail Ops can work */
+       ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+       IXGBE_WRITE_FLUSH(hw);
+
+       return status;
+}
+
+static inline void
+ixgbe_enable_intr(struct rte_eth_dev *dev)
+{
+       struct ixgbe_interrupt *intr =
+               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+       struct ixgbe_hw *hw = 
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       
+       IXGBE_WRITE_REG(hw, IXGBE_EIMS, intr->mask);
+       IXGBE_WRITE_FLUSH(hw);
+}
+
 /*
  * This function is based on ixgbe_disable_intr() in ixgbe/ixgbe.h.
  */
@@ -556,6 +589,9 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        hw->device_id = pci_dev->id.device_id;
        hw->vendor_id = pci_dev->id.vendor_id;
        hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
+#ifdef RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP
+       hw->allow_unsupported_sfp = 1;
+#endif
 
        /* Initialize the shared code */
        diag = ixgbe_init_shared_code(hw);
@@ -577,8 +613,6 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        }
        hw->fc.send_xon = 1;
 
-       ixgbe_disable_intr(hw);
-
        /* Make sure we have a good EEPROM before we read from it */
        diag = ixgbe_validate_eeprom_checksum(hw, &csum);
        if (diag != IXGBE_SUCCESS) {
@@ -616,6 +650,9 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                return -EIO;
        }
 
+       /* disable interrupt */
+       ixgbe_disable_intr(hw);
+
        /* pick up the PCI bus settings for reporting later */
        ixgbe_get_bus_info(hw);
 
@@ -641,10 +678,16 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        /* initialize the hw strip bitmap*/
        memset(hwstrip, 0, sizeof(*hwstrip));
 
-       /* let hardware know driver is loaded */
+       /* initialize PF if max_vfs not zero */
+       ixgbe_pf_host_init(eth_dev);
+
        ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+       /* let hardware know driver is loaded */
        ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD;
+       /* Set PF Reset Done bit so PF/VF Mail Ops can work */
+       ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
        IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+       IXGBE_WRITE_FLUSH(hw);
 
        if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
                PMD_INIT_LOG(DEBUG,
@@ -662,6 +705,12 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
        rte_intr_callback_register(&(pci_dev->intr_handle),
                ixgbe_dev_interrupt_handler, (void *)eth_dev);
 
+       /* enable uio intr after callback register */
+       rte_intr_enable(&(pci_dev->intr_handle));
+
+       /* enable support intr */
+       ixgbe_enable_intr(eth_dev);
+
        return 0;
 }
 
@@ -710,8 +759,14 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
 
        hw->mac.num_rar_entries = hw->mac.max_rx_queues;
        diag = hw->mac.ops.reset_hw(hw);
+
        if (diag != IXGBE_SUCCESS) {
                PMD_INIT_LOG(ERR, "VF Initialization Failure: %d", diag);
+                       RTE_LOG(ERR, PMD, "\tThe MAC address is not valid.\n"
+                                       "\tThe most likely cause of this error is that the VM host\n"
+                                       "\thas not assigned a valid MAC address to this VF device.\n"
+                                       "\tPlease consult the DPDK Release Notes (FAQ section) for\n"
+                                       "\ta possible solution to this problem.\n");
                return (diag);
        }
 
@@ -724,6 +779,7 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv,
                        ETHER_ADDR_LEN * hw->mac.num_rar_entries);
                return -ENOMEM;
        }
+
        /* Copy the permanent MAC address */
        ether_addr_copy((struct ether_addr *) hw->mac.perm_addr,
                        &eth_dev->data->mac_addrs[0]);
@@ -750,7 +806,9 @@ static struct eth_driver rte_ixgbe_pmd = {
        {
                .name = "rte_ixgbe_pmd",
                .id_table = pci_id_ixgbe_map,
+#ifdef RTE_EAL_UNBIND_PORTS
                .drv_flags = RTE_PCI_DRV_NEED_IGB_UIO,
+#endif
        },
        .eth_dev_init = eth_ixgbe_dev_init,
        .dev_private_size = sizeof(struct ixgbe_adapter),
@@ -763,7 +821,9 @@ static struct eth_driver rte_ixgbevf_pmd = {
        {
                .name = "rte_ixgbevf_pmd",
                .id_table = pci_id_ixgbevf_map,
+#ifdef RTE_EAL_UNBIND_PORTS
                .drv_flags = RTE_PCI_DRV_NEED_IGB_UIO,
+#endif
        },
        .eth_dev_init = eth_ixgbevf_dev_init,
        .dev_private_size = sizeof(struct ixgbe_adapter),
@@ -842,7 +902,7 @@ ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid)
        IXGBE_WRITE_REG(hw, IXGBE_EXVET, tpid << 16);
 }
 
-static void
+void
 ixgbe_vlan_hw_filter_disable(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw =
@@ -858,7 +918,7 @@ ixgbe_vlan_hw_filter_disable(struct rte_eth_dev *dev)
        IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 }
 
-static void
+void
 ixgbe_vlan_hw_filter_enable(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw =
@@ -945,7 +1005,7 @@ ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue)
        ixgbe_vlan_hw_strip_bitmap_set(dev, queue, 1);
 }
 
-static void
+void
 ixgbe_vlan_hw_strip_disable_all(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw =
@@ -973,7 +1033,7 @@ ixgbe_vlan_hw_strip_disable_all(struct rte_eth_dev *dev)
        }
 }
 
-static void
+void
 ixgbe_vlan_hw_strip_enable_all(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw *hw =
@@ -1098,6 +1158,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        int err, link_up = 0, negotiate = 0;
        uint32_t speed = 0;
        int mask = 0;
+       int status;
        
        PMD_INIT_FUNC_TRACE();
 
@@ -1116,11 +1177,17 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
 
        /* reinitialize adapter
         * this calls reset and start */
-       ixgbe_init_hw(hw);
+       status = ixgbe_pf_reset_hw(hw);
+       if (status != 0)
+               return -1;
+       hw->mac.ops.start_hw(hw);
+
+       /* configure PF module if SRIOV enabled */
+       ixgbe_pf_host_configure(dev);
 
        /* initialize transmission unit */
        ixgbe_dev_tx_init(dev);
-
+      
        /* This can fail when allocating mbufs for descriptor rings */
        err = ixgbe_dev_rx_init(dev);
        if (err) {
@@ -1137,8 +1204,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        }
 
        /* Turn on the laser */
-       if (hw->phy.multispeed_fiber)
-               ixgbe_enable_tx_laser(hw);
+       ixgbe_enable_tx_laser(hw);
 
        err = ixgbe_check_link(hw, &speed, &link_up, 0);
        if (err)
@@ -1177,11 +1243,11 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
                goto error;
 
        /* check if lsc interrupt is enabled */
-       if (dev->data->dev_conf.intr_conf.lsc != 0) {
-               err = ixgbe_dev_interrupt_setup(dev);
-               if (err)
-                       goto error;
-       }
+       if (dev->data->dev_conf.intr_conf.lsc != 0)
+               ixgbe_dev_lsc_interrupt_setup(dev);
+
+       /* resume enabled intr since hw reset */
+       ixgbe_enable_intr(dev);
 
        mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
                ETH_VLAN_EXTEND_MASK;
@@ -1222,15 +1288,14 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
        ixgbe_disable_intr(hw);
 
        /* reset the NIC */
-       ixgbe_reset_hw(hw);
+       ixgbe_pf_reset_hw(hw);
        hw->adapter_stopped = FALSE;
 
        /* stop adapter */
        ixgbe_stop_adapter(hw);
 
        /* Turn off the laser */
-       if (hw->phy.multispeed_fiber)
-               ixgbe_disable_tx_laser(hw);
+       ixgbe_disable_tx_laser(hw);
 
        ixgbe_dev_clear_queues(dev);
 
@@ -1250,8 +1315,7 @@ ixgbe_dev_close(struct rte_eth_dev *dev)
 
        PMD_INIT_FUNC_TRACE();
 
-       ixgbe_reset_hw(hw);
-
+       ixgbe_pf_reset_hw(hw);
 
        ixgbe_dev_stop(dev);
        hw->adapter_stopped = 1;
@@ -1644,14 +1708,13 @@ ixgbe_dev_allmulticast_disable(struct rte_eth_dev *dev)
  *  - On failure, a negative value.
  */
 static int
-ixgbe_dev_interrupt_setup(struct rte_eth_dev *dev)
+ixgbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev)
 {
-       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_interrupt *intr =
+               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
 
        ixgbe_dev_link_status_print(dev);
-       IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_LSC);
-       IXGBE_WRITE_FLUSH(hw);
-       rte_intr_enable(&(dev->pci_dev->intr_handle));
+       intr->mask |= IXGBE_EICR_LSC;
 
        return 0;
 }
@@ -1674,17 +1737,22 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
        struct ixgbe_interrupt *intr =
                IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
 
-       IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_LSC);
-       IXGBE_WRITE_FLUSH(hw);
+       /* clear all cause mask */
+       ixgbe_disable_intr(hw);
 
        /* read-on-clear nic registers here */
        eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
-       PMD_INIT_LOG(INFO, "eicr %x", eicr);
+       PMD_DRV_LOG(INFO, "eicr %x", eicr);
+       
+       intr->flags = 0;
        if (eicr & IXGBE_EICR_LSC) {
                /* set flag for async link update */
                intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
        }
 
+       if (eicr & IXGBE_EICR_MAILBOX)
+               intr->flags |= IXGBE_FLAG_MAILBOX;
+
        return 0;
 }
 
@@ -1737,11 +1805,48 @@ 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;
+       int intr_enable_delay = false;  
 
-       if (!(intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) {
-               return -1;
+       PMD_DRV_LOG(DEBUG, "intr action type %d\n", intr->flags);
+
+       if (intr->flags & IXGBE_FLAG_MAILBOX) {
+               ixgbe_pf_mbx_process(dev);
+               intr->flags &= ~IXGBE_FLAG_MAILBOX;
+       } 
+
+       if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
+               /* get the link status before link update, for predicting later */
+               memset(&link, 0, sizeof(link));
+               rte_ixgbe_dev_atomic_read_link_status(dev, &link);
+
+               ixgbe_dev_link_update(dev, 0);
+
+               /* likely to up */
+               if (!link.link_status)
+                       /* handle it 1 sec later, wait it being stable */
+                       timeout = IXGBE_LINK_UP_CHECK_TIMEOUT;
+               /* likely to down */
+               else
+                       /* handle it 4 sec later, wait it being stable */
+                       timeout = IXGBE_LINK_DOWN_CHECK_TIMEOUT;
+               
+               ixgbe_dev_link_status_print(dev);
+
+               intr_enable_delay = true;
+       } 
+
+       if (intr_enable_delay) {
+               if (rte_eal_alarm_set(timeout * 1000,
+                                     ixgbe_dev_interrupt_delayed_handler, (void*)dev) < 0)
+                       PMD_DRV_LOG(ERR, "Error setting alarm");
+       } else {
+               PMD_DRV_LOG(DEBUG, "enable intr immediately");
+               ixgbe_enable_intr(dev);
+               rte_intr_enable(&(dev->pci_dev->intr_handle));
        }
-       ixgbe_dev_link_update(dev, 0);
+                       
 
        return 0;
 }
@@ -1768,17 +1873,22 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
                IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
        struct ixgbe_hw *hw =
                IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t eicr;
+
+       eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+       if (eicr & IXGBE_EICR_MAILBOX)
+               ixgbe_pf_mbx_process(dev);
 
-       IXGBE_READ_REG(hw, IXGBE_EICR);
-       ixgbe_dev_interrupt_action(dev);
        if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
+               ixgbe_dev_link_update(dev, 0);
                intr->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
-               rte_intr_enable(&(dev->pci_dev->intr_handle));
-               IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_LSC);
-               IXGBE_WRITE_FLUSH(hw);
                ixgbe_dev_link_status_print(dev);
                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC);
        }
+
+       PMD_DRV_LOG(DEBUG, "enable intr in delayed handler S[%08x]\n", eicr);
+       ixgbe_enable_intr(dev);
+       rte_intr_enable(&(dev->pci_dev->intr_handle));
 }
 
 /**
@@ -1797,34 +1907,9 @@ static void
 ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
                                                        void *param)
 {
-       int64_t timeout;
-       struct rte_eth_link link;
        struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
-       struct ixgbe_interrupt *intr =
-               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-
-       /* get the link status before link update, for predicting later */
-       memset(&link, 0, sizeof(link));
-       rte_ixgbe_dev_atomic_read_link_status(dev, &link);
        ixgbe_dev_interrupt_get_status(dev);
        ixgbe_dev_interrupt_action(dev);
-
-       if (!(intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE))
-               return;
-
-       /* likely to up */
-       if (!link.link_status)
-               /* handle it 1 sec later, wait it being stable */
-               timeout = IXGBE_LINK_UP_CHECK_TIMEOUT;
-       /* likely to down */
-       else
-               /* handle it 4 sec later, wait it being stable */
-               timeout = IXGBE_LINK_DOWN_CHECK_TIMEOUT;
-
-       ixgbe_dev_link_status_print(dev);
-       if (rte_eal_alarm_set(timeout * 1000,
-               ixgbe_dev_interrupt_delayed_handler, param) < 0)
-               PMD_INIT_LOG(ERR, "Error setting alarm");
 }
 
 static int
@@ -2098,6 +2183,79 @@ ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *p
        return -EIO;
 }      
 
+static int 
+ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
+                               struct rte_eth_rss_reta *reta_conf)
+{      
+       uint8_t i,j,mask;
+       uint32_t reta;
+       struct ixgbe_hw *hw = 
+                       IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       PMD_INIT_FUNC_TRACE();
+       /*  
+       * Update Redirection Table RETA[n],n=0...31,The redirection table has 
+       * 128-entries in 32 registers
+        */ 
+       for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
+               if (i < ETH_RSS_RETA_NUM_ENTRIES/2) 
+                       mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+               else
+                       mask = (uint8_t)((reta_conf->mask_hi >> 
+                               (i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF);
+               if (mask != 0) {
+                       reta = 0;
+                       if (mask != 0xF)
+                               reta = IXGBE_READ_REG(hw,IXGBE_RETA(i >> 2));
+
+                       for (j = 0; j < 4; j++) {
+                               if (mask & (0x1 << j)) {
+                                       if (mask != 0xF)
+                                               reta &= ~(0xFF << 8 * j);
+                                       reta |= reta_conf->reta[i + j] << 8*j;
+                               }
+                       }
+                       IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2),reta);
+               }
+       }
+
+       return 0;
+}
+
+static int
+ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev,
+                               struct rte_eth_rss_reta *reta_conf)
+{
+       uint8_t i,j,mask;
+       uint32_t reta;
+       struct ixgbe_hw *hw =
+                       IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       
+       PMD_INIT_FUNC_TRACE();
+       /* 
+        * Read Redirection Table RETA[n],n=0...31,The redirection table has 
+        * 128-entries in 32 registers
+        */
+       for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
+               if (i < ETH_RSS_RETA_NUM_ENTRIES/2)
+                       mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+               else
+                       mask = (uint8_t)((reta_conf->mask_hi >> 
+                               (i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF);
+
+               if (mask != 0) {
+                       reta = IXGBE_READ_REG(hw,IXGBE_RETA(i >> 2));
+                       for (j = 0; j < 4; j++) {
+                               if (mask & (0x1 << j))
+                                       reta_conf->reta[i + j] = 
+                                               (uint8_t)((reta >> 8 * j) & 0xFF);
+                       } 
+               }
+       }
+
+       return 0;               
+}
+
 static void
 ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
                                uint32_t index, uint32_t pool)
@@ -2160,10 +2318,14 @@ ixgbevf_dev_configure(struct rte_eth_dev *dev)
 static int
 ixgbevf_dev_start(struct rte_eth_dev *dev)
 {
+       struct ixgbe_hw *hw = 
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        int err, mask = 0;
        
        PMD_INIT_LOG(DEBUG, "ixgbevf_dev_start");
 
+       hw->mac.ops.reset_hw(hw);
+
        ixgbevf_dev_tx_init(dev);
 
        /* This can fail when allocating mbufs for descriptor rings */