📄 e1000_ich8lan.c
字号:
* routines for the PHY and NVM parts. **/static void e1000_release_swflag_ich8lan(struct e1000_hw *hw){ u32 extcnf_ctrl; DEBUGFUNC("e1000_release_swflag_ich8lan"); extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); return;}/** * e1000_check_mng_mode_ich8lan - Checks management mode * @hw: pointer to the HW structure * * This checks if the adapter has manageability enabled. * This is a function pointer entry point only called by read/write * routines for the PHY and NVM parts. **/static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw){ u32 fwsm; DEBUGFUNC("e1000_check_mng_mode_ich8lan"); fwsm = E1000_READ_REG(hw, E1000_FWSM); return ((fwsm & E1000_FWSM_MODE_MASK) == (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));}/** * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked * @hw: pointer to the HW structure * * Checks if firmware is blocking the reset of the PHY. * This is a function pointer entry point only called by * reset routines. **/static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw){ u32 fwsm; DEBUGFUNC("e1000_check_reset_block_ich8lan"); fwsm = E1000_READ_REG(hw, E1000_FWSM); return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS : E1000_BLK_PHY_RESET;}/** * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex * @hw: pointer to the HW structure * * Forces the speed and duplex settings of the PHY. * This is a function pointer entry point only called by * PHY setup routines. **/static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 data; bool link; DEBUGFUNC("e1000_phy_force_speed_duplex_ich8lan"); if (phy->type != e1000_phy_ife) { ret_val = e1000_phy_force_speed_duplex_igp(hw); goto out; } ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); if (ret_val) goto out; e1000_phy_force_speed_duplex_setup(hw, &data); ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); if (ret_val) goto out; /* Disable MDI-X support for 10/100 */ ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); if (ret_val) goto out; data &= ~IFE_PMC_AUTO_MDIX; data &= ~IFE_PMC_FORCE_MDIX; ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); if (ret_val) goto out; DEBUGOUT1("IFE PMC: %X\n", data); usec_delay(1); if (phy->autoneg_wait_to_complete) { DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, 100000, &link); if (ret_val) goto out; if (!link) { DEBUGOUT("Link taking longer than expected.\n"); } /* Try once more */ ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, 100000, &link); if (ret_val) goto out; }out: return ret_val;}/** * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure * * Resets the PHY * This is a function pointer entry point called by drivers * or other shared routines. **/static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; struct e1000_nvm_info *nvm = &hw->nvm; u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; s32 ret_val; u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT; u16 word_addr, reg_data, reg_addr, phy_page = 0; DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); ret_val = e1000_phy_hw_reset_generic(hw); if (ret_val) goto out; /* * Initialize the PHY from the NVM on ICH platforms. This * is needed due to an issue where the NVM configuration is * not properly autoloaded after power transitions. * Therefore, after each PHY reset, we will load the * configuration data out of the NVM manually. */ if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { /* Check if SW needs configure the PHY */ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || (hw->device_id == E1000_DEV_ID_ICH8_IGP_M)) sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; else sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; data = E1000_READ_REG(hw, E1000_FEXTNVM); if (!(data & sw_cfg_mask)) goto out; /* Wait for basic configuration completes before proceeding*/ do { data = E1000_READ_REG(hw, E1000_STATUS); data &= E1000_STATUS_LAN_INIT_DONE; usec_delay(100); } while ((!data) && --loop); /* * If basic configuration is incomplete before the above loop * count reaches 0, loading the configuration from NVM will * leave the PHY in a bad state possibly resulting in no link. */ if (loop == 0) { DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n"); } /* Clear the Init Done bit for the next init event */ data = E1000_READ_REG(hw, E1000_STATUS); data &= ~E1000_STATUS_LAN_INIT_DONE; E1000_WRITE_REG(hw, E1000_STATUS, data); /* * Make sure HW does not configure LCD from PHY * extended configuration before SW configuration */ data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) goto out; cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; if (!cnf_size) goto out; cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; /* * Configure LCD from extended configuration * region. */ /* cnf_base_addr is in DWORD */ word_addr = (u16)(cnf_base_addr << 1); for (i = 0; i < cnf_size; i++) { ret_val = nvm->ops.read(hw, (word_addr + i * 2), 1, ®_data); if (ret_val) goto out; ret_val = nvm->ops.read(hw, (word_addr + i * 2 + 1), 1, ®_addr); if (ret_val) goto out; /* Save off the PHY page for future writes. */ if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { phy_page = reg_data; continue; } reg_addr |= phy_page; ret_val = phy->ops.write_reg(hw, (u32)reg_addr, reg_data); if (ret_val) goto out; } }out: return ret_val;}/** * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info * @hw: pointer to the HW structure * * Wrapper for calling the get_phy_info routines for the appropriate phy type. * This is a function pointer entry point called by drivers * or other shared routines. **/static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw){ s32 ret_val = -E1000_ERR_PHY_TYPE; DEBUGFUNC("e1000_get_phy_info_ich8lan"); switch (hw->phy.type) { case e1000_phy_ife: ret_val = e1000_get_phy_info_ife_ich8lan(hw); break; case e1000_phy_igp_3: case e1000_phy_bm: ret_val = e1000_get_phy_info_igp(hw); break; default: break; } return ret_val;}/** * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states * @hw: pointer to the HW structure * * Populates "phy" structure with various feature states. * This function is only called by other family-specific * routines. **/static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 data; bool link; DEBUGFUNC("e1000_get_phy_info_ife_ich8lan"); ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); if (ret_val) goto out; if (!link) { DEBUGOUT("Phy info is only valid if link is up\n"); ret_val = -E1000_ERR_CONFIG; goto out; } ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data); if (ret_val) goto out; phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) ? false : true; if (phy->polarity_correction) { ret_val = e1000_check_polarity_ife_ich8lan(hw); if (ret_val) goto out; } else { /* Polarity is forced */ phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) ? e1000_rev_polarity_reversed : e1000_rev_polarity_normal; } ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); if (ret_val) goto out; phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false; /* The following parameters are undefined for 10/100 operation. */ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; phy->local_rx = e1000_1000t_rx_status_undefined; phy->remote_rx = e1000_1000t_rx_status_undefined;out: return ret_val;}/** * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY * @hw: pointer to the HW structure * * Polarity is determined on the polarity reversal feature being enabled. * This function is only called by other family-specific * routines. **/static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 phy_data, offset, mask; DEBUGFUNC("e1000_check_polarity_ife_ich8lan"); /* * Polarity is determined based on the reversal feature * being enabled. */ if (phy->polarity_correction) { offset = IFE_PHY_EXTENDED_STATUS_CONTROL; mask = IFE_PESC_POLARITY_REVERSED; } else { offset = IFE_PHY_SPECIAL_CONTROL; mask = IFE_PSC_FORCE_POLARITY; } ret_val = phy->ops.read_reg(hw, offset, &phy_data); if (!ret_val) phy->cable_polarity = (phy_data & mask) ? e1000_rev_polarity_reversed : e1000_rev_polarity_normal; return ret_val;}/** * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state * @hw: pointer to the HW structure * @active: true to enable LPLU, false to disable * * Sets the LPLU D0 state according to the active flag. When * activating LPLU this function also disables smart speed * and vice versa. LPLU will not be activated unless the * device autonegotiation advertisement meets standards of * either 10 or 10/100 or 10/100/1000 at all duplexes. * This is a function pointer entry point only called by * PHY setup routines. **/static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active){ struct e1000_phy_info *phy = &hw->phy; u32 phy_ctrl; s32 ret_val = E1000_SUCCESS; u16 data; DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan"); if (phy->type == e1000_phy_ife) goto out; phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); if (active) { phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); /* * Call gig speed drop workaround on LPLU before accessing * any PHY registers */ if ((hw->mac.type == e1000_ich8lan) && (hw->phy.type == e1000_phy_igp_3)) e1000_gig_downshift_workaround_ich8lan(hw); /* When LPLU is enabled, we should disable SmartSpeed */ ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &data); data &= ~IGP01E1000_PSCFR_SMART_SPEED; ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, data); if (ret_val) goto out; } else { phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); /* * LPLU and SmartSpeed are mutually exclusive. LPLU is used * during Dx states where the power conservation is most * important. During driver activity we should enable * SmartSpeed, so performance is maintained. */ if (phy->smart_speed == e1000_smart_speed_on) { ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &data); if (ret_val) goto out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -