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);

Reply via email to