git: 262519268925 - main - e1000: Separate hardware semaphore policies by family
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 11 Aug 2026 20:10:43 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=26251926892585e0746c2b65227e56cf9b2fed58
commit 26251926892585e0746c2b65227e56cf9b2fed58
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-11 18:58:17 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
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);