lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251127043047.728116-1-vitaly.lifshits@intel.com>
Date: Thu, 27 Nov 2025 06:30:47 +0200
From: Vitaly Lifshits <vitaly.lifshits@...el.com>
To: intel-wired-lan@...osl.org,
	netdev@...r.kernel.org,
	andrew+netdev@...n.ch,
	horms@...nel.org,
	kuba@...nel.org,
	edumazet@...gle.com,
	davem@...emloft.net,
	pabeni@...hat.com
Cc: Vitaly Lifshits <vitaly.lifshits@...el.com>
Subject: [PATCH iwl-next v1 1/1] e1000e: introduce private flag to override XTAL clock frequency

On some TGP and ADP systems, the hardware XTAL clock is incorrectly
set to 24MHz instead of the expected 38.4MHz, causing PTP timer
inaccuracies. Since affected systems cannot be reliably detected,
introduce an ethtool private flag that allows user-space to override
the XTAL clock frequency.

Tested on an affected system using the phc_ctl tool:

Without the flag:
  sudo phc_ctl enp0s31f6 set 0.0 wait 10 get
  phc_ctl[...] clock time is 16.000541250 (expected ~10s)

With the flag:
  sudo phc_ctl enp0s31f6 set 0.0 wait 10 get
  phc_ctl[...] clock time is 9.984407212 (expected ~10s)

