ixgbe: remove open-coded skb_cow_head
[linux-2.6-microblaze.git] / drivers / net / ethernet / intel / ixgbe / ixgbe_main.c
index 18076c4..c4c526b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -67,7 +68,7 @@ static char ixgbe_default_device_descr[] =
 #define DRV_VERSION "3.19.1-k"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static const char ixgbe_copyright[] =
-                               "Copyright (c) 1999-2013 Intel Corporation.";
+                               "Copyright (c) 1999-2014 Intel Corporation.";
 
 static const struct ixgbe_info *ixgbe_info_tbl[] = {
        [board_82598] = &ixgbe_82598_info,
@@ -151,6 +152,8 @@ MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
+
 static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
                                          u32 reg, u16 *value)
 {
@@ -169,6 +172,9 @@ static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
                return -1;
 
        pcie_capability_read_word(parent_dev, reg, value);
+       if (*value == IXGBE_FAILED_READ_CFG_WORD &&
+           ixgbe_check_cfg_remove(&adapter->hw, parent_dev))
+               return -1;
        return 0;
 }
 
@@ -291,7 +297,8 @@ static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
                return;
        hw->hw_addr = NULL;
        e_dev_err("Adapter removed\n");
-       ixgbe_service_event_schedule(adapter);
+       if (test_bit(__IXGBE_SERVICE_INITED, &adapter->state))
+               ixgbe_service_event_schedule(adapter);
 }
 
 void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
@@ -313,6 +320,57 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
                ixgbe_remove_adapter(hw);
 }
 
