diff options
author | Jakub Kicinski <kubakici@wp.pl> | 2014-03-15 10:55:00 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2014-03-28 09:54:01 -0400 |
commit | 59c871c5f0540c974db85eaa77f518de26940c1f (patch) | |
tree | 0dfcd92ddb191648b8cc2578ddade2e5dbdd7b92 /drivers/net | |
parent | 13c2884f155bc524c5e94482216030de480fea60 (diff) |
e1000e: add timeout for TX HW time stamping work
Hardware may fail to report time stamp e.g.:
- when hardware time stamping is not enabled
- when time stamp is requested shortly after ifup
Timeout time stamp reading work to prevent it from
scheduling itself indefinitely. Report timeout events
via system log and device stats.
Signed-off-by: Jakub Kicinski <kubakici@wp.pl>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/e1000.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/ethtool.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/netdev.c | 7 |
3 files changed, 10 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 5325e3e2154e..1471c5464a89 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h | |||
@@ -262,6 +262,7 @@ struct e1000_adapter { | |||
262 | u32 tx_head_addr; | 262 | u32 tx_head_addr; |
263 | u32 tx_fifo_size; | 263 | u32 tx_fifo_size; |
264 | u32 tx_dma_failed; | 264 | u32 tx_dma_failed; |
265 | u32 tx_hwtstamp_timeouts; | ||
265 | 266 | ||
266 | /* Rx */ | 267 | /* Rx */ |
267 | bool (*clean_rx) (struct e1000_ring *ring, int *work_done, | 268 | bool (*clean_rx) (struct e1000_ring *ring, int *work_done, |
@@ -334,6 +335,7 @@ struct e1000_adapter { | |||
334 | struct hwtstamp_config hwtstamp_config; | 335 | struct hwtstamp_config hwtstamp_config; |
335 | struct delayed_work systim_overflow_work; | 336 | struct delayed_work systim_overflow_work; |
336 | struct sk_buff *tx_hwtstamp_skb; | 337 | struct sk_buff *tx_hwtstamp_skb; |
338 | unsigned long tx_hwtstamp_start; | ||
337 | struct work_struct tx_hwtstamp_work; | 339 | struct work_struct tx_hwtstamp_work; |
338 | spinlock_t systim_lock; /* protects SYSTIML/H regsters */ | 340 | spinlock_t systim_lock; /* protects SYSTIML/H regsters */ |
339 | struct cyclecounter cc; | 341 | struct cyclecounter cc; |
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 3c2898d0c2aa..cad250bc1b99 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c | |||
@@ -104,6 +104,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { | |||
104 | E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), | 104 | E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), |
105 | E1000_STAT("uncorr_ecc_errors", uncorr_errors), | 105 | E1000_STAT("uncorr_ecc_errors", uncorr_errors), |
106 | E1000_STAT("corr_ecc_errors", corr_errors), | 106 | E1000_STAT("corr_ecc_errors", corr_errors), |
107 | E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), | ||
107 | }; | 108 | }; |
108 | 109 | ||
109 | #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) | 110 | #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) |
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6bd1832e3f3e..b8d252fcad18 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c | |||
@@ -1163,6 +1163,12 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) | |||
1163 | skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); | 1163 | skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); |
1164 | dev_kfree_skb_any(adapter->tx_hwtstamp_skb); | 1164 | dev_kfree_skb_any(adapter->tx_hwtstamp_skb); |
1165 | adapter->tx_hwtstamp_skb = NULL; | 1165 | adapter->tx_hwtstamp_skb = NULL; |
1166 | } else if (time_after(jiffies, adapter->tx_hwtstamp_start | ||
1167 | + adapter->tx_timeout_factor * HZ)) { | ||
1168 | dev_kfree_skb_any(adapter->tx_hwtstamp_skb); | ||
1169 | adapter->tx_hwtstamp_skb = NULL; | ||
1170 | adapter->tx_hwtstamp_timeouts++; | ||
1171 | e_warn("clearing Tx timestamp hang"); | ||
1166 | } else { | 1172 | } else { |
1167 | /* reschedule to check later */ | 1173 | /* reschedule to check later */ |
1168 | schedule_work(&adapter->tx_hwtstamp_work); | 1174 | schedule_work(&adapter->tx_hwtstamp_work); |
@@ -5567,6 +5573,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, | |||
5567 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; | 5573 | skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
5568 | tx_flags |= E1000_TX_FLAGS_HWTSTAMP; | 5574 | tx_flags |= E1000_TX_FLAGS_HWTSTAMP; |
5569 | adapter->tx_hwtstamp_skb = skb_get(skb); | 5575 | adapter->tx_hwtstamp_skb = skb_get(skb); |
5576 | adapter->tx_hwtstamp_start = jiffies; | ||
5570 | schedule_work(&adapter->tx_hwtstamp_work); | 5577 | schedule_work(&adapter->tx_hwtstamp_work); |
5571 | } else { | 5578 | } else { |
5572 | skb_tx_timestamp(skb); | 5579 | skb_tx_timestamp(skb); |