git: 262519268925 - main - e1000: Separate hardware semaphore policies by family

Kevin Bowling <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7b81c3.31774.1f28e774__34303.4975741588$1786479080$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=26251926892585e0746c2b65227e56cf9b2fed58

commit 26251926892585e0746c2b65227e56cf9b2fed58
Author:     Kevin Bowling <[email protected]>
AuthorDate: 2026-08-11 18:58:17 +0000
Commit:     Kevin Bowling <[email protected]>
CommitDate: 2026-08-11 20:08:43 +0000

    e1000: Separate hardware semaphore policies by family
    
    The shared semaphore helper accesses both the 82571 retry counter and
    the I210 one-time-clear flag.  Those fields occupy overlapping members
    of the device-specific union.  On 82571, incrementing the counter thus
    enables the I210 recovery and clears SMBI after the first timeout.
    
    Give 82571, generic 80003/82575, and I210/I211 users distinct acquire
    paths.  Preserve the legacy peer-driver policy on 82571 and one-time
    recovery on I210.
    
    The separation follows the Intel e1000 base code in DPDK.
    
    MFC after:      2 weeks
---
 sys/dev/e1000/e1000_82571.c |  62 ++++++++++++++++++++--
 sys/dev/e1000/e1000_82575.c |   5 +-
 sys/dev/e1000/e1000_i210.c  | 126 +++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/e1000/e1000_i210.h  |   2 +
 sys/dev/e1000/e1000_mac.c   |  51 ++++--------------
 sys/dev/e1000/e1000_mac.h   |   2 +-
 6 files changed, 201 insertions(+), 47 deletions(-)

diff --git a/sys/dev/e1000/e1000_82571.c b/sys/dev/e1000/e1000_82571.c
index 650169663f56..a0a183e326ca 100644
--- a/sys/dev/e1000/e1000_82571.c
+++ b/sys/dev/e1000/e1000_82571.c
@@ -72,6 +72,7 @@ static s32  e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
 static s32  e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
 static s32  e1000_get_phy_id_82571(struct e1000_hw *hw);
+static s32  e1000_get_hw_semaphore_82571(struct e1000_hw *hw);
 static s32  e1000_get_hw_semaphore_82574(struct e1000_hw *hw);
 static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw);
 static s32  e1000_set_d0_lplu_state_82574(struct e1000_hw *hw,
@@ -122,7 +123,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
 		phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
 		phy->ops.read_reg	= e1000_read_phy_reg_igp;
 		phy->ops.write_reg	= e1000_write_phy_reg_igp;
-		phy->ops.acquire	= e1000_get_hw_semaphore;
+		phy->ops.acquire	= e1000_get_hw_semaphore_82571;
 		phy->ops.release	= e1000_put_hw_semaphore;
 		break;
 	case e1000_82573:
@@ -135,7 +136,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
 		phy->ops.get_cable_length = e1000_get_cable_length_m88;
 		phy->ops.read_reg	= e1000_read_phy_reg_m88;
 		phy->ops.write_reg	= e1000_write_phy_reg_m88;
-		phy->ops.acquire	= e1000_get_hw_semaphore;
+		phy->ops.acquire	= e1000_get_hw_semaphore_82571;
 		phy->ops.release	= e1000_put_hw_semaphore;
 		break;
 	case e1000_82574:
@@ -615,6 +616,61 @@ static s32 e1000_set_d3_lplu_state_82574(struct e1000_hw *hw, bool active)
 	return E1000_SUCCESS;
 }
 
+/**
+ *  e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the hardware semaphore while preserving the 82571 inter-port
+ *  compatibility policy.
+ **/
+static s32
+e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 sw_timeout = hw->nvm.word_size + 1;
+	s32 fw_timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	DEBUGFUNC("e1000_get_hw_semaphore_82571");
+
+	/*
+	 * After three SMBI timeouts, minimize interference with an older
+	 * peer driver which may not release the inter-port semaphore.
+	 */
+	if (hw->dev_spec._82571.smb_counter > 2)
+		sw_timeout = 1;
+
+	while (i < sw_timeout) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == sw_timeout) {
+		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+		hw->dev_spec._82571.smb_counter++;
+	}
+
+	for (i = 0; i < fw_timeout; i++) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM,
+		    swsm | E1000_SWSM_SWESMBI);
+		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+		usec_delay(50);
+	}
+
+	if (i == fw_timeout) {
+		e1000_put_hw_semaphore(hw);
+		DEBUGOUT("Driver can't access the NVM\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return E1000_SUCCESS;
+}
+
 /**
  *  e1000_acquire_nvm_82571 - Request for access to the EEPROM
  *  @hw: pointer to the HW structure
@@ -630,7 +686,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
 
 	DEBUGFUNC("e1000_acquire_nvm_82571");
 
-	ret_val = e1000_get_hw_semaphore(hw);
+	ret_val = e1000_get_hw_semaphore_82571(hw);
 	if (ret_val)
 		return ret_val;
 
diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c
index d0aebbce74d8..f8b512266acf 100644
--- a/sys/dev/e1000/e1000_82575.c
+++ b/sys/dev/e1000/e1000_82575.c
@@ -426,6 +426,10 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
 	mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync;
 	/* release SW_FW sync */
 	mac->ops.release_swfw_sync = e1000_release_swfw_sync;
+	if (mac->type == e1000_i210 || mac->type == e1000_i211) {
+		mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync_i210;
+		mac->ops.release_swfw_sync = e1000_release_swfw_sync_i210;
+	}
 
 	/* set lan id for port to determine which phy lock to use */
 	hw->mac.ops.set_lan_id(hw);
@@ -3532,4 +3536,3 @@ void e1000_i2c_bus_clear(struct e1000_hw *hw)
 	/* Put the i2c bus back to default state */
 	e1000_i2c_stop(hw);
 }
