i40e: prevent overlapping tx_timeout recover
authorAlan Brady <alan.brady@intel.com>
Mon, 29 Oct 2018 18:27:21 +0000 (11:27 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Feb 2019 18:47:00 +0000 (19:47 +0100)
[ Upstream commit d5585b7b6846a6d0f9517afe57be3843150719da ]

If a TX hang occurs, we attempt to recover by incrementally resetting.
If we're starved for CPU time, it's possible the reset doesn't actually
complete (or even fire) before another tx_timeout fires causing us to
fly through the different resets without actually doing them.

This adds a bit to set and check if a timeout recovery is already
pending and, if so, bail out of tx_timeout.  The bit will get cleared at
the end of i40e_rebuild when reset is complete.

Signed-off-by: Alan Brady <alan.brady@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c

index 7a80652..f84e2c2 100644 (file)
@@ -122,6 +122,7 @@ enum i40e_state_t {
        __I40E_MDD_EVENT_PENDING,
        __I40E_VFLR_EVENT_PENDING,
        __I40E_RESET_RECOVERY_PENDING,
+       __I40E_TIMEOUT_RECOVERY_PENDING,
        __I40E_MISC_IRQ_REQUESTED,
        __I40E_RESET_INTR_RECEIVED,
        __I40E_REINIT_REQUESTED,
index ed9d3fc..bfa5c52 100644 (file)
@@ -336,6 +336,10 @@ static void i40e_tx_timeout(struct net_device *netdev)
                      (pf->tx_timeout_last_recovery + netdev->watchdog_timeo)))
                return;   /* don't do any new action before the next timeout */
 
+       /* don't kick off another recovery if one is already pending */
+       if (test_and_set_bit(__I40E_TIMEOUT_RECOVERY_PENDING, pf->state))
+               return;
+
        if (tx_ring) {
                head = i40e_get_head(tx_ring);
                /* Read interrupt register */
@@ -9566,6 +9570,7 @@ end_core_reset:
        clear_bit(__I40E_RESET_FAILED, pf->state);
 clear_recovery:
        clear_bit(__I40E_RESET_RECOVERY_PENDING, pf->state);
+       clear_bit(__I40E_TIMEOUT_RECOVERY_PENDING, pf->state);
 }
 
 /**