diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2010-02-03 14:23:32 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-03 19:39:56 -0800 |
commit | 10eec95569513206877769ad9336591c08015cfe (patch) | |
tree | c372678363eb4d192a138fa11d2abf08a10b1897 /drivers/net/ixgbe/ixgbe_main.c | |
parent | 9c119ba54c0fcae72881948af3d37b47a2f8e1f9 (diff) | |
download | lwn-10eec95569513206877769ad9336591c08015cfe.tar.gz lwn-10eec95569513206877769ad9336591c08015cfe.zip |
ixgbe: only process one ixgbe_watchdog_task at a time.
Processing multiple ixgbe_watchdog_task calls may cause
the link_up variable and IXGBE_FLAG_NEED_LINK_UPDATE flag
to be set incorrectly. In the worse case this is causing
the netif_carrier_off to be called inappropriately which
results in an interface that can't be brought up.
Although schedule_work() will only schedule the task if
it is not already on the work queue the WORK_STRUCT_PENDING
bits are cleared just before calling the work function.
This allows WORK_STRUCT_PENDING to be cleared, the work
function to start and meanwhile schedule another task.
This patch adds a mutex to the watchdog task. This bug is
actualized by changing DCB settings or doing extended
cable pull or reset tests.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_main.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f098816d4199..1ec3cbdf8729 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -4996,6 +4996,8 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work) netif_tx_start_all_queues(adapter->netdev); } +static DEFINE_MUTEX(ixgbe_watchdog_lock); + /** * ixgbe_watchdog_task - worker thread to bring link up * @work: pointer to work_struct containing our data @@ -5007,13 +5009,16 @@ static void ixgbe_watchdog_task(struct work_struct *work) watchdog_task); struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; - u32 link_speed = adapter->link_speed; - bool link_up = adapter->link_up; + u32 link_speed; + bool link_up; int i; struct ixgbe_ring *tx_ring; int some_tx_pending = 0; - adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; + mutex_lock(&ixgbe_watchdog_lock); + + link_up = adapter->link_up; + link_speed = adapter->link_speed; if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { hw->mac.ops.check_link(hw, &link_speed, &link_up, false); @@ -5102,7 +5107,7 @@ static void ixgbe_watchdog_task(struct work_struct *work) } ixgbe_update_stats(adapter); - adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; + mutex_unlock(&ixgbe_watchdog_lock); } static int ixgbe_tso(struct ixgbe_adapter *adapter, |