On Mon, Apr 02, 2018 at 11:52:08AM +0200, Stefan Fritsch wrote: > Hi, > > We have seen problems with em on i219V and i219LM. For example, "Hardware > Initialization Failed" if no cable is plugged in during boot, or watchdog > timeouts / hangs until next boot if the cable is removed while data is > transmitted. > > This patch adds a bunch of quirks and fixes from freebsd. > > It would be nice if people could give it a try on various em(4) hardware > to check if there are any regressions. >
No regressions on em0 at pci0 dev 25 function 0 "Intel 82579LM" rev 0x04: msi, mac_type 0x1c phy_type 0xa (my x230). -ml > Comments on the patch are of course welcome, too. > > Cheers, > Stefan > > * Some em chips have a semaphore ("software flag") to synchronize access > to certain registers between OS and firmware (ME/AMT). > > Make the logic to get the flag match the logic in freebsd. This includes > higher timeouts and waiting for a previous unlock to complete before > trying a lock again. > > * Another problem was that openbsd em driver calls em_get_software_flag > recursively, which causes the semaphore to be unlocked too early. Make > em_get_software_flag/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. > > * Port the logic from freebsd to em_check_phy_reset_block(). A single > read does not seem to be reliable. > > * Also, increase delay after reset to 20ms, which is the value in freebsd > for ich8lan. > > * Add another magic 1ms delay that seems to help with some remaining issues > on an HP elitebook 820 G3. A printf() at the same place helps, too. > > * Port a silicon errata workaround from FreeBSD. > > > https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/i218-i219-ethernet-connection-spec-update.pdf?asset=9561 > > * While there, print mac+phy type in em_attach(). This makes it easier to > determine which quirks are hit/missing when comparing to freebsd. > > * Also print em_init_hw() error code if something goes wrong. > > > diff --git sys/dev/pci/if_em.c sys/dev/pci/if_em.c > index ec8e35245ef..f6a1f1c3894 100644 > --- sys/dev/pci/if_em.c > +++ sys/dev/pci/if_em.c > @@ -557,6 +557,8 @@ em_attach(struct device *parent, struct device *self, > void *aux) > if (!defer) > em_update_link_status(sc); > > + printf(", mac_type %#x phy_type %#x", sc->hw.mac_type, > + sc->hw.phy_type); > printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); > > /* Indicate SOL/IDER usage */ > @@ -1860,8 +1862,8 @@ em_hardware_init(struct em_softc *sc) > INIT_DEBUGOUT("\nHardware Initialization Deferred "); > return (EAGAIN); > } > - printf("\n%s: Hardware Initialization Failed\n", > - DEVNAME(sc)); > + printf("\n%s: Hardware Initialization Failed: %d\n", > + DEVNAME(sc), ret_val); > return (EIO); > } > > @@ -2265,7 +2267,9 @@ em_initialize_transmit_unit(struct em_softc *sc) > EM_WRITE_REG(&sc->hw, E1000_IOSFPC, reg_val); > > reg_val = E1000_READ_REG(&sc->hw, TARC0); > - reg_val |= E1000_TARC0_CB_MULTIQ_3_REQ; > + /* i218-i219 Specification Update 1.5.4.5 */ > + reg_val &= ~E1000_TARC0_CB_MULTIQ_3_REQ; > + reg_val |= E1000_TARC0_CB_MULTIQ_2_REQ; > E1000_WRITE_REG(&sc->hw, TARC0, reg_val); > } > } > diff --git sys/dev/pci/if_em_hw.c sys/dev/pci/if_em_hw.c > index df0fa571736..d122e727875 100644 > --- sys/dev/pci/if_em_hw.c > +++ sys/dev/pci/if_em_hw.c > @@ -945,7 +945,9 @@ em_reset_hw(struct em_hw *hw) > } > em_get_software_flag(hw); > E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); > - msec_delay(5); > + /* HW reset releases software_flag */ > + hw->sw_flag = 0; > + msec_delay(20); > > /* Ungate automatic PHY configuration on non-managed 82579 */ > if (hw->mac_type == em_pch2lan && !hw->phy_reset_disable && > @@ -1491,6 +1493,8 @@ em_init_hw(struct em_hw *hw) > /* Set the media type and TBI compatibility */ > em_set_media_type(hw); > > + /* Magic delay that improves problems with i219LM on HP Elitebook */ > + msec_delay(1); > /* Must be called after em_set_media_type because media_type is used */ > em_initialize_hardware_bits(hw); > > @@ -9539,9 +9543,18 @@ em_check_phy_reset_block(struct em_hw *hw) > DEBUGFUNC("em_check_phy_reset_block\n"); > > if (IS_ICH8(hw->mac_type)) { > - fwsm = E1000_READ_REG(hw, FWSM); > - return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS : > - E1000_BLK_PHY_RESET; > + int i = 0; > + int blocked = 0; > + do { > + fwsm = E1000_READ_REG(hw, FWSM); > + if (!(fwsm & E1000_FWSM_RSPCIPHY)) { > + blocked = 1; > + msec_delay(10); > + continue; > + } > + blocked = 0; > + } while (blocked && (i++ < 30)); > + return blocked ? E1000_BLK_PHY_RESET : E1000_SUCCESS; > } > if (hw->mac_type > em_82547_rev_2) > manc = E1000_READ_REG(hw, MANC); > @@ -9602,11 +9615,27 @@ 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); > - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; > - E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); > + if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) > + break; > + msec_delay_irq(1); > + timeout--; > + } > + if (!timeout) { > + printf("%s: SW has already locked the resource?\n", > + __func__); > + return -E1000_ERR_CONFIG; > + } > + timeout = SW_FLAG_TIMEOUT; > + extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; > + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); > > + while (timeout) { > extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); > if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) > break; > @@ -9615,10 +9644,15 @@ em_get_software_flag(struct em_hw *hw) > } > > if (!timeout) { > - DEBUGOUT("FW or HW locks the resource too long.\n"); > + printf("Failed to acquire the semaphore, FW or HW " > + "has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n", > + E1000_READ_REG(hw, FWSM), extcnf_ctrl); > + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; > + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); > return -E1000_ERR_CONFIG; > } > } > + hw->sw_flag++; > return E1000_SUCCESS; > } > > @@ -9638,6 +9672,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 5e415e60a34..9c2cfe97569 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 */ > @@ -2295,6 +2296,7 @@ struct em_hw { > #define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters > */ > > /* TRAC0 bits */ > +#define E1000_TARC0_CB_MULTIQ_2_REQ (1 << 29) > #define E1000_TARC0_CB_MULTIQ_3_REQ (1 << 28 | 1 << 29) > > /* Management Control */ > @@ -2755,6 +2757,8 @@ struct em_host_command_info { > #define AUTO_READ_DONE_TIMEOUT 10 > /* Number of milliseconds we wait for PHY configuration done after MAC reset > */ > #define PHY_CFG_TIMEOUT 100 > +/* SW Semaphore flag timeout in ms */ > +#define SW_FLAG_TIMEOUT 1000 > > #define E1000_TX_BUFFER_SIZE ((uint32_t)1514) > >