]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
i40e: check for Tx timestamp timeouts during watchdog
authorJacob Keller <jacob.e.keller@intel.com>
Wed, 3 May 2017 17:29:02 +0000 (10:29 -0700)
committerJack Vogel <jack.vogel@oracle.com>
Tue, 10 Oct 2017 21:15:24 +0000 (14:15 -0700)
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 <jacob.e.keller@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Orabug: 26785018
(cherry picked from commit 0bc0706b46cd345537f9bd3cdf5d84c33f5484e4)
Signed-off-by: Jack Vogel <jack.vogel@oracle.com>
Reviewed-by: Kyle Fortin <kyle.fortin@oracle.com>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c

index 1c2a1bed7cf746259192231b06042f114a6387c6..67f9f7f3ca5d006d5d87652d07715659dc2336cd 100644 (file)
@@ -507,6 +507,7 @@ struct i40e_pf {
        struct ptp_clock *ptp_clock;
        struct ptp_clock_info ptp_caps;
        struct sk_buff *ptp_tx_skb;
+       unsigned long ptp_tx_start;
        struct hwtstamp_config tstamp_config;
        struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */
        u64 ptp_base_adj;
@@ -1004,6 +1005,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                            struct i40e_dcbx_config *new_cfg);
 #endif /* CONFIG_I40E_DCB */
 void i40e_ptp_rx_hang(struct i40e_pf *pf);
+void i40e_ptp_tx_hang(struct i40e_pf *pf);
 void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf);
 void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index);
 void i40e_ptp_set_increment(struct i40e_pf *pf);
index b9439fc12cc4d3b7546c9fee60a8fb9dbd2319da..6721f25d942d4bc1e2d2e320e99b6420fb32c22d 100644 (file)
@@ -6435,6 +6435,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
        }
 
        i40e_ptp_rx_hang(pf);
+       i40e_ptp_tx_hang(pf);
 }
 
 /**
index 8c2a3b5cb4400c477c7b0a1c11b967544b75f834..b6f14b5d21d95ee2a6dfd015ec9be71ddb5507c4 100644 (file)
@@ -327,6 +327,36 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf)
        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
index cc895fc149921e39c6c08153e97c8b1cae125f65..7227e14ce416637aa94fac9e5f0157e74fc17ae9 100644 (file)
@@ -2566,6 +2566,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (pf->ptp_tx &&
            !test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, &pf->state)) {
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               pf->ptp_tx_start = jiffies;
                pf->ptp_tx_skb = skb_get(skb);
        } else {
                pf->tx_hwtstamp_skipped++;