ixgbe: check for Tx timestamp timeouts during watchdog
authorJacob Keller <jacob.e.keller@intel.com>
Wed, 3 May 2017 17:29:04 +0000 (10:29 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tue, 13 Jun 2017 23:11:48 +0000 (16:11 -0700)
The ixgbe 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 ixgbe_ptp_tx_hang() function similar to the already existing
ixgbe_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: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c

index eb36106218ad0d47637b2f7e0c6fdad9dcf58450..dd5578756ae0fd361850f1ddf959c5ab613826b0 100644 (file)
@@ -961,6 +961,7 @@ void ixgbe_ptp_suspend(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_stop(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter);
+void ixgbe_ptp_tx_hang(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_rx_pktstamp(struct ixgbe_q_vector *, struct sk_buff *);
 void ixgbe_ptp_rx_rgtstamp(struct ixgbe_q_vector *, struct sk_buff *skb);
 static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
index 4ea1137ea23f7669627636982a01585c3ace382e..3ed212f5a43e93f43e762d321ebd5bd16cc8f84a 100644 (file)
@@ -7635,6 +7635,7 @@ static void ixgbe_service_task(struct work_struct *work)
        if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state)) {
                ixgbe_ptp_overflow_check(adapter);
                ixgbe_ptp_rx_hang(adapter);
+               ixgbe_ptp_tx_hang(adapter);
        }
 
        ixgbe_service_event_complete(adapter);
index 4a2000bfd4aec39e49b777d7128e8366e63a1301..86d6924a2b714ad7535e34149078f10f31ca53dc 100644 (file)
@@ -662,6 +662,33 @@ static void ixgbe_ptp_clear_tx_timestamp(struct ixgbe_adapter *adapter)
        clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state);
 }
 
+/**
+ * ixgbe_ptp_tx_hang - detect error case where Tx timestamp never finishes
+ * @adapter: private network adapter structure
+ */
+void ixgbe_ptp_tx_hang(struct ixgbe_adapter *adapter)
+{
+       bool timeout = time_is_before_jiffies(adapter->ptp_tx_start +
+                                             IXGBE_PTP_TX_TIMEOUT);
+
+       if (!adapter->ptp_tx_skb)
+               return;
+
+       if (!test_bit(__IXGBE_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);
+               ixgbe_ptp_clear_tx_timestamp(adapter);
+               adapter->tx_hwtstamp_timeouts++;
+               e_warn(drv, "clearing Tx timestamp hang\n");
+       }
+}
+
 /**
  * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp
  * @adapter: the private adapter struct