diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2010-02-03 09:23:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-03 22:39:56 -0500 |
commit | 10eec95569513206877769ad9336591c08015cfe (patch) | |
tree | c372678363eb4d192a138fa11d2abf08a10b1897 /drivers/net/ixgbe | |
parent | 9c119ba54c0fcae72881948af3d37b47a2f8e1f9 (diff) |
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')
-rw-r--r-- | drivers/net/ixgbe/ixgbe.h | 17 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 13 |
2 files changed, 17 insertions, 13 deletions
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index e576fb4740bc..55a319e3a57a 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h | |||
@@ -341,15 +341,14 @@ struct ixgbe_adapter { | |||
341 | #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) | 341 | #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) |
342 | #define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) | 342 | #define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) |
343 | #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) | 343 | #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) |
344 | #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) | 344 | #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23) |
345 | #define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 24) | 345 | #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24) |
346 | #define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 25) | 346 | #define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25) |
347 | #define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 26) | 347 | #define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26) |
348 | #define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 27) | 348 | #define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27) |
349 | #define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 28) | 349 | #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28) |
350 | #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 29) | 350 | #define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29) |
351 | #define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 30) | 351 | #define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30) |
352 | #define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 31) | ||
353 | 352 | ||
354 | u32 flags2; | 353 | u32 flags2; |
355 | #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) | 354 | #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) |
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) | |||
4996 | netif_tx_start_all_queues(adapter->netdev); | 4996 | netif_tx_start_all_queues(adapter->netdev); |
4997 | } | 4997 | } |
4998 | 4998 | ||
4999 | static DEFINE_MUTEX(ixgbe_watchdog_lock); | ||
5000 | |||
4999 | /** | 5001 | /** |
5000 | * ixgbe_watchdog_task - worker thread to bring link up | 5002 | * ixgbe_watchdog_task - worker thread to bring link up |
5001 | * @work: pointer to work_struct containing our data | 5003 | * @work: pointer to work_struct containing our data |
@@ -5007,13 +5009,16 @@ static void ixgbe_watchdog_task(struct work_struct *work) | |||
5007 | watchdog_task); | 5009 | watchdog_task); |
5008 | struct net_device *netdev = adapter->netdev; | 5010 | struct net_device *netdev = adapter->netdev; |
5009 | struct ixgbe_hw *hw = &adapter->hw; | 5011 | struct ixgbe_hw *hw = &adapter->hw; |
5010 | u32 link_speed = adapter->link_speed; | 5012 | u32 link_speed; |
5011 | bool link_up = adapter->link_up; | 5013 | bool link_up; |
5012 | int i; | 5014 | int i; |
5013 | struct ixgbe_ring *tx_ring; | 5015 | struct ixgbe_ring *tx_ring; |
5014 | int some_tx_pending = 0; | 5016 | int some_tx_pending = 0; |
5015 | 5017 | ||
5016 | adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK; | 5018 | mutex_lock(&ixgbe_watchdog_lock); |
5019 | |||
5020 | link_up = adapter->link_up; | ||
5021 | link_speed = adapter->link_speed; | ||
5017 | 5022 | ||
5018 | if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { | 5023 | if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { |
5019 | hw->mac.ops.check_link(hw, &link_speed, &link_up, false); | 5024 | hw->mac.ops.check_link(hw, &link_speed, &link_up, false); |
@@ -5102,7 +5107,7 @@ static void ixgbe_watchdog_task(struct work_struct *work) | |||
5102 | } | 5107 | } |
5103 | 5108 | ||
5104 | ixgbe_update_stats(adapter); | 5109 | ixgbe_update_stats(adapter); |
5105 | adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK; | 5110 | mutex_unlock(&ixgbe_watchdog_lock); |
5106 | } | 5111 | } |
5107 | 5112 | ||
5108 | static int ixgbe_tso(struct ixgbe_adapter *adapter, | 5113 | static int ixgbe_tso(struct ixgbe_adapter *adapter, |