summaryrefslogtreecommitdiff
path: root/drivers/net/ixgbe/ixgbe_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_common.c')
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c47
1 files changed, 41 insertions, 6 deletions
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 345c32eab4a5..6d87c7491d10 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -454,8 +454,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw)
* Prevent the PCI-E bus from from hanging by disabling PCI-E master
* access and verify no pending requests
*/
- if (ixgbe_disable_pcie_master(hw) != 0)
- hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+ ixgbe_disable_pcie_master(hw);
return 0;
}
@@ -2161,10 +2160,16 @@ out:
**/
s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
{
+ struct ixgbe_adapter *adapter = hw->back;
u32 i;
u32 reg_val;
u32 number_of_queues;
- s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+ s32 status = 0;
+ u16 dev_status = 0;
+
+ /* Just jump out if bus mastering is already disabled */
+ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
+ goto out;
/* Disable the receive unit by stopping each queue */
number_of_queues = hw->mac.max_rx_queues;
@@ -2181,13 +2186,43 @@ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
IXGBE_WRITE_REG(hw, IXGBE_CTRL, reg_val);
for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
- if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) {
- status = 0;
+ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
+ goto check_device_status;
+ udelay(100);
+ }
+
+ hw_dbg(hw, "GIO Master Disable bit didn't clear - requesting resets\n");
+ status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+
+ /*
+ * Before proceeding, make sure that the PCIe block does not have
+ * transactions pending.
+ */
+check_device_status:
+ for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+ pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS,
+ &dev_status);
+ if (!(dev_status & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
break;
- }
udelay(100);
}
+ if (i == IXGBE_PCI_MASTER_DISABLE_TIMEOUT)
+ hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n");
+ else
+ goto out;
+
+ /*
+ * Two consecutive resets are required via CTRL.RST per datasheet
+ * 5.2.5.3.2 Master Disable. We set a flag to inform the reset routine
+ * of this need. The first reset prevents new master requests from
+ * being issued by our device. We then must wait 1usec for any
+ * remaining completions from the PCIe bus to trickle in, and then reset
+ * again to clear out any effects they may have had on our device.
+ */
+ hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED;
+
+out:
return status;
}