-
diff --git a/sys/dev/e1000/e1000_i210.c b/sys/dev/e1000/e1000_i210.c
index 4005034d7d31..a38e1c10ab67 100644
--- a/sys/dev/e1000/e1000_i210.c
+++ b/sys/dev/e1000/e1000_i210.c
@@ -37,6 +37,7 @@
 
 static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw);
 static void e1000_release_nvm_i210(struct e1000_hw *hw);
+static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw);
 static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
 				u16 *data);
 static s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw);
@@ -57,7 +58,7 @@ static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw)
 
 	DEBUGFUNC("e1000_acquire_nvm_i210");
 
-	ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM);
+	ret_val = e1000_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
 
 	return ret_val;
 }
@@ -73,7 +74,128 @@ static void e1000_release_nvm_i210(struct e1000_hw *hw)
 {
 	DEBUGFUNC("e1000_release_nvm_i210");
 
-	e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM);
+	e1000_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  e1000_acquire_swfw_sync_i210 - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ **/
+s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 ret_val = E1000_SUCCESS;
+	s32 i = 0, timeout = 200;
+
+	DEBUGFUNC("e1000_acquire_swfw_sync_i210");
+	ASSERT_NO_LOCKS();
+
+	while (i < timeout) {
+		if (e1000_get_hw_semaphore_i210(hw)) {
+			ret_val = -E1000_ERR_SWFW_SYNC;
+			goto out;
+		}
+
+		swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		e1000_put_hw_semaphore(hw);
+		msec_delay_irq(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -E1000_ERR_SWFW_SYNC;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+	e1000_put_hw_semaphore(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_swfw_sync_i210 - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to release
+ **/
+void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	DEBUGFUNC("e1000_release_swfw_sync_i210");
+
+	while (e1000_get_hw_semaphore_i210(hw) != E1000_SUCCESS)
+		; /* Empty */
+
+	swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
+	swfw_sync &= (u32)~mask;
+	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
+	e1000_put_hw_semaphore(hw);
+}
+
+/**
+ *  e1000_get_hw_semaphore_i210 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ **/
+static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	DEBUGFUNC("e1000_get_hw_semaphore_i210");
+
+	while (i < timeout) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+		usec_delay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		/* Clear an unintentionally retained semaphore once. */
+		if (hw->dev_spec._82575.clear_semaphore_once) {
+			hw->dev_spec._82575.clear_semaphore_once = false;
+			e1000_put_hw_semaphore(hw);
+			for (i = 0; i < timeout; i++) {
+				swsm = E1000_READ_REG(hw, E1000_SWSM);
+				if (!(swsm & E1000_SWSM_SMBI))
+					break;
+				usec_delay(50);
+			}
+		}
+		if (i == timeout) {
+			DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
+			return -E1000_ERR_NVM;
+		}
+	}
+
+	for (i = 0; i < timeout; i++) {
+		swsm = E1000_READ_REG(hw, E1000_SWSM);
+		E1000_WRITE_REG(hw, E1000_SWSM,
+		    swsm | E1000_SWSM_SWESMBI);
+		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+		usec_delay(50);
+	}
+
+	if (i == timeout) {
+		e1000_put_hw_semaphore(hw);
+		DEBUGOUT("Driver can't access the NVM\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return E1000_SUCCESS;
 }
 
 /**
diff --git a/sys/dev/e1000/e1000_i210.h b/sys/dev/e1000/e1000_i210.h
index 6f82462246e0..1d648ce41261 100644
--- a/sys/dev/e1000/e1000_i210.h
+++ b/sys/dev/e1000/e1000_i210.h
@@ -46,6 +46,8 @@ s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset,
 s32 e1000_read_invm_version(struct e1000_hw *hw,
 			    struct e1000_fw_version *invm_ver);
 s32 e1000_init_hw_i210(struct e1000_hw *hw);
+s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
+void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
 
 #define E1000_STM_OPCODE		0xDB00
 #define E1000_EEPROM_FLASH_SIZE_WORD	0x11
diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c
index dcebd9cf1eb9..a2e05498c681 100644
--- a/sys/dev/e1000/e1000_mac.c
+++ b/sys/dev/e1000/e1000_mac.c
@@ -2190,34 +2190,21 @@ s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
 }
 
 /**
- *  e1000_get_hw_semaphore - Acquire hardware semaphore
+ *  e1000_get_hw_semaphore_generic - Acquire hardware semaphore
  *  @hw: pointer to the HW structure
  *
  *  Acquire the HW semaphore to access the PHY or NVM
  **/
-s32 e1000_get_hw_semaphore(struct e1000_hw *hw)
+s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw)
 {
 	u32 swsm;
-	s32 fw_timeout = hw->nvm.word_size + 1;
-	s32 sw_timeout = hw->nvm.word_size + 1;
+	s32 timeout = hw->nvm.word_size + 1;
 	s32 i = 0;
 	
-	DEBUGFUNC("e1000_get_hw_semaphore");
-
-	/* _82571 */
-	/* If we have timedout 3 times on trying to acquire
-	 * the inter-port SMBI semaphore, there is old code
-	 * operating on the other port, and it is not
-	 * releasing SMBI. Modify the number of times that
-	 * we try for the semaphore to interwork with this
-	 * older code.
-	 */
-	if (hw->dev_spec._82571.smb_counter > 2)
-		sw_timeout = 1;
-
+	DEBUGFUNC("e1000_get_hw_semaphore_generic");
 
 	/* Get the SW semaphore */
-	while (i < sw_timeout) {
+	while (i < timeout) {
 		swsm = E1000_READ_REG(hw, E1000_SWSM);
 		if (!(swsm & E1000_SWSM_SMBI))
 			break;
@@ -2226,28 +2213,13 @@ s32 e1000_get_hw_semaphore(struct e1000_hw *hw)
 		i++;
 	}
 
-	if (i == sw_timeout) {
+	if (i == timeout) {
 		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
-		hw->dev_spec._82571.smb_counter++;
+		return -E1000_ERR_NVM;
 	}
 
-	/* In rare circumstances, the SW semaphore may already be held
-	 * unintentionally. Clear the semaphore once before giving up.
-	 */
-	if (hw->dev_spec._82575.clear_semaphore_once) {
-	 	hw->dev_spec._82575.clear_semaphore_once = false;
-		e1000_put_hw_semaphore(hw);
-		for (i = 0; i < fw_timeout; i++) {
-			swsm = E1000_READ_REG(hw, E1000_SWSM);
-	 		if (!(swsm & E1000_SWSM_SMBI))
-	 			break;
-
-	 		usec_delay(50);
-	 	}
-	 }
-
 	/* Get the FW semaphore. */
-	for (i = 0; i < fw_timeout; i++) {
+	for (i = 0; i < timeout; i++) {
 		swsm = E1000_READ_REG(hw, E1000_SWSM);
 		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
 
@@ -2258,7 +2230,7 @@ s32 e1000_get_hw_semaphore(struct e1000_hw *hw)
 		usec_delay(50);
 	}
 
-	if (i == fw_timeout) {
+	if (i == timeout) {
 		/* Release semaphores */
 		e1000_put_hw_semaphore(hw);
 		DEBUGOUT("Driver can't access the NVM\n");
@@ -2308,7 +2280,7 @@ e1000_acquire_swfw_sync(struct e1000_hw *hw, u16 mask)
 	DEBUGFUNC("e1000_acquire_swfw_sync");
 	ASSERT_NO_LOCKS();
 	while (i < timeout) {
-		if (e1000_get_hw_semaphore(hw)) {
+		if (e1000_get_hw_semaphore_generic(hw)) {
 			ret_val = -E1000_ERR_SWFW_SYNC;
 			goto out;
 		}
@@ -2356,7 +2328,7 @@ e1000_release_swfw_sync(struct e1000_hw *hw, u16 mask)
 
 	DEBUGFUNC("e1000_release_swfw_sync");
 
-	while (e1000_get_hw_semaphore(hw) != E1000_SUCCESS)
+	while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS)
 		; /* Empty */
 
 	swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
@@ -2365,4 +2337,3 @@ e1000_release_swfw_sync(struct e1000_hw *hw, u16 mask)
 
 	e1000_put_hw_semaphore(hw);
 }
-
diff --git a/sys/dev/e1000/e1000_mac.h b/sys/dev/e1000/e1000_mac.h
index a0d609e311d9..a08e64c4b23e 100644
--- a/sys/dev/e1000/e1000_mac.h
+++ b/sys/dev/e1000/e1000_mac.h
@@ -91,7 +91,7 @@ void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
 void e1000_update_adaptive_generic(struct e1000_hw *hw);
 void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
 
-s32  e1000_get_hw_semaphore(struct e1000_hw *hw);
+s32  e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
 void e1000_put_hw_semaphore(struct e1000_hw *hw);
 s32 e1000_acquire_swfw_sync(struct e1000_hw *hw, u16 mask);
 void e1000_release_swfw_sync(struct e1000_hw *hw, u16 mask);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.