📄 ich8lan.c
字号:
* control. Calls the appropriate media-specific link configuration * function. Assuming the adapter has a valid link partner, a valid link * should be established. Assumes the hardware has previously been reset * and the transmitter and receiver are not enabled. **/static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw){ s32 ret_val; if (e1000_check_reset_block(hw)) return 0; /* * ICH parts do not have a word in the NVM to determine * the default flow control setting, so we explicitly * set it to full. */ if (hw->fc.type == e1000_fc_default) hw->fc.type = e1000_fc_full; hw->fc.original_type = hw->fc.type; hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); /* Continue to configure the copper link. */ ret_val = e1000_setup_copper_link_ich8lan(hw); if (ret_val) return ret_val; ew32(FCTTV, hw->fc.pause_time); return e1000e_set_fc_watermarks(hw);}/** * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface * @hw: pointer to the HW structure * * Configures the kumeran interface to the PHY to wait the appropriate time * when polling the PHY, then call the generic setup_copper_link to finish * configuring the copper link. **/static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw){ u32 ctrl; s32 ret_val; u16 reg_data; ctrl = er32(CTRL); ctrl |= E1000_CTRL_SLU; ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ew32(CTRL, ctrl); /* * Set the mac to wait the maximum time between each iteration * and increase the max iterations when polling the phy; * this fixes erroneous timeouts at 10Mbps. */ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); if (ret_val) return ret_val; ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); if (ret_val) return ret_val; reg_data |= 0x3F; ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); if (ret_val) return ret_val; if (hw->phy.type == e1000_phy_igp_3) { ret_val = e1000e_copper_link_setup_igp(hw); if (ret_val) return ret_val; } else if (hw->phy.type == e1000_phy_bm) { ret_val = e1000e_copper_link_setup_m88(hw); if (ret_val) return ret_val; } if (hw->phy.type == e1000_phy_ife) { ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, ®_data); if (ret_val) return ret_val; reg_data &= ~IFE_PMC_AUTO_MDIX; switch (hw->phy.mdix) { case 1: reg_data &= ~IFE_PMC_FORCE_MDIX; break; case 2: reg_data |= IFE_PMC_FORCE_MDIX; break; case 0: default: reg_data |= IFE_PMC_AUTO_MDIX; break; } ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data); if (ret_val) return ret_val; } return e1000e_setup_copper_link(hw);}/** * e1000_get_link_up_info_ich8lan - Get current link speed and duplex * @hw: pointer to the HW structure * @speed: pointer to store current link speed * @duplex: pointer to store the current link duplex * * Calls the generic get_speed_and_duplex to retrieve the current link * information and then calls the Kumeran lock loss workaround for links at * gigabit speeds. **/static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, u16 *duplex){ s32 ret_val; ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); if (ret_val) return ret_val; if ((hw->mac.type == e1000_ich8lan) && (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); } return ret_val;}/** * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround * @hw: pointer to the HW structure * * Work-around for 82566 Kumeran PCS lock loss: * On link status change (i.e. PCI reset, speed change) and link is up and * speed is gigabit- * 0) if workaround is optionally disabled do nothing * 1) wait 1ms for Kumeran link to come up * 2) check Kumeran Diagnostic register PCS lock loss bit * 3) if not set the link is locked (all is good), otherwise... * 4) reset the PHY * 5) repeat up to 10 times * Note: this is only called for IGP3 copper when speed is 1gb. **/static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw){ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; u32 phy_ctrl; s32 ret_val; u16 i, data; bool link; if (!dev_spec->kmrn_lock_loss_workaround_enabled) return 0; /* * Make sure link is up before proceeding. If not just return. * Attempting this while link is negotiating fouled up link * stability */ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); if (!link) return 0; for (i = 0; i < 10; i++) { /* read once to clear */ ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); if (ret_val) return ret_val; /* and again to get new status */ ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); if (ret_val) return ret_val; /* check for PCS lock */ if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) return 0; /* Issue PHY reset */ e1000_phy_hw_reset(hw); mdelay(5); } /* Disable GigE link negotiation */ phy_ctrl = er32(PHY_CTRL); phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | E1000_PHY_CTRL_NOND0A_GBE_DISABLE); ew32(PHY_CTRL, phy_ctrl); /* * Call gig speed drop workaround on Gig disable before accessing * any PHY registers */ e1000e_gig_downshift_workaround_ich8lan(hw); /* unable to acquire PCS lock */ return -E1000_ERR_PHY;}/** * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state * @hw: pointer to the HW structure * @state: boolean value used to set the current Kumeran workaround state * * If ICH8, set the current Kumeran workaround state (enabled - TRUE * /disabled - FALSE). **/void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, bool state){ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; if (hw->mac.type != e1000_ich8lan) { hw_dbg(hw, "Workaround applies to ICH8 only.\n"); return; } dev_spec->kmrn_lock_loss_workaround_enabled = state;}/** * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 * @hw: pointer to the HW structure * * Workaround for 82566 power-down on D3 entry: * 1) disable gigabit link * 2) write VR power-down enable * 3) read it back * Continue if successful, else issue LCD reset and repeat **/void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw){ u32 reg; u16 data; u8 retry = 0; if (hw->phy.type != e1000_phy_igp_3) return; /* Try the workaround twice (if needed) */ do { /* Disable link */ reg = er32(PHY_CTRL); reg |= (E1000_PHY_CTRL_GBE_DISABLE | E1000_PHY_CTRL_NOND0A_GBE_DISABLE); ew32(PHY_CTRL, reg); /* * Call gig speed drop workaround on Gig disable before * accessing any PHY registers */ if (hw->mac.type == e1000_ich8lan) e1000e_gig_downshift_workaround_ich8lan(hw); /* Write VR power-down enable */ e1e_rphy(hw, IGP3_VR_CTRL, &data); data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN); /* Read it back and test */ e1e_rphy(hw, IGP3_VR_CTRL, &data); data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) break; /* Issue PHY reset and repeat at most one more time */ reg = er32(CTRL); ew32(CTRL, reg | E1000_CTRL_PHY_RST); retry++; } while (retry);}/** * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working * @hw: pointer to the HW structure * * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), * LPLU, Gig disable, MDIC PHY reset): * 1) Set Kumeran Near-end loopback * 2) Clear Kumeran Near-end loopback * Should only be called for ICH8[m] devices with IGP_3 Phy. **/void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw){ s32 ret_val; u16 reg_data; if ((hw->mac.type != e1000_ich8lan) || (hw->phy.type != e1000_phy_igp_3)) return; ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, ®_data); if (ret_val) return; reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, reg_data); if (ret_val) return; reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, reg_data);}/** * e1000e_disable_gig_wol_ich8lan - disable gig during WoL * @hw: pointer to the HW structure * * During S0 to Sx transition, it is possible the link remains at gig * instead of negotiating to a lower speed. Before going to Sx, set * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation * to a lower speed. * * Should only be called for ICH9 devices. **/void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw){ u32 phy_ctrl; if (hw->mac.type == e1000_ich9lan) { phy_ctrl = er32(PHY_CTRL); phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; ew32(PHY_CTRL, phy_ctrl); } return;}/** * e1000_cleanup_led_ich8lan - Restore the default LED operation * @hw: pointer to the HW structure * * Return the LED back to the default configuration. **/static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw){ if (hw->phy.type == e1000_phy_ife) return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); ew32(LEDCTL, hw->mac.ledctl_default); return 0;}/** * e1000_led_on_ich8lan - Turn LEDs on * @hw: pointer to the HW structure * * Turn on the LEDs. **/static s32 e1000_led_on_ich8lan(struct e1000_hw *hw){ if (hw->phy.type == e1000_phy_ife) return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); ew32(LEDCTL, hw->mac.ledctl_mode2); return 0;}/** * e1000_led_off_ich8lan - Turn LEDs off * @hw: pointer to the HW structure * * Turn off the LEDs. **/static s32 e1000_led_off_ich8lan(struct e1000_hw *hw){ if (hw->phy.type == e1000_phy_ife) return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); ew32(LEDCTL, hw->mac.ledctl_mode1); return 0;}/** * e1000_phy_init_script_igp3 - Inits the IGP3 PHY * @hw: pointer to the HW structure * * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. **/static s32 e1000_phy_init_script_igp3(struct e1000_hw *hw){ /* PHY init IGP 3 */ /* Enable rise/fall, 10-mode work in class-A */ e1e_wphy(hw, 0x2F5B, 0x9018); /* Remove all caps from Replica path filter */ e1e_wphy(hw, 0x2F52, 0x0000); /* Bias trimming for ADC, AFE and Driver (Default) */ e1e_wphy(hw, 0x2FB1, 0x8B24); /* Increase Hybrid poly bias */ e1e_wphy(hw, 0x2FB2, 0xF8F0); /* Add 4% to Tx amplitude in Gig mode */ e1e_wphy(hw, 0x2010, 0x10B0); /* Disable trimming (TTT) */ e1e_wphy(hw, 0x2011, 0x0000); /* Poly DC correction to 94.6% + 2% for all channels */ e1e_wphy(hw, 0x20DD, 0x249A); /* ABS DC correction to 95.9% */ e1e_wphy(hw, 0x20DE, 0x00D3); /* BG temp curve trim */ e1e_wphy(hw, 0x28B4, 0x04CE); /* Increasing ADC OPAMP stage 1 currents to max */ e1e_wphy(hw, 0x2F70, 0x29E4); /* Force 1000 ( required for enabling PHY regs configuration) */ e1e_wphy(hw, 0x0000, 0x0140); /* Set upd_freq to 6 */ e1e_wphy(hw, 0x1F30, 0x1606); /* Disable NPDFE */ e1e_wphy(hw, 0x1F31, 0xB814); /* Disable adaptive fixed FFE (Default) */ e1e_wphy(hw, 0x1F35, 0x002A); /* Enable FFE hysteresis */ e1e_wphy(hw, 0x1F3E, 0x0067); /* Fixed FFE for short cable lengths */ e1e_wphy(hw, 0x1F54, 0x0065); /* Fixed FFE for medium cable lengths */ e1e_wphy(hw, 0x1F55, 0x002A); /* Fixed FFE for long cable lengths */ e1e_wphy(hw, 0x1F56, 0x002A); /* Enable Adaptive Clip Threshold */ e1e_wphy(hw, 0x1F72, 0x3FB0); /* AHT reset limit to 1 */ e1e_wphy(hw, 0x1F76, 0xC0FF); /* Set AHT master delay to 127 msec */ e1e_wphy(hw, 0x1F77, 0x1DEC); /* Set scan bits for AHT */ e1e_wphy(hw, 0x1F78, 0xF9EF); /* Set AHT Preset bits */ e1e_wphy(hw, 0x1F79, 0x0210); /* Change integ_factor of channel A to 3 */ e1e_wphy(hw, 0x1895, 0x0003); /* Change prop_factor of channels BCD to 8 */ e1e_wphy(hw, 0x1796, 0x0008); /* Change cg_icount + enable integbp for channels BCD */ e1e_wphy(hw, 0x1798, 0xD008); /* * Change cg_icount + enable integbp + change prop_factor_master * to 8 for channel A */ e1e_wphy(hw, 0x1898, 0xD918); /* Disable AHT in Slave mode on channel A */ e1e_wphy(hw, 0x187A, 0x0800); /* * Enable LPLU and disable AN to 1000 in non-D0a states, * Enable SPD+B2B */ e1e_wphy(hw, 0x0019, 0x008D); /* Enable restart AN on an1000_dis change */ e1e_wphy(hw, 0x001B, 0x2080); /* Enable wh_fifo read clock in 10/100 modes */ e1e_wphy(hw, 0x0014, 0x0045); /* Restart AN, Speed selection is 1000 */ e1e_wphy(hw, 0x0000, 0x1340); return 0;}/** * e1000_get_cfg_done_ich8lan - Read config done bit * @hw: pointer to the HW structure * * Read the management control register for the config done bit for * completion status. NOTE: silicon which is EEPROM-less will fail trying * to read the config done bit, so an error is *ONLY* logged and returns * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon * would not be able to be reset or change link. **/sta
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -