Commit b03c49cd authored by Vinicius Costa Gomes's avatar Vinicius Costa Gomes Committed by Tony Nguyen

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 bf4bf09b ("i40e: save PTP time
before a device reset").
Signed-off-by: default avatarVinicius Costa Gomes <vinicius.gomes@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent e5f020ad
...@@ -215,6 +215,8 @@ struct igc_adapter { ...@@ -215,6 +215,8 @@ struct igc_adapter {
spinlock_t tmreg_lock; spinlock_t tmreg_lock;
struct cyclecounter cc; struct cyclecounter cc;
struct timecounter tc; 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); void igc_up(struct igc_adapter *adapter);
......
...@@ -3778,6 +3778,8 @@ void igc_down(struct igc_adapter *adapter) ...@@ -3778,6 +3778,8 @@ void igc_down(struct igc_adapter *adapter)
set_bit(__IGC_DOWN, &adapter->state); set_bit(__IGC_DOWN, &adapter->state);
igc_ptp_suspend(adapter);
/* disable receives in the hardware */ /* disable receives in the hardware */
rctl = rd32(IGC_RCTL); rctl = rd32(IGC_RCTL);
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/ptp_classify.h> #include <linux/ptp_classify.h>
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/ktime.h>
#define INCVALUE_MASK 0x7fffffff #define INCVALUE_MASK 0x7fffffff
#define ISGN 0x80000000 #define ISGN 0x80000000
...@@ -500,6 +501,9 @@ void igc_ptp_init(struct igc_adapter *adapter) ...@@ -500,6 +501,9 @@ void igc_ptp_init(struct igc_adapter *adapter)
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; 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->ptp_clock = ptp_clock_register(&adapter->ptp_caps,
&adapter->pdev->dev); &adapter->pdev->dev);
if (IS_ERR(adapter->ptp_clock)) { if (IS_ERR(adapter->ptp_clock)) {
...@@ -511,6 +515,24 @@ void igc_ptp_init(struct igc_adapter *adapter) ...@@ -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 * igc_ptp_suspend - Disable PTP work items and prepare for suspend
* @adapter: Board private structure * @adapter: Board private structure
...@@ -527,6 +549,8 @@ void igc_ptp_suspend(struct igc_adapter *adapter) ...@@ -527,6 +549,8 @@ void igc_ptp_suspend(struct igc_adapter *adapter)
dev_kfree_skb_any(adapter->ptp_tx_skb); dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL; adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); 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) ...@@ -576,9 +600,7 @@ void igc_ptp_reset(struct igc_adapter *adapter)
/* Re-initialize the timer. */ /* Re-initialize the timer. */
if (hw->mac.type == igc_i225) { if (hw->mac.type == igc_i225) {
struct timespec64 ts64 = ktime_to_timespec64(ktime_get_real()); igc_ptp_time_restore(adapter);
igc_ptp_write_i225(adapter, &ts64);
} else { } else {
timecounter_init(&adapter->tc, &adapter->cc, timecounter_init(&adapter->tc, &adapter->cc,
ktime_to_ns(ktime_get_real())); ktime_to_ns(ktime_get_real()));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment