The em driver calls em_get_software_flag() recursively, which causes the semaphore to be unlocked too early. Make em_get_software_flag and em_release_software_flag handle this correctly. Freebsd does not do this, but they have a mutex that probably allows them to detect recursive calls to e1000_acquire_swflag_ich8lan(). Reworking the openbsd driver to not recursively get the semaphore would be very invasive. --- sys/dev/pci/if_em_hw.c | 14 ++++++++++++++ sys/dev/pci/if_em_hw.h | 1 + 2 files changed, 15 insertions(+)
diff --git sys/dev/pci/if_em_hw.c sys/dev/pci/if_em_hw.c index 5bba83cbcd4..7709a4c5805 100644 --- sys/dev/pci/if_em_hw.c +++ sys/dev/pci/if_em_hw.c @@ -945,6 +945,8 @@ em_reset_hw(struct em_hw *hw) } em_get_software_flag(hw); E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); + /* HW reset releases software_flag */ + hw->sw_flag = 0; msec_delay(20); /* Ungate automatic PHY configuration on non-managed 82579 */ @@ -9611,6 +9613,10 @@ em_get_software_flag(struct em_hw *hw) DEBUGFUNC("em_get_software_flag"); if (IS_ICH8(hw->mac_type)) { + if (hw->sw_flag) { + hw->sw_flag++; + return E1000_SUCCESS; + } while (timeout) { extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) @@ -9644,6 +9650,7 @@ em_get_software_flag(struct em_hw *hw) return -E1000_ERR_CONFIG; } } + hw->sw_flag++; return E1000_SUCCESS; } @@ -9663,6 +9670,13 @@ em_release_software_flag(struct em_hw *hw) DEBUGFUNC("em_release_software_flag"); if (IS_ICH8(hw->mac_type)) { + if (hw->sw_flag <= 0) { + printf("%s: not locked!\n", __func__); + return; + } + hw->sw_flag--; + if (hw->sw_flag > 0) + return; extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); diff --git sys/dev/pci/if_em_hw.h sys/dev/pci/if_em_hw.h index 71dc91e5582..91993a6eb66 100644 --- sys/dev/pci/if_em_hw.h +++ sys/dev/pci/if_em_hw.h @@ -1634,6 +1634,7 @@ struct em_hw { uint8_t bus_func; uint16_t swfw; boolean_t eee_enable; + int sw_flag; }; #define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */ -- 2.13.0