mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue
Tony Nguyen says: ==================== igc: Fix PTM timeout Christopher S M Hall says: There have been sporadic reports of PTM timeouts using i225/i226 devices These timeouts have been root caused to: 1) Manipulating the PTM status register while PTM is enabled and triggered 2) The hardware retrying too quickly when an inappropriate response is received from the upstream device The issue can be reproduced with the following: $ sudo phc2sys -R 1000 -O 0 -i tsn0 -m Note: 1000 Hz (-R 1000) is unrealistically large, but provides a way to quickly reproduce the issue. PHC2SYS exits with: "ioctl PTP_OFFSET_PRECISE: Connection timed out" when the PTM transaction fails The first patch in this series also resolves an issue reported by Corinna Vinschen relating to kdump: This patch also fixes a hang in igc_probe() when loading the igc driver in the kdump kernel on systems supporting PTM. The igc driver running in the base kernel enables PTM trigger in igc_probe(). Therefore the driver is always in PTM trigger mode, except in brief periods when manually triggering a PTM cycle. When a crash occurs, the NIC is reset while PTM trigger is enabled. Due to a hardware problem, the NIC is subsequently in a bad busmaster state and doesn't handle register reads/writes. When running igc_probe() in the kdump kernel, the first register access to a NIC register hangs driver probing and ultimately breaks kdump. With this patch, igc has PTM trigger disabled most of the time, and the trigger is only enabled for very brief (10 - 100 us) periods when manually triggering a PTM cycle. Chances that a crash occurs during a PTM trigger are not zero, but extremly reduced. * '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue: igc: add lock preventing multiple simultaneous PTM transactions igc: cleanup PTP module if probe fails igc: handle the IGC_PTP_ENABLED flag correctly igc: move ktime snapshot into PTM retry loop igc: increase wait time before retrying PTM igc: fix PTM cycle trigger logic ==================== Link: https://patch.msgid.link/20250411162857.2754883-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
186e5888fd
@ -319,6 +319,7 @@ struct igc_adapter {
|
||||
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
|
||||
ktime_t ptp_reset_start; /* Reset time in clock mono */
|
||||
struct system_time_snapshot snapshot;
|
||||
struct mutex ptm_lock; /* Only allow one PTM transaction at a time */
|
||||
|
||||
char fw_version[32];
|
||||
|
||||
|
@ -574,7 +574,10 @@
|
||||
#define IGC_PTM_CTRL_SHRT_CYC(usec) (((usec) & 0x3f) << 2)
|
||||
#define IGC_PTM_CTRL_PTM_TO(usec) (((usec) & 0xff) << 8)
|
||||
|
||||
#define IGC_PTM_SHORT_CYC_DEFAULT 1 /* Default short cycle interval */
|
||||
/* A short cycle time of 1us theoretically should work, but appears to be too
|
||||
* short in practice.
|
||||
*/
|
||||
#define IGC_PTM_SHORT_CYC_DEFAULT 4 /* Default short cycle interval */
|
||||
#define IGC_PTM_CYC_TIME_DEFAULT 5 /* Default PTM cycle time */
|
||||
#define IGC_PTM_TIMEOUT_DEFAULT 255 /* Default timeout for PTM errors */
|
||||
|
||||
@ -593,6 +596,7 @@
|
||||
#define IGC_PTM_STAT_T4M1_OVFL BIT(3) /* T4 minus T1 overflow */
|
||||
#define IGC_PTM_STAT_ADJUST_1ST BIT(4) /* 1588 timer adjusted during 1st PTM cycle */
|
||||
#define IGC_PTM_STAT_ADJUST_CYC BIT(5) /* 1588 timer adjusted during non-1st PTM cycle */
|
||||
#define IGC_PTM_STAT_ALL GENMASK(5, 0) /* Used to clear all status */
|
||||
|
||||
/* PCIe PTM Cycle Control */
|
||||
#define IGC_PTM_CYCLE_CTRL_CYC_TIME(msec) ((msec) & 0x3ff) /* PTM Cycle Time (msec) */
|
||||
|
@ -7231,6 +7231,7 @@ static int igc_probe(struct pci_dev *pdev,
|
||||
|
||||
err_register:
|
||||
igc_release_hw_control(adapter);
|
||||
igc_ptp_stop(adapter);
|
||||
err_eeprom:
|
||||
if (!igc_check_reset_block(hw))
|
||||
igc_reset_phy(hw);
|
||||
|
@ -974,45 +974,62 @@ static void igc_ptm_log_error(struct igc_adapter *adapter, u32 ptm_stat)
|
||||
}
|
||||
}
|
||||
|
||||
/* The PTM lock: adapter->ptm_lock must be held when calling igc_ptm_trigger() */
|
||||
static void igc_ptm_trigger(struct igc_hw *hw)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
/* To "manually" start the PTM cycle we need to set the
|
||||
* trigger (TRIG) bit
|
||||
*/
|
||||
ctrl = rd32(IGC_PTM_CTRL);
|
||||
ctrl |= IGC_PTM_CTRL_TRIG;
|
||||
wr32(IGC_PTM_CTRL, ctrl);
|
||||
/* Perform flush after write to CTRL register otherwise
|
||||
* transaction may not start
|
||||
*/
|
||||
wrfl();
|
||||
}
|
||||
|
||||
/* The PTM lock: adapter->ptm_lock must be held when calling igc_ptm_reset() */
|
||||
static void igc_ptm_reset(struct igc_hw *hw)
|
||||
{
|
||||
u32 ctrl;
|
||||
|
||||
ctrl = rd32(IGC_PTM_CTRL);
|
||||
ctrl &= ~IGC_PTM_CTRL_TRIG;
|
||||
wr32(IGC_PTM_CTRL, ctrl);
|
||||
/* Write to clear all status */
|
||||
wr32(IGC_PTM_STAT, IGC_PTM_STAT_ALL);
|
||||
}
|
||||
|
||||
static int igc_phc_get_syncdevicetime(ktime_t *device,
|
||||
struct system_counterval_t *system,
|
||||
void *ctx)
|
||||
{
|
||||
u32 stat, t2_curr_h, t2_curr_l, ctrl;
|
||||
struct igc_adapter *adapter = ctx;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 stat, t2_curr_h, t2_curr_l;
|
||||
int err, count = 100;
|
||||
ktime_t t1, t2_curr;
|
||||
|
||||
/* Get a snapshot of system clocks to use as historic value. */
|
||||
ktime_get_snapshot(&adapter->snapshot);
|
||||
|
||||
/* Doing this in a loop because in the event of a
|
||||
* badly timed (ha!) system clock adjustment, we may
|
||||
* get PTM errors from the PCI root, but these errors
|
||||
* are transitory. Repeating the process returns valid
|
||||
* data eventually.
|
||||
*/
|
||||
do {
|
||||
/* Doing this in a loop because in the event of a
|
||||
* badly timed (ha!) system clock adjustment, we may
|
||||
* get PTM errors from the PCI root, but these errors
|
||||
* are transitory. Repeating the process returns valid
|
||||
* data eventually.
|
||||
*/
|
||||
/* Get a snapshot of system clocks to use as historic value. */
|
||||
ktime_get_snapshot(&adapter->snapshot);
|
||||
|
||||
/* To "manually" start the PTM cycle we need to clear and
|
||||
* then set again the TRIG bit.
|
||||
*/
|
||||
ctrl = rd32(IGC_PTM_CTRL);
|
||||
ctrl &= ~IGC_PTM_CTRL_TRIG;
|
||||
wr32(IGC_PTM_CTRL, ctrl);
|
||||
ctrl |= IGC_PTM_CTRL_TRIG;
|
||||
wr32(IGC_PTM_CTRL, ctrl);
|
||||
|
||||
/* The cycle only starts "for real" when software notifies
|
||||
* that it has read the registers, this is done by setting
|
||||
* VALID bit.
|
||||
*/
|
||||
wr32(IGC_PTM_STAT, IGC_PTM_STAT_VALID);
|
||||
igc_ptm_trigger(hw);
|
||||
|
||||
err = readx_poll_timeout(rd32, IGC_PTM_STAT, stat,
|
||||
stat, IGC_PTM_STAT_SLEEP,
|
||||
IGC_PTM_STAT_TIMEOUT);
|
||||
igc_ptm_reset(hw);
|
||||
|
||||
if (err < 0) {
|
||||
netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n");
|
||||
return err;
|
||||
@ -1021,15 +1038,7 @@ static int igc_phc_get_syncdevicetime(ktime_t *device,
|
||||
if ((stat & IGC_PTM_STAT_VALID) == IGC_PTM_STAT_VALID)
|
||||
break;
|
||||
|
||||
if (stat & ~IGC_PTM_STAT_VALID) {
|
||||
/* An error occurred, log it. */
|
||||
igc_ptm_log_error(adapter, stat);
|
||||
/* The STAT register is write-1-to-clear (W1C),
|
||||
* so write the previous error status to clear it.
|
||||
*/
|
||||
wr32(IGC_PTM_STAT, stat);
|
||||
continue;
|
||||
}
|
||||
igc_ptm_log_error(adapter, stat);
|
||||
} while (--count);
|
||||
|
||||
if (!count) {
|
||||
@ -1061,9 +1070,16 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
|
||||
{
|
||||
struct igc_adapter *adapter = container_of(ptp, struct igc_adapter,
|
||||
ptp_caps);
|
||||
int ret;
|
||||
|
||||
return get_device_system_crosststamp(igc_phc_get_syncdevicetime,
|
||||
adapter, &adapter->snapshot, cts);
|
||||
/* This blocks until any in progress PTM transactions complete */
|
||||
mutex_lock(&adapter->ptm_lock);
|
||||
|
||||
ret = get_device_system_crosststamp(igc_phc_get_syncdevicetime,
|
||||
adapter, &adapter->snapshot, cts);
|
||||
mutex_unlock(&adapter->ptm_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int igc_ptp_getcyclesx64(struct ptp_clock_info *ptp,
|
||||
@ -1162,6 +1178,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
|
||||
spin_lock_init(&adapter->ptp_tx_lock);
|
||||
spin_lock_init(&adapter->free_timer_lock);
|
||||
spin_lock_init(&adapter->tmreg_lock);
|
||||
mutex_init(&adapter->ptm_lock);
|
||||
|
||||
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
|
||||
adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
|
||||
@ -1174,6 +1191,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
|
||||
if (IS_ERR(adapter->ptp_clock)) {
|
||||
adapter->ptp_clock = NULL;
|
||||
netdev_err(netdev, "ptp_clock_register failed\n");
|
||||
mutex_destroy(&adapter->ptm_lock);
|
||||
} else if (adapter->ptp_clock) {
|
||||
netdev_info(netdev, "PHC added\n");
|
||||
adapter->ptp_flags |= IGC_PTP_ENABLED;
|
||||
@ -1203,10 +1221,12 @@ static void igc_ptm_stop(struct igc_adapter *adapter)
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 ctrl;
|
||||
|
||||
mutex_lock(&adapter->ptm_lock);
|
||||
ctrl = rd32(IGC_PTM_CTRL);
|
||||
ctrl &= ~IGC_PTM_CTRL_EN;
|
||||
|
||||
wr32(IGC_PTM_CTRL, ctrl);
|
||||
mutex_unlock(&adapter->ptm_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1237,13 +1257,18 @@ void igc_ptp_suspend(struct igc_adapter *adapter)
|
||||
**/
|
||||
void igc_ptp_stop(struct igc_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->ptp_flags & IGC_PTP_ENABLED))
|
||||
return;
|
||||
|
||||
igc_ptp_suspend(adapter);
|
||||
|
||||
adapter->ptp_flags &= ~IGC_PTP_ENABLED;
|
||||
if (adapter->ptp_clock) {
|
||||
ptp_clock_unregister(adapter->ptp_clock);
|
||||
netdev_info(adapter->netdev, "PHC removed\n");
|
||||
adapter->ptp_flags &= ~IGC_PTP_ENABLED;
|
||||
}
|
||||
mutex_destroy(&adapter->ptm_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1255,10 +1280,13 @@ void igc_ptp_stop(struct igc_adapter *adapter)
|
||||
void igc_ptp_reset(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 cycle_ctrl, ctrl;
|
||||
u32 cycle_ctrl, ctrl, stat;
|
||||
unsigned long flags;
|
||||
u32 timadj;
|
||||
|
||||
if (!(adapter->ptp_flags & IGC_PTP_ENABLED))
|
||||
return;
|
||||
|
||||
/* reset the tstamp_config */
|
||||
igc_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
|
||||
|
||||
@ -1280,6 +1308,7 @@ void igc_ptp_reset(struct igc_adapter *adapter)
|
||||
if (!igc_is_crosststamp_supported(adapter))
|
||||
break;
|
||||
|
||||
mutex_lock(&adapter->ptm_lock);
|
||||
wr32(IGC_PCIE_DIG_DELAY, IGC_PCIE_DIG_DELAY_DEFAULT);
|
||||
wr32(IGC_PCIE_PHY_DELAY, IGC_PCIE_PHY_DELAY_DEFAULT);
|
||||
|
||||
@ -1290,14 +1319,20 @@ void igc_ptp_reset(struct igc_adapter *adapter)
|
||||
ctrl = IGC_PTM_CTRL_EN |
|
||||
IGC_PTM_CTRL_START_NOW |
|
||||
IGC_PTM_CTRL_SHRT_CYC(IGC_PTM_SHORT_CYC_DEFAULT) |
|
||||
IGC_PTM_CTRL_PTM_TO(IGC_PTM_TIMEOUT_DEFAULT) |
|
||||
IGC_PTM_CTRL_TRIG;
|
||||
IGC_PTM_CTRL_PTM_TO(IGC_PTM_TIMEOUT_DEFAULT);
|
||||
|
||||
wr32(IGC_PTM_CTRL, ctrl);
|
||||
|
||||
/* Force the first cycle to run. */
|
||||
wr32(IGC_PTM_STAT, IGC_PTM_STAT_VALID);
|
||||
igc_ptm_trigger(hw);
|
||||
|
||||
if (readx_poll_timeout_atomic(rd32, IGC_PTM_STAT, stat,
|
||||
stat, IGC_PTM_STAT_SLEEP,
|
||||
IGC_PTM_STAT_TIMEOUT))
|
||||
netdev_err(adapter->netdev, "Timeout reading IGC_PTM_STAT register\n");
|
||||
|
||||
igc_ptm_reset(hw);
|
||||
mutex_unlock(&adapter->ptm_lock);
|
||||
break;
|
||||
default:
|
||||
/* No work to do. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user