Index: sys/dev/e1000/e1000_82571.c =================================================================== --- sys/dev/e1000/e1000_82571.c +++ sys/dev/e1000/e1000_82571.c @@ -515,7 +515,7 @@ u32 extcnf_ctrl; s32 i = 0; /* XXX assert that mutex is held */ - DEBUGFUNC("e1000_get_hw_semaphore_82573"); + DEBUGFUNC("e1000_get_hw_semaphore_82574"); ASSERT_CTX_LOCK_HELD(hw); extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); Index: sys/dev/e1000/e1000_api.h =================================================================== --- sys/dev/e1000/e1000_api.h +++ sys/dev/e1000/e1000_api.h @@ -100,6 +100,7 @@ s32 e1000_read_mac_addr(struct e1000_hw *hw); s32 e1000_read_pba_string(struct e1000_hw *hw, u8 *pba_num, u32 pba_num_size); s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size); +s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num); void e1000_reload_nvm(struct e1000_hw *hw); s32 e1000_update_nvm_checksum(struct e1000_hw *hw); s32 e1000_validate_nvm_checksum(struct e1000_hw *hw); Index: sys/dev/e1000/e1000_api.c =================================================================== --- sys/dev/e1000/e1000_api.c +++ sys/dev/e1000/e1000_api.c @@ -383,6 +383,7 @@ break; case E1000_DEV_ID_I210_COPPER_FLASHLESS: case E1000_DEV_ID_I210_SERDES_FLASHLESS: + case E1000_DEV_ID_I210_SGMII_FLASHLESS: case E1000_DEV_ID_I210_COPPER: case E1000_DEV_ID_I210_COPPER_OEM1: case E1000_DEV_ID_I210_COPPER_IT: @@ -1268,6 +1269,21 @@ return e1000_read_pba_length_generic(hw, pba_num_size); } +/** + * e1000_read_pba_num - Read device part number + * @hw: pointer to the HW structure + * @pba_num: pointer to device part number + * + * Reads the product board assembly (PBA) number from the EEPROM and stores + * the value in pba_num. + * Currently no func pointer exists and all implementations are handled in the + * generic version of this function. + **/ +s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num) +{ + return e1000_read_pba_num_generic(hw, pba_num); +} + /** * e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum * @hw: pointer to the HW structure Index: sys/dev/e1000/e1000_defines.h =================================================================== --- sys/dev/e1000/e1000_defines.h +++ sys/dev/e1000/e1000_defines.h @@ -1069,11 +1069,44 @@ /* NVM Word Offsets */ #define NVM_COMPAT 0x0003 #define NVM_ID_LED_SETTINGS 0x0004 +#define NVM_VERSION 0x0005 #define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */ #define NVM_PHY_CLASS_WORD 0x0007 #define E1000_I210_NVM_FW_MODULE_PTR 0x0010 #define E1000_I350_NVM_FW_MODULE_PTR 0x0051 #define NVM_FUTURE_INIT_WORD1 0x0019 +#define NVM_ETRACK_WORD 0x0042 +#define NVM_ETRACK_HIWORD 0x0043 +#define NVM_COMB_VER_OFF 0x0083 +#define NVM_COMB_VER_PTR 0x003D + +/* NVM version defines */ +#define NVM_MAJOR_MASK 0xF000 +#define NVM_MINOR_MASK 0x0FF0 +#define NVM_IMAGE_ID_MASK 0x000F +#define NVM_COMB_VER_MASK 0x00FF +#define NVM_MAJOR_SHIFT 12 +#define NVM_MINOR_SHIFT 4 +#define NVM_COMB_VER_SHFT 8 +#define NVM_VER_INVALID 0xFFFF +#define NVM_ETRACK_SHIFT 16 +#define NVM_ETRACK_VALID 0x8000 +#define NVM_NEW_DEC_MASK 0x0F00 +#define NVM_HEX_CONV 16 +#define NVM_HEX_TENS 10 + +/* FW version defines */ +/* Offset of "Loader patch ptr" in Firmware Header */ +#define E1000_I350_NVM_FW_LOADER_PATCH_PTR_OFFSET 0x01 +/* Patch generation hour & minutes */ +#define E1000_I350_NVM_FW_VER_WORD1_OFFSET 0x04 +/* Patch generation month & day */ +#define E1000_I350_NVM_FW_VER_WORD2_OFFSET 0x05 +/* Patch generation year */ +#define E1000_I350_NVM_FW_VER_WORD3_OFFSET 0x06 +/* Patch major & minor numbers */ +#define E1000_I350_NVM_FW_VER_WORD4_OFFSET 0x07 + #define NVM_MAC_ADDR 0x0000 #define NVM_SUB_DEV_ID 0x000B #define NVM_SUB_VEN_ID 0x000C Index: sys/dev/e1000/e1000_hw.h =================================================================== --- sys/dev/e1000/e1000_hw.h +++ sys/dev/e1000/e1000_hw.h @@ -209,6 +209,7 @@ #define E1000_DEV_ID_I210_SGMII 0x1538 #define E1000_DEV_ID_I210_COPPER_FLASHLESS 0x157B #define E1000_DEV_ID_I210_SERDES_FLASHLESS 0x157C +#define E1000_DEV_ID_I210_SGMII_FLASHLESS 0x15F6 #define E1000_DEV_ID_I211_COPPER 0x1539 #define E1000_DEV_ID_I354_BACKPLANE_1GBPS 0x1F40 #define E1000_DEV_ID_I354_SGMII 0x1F41 Index: sys/dev/e1000/e1000_i210.h =================================================================== --- sys/dev/e1000/e1000_i210.h +++ sys/dev/e1000/e1000_i210.h @@ -44,6 +44,8 @@ u16 words, u16 *data); s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +s32 e1000_read_invm_version(struct e1000_hw *hw, + struct e1000_fw_version *invm_ver); s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data); s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, Index: sys/dev/e1000/e1000_i210.c =================================================================== --- sys/dev/e1000/e1000_i210.c +++ sys/dev/e1000/e1000_i210.c @@ -195,6 +195,7 @@ } for (i = 0; i < words; i++) { + ret_val = -E1000_ERR_NVM; eewr = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | (data[i] << E1000_NVM_RW_REG_DATA) | E1000_NVM_RW_REG_START; @@ -343,6 +344,105 @@ return ret_val; } +/** + * e1000_read_invm_version - Reads iNVM version and image type + * @hw: pointer to the HW structure + * @invm_ver: version structure for the version read + * + * Reads iNVM version and image type. + **/ +s32 e1000_read_invm_version(struct e1000_hw *hw, + struct e1000_fw_version *invm_ver) +{ + u32 *record = NULL; + u32 *next_record = NULL; + u32 i = 0; + u32 invm_dword = 0; + u32 invm_blocks = E1000_INVM_SIZE - (E1000_INVM_ULT_BYTES_SIZE / + E1000_INVM_RECORD_SIZE_IN_BYTES); + u32 buffer[E1000_INVM_SIZE]; + s32 status = -E1000_ERR_INVM_VALUE_NOT_FOUND; + u16 version = 0; + + DEBUGFUNC("e1000_read_invm_version"); + + /* Read iNVM memory */ + for (i = 0; i < E1000_INVM_SIZE; i++) { + invm_dword = E1000_READ_REG(hw, E1000_INVM_DATA_REG(i)); + buffer[i] = invm_dword; + } + + /* Read version number */ + for (i = 1; i < invm_blocks; i++) { + record = &buffer[invm_blocks - i]; + next_record = &buffer[invm_blocks - i + 1]; + + /* Check if we have first version location used */ + if ((i == 1) && ((*record & E1000_INVM_VER_FIELD_ONE) == 0)) { + version = 0; + status = E1000_SUCCESS; + break; + } + /* Check if we have second version location used */ + else if ((i == 1) && + ((*record & E1000_INVM_VER_FIELD_TWO) == 0)) { + version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3; + status = E1000_SUCCESS; + break; + } + /* + * Check if we have odd version location + * used and it is the last one used + */ + else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) && + ((*record & 0x3) == 0)) || (((*record & 0x3) != 0) && + (i != 1))) { + version = (*next_record & E1000_INVM_VER_FIELD_TWO) + >> 13; + status = E1000_SUCCESS; + break; + } + /* + * Check if we have even version location + * used and it is the last one used + */ + else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) && + ((*record & 0x3) == 0)) { + version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3; + status = E1000_SUCCESS; + break; + } + } + + if (status == E1000_SUCCESS) { + invm_ver->invm_major = (version & E1000_INVM_MAJOR_MASK) + >> E1000_INVM_MAJOR_SHIFT; + invm_ver->invm_minor = version & E1000_INVM_MINOR_MASK; + } + /* Read Image Type */ + for (i = 1; i < invm_blocks; i++) { + record = &buffer[invm_blocks - i]; + next_record = &buffer[invm_blocks - i + 1]; + + /* Check if we have image type in first location used */ + if ((i == 1) && ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) { + invm_ver->invm_img_type = 0; + status = E1000_SUCCESS; + break; + } + /* Check if we have image type in first location used */ + else if ((((*record & 0x3) == 0) && + ((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) || + ((((*record & 0x3) != 0) && (i != 1)))) { + invm_ver->invm_img_type = + (*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23; + status = E1000_SUCCESS; + break; + } + } + return status; +} + /** * e1000_validate_nvm_checksum_i210 - Validate EEPROM checksum * @hw: pointer to the HW structure Index: sys/dev/e1000/e1000_ich8lan.h =================================================================== --- sys/dev/e1000/e1000_ich8lan.h +++ sys/dev/e1000/e1000_ich8lan.h @@ -113,11 +113,12 @@ #define E1000_FEXTNVM7_DISABLE_PB_READ 0x00040000 #define E1000_FEXTNVM7_SIDE_CLK_UNGATE 0x00000004 #define E1000_FEXTNVM7_DISABLE_SMB_PERST 0x00000020 +#define E1000_FEXTNVM8_UNBIND_DPG_FROM_MPHY 0x00000400 #define E1000_FEXTNVM9_IOSFSB_CLKGATE_DIS 0x00000800 #define E1000_FEXTNVM9_IOSFSB_CLKREQ_DIS 0x00001000 #define E1000_FEXTNVM11_DISABLE_PB_READ 0x00000200 #define E1000_FEXTNVM11_DISABLE_MULR_FIX 0x00002000 - +#define E1000_FEXTNVM12_DONT_WAK_DPG_CLKREQ 0x00001000 /* bit24: RXDCTL thresholds granularity: 0 - cache lines, 1 - descriptors */ #define E1000_RXDCTL_THRESH_UNIT_DESC 0x01000000 @@ -327,6 +328,9 @@ #define E1000_SVCR_OFF_TIMER_SHIFT 16 #define E1000_SVT_OFF_HWM_MASK 0x0000001F +#define E1000_PCI_VENDOR_ID_REGISTER 0x00 +#define E1000_PCI_REVISION_ID_REG 0x08 + void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, bool state); void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); Index: sys/dev/e1000/e1000_ich8lan.c =================================================================== --- sys/dev/e1000/e1000_ich8lan.c +++ sys/dev/e1000/e1000_ich8lan.c @@ -3,21 +3,21 @@ Copyright (c) 2001-2015, Intel Corporation All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + 3. Neither the name of the Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -72,6 +72,7 @@ #include "e1000_api.h" +static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state); static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw); static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); @@ -730,6 +731,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) { struct e1000_mac_info *mac = &hw->mac; + u16 pci_cfg; DEBUGFUNC("e1000_init_mac_params_ich8lan"); @@ -808,6 +810,15 @@ e1000_update_mc_addr_list_pch2lan; /* fall-through */ case e1000_pchlan: + /* save PCH revision_id */ + e1000_read_pci_cfg(hw, E1000_PCI_REVISION_ID_REG, &pci_cfg); + /* SPT uses full byte for revision ID, + * as opposed to previous generations + */ + if (hw->mac.type >= e1000_pch_spt) + hw->revision_id = (u8)(pci_cfg &= 0x00FF); + else + hw->revision_id = (u8)(pci_cfg &= 0x000F); /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; /* ID LED init */ @@ -841,7 +852,7 @@ /** * __e1000_access_emi_reg_locked - Read/write EMI register * @hw: pointer to the HW structure - * @addr: EMI address to program + * @address: EMI address to program * @data: pointer to value to read/write from/to the EMI address * @read: boolean flag to indicate read or write * @@ -1279,34 +1290,35 @@ (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on)) return 0; - if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) { - /* Request ME configure ULP mode in the PHY */ - mac_reg = E1000_READ_REG(hw, E1000_H2ME); - mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; - E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); - - goto out; - } - if (!to_sx) { int i = 0; - /* Poll up to 5 seconds for Cable Disconnected indication */ while (!(E1000_READ_REG(hw, E1000_FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) { /* Bail if link is re-acquired */ if (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU) return -E1000_ERR_PHY; - if (i++ == 100) break; msec_delay(50); } DEBUGOUT2("CABLE_DISCONNECTED %s set after %dmsec\n", - (E1000_READ_REG(hw, E1000_FEXT) & - E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", - i * 50); + (E1000_READ_REG(hw, E1000_FEXT) & + E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", + i * 50); + if (!(E1000_READ_REG(hw, E1000_FEXT) & + E1000_FEXT_PHY_CABLE_DISCONNECTED)) + return 0; + } + + if (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID) { + /* Request ME configure ULP mode in the PHY */ + mac_reg = E1000_READ_REG(hw, E1000_H2ME); + mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; + E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); + + goto out; } ret_val = hw->phy.ops.acquire(hw); @@ -1376,6 +1388,15 @@ phy_reg |= I218_ULP_CONFIG1_START; e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + if (!to_sx) { + /* Disable Tx so that the MAC doesn't send any (buffered) + * packets to the PHY. + */ + mac_reg = E1000_READ_REG(hw, E1000_TCTL); + mac_reg &= ~E1000_TCTL_EN; + E1000_WRITE_REG(hw, E1000_TCTL, mac_reg); + } + if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) && to_sx && (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, @@ -1409,10 +1430,17 @@ * to disable ULP mode (force=FALSE); otherwise, for example when unloading * the driver or during Sx->S0 transitions, this is called with force=TRUE * to forcibly disable ULP. + + * When the cable is plugged in while the device is in D0, a Cable Status + * Change interrupt is generated which causes this function to be called + * to partially disable ULP mode and restart autonegotiation. This function + * is then called again due to the resulting Link Status Change interrupt + * to finish cleaning up after the ULP flow. */ s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) { s32 ret_val = E1000_SUCCESS; + u8 ulp_exit_timeout = 30; u32 mac_reg; u16 phy_reg; int i = 0; @@ -1434,10 +1462,12 @@ E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); } - /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */ + if (hw->mac.type == e1000_pch_cnp) + ulp_exit_timeout = 100; + while (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_ULP_CFG_DONE) { - if (i++ == 30) { + if (i++ == ulp_exit_timeout) { ret_val = -E1000_ERR_PHY; goto out; } @@ -1455,6 +1485,20 @@ mac_reg = E1000_READ_REG(hw, E1000_H2ME); mac_reg &= ~E1000_H2ME_ULP; E1000_WRITE_REG(hw, E1000_H2ME, mac_reg); + + /* Restore link speed advertisements and restart + * Auto-negotiation + */ + if (hw->mac.autoneg) { + ret_val = e1000_phy_setup_autoneg(hw); + if (ret_val) + goto out; + } else { + ret_val = e1000_setup_copper_link_generic(hw); + if (ret_val) + goto out; + } + ret_val = e1000_oem_bits_config_ich8lan(hw, true); } goto out; @@ -1464,6 +1508,16 @@ if (ret_val) goto out; + /* Revert the change to the 'Link Status Change' + * interrupt to trigger on 'Cable Status Change' + */ + ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES, + &phy_reg); + if (ret_val) + goto release; + phy_reg &= ~E1000_KMRNCTRLSTA_OP_MODES_LSC2CSC; + e1000_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_OP_MODES, phy_reg); + if (force) /* Toggle LANPHYPC Value bit */ e1000_toggle_lanphypc_pch_lpt(hw); @@ -1506,24 +1560,54 @@ ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); if (ret_val) goto release; - phy_reg &= ~(I218_ULP_CONFIG1_IND | - I218_ULP_CONFIG1_STICKY_ULP | - I218_ULP_CONFIG1_RESET_TO_SMBUS | - I218_ULP_CONFIG1_WOL_HOST | - I218_ULP_CONFIG1_INBAND_EXIT | - I218_ULP_CONFIG1_EN_ULP_LANPHYPC | - I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST | - I218_ULP_CONFIG1_DISABLE_SMB_PERST); - e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + /* CSC interrupt received due to ULP Indication */ + if ((phy_reg & I218_ULP_CONFIG1_IND) || force) { + phy_reg &= ~(I218_ULP_CONFIG1_IND | + I218_ULP_CONFIG1_STICKY_ULP | + I218_ULP_CONFIG1_RESET_TO_SMBUS | + I218_ULP_CONFIG1_WOL_HOST | + I218_ULP_CONFIG1_INBAND_EXIT | + I218_ULP_CONFIG1_EN_ULP_LANPHYPC | + I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST | + I218_ULP_CONFIG1_DISABLE_SMB_PERST); + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Commit ULP changes by starting auto ULP configuration */ + phy_reg |= I218_ULP_CONFIG1_START; + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Clear Disable SMBus Release on PERST# in MAC */ + mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7); + mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; + E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg); + + if (!force) { + hw->phy.ops.release(hw); + + if (hw->mac.autoneg) + e1000_phy_setup_autoneg(hw); + else + e1000_setup_copper_link_generic(hw); - /* Commit ULP changes by starting auto ULP configuration */ - phy_reg |= I218_ULP_CONFIG1_START; - e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + e1000_sw_lcd_config_ich8lan(hw); - /* Clear Disable SMBus Release on PERST# in MAC */ - mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM7); - mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; - E1000_WRITE_REG(hw, E1000_FEXTNVM7, mac_reg); + e1000_oem_bits_config_ich8lan(hw, true); + + /* Set ULP state to unknown and return non-zero to + * indicate no link (yet) and re-enter on the next LSC + * to finish disabling ULP flow. + */ + hw->dev_spec.ich8lan.ulp_state = + e1000_ulp_state_unknown; + + return 1; + } + } + + /* Re-enable Tx */ + mac_reg = E1000_READ_REG(hw, E1000_TCTL); + mac_reg |= E1000_TCTL_EN; + E1000_WRITE_REG(hw, E1000_TCTL, mac_reg); release: hw->phy.ops.release(hw); @@ -1553,7 +1637,7 @@ struct e1000_mac_info *mac = &hw->mac; s32 ret_val, tipg_reg = 0; u16 emi_addr, emi_val = 0; - bool link; + bool link = false; u16 phy_reg; DEBUGFUNC("e1000_check_for_copper_link_ich8lan"); @@ -1566,13 +1650,28 @@ if (!mac->get_link_status) return E1000_SUCCESS; - /* First we want to see if the MII Status Register reports - * link. If so, then we want to get the current speed/duplex - * of the PHY. - */ - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - return ret_val; + if ((hw->mac.type < e1000_pch_lpt) || + (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_LM) || + (hw->device_id == E1000_DEV_ID_PCH_LPT_I217_V)) { + /* First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + return ret_val; + } else { + /* Check the MAC's STATUS register to determine link state + * since the PHY could be inaccessible while in ULP mode. + */ + link = !!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU); + if (link) + ret_val = e1000_disable_ulp_lpt_lp(hw, false); + else + ret_val = e1000_enable_ulp_lpt_lp(hw, false); + if (ret_val) + return ret_val; + } if (hw->mac.type == e1000_pchlan) { ret_val = e1000_k1_gig_workaround_hv(hw, link); @@ -1619,8 +1718,6 @@ if (hw->mac.type >= e1000_pch_lpt) { - u16 phy_reg; - hw->phy.ops.read_reg_locked(hw, I217_PLL_CLOCK_GATE_REG, &phy_reg); phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; @@ -2474,7 +2571,7 @@ /** * e1000_configure_k1_ich8lan - Configure K1 power state * @hw: pointer to the HW structure - * @enable: K1 state to configure + * @k1_enable: K1 state to configure * * Configure the K1 power state based on the provided parameter. * Assumes semaphore already acquired. @@ -2622,6 +2719,7 @@ /** * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be * done after every PHY reset. + * @hw: pointer to the HW structure **/ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) { @@ -2943,6 +3041,7 @@ /** * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be * done after every PHY reset. + * @hw: pointer to the HW structure **/ static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) { @@ -4307,7 +4406,7 @@ (u8)(data >> 8)); if (ret_val) break; - } + } /* Don't bother writing the segment valid bits if sector * programming failed. @@ -4961,6 +5060,7 @@ u16 kum_cfg; u32 ctrl, reg; s32 ret_val; + u16 pci_cfg; DEBUGFUNC("e1000_reset_hw_ich8lan"); @@ -5021,11 +5121,28 @@ e1000_gate_hw_phy_config_ich8lan(hw, TRUE); } ret_val = e1000_acquire_swflag_ich8lan(hw); + + /* Read from EXTCNF_CTRL in e1000_acquire_swflag_ich8lan function + * may occur during global reset and cause system hang. + * Configuration space access creates the needed delay. + * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER value + * insures configuration space read is done before global reset. + */ + e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg); + E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg); DEBUGOUT("Issuing a global reset to ich8lan\n"); E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST)); /* cannot issue a flush here because it hangs the hardware */ msec_delay(20); + /* Configuration space access improve HW level time sync mechanism. + * Write to E1000_STRAP RO register E1000_PCI_VENDOR_ID_REGISTER + * value to insure configuration space read is done + * before any access to mac register. + */ + e1000_read_pci_cfg(hw, E1000_PCI_VENDOR_ID_REGISTER, &pci_cfg); + E1000_WRITE_REG(hw, E1000_STRAP, pci_cfg); + /* Set Phy Config Counter to 50msec */ if (hw->mac.type == e1000_pch2lan) { reg = E1000_READ_REG(hw, E1000_FEXTNVM3); @@ -5597,7 +5714,7 @@ void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) { s32 ret_val; - u16 reg_data; + u16 reg_data = 0; DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan"); Index: sys/dev/e1000/e1000_nvm.h =================================================================== --- sys/dev/e1000/e1000_nvm.h +++ sys/dev/e1000/e1000_nvm.h @@ -41,6 +41,21 @@ u16 *pba_block; }; +struct e1000_fw_version { + u32 etrack_id; + u16 eep_major; + u16 eep_minor; + u16 eep_build; + + u8 invm_major; + u8 invm_minor; + u8 invm_img_type; + + bool or_valid; + u16 or_major; + u16 or_build; + u16 or_patch; +}; void e1000_init_nvm_ops_generic(struct e1000_hw *hw); s32 e1000_null_read_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c); @@ -51,6 +66,7 @@ s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); s32 e1000_read_mac_addr_generic(struct e1000_hw *hw); +s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num); s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num, u32 pba_num_size); s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size); @@ -75,6 +91,8 @@ s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw); void e1000_stop_nvm(struct e1000_hw *hw); void e1000_release_nvm_generic(struct e1000_hw *hw); +void e1000_get_fw_version(struct e1000_hw *hw, + struct e1000_fw_version *fw_vers); #define E1000_STM_OPCODE 0xDB00 Index: sys/dev/e1000/e1000_nvm.c =================================================================== --- sys/dev/e1000/e1000_nvm.c +++ sys/dev/e1000/e1000_nvm.c @@ -63,6 +63,9 @@ /** * e1000_null_nvm_read - No-op function, return 0 * @hw: pointer to the HW structure + * @a: dummy variable + * @b: dummy variable + * @c: dummy variable **/ s32 e1000_null_read_nvm(struct e1000_hw E1000_UNUSEDARG *hw, u16 E1000_UNUSEDARG a, u16 E1000_UNUSEDARG b, @@ -85,6 +88,7 @@ /** * e1000_null_led_default - No-op function, return 0 * @hw: pointer to the HW structure + * @data: dummy variable **/ s32 e1000_null_led_default(struct e1000_hw E1000_UNUSEDARG *hw, u16 E1000_UNUSEDARG *data) @@ -96,6 +100,9 @@ /** * e1000_null_write_nvm - No-op function, return 0 * @hw: pointer to the HW structure + * @a: dummy variable + * @b: dummy variable + * @c: dummy variable **/ s32 e1000_null_write_nvm(struct e1000_hw E1000_UNUSEDARG *hw, u16 E1000_UNUSEDARG a, u16 E1000_UNUSEDARG b, @@ -776,8 +783,9 @@ DEBUGFUNC("e1000_read_pba_string_generic"); - if ((hw->mac.type >= e1000_i210) && - !e1000_get_flash_presence_i210(hw)) { + if ((hw->mac.type == e1000_i210 || + hw->mac.type == e1000_i211) && + !e1000_get_flash_presence_i210(hw)) { DEBUGOUT("Flashless no PBA string\n"); return -E1000_ERR_NVM_PBA_SECTION; } @@ -931,6 +939,41 @@ return E1000_SUCCESS; } +/** + * e1000_read_pba_num_generic - Read device part number + * @hw: pointer to the HW structure + * @pba_num: pointer to device part number + * + * Reads the product board assembly (PBA) number from the EEPROM and stores + * the value in pba_num. + **/ +s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) +{ + s32 ret_val; + u16 nvm_data; + + DEBUGFUNC("e1000_read_pba_num_generic"); + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + return ret_val; + } else if (nvm_data == NVM_PBA_PTR_GUARD) { + DEBUGOUT("NVM Not Supported\n"); + return -E1000_NOT_IMPLEMENTED; + } + *pba_num = (u32)(nvm_data << 16); + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + return ret_val; + } + *pba_num |= nvm_data; + + return E1000_SUCCESS; +} + /** * e1000_read_pba_raw @@ -1233,4 +1276,116 @@ E1000_WRITE_FLUSH(hw); } +/** + * e1000_get_fw_version - Get firmware version information + * @hw: pointer to the HW structure + * @fw_vers: pointer to output version structure + * + * unsupported/not present features return 0 in version structure + **/ +void e1000_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers) +{ + u16 eeprom_verh, eeprom_verl, etrack_test, fw_version; + u8 q, hval, rem, result; + u16 comb_verh, comb_verl, comb_offset; + + memset(fw_vers, 0, sizeof(struct e1000_fw_version)); + + /* basic eeprom version numbers, bits used vary by part and by tool + * used to create the nvm images */ + /* Check which data format we have */ + switch (hw->mac.type) { + case e1000_i211: + e1000_read_invm_version(hw, fw_vers); + return; + case e1000_82575: + case e1000_82576: + case e1000_82580: + case e1000_i354: + hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test); + /* Use this format, unless EETRACK ID exists, + * then use alternate format + */ + if ((etrack_test & NVM_MAJOR_MASK) != NVM_ETRACK_VALID) { + hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version); + fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) + >> NVM_MAJOR_SHIFT; + fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK) + >> NVM_MINOR_SHIFT; + fw_vers->eep_build = (fw_version & NVM_IMAGE_ID_MASK); + goto etrack_id; + } + break; + case e1000_i210: + if (!(e1000_get_flash_presence_i210(hw))) { + e1000_read_invm_version(hw, fw_vers); + return; + } + /* fall through */ + case e1000_i350: + hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test); + /* find combo image version */ + hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset); + if ((comb_offset != 0x0) && + (comb_offset != NVM_VER_INVALID)) { + + hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset + + 1), 1, &comb_verh); + hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset), + 1, &comb_verl); + + /* get Option Rom version if it exists and is valid */ + if ((comb_verh && comb_verl) && + ((comb_verh != NVM_VER_INVALID) && + (comb_verl != NVM_VER_INVALID))) { + + fw_vers->or_valid = true; + fw_vers->or_major = + comb_verl >> NVM_COMB_VER_SHFT; + fw_vers->or_build = + (comb_verl << NVM_COMB_VER_SHFT) + | (comb_verh >> NVM_COMB_VER_SHFT); + fw_vers->or_patch = + comb_verh & NVM_COMB_VER_MASK; + } + } + break; + default: + hw->nvm.ops.read(hw, NVM_ETRACK_HIWORD, 1, &etrack_test); + return; + } + hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version); + fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) + >> NVM_MAJOR_SHIFT; + + /* check for old style version format in newer images*/ + if ((fw_version & NVM_NEW_DEC_MASK) == 0x0) { + eeprom_verl = (fw_version & NVM_COMB_VER_MASK); + } else { + eeprom_verl = (fw_version & NVM_MINOR_MASK) + >> NVM_MINOR_SHIFT; + } + /* Convert minor value to hex before assigning to output struct + * Val to be converted will not be higher than 99, per tool output + */ + q = eeprom_verl / NVM_HEX_CONV; + hval = q * NVM_HEX_TENS; + rem = eeprom_verl % NVM_HEX_CONV; + result = hval + rem; + fw_vers->eep_minor = result; + +etrack_id: + if ((etrack_test & NVM_MAJOR_MASK) == NVM_ETRACK_VALID) { + hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl); + hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh); + fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) + | eeprom_verl; + } else if ((etrack_test & NVM_ETRACK_VALID) == 0) { + hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verh); + hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verl); + fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) | + eeprom_verl; + } +} + Index: sys/dev/e1000/e1000_phy.h =================================================================== --- sys/dev/e1000/e1000_phy.h +++ sys/dev/e1000/e1000_phy.h @@ -276,6 +276,8 @@ #define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 #define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 /* enable K1 */ #define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */ +#define E1000_KMRNCTRLSTA_OP_MODES 0x1F /* Kumeran Modes of Operation */ +#define E1000_KMRNCTRLSTA_OP_MODES_LSC2CSC 0x0002 /* change LSC to CSC */ #define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 #define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Ctrl */ Index: sys/dev/e1000/e1000_phy.c =================================================================== --- sys/dev/e1000/e1000_phy.c +++ sys/dev/e1000/e1000_phy.c @@ -4148,12 +4148,13 @@ *data = E1000_READ_REG(hw, E1000_MPHY_DATA); /* Disable access to mPHY if it was originally disabled */ - if (locked) + if (locked) { ready = e1000_is_mphy_ready(hw); - if (!ready) - return -E1000_ERR_PHY; - E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, - E1000_MPHY_DIS_ACCESS); + if (!ready) + return -E1000_ERR_PHY; + E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, + E1000_MPHY_DIS_ACCESS); + } return E1000_SUCCESS; } @@ -4213,12 +4214,13 @@ E1000_WRITE_REG(hw, E1000_MPHY_DATA, data); /* Disable access to mPHY if it was originally disabled */ - if (locked) + if (locked) { ready = e1000_is_mphy_ready(hw); - if (!ready) - return -E1000_ERR_PHY; - E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, - E1000_MPHY_DIS_ACCESS); + if (!ready) + return -E1000_ERR_PHY; + E1000_WRITE_REG(hw, E1000_MPHY_ADDR_CTRL, + E1000_MPHY_DIS_ACCESS); + } return E1000_SUCCESS; } Index: sys/dev/e1000/e1000_regs.h =================================================================== --- sys/dev/e1000/e1000_regs.h +++ sys/dev/e1000/e1000_regs.h @@ -64,11 +64,15 @@ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ +#define E1000_FEXTNVM5 0x00014 /* Future Extended NVM 5 - RW */ #define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */ #define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */ +#define E1000_FEXTNVM8 0x5BB0 /* Future Extended NVM 8 - RW */ #define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */ #define E1000_FEXTNVM11 0x5BBC /* Future Extended NVM 11 - RW */ +#define E1000_FEXTNVM12 0x5BC0 /* Future Extended NVM 12 - RW */ #define E1000_PCIEANACFG 0x00F18 /* PCIE Analog Config */ +#define E1000_DPGFR 0x00FAC /* Dynamic Power Gate Force Control Register */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ #define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ #define E1000_VET 0x00038 /* VLAN Ether Type - RW */ @@ -168,6 +172,8 @@ #define E1000_EMIADD 0x10 /* Extended Memory Indirect Address */ #define E1000_EMIDATA 0x11 /* Extended Memory Indirect Data */ #define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */ +#define E1000_EEC_REG 0x12010 + #define E1000_I210_FLMNGCTL 0x12038 #define E1000_I210_FLMNGDATA 0x1203C #define E1000_I210_FLMNGCNT 0x12040 @@ -178,6 +184,9 @@ #define E1000_I210_FLA 0x1201C +#define E1000_SHADOWINF 0x12068 +#define E1000_FLFWUPDATE 0x12108 + #define E1000_INVM_DATA_REG(_n) (0x12120 + 4*(_n)) #define E1000_INVM_SIZE 64 /* Number of INVM Data Registers */ @@ -312,6 +321,7 @@ #define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */ #define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */ #define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ +/* Statistics Register Descriptions */ #define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ #define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ #define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ @@ -371,6 +381,7 @@ #define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ #define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ #define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +/* Interrupt Cause */ #define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */ #define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */ #define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */ @@ -493,12 +504,14 @@ #define E1000_WUC 0x05800 /* Wakeup Control - RW */ #define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ #define E1000_WUS 0x05810 /* Wakeup Status - RO */ +/* Management registers */ #define E1000_MANC 0x05820 /* Management Control - RW */ #define E1000_IPAV 0x05838 /* IP Address Valid - RW */ #define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ #define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ #define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ #define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ +/* MSI-X Table Register Descriptions */ #define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */ #define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ #define E1000_HOST_IF 0x08800 /* Host Interface */ @@ -513,10 +526,12 @@ #define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ /* Management Decision Filters */ #define E1000_MDEF(_n) (0x05890 + (4 * (_n))) +/* Semaphore registers */ #define E1000_SW_FW_SYNC 0x05B5C /* SW-FW Synchronization - RW */ #define E1000_CCMCTL 0x05B48 /* CCM Control Register */ #define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ #define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ +/* PCIe Register Description */ #define E1000_GCR 0x05B00 /* PCI-Ex Control */ #define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */ #define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ Index: sys/dev/e1000/e1000_vf.c =================================================================== --- sys/dev/e1000/e1000_vf.c +++ sys/dev/e1000/e1000_vf.c @@ -419,12 +419,13 @@ DEBUGOUT1("MC Addr Count = %d\n", mc_addr_count); + msgbuf[0] = E1000_VF_SET_MULTICAST; + if (mc_addr_count > 30) { msgbuf[0] |= E1000_VF_SET_MULTICAST_OVERFLOW; mc_addr_count = 30; } - msgbuf[0] = E1000_VF_SET_MULTICAST; msgbuf[0] |= mc_addr_count << E1000_VT_MSGINFO_SHIFT; for (i = 0; i < mc_addr_count; i++) { Index: sys/dev/e1000/if_em.c =================================================================== --- sys/dev/e1000/if_em.c +++ sys/dev/e1000/if_em.c @@ -233,6 +233,7 @@ PVID(0x8086, E1000_DEV_ID_I210_COPPER_OEM1, "Intel(R) I210 (OEM)"), PVID(0x8086, E1000_DEV_ID_I210_COPPER_FLASHLESS, "Intel(R) I210 Flashless (Copper)"), PVID(0x8086, E1000_DEV_ID_I210_SERDES_FLASHLESS, "Intel(R) I210 Flashless (SERDES)"), + PVID(0x8086, E1000_DEV_ID_I210_SGMII_FLASHLESS, "Intel(R) I210 Flashless (SGMII)"), PVID(0x8086, E1000_DEV_ID_I210_FIBER, "Intel(R) I210 (Fiber)"), PVID(0x8086, E1000_DEV_ID_I210_SERDES, "Intel(R) I210 (SERDES)"), PVID(0x8086, E1000_DEV_ID_I210_SGMII, "Intel(R) I210 (SGMII)"),