Skip to content

Commit 0bc0706

Browse files
jacob-kellerJeff Kirsher
authored andcommitted
i40e: check for Tx timestamp timeouts during watchdog
The i40e 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 i40e_ptp_tx_hang() function similar to the already existing i40e_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 <[email protected]> Signed-off-by: Jeff Kirsher <[email protected]>
1 parent 6118955 commit 0bc0706

File tree

4 files changed

+34
-0
lines changed

4 files changed

+34
-0
lines changed

drivers/net/ethernet/intel/i40e/i40e.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ struct i40e_pf {
502502
struct ptp_clock *ptp_clock;
503503
struct ptp_clock_info ptp_caps;
504504
struct sk_buff *ptp_tx_skb;
505+
unsigned long ptp_tx_start;
505506
struct hwtstamp_config tstamp_config;
506507
struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */
507508
u64 ptp_base_adj;
@@ -957,6 +958,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
957958
struct i40e_dcbx_config *new_cfg);
958959
#endif /* CONFIG_I40E_DCB */
959960
void i40e_ptp_rx_hang(struct i40e_pf *pf);
961+
void i40e_ptp_tx_hang(struct i40e_pf *pf);
960962
void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf);
961963
void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index);
962964
void i40e_ptp_set_increment(struct i40e_pf *pf);

drivers/net/ethernet/intel/i40e/i40e_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6373,6 +6373,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
63736373
}
63746374

63756375
i40e_ptp_rx_hang(pf);
6376+
i40e_ptp_tx_hang(pf);
63766377
}
63776378

63786379
/**

drivers/net/ethernet/intel/i40e/i40e_ptp.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,36 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf)
327327
pf->rx_hwtstamp_cleared += cleared;
328328
}
329329

330+
/**
331+
* i40e_ptp_tx_hang - Detect error case when Tx timestamp register is hung
332+
* @pf: The PF private data structure
333+
*
334+
* This watchdog task is run periodically to make sure that we clear the Tx
335+
* timestamp logic if we don't obtain a timestamp in a reasonable amount of
336+
* time. It is unexpected in the normal case but if it occurs it results in
337+
* permanently prevent timestamps of future packets
338+
**/
339+
void i40e_ptp_tx_hang(struct i40e_pf *pf)
340+
{
341+
if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
342+
return;
343+
344+
/* Nothing to do if we're not already waiting for a timestamp */
345+
if (!test_bit(__I40E_PTP_TX_IN_PROGRESS, pf->state))
346+
return;
347+
348+
/* We already have a handler routine which is run when we are notified
349+
* of a Tx timestamp in the hardware. If we don't get an interrupt
350+
* within a second it is reasonable to assume that we never will.
351+
*/
352+
if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) {
353+
dev_kfree_skb_any(pf->ptp_tx_skb);
354+
pf->ptp_tx_skb = NULL;
355+
clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state);
356+
pf->tx_hwtstamp_timeouts++;
357+
}
358+
}
359+
330360
/**
331361
* i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp
332362
* @pf: Board private structure

drivers/net/ethernet/intel/i40e/i40e_txrx.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2628,6 +2628,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
26282628
if (pf->ptp_tx &&
26292629
!test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, pf->state)) {
26302630
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
2631+
pf->ptp_tx_start = jiffies;
26312632
pf->ptp_tx_skb = skb_get(skb);
26322633
} else {
26332634
pf->tx_hwtstamp_skipped++;

0 commit comments

Comments
 (0)