+static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev)
+{
+       u16 value;
+
+       pci_read_config_word(pdev, PCI_VENDOR_ID, &value);
+       if (value == IXGBE_FAILED_READ_CFG_WORD) {
+               ixgbe_remove_adapter(hw);
+               return true;
+       }
+       return false;
+}
+
+u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       u16 value;
+
+       if (ixgbe_removed(hw->hw_addr))
+               return IXGBE_FAILED_READ_CFG_WORD;
+       pci_read_config_word(adapter->pdev, reg, &value);
+       if (value == IXGBE_FAILED_READ_CFG_WORD &&
+           ixgbe_check_cfg_remove(hw, adapter->pdev))
+               return IXGBE_FAILED_READ_CFG_WORD;
+       return value;
+}
+
+#ifdef CONFIG_PCI_IOV
+static u32 ixgbe_read_pci_cfg_dword(struct ixgbe_hw *hw, u32 reg)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       u32 value;
+
+       if (ixgbe_removed(hw->hw_addr))
+               return IXGBE_FAILED_READ_CFG_DWORD;
+       pci_read_config_dword(adapter->pdev, reg, &value);
+       if (value == IXGBE_FAILED_READ_CFG_DWORD &&
+           ixgbe_check_cfg_remove(hw, adapter->pdev))
+               return IXGBE_FAILED_READ_CFG_DWORD;
+       return value;
+}
+#endif /* CONFIG_PCI_IOV */
+
+void ixgbe_write_pci_cfg_word(struct ixgbe_hw *hw, u32 reg, u16 value)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+
+       if (ixgbe_removed(hw->hw_addr))
+               return;
+       pci_write_config_word(adapter->pdev, reg, value);
+}
+
 static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
 {
        BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
@@ -1264,7 +1322,9 @@ static inline void ixgbe_rx_hash(struct ixgbe_ring *ring,
                                 struct sk_buff *skb)
 {
        if (ring->netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+               skb_set_hash(skb,
+                            le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+                            PKT_HASH_TYPE_L3);
 }
 
 #ifdef IXGBE_FCOE
@@ -1480,7 +1540,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
        hdr.network += ETH_HLEN;
 
        /* handle any vlan tag if present */
-       if (protocol == __constant_htons(ETH_P_8021Q)) {
+       if (protocol == htons(ETH_P_8021Q)) {
                if ((hdr.network - data) > (max_len - VLAN_HLEN))
                        return max_len;
 
@@ -1489,7 +1549,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
        }
 
        /* handle L3 protocols */
-       if (protocol == __constant_htons(ETH_P_IP)) {
+       if (protocol == htons(ETH_P_IP)) {
                if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
                        return max_len;
 
@@ -1503,7 +1563,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
                /* record next protocol if header is present */
                if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
                        nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == __constant_htons(ETH_P_IPV6)) {
+       } else if (protocol == htons(ETH_P_IPV6)) {
                if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
                        return max_len;
 
@@ -1511,7 +1571,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
                nexthdr = hdr.ipv6->nexthdr;
                hlen = sizeof(struct ipv6hdr);
 #ifdef IXGBE_FCOE
-       } else if (protocol == __constant_htons(ETH_P_FCOE)) {
+       } else if (protocol == htons(ETH_P_FCOE)) {
                if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
                        return max_len;
                hlen = FCOE_HEADER_LEN;
@@ -2026,7 +2086,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 #endif /* IXGBE_FCOE */
        u16 cleaned_count = ixgbe_desc_unused(rx_ring);
 
-       do {
+       while (likely(total_rx_packets < budget)) {
                union ixgbe_adv_rx_desc *rx_desc;
                struct sk_buff *skb;
 
@@ -2101,7 +2161,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 
                /* update budget accounting */
                total_rx_packets++;
-       } while (likely(total_rx_packets < budget));
+       }
 
        u64_stats_update_begin(&rx_ring->syncp);
        rx_ring->stats.packets += total_rx_packets;
@@ -2630,9 +2690,12 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
        switch (hw->mac.type) {
        case ixgbe_mac_82599EB:
        case ixgbe_mac_X540:
-               if (eicr & IXGBE_EICR_ECC)
-                       e_info(link, "Received unrecoverable ECC Err, please "
-                              "reboot\n");
+               if (eicr & IXGBE_EICR_ECC) {
+                       e_info(link, "Received ECC Err, initiating reset\n");
+                       adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+                       ixgbe_service_event_schedule(adapter);
+                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
+               }
                /* Handle Flow Director Full threshold interrupt */
                if (eicr & IXGBE_EICR_FLOW_DIR) {
                        int reinit_count = 0;
@@ -2846,9 +2909,12 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
                ixgbe_check_sfp_event(adapter, eicr);
                /* Fall through */
        case ixgbe_mac_X540:
-               if (eicr & IXGBE_EICR_ECC)
-                       e_info(link, "Received unrecoverable ECC err, please "
-                                    "reboot\n");
+               if (eicr & IXGBE_EICR_ECC) {
+                       e_info(link, "Received ECC Err, initiating reset\n");
+                       adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+                       ixgbe_service_event_schedule(adapter);
+                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
+               }
                ixgbe_check_overtemp_event(adapter, eicr);
                break;
        default:
@@ -4590,8 +4656,6 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
 static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       struct net_device *upper;
-       struct list_head *iter;
        int err;
        u32 ctrl_ext;
 
@@ -4633,19 +4697,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
                        e_crit(drv, "Fan has stopped, replace the adapter\n");
        }
 
-       /* enable transmits */
-       netif_tx_start_all_queues(adapter->netdev);
-
-       /* enable any upper devices */
-       netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
-               if (netif_is_macvlan(upper)) {
-                       struct macvlan_dev *vlan = netdev_priv(upper);
-
-                       if (vlan->fwd_priv)
-                               netif_tx_start_all_queues(upper);
-               }
-       }
-
        /* bring the link up in the watchdog, this could race with our first
         * link up interrupt but shouldn't be a problem */
        adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -5502,6 +5553,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
        struct net_device *netdev = adapter->netdev;
        u32 err;
 
+       adapter->hw.hw_addr = adapter->io_addr;
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        /*
@@ -5515,6 +5567,8 @@ static int ixgbe_resume(struct pci_dev *pdev)
                e_dev_err("Cannot enable PCI device from suspend\n");
                return err;
        }
+       smp_mb__before_clear_bit();
+       clear_bit(__IXGBE_DISABLED, &adapter->state);
        pci_set_master(pdev);
 
        pci_wake_from_d3(pdev, false);
@@ -5612,7 +5666,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
 
        ixgbe_release_hw_control(adapter);
 
-       pci_disable_device(pdev);
+       if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+               pci_disable_device(pdev);
 
        return 0;
 }
@@ -6016,6 +6071,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
+       struct net_device *upper;
+       struct list_head *iter;
        u32 link_speed = adapter->link_speed;
        bool flow_rx, flow_tx;
 
@@ -6067,6 +6124,21 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
        netif_carrier_on(netdev);
        ixgbe_check_vf_rate_limit(adapter);
 
+       /* enable transmits */
+       netif_tx_wake_all_queues(adapter->netdev);
+
+       /* enable any upper devices */
+       rtnl_lock();
+       netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+               if (netif_is_macvlan(upper)) {
+                       struct macvlan_dev *vlan = netdev_priv(upper);
+
+                       if (vlan->fwd_priv)
+                               netif_tx_wake_all_queues(upper);
+               }
+       }
+       rtnl_unlock();
+
        /* update the default user priority for VFs */
        ixgbe_update_default_up(adapter);
 
@@ -6438,6 +6510,7 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
        struct sk_buff *skb = first->skb;
        u32 vlan_macip_lens, type_tucmd;
        u32 mss_l4len_idx, l4len;
+       int err;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
@@ -6445,16 +6518,14 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
        if (!skb_is_gso(skb))
                return 0;
 
-       if (skb_header_cloned(skb)) {
-               int err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-               if (err)
-                       return err;
-       }
+       err = skb_cow_head(skb, 0);
+       if (err < 0)
+               return err;
 
        /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
        type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
 
-       if (first->protocol == __constant_htons(ETH_P_IP)) {
+       if (first->protocol == htons(ETH_P_IP)) {
                struct iphdr *iph = ip_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
@@ -6514,12 +6585,12 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
        } else {
                u8 l4_hdr = 0;
                switch (first->protocol) {
-               case __constant_htons(ETH_P_IP):
+               case htons(ETH_P_IP):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
                        l4_hdr = ip_hdr(skb)->protocol;
                        break;
-               case __constant_htons(ETH_P_IPV6):
+               case htons(ETH_P_IPV6):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        l4_hdr = ipv6_hdr(skb)->nexthdr;
                        break;
@@ -6794,9 +6865,9 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
        hdr.network = skb_network_header(first->skb);
 
        /* Currently only IPv4/IPv6 with TCP is supported */
-       if ((first->protocol != __constant_htons(ETH_P_IPV6) ||
+       if ((first->protocol != htons(ETH_P_IPV6) ||
             hdr.ipv6->nexthdr != IPPROTO_TCP) &&
-           (first->protocol != __constant_htons(ETH_P_IP) ||
+           (first->protocol != htons(ETH_P_IP) ||
             hdr.ipv4->protocol != IPPROTO_TCP))
                return;
 
@@ -6829,12 +6900,12 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
         * and write the value to source port portion of compressed dword
         */
        if (first->tx_flags & (IXGBE_TX_FLAGS_SW_VLAN | IXGBE_TX_FLAGS_HW_VLAN))
-               common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q);
+               common.port.src ^= th->dest ^ htons(ETH_P_8021Q);
        else
                common.port.src ^= th->dest ^ first->protocol;
        common.port.dst ^= th->source;
 
-       if (first->protocol == __constant_htons(ETH_P_IP)) {
+       if (first->protocol == htons(ETH_P_IP)) {
                input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
                common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr;
        } else {
@@ -6900,8 +6971,8 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
         * or FIP and we have FCoE enabled on the adapter
         */
        switch (vlan_get_protocol(skb)) {
-       case __constant_htons(ETH_P_FCOE):
-       case __constant_htons(ETH_P_FIP):
+       case htons(ETH_P_FCOE):
+       case htons(ETH_P_FIP):
                adapter = netdev_priv(dev);
 
                if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
@@ -6962,7 +7033,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
                tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
        /* else if it is a SW VLAN check the next protocol and store the tag */
-       } else if (protocol == __constant_htons(ETH_P_8021Q)) {
+       } else if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_hdr *vhdr, _vhdr;
                vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
                if (!vhdr)
@@ -6974,9 +7045,9 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                tx_flags |= IXGBE_TX_FLAGS_SW_VLAN;
        }
 
-       skb_tx_timestamp(skb);
-
-       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
+                    !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS,
+                                           &adapter->state))) {
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                tx_flags |= IXGBE_TX_FLAGS_TSTAMP;
 
@@ -6986,6 +7057,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                schedule_work(&adapter->ptp_tx_work);
        }
 
+       skb_tx_timestamp(skb);
+
 #ifdef CONFIG_PCI_IOV
        /*
         * Use the l2switch_enable flag - would be false if the DMA
@@ -7004,8 +7077,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                                        IXGBE_TX_FLAGS_VLAN_PRIO_SHIFT;
                if (tx_flags & IXGBE_TX_FLAGS_SW_VLAN) {
                        struct vlan_ethhdr *vhdr;
-                       if (skb_header_cloned(skb) &&
-                           pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+
+                       if (skb_cow_head(skb, 0))
                                goto out_drop;
                        vhdr = (struct vlan_ethhdr *)skb->data;
                        vhdr->h_vlan_TCI = htons(tx_flags >>
@@ -7021,7 +7094,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
 
 #ifdef IXGBE_FCOE
        /* setup tx offload for FCoE */
-       if ((protocol == __constant_htons(ETH_P_FCOE)) &&
+       if ((protocol == htons(ETH_P_FCOE)) &&
            (tx_ring->netdev->features & (NETIF_F_FSO | NETIF_F_FCOE_CRC))) {
                tso = ixgbe_fso(tx_ring, first, &hdr_len);
                if (tso < 0)
@@ -7143,7 +7216,9 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
 
        switch (cmd) {
        case SIOCSHWTSTAMP:
-               return ixgbe_ptp_hwtstamp_ioctl(adapter, req, cmd);
+               return ixgbe_ptp_set_ts_config(adapter, req);
+       case SIOCGHWTSTAMP:
+               return ixgbe_ptp_get_ts_config(adapter, req);
        default:
                return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd);
        }
@@ -7234,10 +7309,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
 
                if (ring) {
                        do {
-                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               start = u64_stats_fetch_begin_irq(&ring->syncp);
                                packets = ring->stats.packets;
                                bytes   = ring->stats.bytes;
-                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                        stats->rx_packets += packets;
                        stats->rx_bytes   += bytes;
                }
@@ -7250,10 +7325,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
 
                if (ring) {
                        do {
-                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               start = u64_stats_fetch_begin_irq(&ring->syncp);
                                packets = ring->stats.packets;
                                bytes   = ring->stats.bytes;
-                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                        stats->tx_packets += packets;
                        stats->tx_bytes   += bytes;
                }
@@ -7792,6 +7867,7 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
        case IXGBE_DEV_ID_82599_SFP:
                /* Only these subdevices could supports WOL */
                switch (subdevice_id) {
+               case IXGBE_SUBDEV_ID_82599_SFP_WOL0:
                case IXGBE_SUBDEV_ID_82599_560FLR:
                        /* only support first port */
                        if (hw->bus.func != 0)
@@ -7947,6 +8023,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* EEPROM */
        memcpy(&hw->eeprom.ops, ii->eeprom_ops, sizeof(hw->eeprom.ops));
        eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+       if (ixgbe_removed(hw->hw_addr)) {
+               err = -EIO;
+               goto err_ioremap;
+       }
        /* If EEPROM is valid (bit 8 = 1), use default otherwise use bit bang */
        if (!(eec & (1 << 8)))
                hw->eeprom.ops.read = &ixgbe_read_eeprom_bit_bang_generic;
@@ -7969,10 +8049,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                goto err_sw_init;
 
-       /* Cache if MNG FW is up so we don't have to read the REG later */
-       if (hw->mac.ops.mng_fw_enabled)
-               hw->mng_fw_enabled = hw->mac.ops.mng_fw_enabled(hw);
-
        /* Make it possible the adapter to be woken up via WOL */
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_82599EB:
@@ -8113,7 +8189,12 @@ skip_sriov:
        setup_timer(&adapter->service_timer, &ixgbe_service_timer,
                    (unsigned long) adapter);
 
+       if (ixgbe_removed(hw->hw_addr)) {
+               err = -EIO;
+               goto err_sw_init;
+       }
        INIT_WORK(&adapter->service_task, ixgbe_service_task);
+       set_bit(__IXGBE_SERVICE_INITED, &adapter->state);
        clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
 
        err = ixgbe_init_interrupt_scheme(adapter);
@@ -8223,7 +8304,7 @@ skip_sriov:
        ixgbe_dbg_adapter_init(adapter);
 
        /* Need link setup for MNG FW, else wait for IXGBE_UP */
-       if (hw->mng_fw_enabled && hw->mac.ops.setup_link)
+       if (ixgbe_mng_enabled(hw) && hw->mac.ops.setup_link)
                hw->mac.ops.setup_link(hw,
                        IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
                        true);
@@ -8244,7 +8325,8 @@ err_alloc_etherdev:
                                     pci_select_bars(pdev, IORESOURCE_MEM));
 err_pci_reg:
 err_dma:
-       pci_disable_device(pdev);
+       if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+               pci_disable_device(pdev);
        return err;
 }
 
@@ -8313,7 +8395,8 @@ static void ixgbe_remove(struct pci_dev *pdev)
 
        pci_disable_pcie_error_reporting(pdev);
 
-       pci_disable_device(pdev);
+       if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+               pci_disable_device(pdev);
 }
 
 /**
@@ -8331,6 +8414,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
        struct net_device *netdev = adapter->netdev;
 
 #ifdef CONFIG_PCI_IOV
+       struct ixgbe_hw *hw = &adapter->hw;
        struct pci_dev *bdev, *vfdev;
        u32 dw0, dw1, dw2, dw3;
        int vf, pos;
@@ -8351,10 +8435,12 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
        if (!pos)
                goto skip_bad_vf_detection;
 
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG, &dw0);
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 4, &dw1);
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 8, &dw2);
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 12, &dw3);
+       dw0 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG);
+       dw1 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 4);
+       dw2 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 8);
+       dw3 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 12);
+       if (ixgbe_removed(hw->hw_addr))
+               goto skip_bad_vf_detection;
 
        req_id = dw1 >> 16;
        /* On the 82599 if bit 7 of the requestor ID is set then it's a VF */
@@ -8417,14 +8503,23 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
 
 skip_bad_vf_detection:
 #endif /* CONFIG_PCI_IOV */
+       if (!test_bit(__IXGBE_SERVICE_INITED, &adapter->state))
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       rtnl_lock();
        netif_device_detach(netdev);
 
-       if (state == pci_channel_io_perm_failure)
+       if (state == pci_channel_io_perm_failure) {
+               rtnl_unlock();
                return PCI_ERS_RESULT_DISCONNECT;
+       }
 
        if (netif_running(netdev))
                ixgbe_down(adapter);
-       pci_disable_device(pdev);
+
+       if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state))
+               pci_disable_device(pdev);
+       rtnl_unlock();
 
        /* Request a slot reset. */
        return PCI_ERS_RESULT_NEED_RESET;
@@ -8446,6 +8541,9 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
                e_err(probe, "Cannot re-enable PCI device after reset.\n");
                result = PCI_ERS_RESULT_DISCONNECT;
        } else {
+               smp_mb__before_clear_bit();
+               clear_bit(__IXGBE_DISABLED, &adapter->state);
+               adapter->hw.hw_addr = adapter->io_addr;
                pci_set_master(pdev);
                pci_restore_state(pdev);
                pci_save_state(pdev);