|
|
@@ -1613,7 +1613,7 @@ void fm10k_down(struct fm10k_intfc *interface)
|
|
|
{
|
|
|
struct net_device *netdev = interface->netdev;
|
|
|
struct fm10k_hw *hw = &interface->hw;
|
|
|
- int err;
|
|
|
+ int err, i = 0, count = 0;
|
|
|
|
|
|
/* signal that we are down to the interrupt handler and service task */
|
|
|
if (test_and_set_bit(__FM10K_DOWN, &interface->state))
|
|
|
@@ -1629,9 +1629,6 @@ void fm10k_down(struct fm10k_intfc *interface)
|
|
|
/* reset Rx filters */
|
|
|
fm10k_reset_rx_state(interface);
|
|
|
|
|
|
- /* allow 10ms for device to quiesce */
|
|
|
- usleep_range(10000, 20000);
|
|
|
-
|
|
|
/* disable polling routines */
|
|
|
fm10k_napi_disable_all(interface);
|
|
|
|
|
|
@@ -1642,11 +1639,46 @@ void fm10k_down(struct fm10k_intfc *interface)
|
|
|
while (test_and_set_bit(__FM10K_UPDATING_STATS, &interface->state))
|
|
|
usleep_range(1000, 2000);
|
|
|
|
|
|
+ /* skip waiting for TX DMA if we lost PCIe link */
|
|
|
+ if (FM10K_REMOVED(hw->hw_addr))
|
|
|
+ goto skip_tx_dma_drain;
|
|
|
+
|
|
|
+ /* In some rare circumstances it can take a while for Tx queues to
|
|
|
+ * quiesce and be fully disabled. Attempt to .stop_hw() first, and
|
|
|
+ * then if we get ERR_REQUESTS_PENDING, go ahead and wait in a loop
|
|
|
+ * until the Tx queues have emptied, or until a number of retries. If
|
|
|
+ * we fail to clear within the retry loop, we will issue a warning
|
|
|
+ * indicating that Tx DMA is probably hung. Note this means we call
|
|
|
+ * .stop_hw() twice but this shouldn't cause any problems.
|
|
|
+ */
|
|
|
+ err = hw->mac.ops.stop_hw(hw);
|
|
|
+ if (err != FM10K_ERR_REQUESTS_PENDING)
|
|
|
+ goto skip_tx_dma_drain;
|
|
|
+
|
|
|
+#define TX_DMA_DRAIN_RETRIES 25
|
|
|
+ for (count = 0; count < TX_DMA_DRAIN_RETRIES; count++) {
|
|
|
+ usleep_range(10000, 20000);
|
|
|
+
|
|
|
+ /* start checking at the last ring to have pending Tx */
|
|
|
+ for (; i < interface->num_tx_queues; i++)
|
|
|
+ if (fm10k_get_tx_pending(interface->tx_ring[i]))
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* if all the queues are drained, we can break now */
|
|
|
+ if (i == interface->num_tx_queues)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count >= TX_DMA_DRAIN_RETRIES)
|
|
|
+ dev_err(&interface->pdev->dev,
|
|
|
+ "Tx queues failed to drain after %d tries. Tx DMA is probably hung.\n",
|
|
|
+ count);
|
|
|
+skip_tx_dma_drain:
|
|
|
/* Disable DMA engine for Tx/Rx */
|
|
|
err = hw->mac.ops.stop_hw(hw);
|
|
|
if (err == FM10K_ERR_REQUESTS_PENDING)
|
|
|
- dev_info(&interface->pdev->dev,
|
|
|
- "due to pending requests hw was not shut down gracefully\n");
|
|
|
+ dev_err(&interface->pdev->dev,
|
|
|
+ "due to pending requests hw was not shut down gracefully\n");
|
|
|
else if (err)
|
|
|
dev_err(&interface->pdev->dev, "stop_hw failed: %d\n", err);
|
|
|
|