Skip to content

Commit

Permalink
igb: check for Tx timestamp timeouts during watchdog
Browse files Browse the repository at this point in the history
The igb driver has logic to handle only one Tx timestamp at a time,
using a state bit lock to avoid multiple requests at once.

It may be possible, if incredibly unlikely, that a Tx timestamp event is
requested but never completes. Since we use an interrupt scheme to
determine when the Tx timestamp occurred we would never clear the state
bit in this case.

Add an igb_ptp_tx_hang() function similar to the already existing
igb_ptp_rx_hang() function. This function runs in the watchdog routine
and makes sure we eventually recover from this case instead of
permanently disabling Tx timestamps.

Note: there is no currently known way to cause this without hacking the
driver code to force it.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
  • Loading branch information
Jacob Keller authored and Jeff Kirsher committed Jun 6, 2017
1 parent c3b8f85 commit e5f36ad
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/igb/igb.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ void igb_ptp_stop(struct igb_adapter *adapter);
void igb_ptp_reset(struct igb_adapter *adapter);
void igb_ptp_suspend(struct igb_adapter *adapter);
void igb_ptp_rx_hang(struct igb_adapter *adapter);
void igb_ptp_tx_hang(struct igb_adapter *adapter);
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
struct sk_buff *skb);
Expand Down
1 change: 1 addition & 0 deletions drivers/net/ethernet/intel/igb/igb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4722,6 +4722,7 @@ static void igb_watchdog_task(struct work_struct *work)

igb_spoof_check(adapter);
igb_ptp_rx_hang(adapter);
igb_ptp_tx_hang(adapter);

/* Check LVMMC register on i350/i354 only */
if ((adapter->hw.mac.type == e1000_i350) ||
Expand Down
29 changes: 29 additions & 0 deletions drivers/net/ethernet/intel/igb/igb_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,35 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
}
}

/**
* igb_ptp_tx_hang - detect error case where Tx timestamp never finishes
* @adapter: private network adapter structure
*/
void igb_ptp_tx_hang(struct igb_adapter *adapter)
{
bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
IGB_PTP_TX_TIMEOUT);

if (!adapter->ptp_tx_skb)
return;

if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state))
return;

/* If we haven't received a timestamp within the timeout, it is
* reasonable to assume that it will never occur, so we can unlock the
* timestamp bit when this occurs.
*/
if (timeout) {
cancel_work_sync(&adapter->ptp_tx_work);
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
adapter->tx_hwtstamp_timeouts++;
dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n");
}
}

/**
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
* @adapter: Board private structure.
Expand Down

0 comments on commit e5f36ad

Please sign in to comment.