aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/igc/igc_ptp.c
diff options
context:
space:
mode:
authorGravatar Vinicius Costa Gomes <vinicius.gomes@intel.com> 2020-08-20 16:02:17 -0700
committerGravatar Tony Nguyen <anthony.l.nguyen@intel.com> 2020-09-28 14:42:46 -0700
commitb03c49cde61f9e5a68cb0b1f3540fcb20b27b6fa (patch)
tree3147c15f3e2c0d268e5bf9db65ee46e960ff1bc0 /drivers/net/ethernet/intel/igc/igc_ptp.c
parentigc: Remove references to SYSTIMR register (diff)
downloadlinux-b03c49cde61f9e5a68cb0b1f3540fcb20b27b6fa.tar.gz
linux-b03c49cde61f9e5a68cb0b1f3540fcb20b27b6fa.tar.bz2
linux-b03c49cde61f9e5a68cb0b1f3540fcb20b27b6fa.zip
igc: Save PTP time before a reset
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>
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_ptp.c')
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c28
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 0300b45b36e2..49abefdab26c 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -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()));