diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igb/igb_ptp.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ptp.c | 42 | 
1 files changed, 40 insertions, 2 deletions
| diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 7a3fd4d74592..841c2a083349 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -712,6 +712,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.   * @@ -721,6 +750,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)   **/  static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)  { +	struct sk_buff *skb = adapter->ptp_tx_skb;  	struct e1000_hw *hw = &adapter->hw;  	struct skb_shared_hwtstamps shhwtstamps;  	u64 regval; @@ -748,10 +778,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)  	shhwtstamps.hwtstamp =  		ktime_add_ns(shhwtstamps.hwtstamp, adjust); -	skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); -	dev_kfree_skb_any(adapter->ptp_tx_skb); +	/* Clear the lock early before calling skb_tstamp_tx so that +	 * applications are not woken up before the lock bit is clear. We use +	 * a copy of the skb pointer to ensure other threads can't change it +	 * while we're notifying the stack. +	 */  	adapter->ptp_tx_skb = NULL;  	clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + +	/* Notify the stack and free the skb after we've unlocked */ +	skb_tstamp_tx(skb, &shhwtstamps); +	dev_kfree_skb_any(skb);  }  /** @@ -941,6 +978,7 @@ static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter,  		is_l4 = true;  		break;  	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: +	case HWTSTAMP_FILTER_NTP_ALL:  	case HWTSTAMP_FILTER_ALL:  		/* 82576 cannot timestamp all packets, which it needs to do to  		 * support both V1 Sync and Delay_Req messages | 
