diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_main.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 6c90b6801cbd..5020f11ae10f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -4110,6 +4110,9 @@ static void ixgbe_watchdog_task(struct work_struct *work) | |||
4110 | struct ixgbe_hw *hw = &adapter->hw; | 4110 | struct ixgbe_hw *hw = &adapter->hw; |
4111 | u32 link_speed = adapter->link_speed; | 4111 | u32 link_speed = adapter->link_speed; |
4112 | bool link_up = adapter->link_up; | 4112 | bool link_up = adapter->link_up; |
4113 | int i; | ||
4114 | struct ixgbe_ring *tx_ring; | ||
4115 | int some_tx_pending = 0; | ||
4113 | 4116 | ||
4114 | adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; | 4117 | adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; |
4115 | 4118 | ||
@@ -4167,6 +4170,25 @@ static void ixgbe_watchdog_task(struct work_struct *work) | |||
4167 | } | 4170 | } |
4168 | } | 4171 | } |
4169 | 4172 | ||
4173 | if (!netif_carrier_ok(netdev)) { | ||
4174 | for (i = 0; i < adapter->num_tx_queues; i++) { | ||
4175 | tx_ring = &adapter->tx_ring[i]; | ||
4176 | if (tx_ring->next_to_use != tx_ring->next_to_clean) { | ||
4177 | some_tx_pending = 1; | ||
4178 | break; | ||
4179 | } | ||
4180 | } | ||
4181 | |||
4182 | if (some_tx_pending) { | ||
4183 | /* We've lost link, so the controller stops DMA, | ||
4184 | * but we've got queued Tx work that's never going | ||
4185 | * to get done, so reset controller to flush Tx. | ||
4186 | * (Do the reset outside of interrupt context). | ||
4187 | */ | ||
4188 | schedule_work(&adapter->reset_task); | ||
4189 | } | ||
4190 | } | ||
4191 | |||
4170 | ixgbe_update_stats(adapter); | 4192 | ixgbe_update_stats(adapter); |
4171 | adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; | 4193 | adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; |
4172 | } | 4194 | } |