|
@@ -269,6 +269,7 @@ static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf)
|
|
|
|
|
|
/**
|
|
|
* i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung
|
|
|
+ * @pf: The PF private data structure
|
|
|
* @vsi: The VSI with the rings relevant to 1588
|
|
|
*
|
|
|
* This watchdog task is scheduled to detect error case where hardware has
|
|
@@ -276,9 +277,8 @@ static u32 i40e_ptp_get_rx_events(struct i40e_pf *pf)
|
|
|
* particular error is rare but leaves the device in a state unable to timestamp
|
|
|
* any future packets.
|
|
|
**/
|
|
|
-void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
|
|
|
+void i40e_ptp_rx_hang(struct i40e_pf *pf)
|
|
|
{
|
|
|
- struct i40e_pf *pf = vsi->back;
|
|
|
struct i40e_hw *hw = &pf->hw;
|
|
|
unsigned int i, cleared = 0;
|
|
|
|
|
@@ -327,6 +327,36 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
|
|
|
pf->rx_hwtstamp_cleared += cleared;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * i40e_ptp_tx_hang - Detect error case when Tx timestamp register is hung
|
|
|
+ * @pf: The PF private data structure
|
|
|
+ *
|
|
|
+ * This watchdog task is run periodically to make sure that we clear the Tx
|
|
|
+ * timestamp logic if we don't obtain a timestamp in a reasonable amount of
|
|
|
+ * time. It is unexpected in the normal case but if it occurs it results in
|
|
|
+ * permanently prevent timestamps of future packets
|
|
|
+ **/
|
|
|
+void i40e_ptp_tx_hang(struct i40e_pf *pf)
|
|
|
+{
|
|
|
+ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Nothing to do if we're not already waiting for a timestamp */
|
|
|
+ if (!test_bit(__I40E_PTP_TX_IN_PROGRESS, pf->state))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* We already have a handler routine which is run when we are notified
|
|
|
+ * of a Tx timestamp in the hardware. If we don't get an interrupt
|
|
|
+ * within a second it is reasonable to assume that we never will.
|
|
|
+ */
|
|
|
+ if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) {
|
|
|
+ dev_kfree_skb_any(pf->ptp_tx_skb);
|
|
|
+ pf->ptp_tx_skb = NULL;
|
|
|
+ clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state);
|
|
|
+ pf->tx_hwtstamp_timeouts++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp
|
|
|
* @pf: Board private structure
|
|
@@ -338,6 +368,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
|
|
|
void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf)
|
|
|
{
|
|
|
struct skb_shared_hwtstamps shhwtstamps;
|
|
|
+ struct sk_buff *skb = pf->ptp_tx_skb;
|
|
|
struct i40e_hw *hw = &pf->hw;
|
|
|
u32 hi, lo;
|
|
|
u64 ns;
|
|
@@ -353,12 +384,19 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf)
|
|
|
hi = rd32(hw, I40E_PRTTSYN_TXTIME_H);
|
|
|
|
|
|
ns = (((u64)hi) << 32) | lo;
|
|
|
-
|
|
|
i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns);
|
|
|
- skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps);
|
|
|
- dev_kfree_skb_any(pf->ptp_tx_skb);
|
|
|
+
|
|
|
+ /* Clear the bit lock as soon as possible after reading the register,
|
|
|
+ * and prior to notifying the stack via skb_tstamp_tx(). Otherwise
|
|
|
+ * applications might wake up and attempt to request another transmit
|
|
|
+ * timestamp prior to the bit lock being cleared.
|
|
|
+ */
|
|
|
pf->ptp_tx_skb = NULL;
|
|
|
clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state);
|
|
|
+
|
|
|
+ /* Notify the stack and free the skb after we've unlocked */
|
|
|
+ skb_tstamp_tx(skb, &shhwtstamps);
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
}
|
|
|
|
|
|
/**
|