Signed-off-by: Vitaly Lifshits <vitaly.lifshits@...el.com>
---
 drivers/net/ethernet/intel/e1000e/e1000.h   |  7 ++--
 drivers/net/ethernet/intel/e1000e/ethtool.c | 39 ++++++++++-----------
 drivers/net/ethernet/intel/e1000e/ich8lan.c |  4 +--
 drivers/net/ethernet/intel/e1000e/netdev.c  | 18 +++++++---
 4 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index aa08f397988e..63145bf5adcf 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -310,6 +310,7 @@ struct e1000_adapter {
 
 	unsigned int flags;
 	unsigned int flags2;
+	unsigned int priv_flags;
 	struct work_struct downshift_task;
 	struct work_struct update_phy_task;
 	struct work_struct print_hang_task;
@@ -460,8 +461,10 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
 #define FLAG2_DFLT_CRC_STRIPPING          BIT(12)
 #define FLAG2_CHECK_RX_HWTSTAMP           BIT(13)
 #define FLAG2_CHECK_SYSTIM_OVERFLOW       BIT(14)
-#define FLAG2_ENABLE_S0IX_FLOWS           BIT(15)
-#define FLAG2_DISABLE_K1		   BIT(16)
+
+#define PRIV_FLAG_ENABLE_S0IX_FLOWS	   BIT(0)
+#define PRIV_FLAG_DISABLE_K1		   BIT(1)
+#define PRIV_FLAG_38_4MHZ_XTAL_CLK	   BIT(2)
 
 #define E1000_RX_DESC_PS(R, i)	    \
 	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index cee57a2149ab..3415c38e1d9a 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -24,10 +24,9 @@ struct e1000_stats {
 };
 
 static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = {
-#define E1000E_PRIV_FLAGS_S0IX_ENABLED	BIT(0)
 	"s0ix-enabled",
-#define E1000E_PRIV_FLAGS_DISABLE_K1	BIT(1)
 	"disable-k1",
+	"force_38_4mhz_xtal_clock",
 };
 
 #define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings)
@@ -2298,49 +2297,49 @@ static int e1000e_get_ts_info(struct net_device *netdev,
 static u32 e1000e_get_priv_flags(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	u32 priv_flags = 0;
 
-	if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
-		priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED;
-
-	if (adapter->flags2 & FLAG2_DISABLE_K1)
-		priv_flags |= E1000E_PRIV_FLAGS_DISABLE_K1;
-
-	return priv_flags;
+	return adapter->priv_flags;
 }
 
 static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	unsigned int flags2 = adapter->flags2;
+	unsigned int temp_flags = 0;
 	unsigned int changed;
 
-	flags2 &= ~(FLAG2_ENABLE_S0IX_FLOWS | FLAG2_DISABLE_K1);
-
-	if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) {
+	if (priv_flags & PRIV_FLAG_ENABLE_S0IX_FLOWS) {
 		if (hw->mac.type < e1000_pch_cnp) {
 			e_err("S0ix is not supported on this device\n");
 			return -EINVAL;
 		}
 
-		flags2 |= FLAG2_ENABLE_S0IX_FLOWS;
+		temp_flags |= PRIV_FLAG_ENABLE_S0IX_FLOWS;
 	}
 
-	if (priv_flags & E1000E_PRIV_FLAGS_DISABLE_K1) {
+	if (priv_flags & PRIV_FLAG_DISABLE_K1) {
 		if (hw->mac.type < e1000_ich8lan) {
 			e_err("Disabling K1 is not supported on this device\n");
 			return -EINVAL;
 		}
 
-		flags2 |= FLAG2_DISABLE_K1;
+		temp_flags |= PRIV_FLAG_DISABLE_K1;
+	}
+
+	if (priv_flags & PRIV_FLAG_38_4MHZ_XTAL_CLK) {
+		if (hw->mac.type != e1000_pch_tgp && hw->mac.type != e1000_pch_adp) {
+			e_err("Forcing 38.4MHz frequency on the XTAL is not supported on this device\n");
+			return -EINVAL;
+		}
+
+		temp_flags |= PRIV_FLAG_38_4MHZ_XTAL_CLK;
 	}
 
-	changed = adapter->flags2 ^ flags2;
+	changed = adapter->priv_flags ^ temp_flags;
 	if (changed)
-		adapter->flags2 = flags2;
+		adapter->priv_flags = temp_flags;
 
-	if (changed & FLAG2_DISABLE_K1) {
+	if (changed & (PRIV_FLAG_DISABLE_K1 | PRIV_FLAG_38_4MHZ_XTAL_CLK)) {
 		/* reset the hardware to apply the changes */
 		while (test_and_set_bit(__E1000_RESETTING,
 					&adapter->state))
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 0ff8688ac3b8..8669dfaf38ea 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -302,7 +302,7 @@ static s32 e1000_reconfigure_k1_params(struct e1000_hw *hw)
 	s32 ret_val;
 
 	if (hw->mac.type < e1000_pch_mtp) {
-		if (hw->adapter->flags2 & FLAG2_DISABLE_K1)
+		if (hw->adapter->priv_flags & PRIV_FLAG_DISABLE_K1)
 			return e1000_configure_k1_ich8lan(hw, false);
 		return 0;
 	}
@@ -315,7 +315,7 @@ static s32 e1000_reconfigure_k1_params(struct e1000_hw *hw)
 
 	/* Wait for the interface the settle */
 	usleep_range(1000, 1100);
-	if (hw->adapter->flags2 & FLAG2_DISABLE_K1)
+	if (hw->adapter->flags2 & PRIV_FLAG_DISABLE_K1)
 		return e1000_configure_k1_ich8lan(hw, false);
 
 	/* Change K1 exit timeout */
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 116f3c92b5bc..93ab22f3cd3e 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -3531,9 +3531,17 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
 		shift = INCVALUE_SHIFT_24MHZ;
 		adapter->cc.shift = shift;
 		break;
-	case e1000_pch_cnp:
 	case e1000_pch_tgp:
 	case e1000_pch_adp:
+		if (adapter->priv_flags & PRIV_FLAG_38_4MHZ_XTAL_CLK) {
+			incperiod = INCPERIOD_38400KHZ;
+			incvalue = INCVALUE_38400KHZ;
+			shift = INCVALUE_SHIFT_38400KHZ;
+			adapter->cc.shift = shift;
+			break;
+		}
+		fallthrough;
+	case e1000_pch_cnp:
 	case e1000_pch_nvp:
 		if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
 			/* Stable 24MHz frequency */
@@ -6987,7 +6995,7 @@ static int e1000e_pm_suspend(struct device *dev)
 	rc = __e1000_shutdown(pdev, false);
 	if (!rc) {
 		/* Introduce S0ix implementation */
-		if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
+		if (adapter->priv_flags & PRIV_FLAG_ENABLE_S0IX_FLOWS)
 			e1000e_s0ix_entry_flow(adapter);
 	}
 
@@ -7002,7 +7010,7 @@ static int e1000e_pm_resume(struct device *dev)
 	int rc;
 
 	/* Introduce S0ix implementation */
-	if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS)
+	if (adapter->priv_flags & PRIV_FLAG_ENABLE_S0IX_FLOWS)
 		e1000e_s0ix_exit_flow(adapter);
 
 	rc = __e1000_resume(pdev);
@@ -7676,7 +7684,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	e1000e_ptp_init(adapter);
 
 	if (hw->mac.type >= e1000_pch_mtp)
-		adapter->flags2 |= FLAG2_DISABLE_K1;
+		adapter->priv_flags |= PRIV_FLAG_DISABLE_K1;
 
 	/* reset the hardware with the new settings */
 	e1000e_reset(adapter);
@@ -7689,7 +7697,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		e1000e_get_hw_control(adapter);
 
 	if (hw->mac.type >= e1000_pch_cnp)
-		adapter->flags2 |= FLAG2_ENABLE_S0IX_FLOWS;
+		adapter->priv_flags |= PRIV_FLAG_ENABLE_S0IX_FLOWS;
 
 	strscpy(netdev->name, "eth%d", sizeof(netdev->name));
 	err = register_netdev(netdev);
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