ixgbe: Check config reads for removal
authorMark Rustad <mark.d.rustad@intel.com>
Fri, 28 Feb 2014 23:48:57 +0000 (15:48 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Mar 2014 00:06:43 +0000 (19:06 -0500)
Configuration space reads should also be checked for removal. So
add some checks related to config space accesses.

v2:
* Fixed indent

Signed-off-by: Mark Rustad <mark.d.rustad@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

index 10e563cb847a096e8b0b2166e0c4b13053887bb2..15506f0780b20e9107915f980b60e92d5acc380c 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,
@@ -61,6 +61,9 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
        u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR);
        u16 pcie_devctl2;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
+
        /* only take action if timeout value is defaulted to 0 */
        if (gcr & IXGBE_GCR_CMPL_TMOUT_MASK)
                goto out;
@@ -79,8 +82,9 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
         * directly in order to set the completion timeout value for
         * 16ms to 55ms
         */
-       pci_read_config_word(adapter->pdev,
-                            IXGBE_PCI_DEVICE_CONTROL2, &pcie_devctl2);
+       pcie_devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2);
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        pcie_devctl2 |= IXGBE_PCI_DEVICE_CONTROL2_16ms;
        pci_write_config_word(adapter->pdev,
                              IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2);
index 263143f53b21c720d9b8c1e05c1913f9e92528a8..4456c235a44a8d579c0cf128d1f57ef9f900e42d 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,
@@ -2487,7 +2487,6 @@ static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw)
  **/
 static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
 {
-       struct ixgbe_adapter *adapter = hw->back;
        s32 status = 0;
        u32 i, poll;
        u16 value;
@@ -2496,7 +2495,8 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
        IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS);
 
        /* Exit if master requests are blocked */
-       if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
+       if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) ||
+           ixgbe_removed(hw->hw_addr))
                goto out;
 
        /* Poll for master request bit to clear */
@@ -2524,8 +2524,9 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
        poll = ixgbe_pcie_timeout_poll(hw);
        for (i = 0; i < poll; i++) {
                udelay(100);
-               pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS,
-                                                        &value);
+               value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS);
+               if (ixgbe_removed(hw->hw_addr))
+                       goto out;
                if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
                        goto out;
        }
@@ -2867,7 +2868,6 @@ san_mac_addr_clr:
  **/
 u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
 {
-       struct ixgbe_adapter *adapter = hw->back;
        u16 msix_count = 1;
        u16 max_msix_count;
        u16 pcie_offset;
@@ -2886,7 +2886,9 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
                return msix_count;
        }
 
-       pci_read_config_word(adapter->pdev, pcie_offset, &msix_count);
+       msix_count = ixgbe_read_pci_cfg_word(hw, pcie_offset);
+       if (ixgbe_removed(hw->hw_addr))
+               msix_count = 0;
        msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK;
 
        /* MSI-X count is zero-based in HW */
index a042db2997f73b4a9d204752cc8c64c01634e81b..ef0fd4cef5df415d685a065de311ac2d5579c5a4 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,
@@ -128,6 +128,10 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
 
 #define IXGBE_FAILED_READ_REG 0xffffffffU
+#define IXGBE_FAILED_READ_CFG_DWORD 0xffffffffU
+#define IXGBE_FAILED_READ_CFG_WORD 0xffffU
+
+u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg);
 
 static inline bool ixgbe_removed(void __iomem *addr)
 {
index 3d576b29f1d1742ac7428d4e252d4752bc96d0b3..72807431c88a1c144c6e016adb00c3a6fe0ba9ad 100644 (file)
@@ -151,6 +151,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 +171,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;
 }
 
@@ -313,6 +318,48 @@ 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 */
+
 static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
 {
        BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
@@ -8339,6 +8386,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;
@@ -8359,10 +8407,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 */