]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
igc: Save PTP time before a reset
authorVinicius Costa Gomes <vinicius.gomes@intel.com>
Thu, 20 Aug 2020 23:02:17 +0000 (16:02 -0700)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Mon, 28 Sep 2020 21:42:46 +0000 (14:42 -0700)
Many TSN features depend on the internal PTP clock, so the internal
PTP jumping when the adapter is reset can cause problems, usually in
the form of "TX Hangs" warnings in the driver.

The solution is to save the PTP time before a reset and restore it
after the reset is done. The value of the PTP time is saved before a
reset and we use the difference from CLOCK_MONOTONIC from reset time
to now, to correct what's going to be the new PTP time.

This is heavily inspired by commit bf4bf09bdd91 ("i40e: save PTP time
before a device reset").

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/igc/igc.h
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/igc/igc_ptp.c

index 2d566f3c827b57a0ed30c1c9eace1baf5b89e335..2e5720d34a16b59341c57cdd420af6073571d440 100644 (file)
@@ -215,6 +215,8 @@ struct igc_adapter {
        spinlock_t tmreg_lock;
        struct cyclecounter cc;
        struct timecounter tc;
+       struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
+       ktime_t ptp_reset_start; /* Reset time in clock mono */
 };
 
 void igc_up(struct igc_adapter *adapter);
index 7576dbfdac99112188c99c74663a701038d5467e..1c16cd35c81c70871ebf59cee6b63be16a389f91 100644 (file)
@@ -3778,6 +3778,8 @@ void igc_down(struct igc_adapter *adapter)
 
        set_bit(__IGC_DOWN, &adapter->state);
 
+       igc_ptp_suspend(adapter);
+
        /* disable receives in the hardware */
        rctl = rd32(IGC_RCTL);
        wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
index 0300b45b36e2ff945f840e6c32bb30b7781b368f..49abefdab26c141f51eb1df8829af0c560590cf4 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/pci.h>
 #include <linux/ptp_classify.h>
 #include <linux/clocksource.h>
+#include <linux/ktime.h>
 
 #define INCVALUE_MASK          0x7fffffff
 #define ISGN                   0x80000000
@@ -500,6 +501,9 @@ void igc_ptp_init(struct igc_adapter *adapter)
        adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
        adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
 
+       adapter->prev_ptp_time = ktime_to_timespec64(ktime_get_real());
+       adapter->ptp_reset_start = ktime_get();
+
        adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
                                                &adapter->pdev->dev);
        if (IS_ERR(adapter->ptp_clock)) {
@@ -511,6 +515,24 @@ void igc_ptp_init(struct igc_adapter *adapter)
        }
 }
 
+static void igc_ptp_time_save(struct igc_adapter *adapter)
+{
+       igc_ptp_read_i225(adapter, &adapter->prev_ptp_time);
+       adapter->ptp_reset_start = ktime_get();
+}
+
+static void igc_ptp_time_restore(struct igc_adapter *adapter)
+{
+       struct timespec64 ts = adapter->prev_ptp_time;
+       ktime_t delta;
+
+       delta = ktime_sub(ktime_get(), adapter->ptp_reset_start);
+
+       timespec64_add_ns(&ts, ktime_to_ns(delta));
+
+       igc_ptp_write_i225(adapter, &ts);
+}
+
 /**
  * igc_ptp_suspend - Disable PTP work items and prepare for suspend
  * @adapter: Board private structure
@@ -527,6 +549,8 @@ void igc_ptp_suspend(struct igc_adapter *adapter)
        dev_kfree_skb_any(adapter->ptp_tx_skb);
        adapter->ptp_tx_skb = NULL;
        clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state);
+
+       igc_ptp_time_save(adapter);
 }
 
 /**
@@ -576,9 +600,7 @@ void igc_ptp_reset(struct igc_adapter *adapter)
 
        /* Re-initialize the timer. */
        if (hw->mac.type == igc_i225) {
-               struct timespec64 ts64 = ktime_to_timespec64(ktime_get_real());
-
-               igc_ptp_write_i225(adapter, &ts64);
+               igc_ptp_time_restore(adapter);
        } else {
                timecounter_init(&adapter->tc, &adapter->cc,
                                 ktime_to_ns(ktime_get_real()));