📄 e1000_hw.c
字号:
DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg); if(ret_val) return ret_val; return E1000_SUCCESS;}/******************************************************************************* Force PHY speed and duplex settings to hw->forced_speed_duplex** hw - Struct containing variables accessed by shared code******************************************************************************/static int32_te1000_phy_force_speed_duplex(struct e1000_hw *hw){ uint32_t ctrl; int32_t ret_val; uint16_t mii_ctrl_reg; uint16_t mii_status_reg; uint16_t phy_data; uint16_t i; DEBUGFUNC("e1000_phy_force_speed_duplex"); /* Turn off Flow control if we are forcing speed and duplex. */ hw->fc = e1000_fc_none; DEBUGOUT1("hw->fc = %d\n", hw->fc); /* Read the Device Control Register. */ ctrl = E1000_READ_REG(hw, CTRL); /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ctrl &= ~(DEVICE_SPEED_MASK); /* Clear the Auto Speed Detect Enable bit. */ ctrl &= ~E1000_CTRL_ASDE; /* Read the MII Control Register. */ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg); if(ret_val) return ret_val; /* We need to disable autoneg in order to force link and duplex. */ mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN; /* Are we forcing Full or Half Duplex? */ if(hw->forced_speed_duplex == e1000_100_full || hw->forced_speed_duplex == e1000_10_full) { /* We want to force full duplex so we SET the full duplex bits in the * Device and MII Control Registers. */ ctrl |= E1000_CTRL_FD; mii_ctrl_reg |= MII_CR_FULL_DUPLEX; DEBUGOUT("Full Duplex\n"); } else { /* We want to force half duplex so we CLEAR the full duplex bits in * the Device and MII Control Registers. */ ctrl &= ~E1000_CTRL_FD; mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX; DEBUGOUT("Half Duplex\n"); } /* Are we forcing 100Mbps??? */ if(hw->forced_speed_duplex == e1000_100_full || hw->forced_speed_duplex == e1000_100_half) { /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */ ctrl |= E1000_CTRL_SPD_100; mii_ctrl_reg |= MII_CR_SPEED_100; mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); DEBUGOUT("Forcing 100mb "); } else { /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); mii_ctrl_reg |= MII_CR_SPEED_10; mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); DEBUGOUT("Forcing 10mb "); } e1000_config_collision_dist(hw); /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); if (hw->phy_type == e1000_phy_m88) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if(ret_val) return ret_val; /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI * forced whenever speed are duplex are forced. */ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data); /* Need to reset the PHY or these changes will be ignored */ mii_ctrl_reg |= MII_CR_RESET; } else { /* Clear Auto-Crossover to force MDI manually. IGP requires MDI * forced whenever speed or duplex are forced. */ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); if(ret_val) return ret_val; phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); if(ret_val) return ret_val; } /* Write back the modified PHY MII control register. */ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg); if(ret_val) return ret_val; udelay(1); /* The wait_autoneg_complete flag may be a little misleading here. * Since we are forcing speed and duplex, Auto-Neg is not enabled. * But we do want to delay for a period while forcing only so we * don't generate false No Link messages. So we will wait here * only if the user has set wait_autoneg_complete to 1, which is * the default. */ if(hw->wait_autoneg_complete) { /* We will wait for autoneg to complete. */ DEBUGOUT("Waiting for forced speed/duplex link.\n"); mii_status_reg = 0; /* We will wait for autoneg to complete or 4.5 seconds to expire. */ for(i = PHY_FORCE_TIME; i > 0; i--) { /* Read the MII Status Register and wait for Auto-Neg Complete bit * to be set. */ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); if(ret_val) return ret_val; ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); if(ret_val) return ret_val; if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } if((i == 0) && (hw->phy_type == e1000_phy_m88)) { /* We didn't get link. Reset the DSP and wait again for link. */ ret_val = e1000_phy_reset_dsp(hw); if(ret_val) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; } } /* This loop will early-out if the link condition has been met. */ for(i = PHY_FORCE_TIME; i > 0; i--) { if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); /* Read the MII Status Register and wait for Auto-Neg Complete bit * to be set. */ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); if(ret_val) return ret_val; ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg); if(ret_val) return ret_val; } } if (hw->phy_type == e1000_phy_m88) { /* Because we reset the PHY above, we need to re-force TX_CLK in the * Extended PHY Specific Control Register to 25MHz clock. This value * defaults back to a 2.5MHz clock when the PHY is reset. */ ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if(ret_val) return ret_val; phy_data |= M88E1000_EPSCR_TX_CLK_25; ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; /* In addition, because of the s/w reset above, we need to enable CRS on * TX. This must be set for both full and half duplex operation. */ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if(ret_val) return ret_val; phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if(ret_val) return ret_val; if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) && (!hw->autoneg) && (hw->forced_speed_duplex == e1000_10_full || hw->forced_speed_duplex == e1000_10_half)) { ret_val = e1000_polarity_reversal_workaround(hw); if(ret_val) return ret_val; } } return E1000_SUCCESS;}/******************************************************************************* Sets the collision distance in the Transmit Control register** hw - Struct containing variables accessed by shared code** Link should have been established previously. Reads the speed and duplex* information from the Device Status register.******************************************************************************/voide1000_config_collision_dist(struct e1000_hw *hw){ uint32_t tctl; DEBUGFUNC("e1000_config_collision_dist"); tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_COLD; tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; E1000_WRITE_REG(hw, TCTL, tctl); E1000_WRITE_FLUSH(hw);}/******************************************************************************* Sets MAC speed and duplex settings to reflect the those in the PHY** hw - Struct containing variables accessed by shared code* mii_reg - data to write to the MII control register** The contents of the PHY register containing the needed information need to* be passed in.******************************************************************************/static int32_te1000_config_mac_to_phy(struct e1000_hw *hw){ uint32_t ctrl; int32_t ret_val; uint16_t phy_data; DEBUGFUNC("e1000_config_mac_to_phy"); /* Read the Device Control Register and set the bits to Force Speed * and Duplex. */ ctrl = E1000_READ_REG(hw, CTRL); ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS); /* Set up duplex in the Device Control and Transmit Control * registers depending on negotiated values. */ if (hw->phy_type == e1000_phy_igp) { ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data); if(ret_val) return ret_val; if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD; else ctrl &= ~E1000_CTRL_FD; e1000_config_collision_dist(hw); /* Set up speed in the Device Control register depending on * negotiated values. */ if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) ctrl |= E1000_CTRL_SPD_1000; else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_100MBPS) ctrl |= E1000_CTRL_SPD_100; } else { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if(ret_val) return ret_val; if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD; else ctrl &= ~E1000_CTRL_FD; e1000_config_collision_dist(hw); /* Set up speed in the Device Control register depending on * negotiated values. */ if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) ctrl |= E1000_CTRL_SPD_1000; else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) ctrl |= E1000_CTRL_SPD_100; } /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); return E1000_SUCCESS;}/****************************************************************************** * Forces the MAC's flow control settings. * * hw - Struct containing variables accessed by shared code * * Sets the TFCE and RFCE bits in the device control register to reflect * the adapter settings. TFCE and RFCE need to be explicitly set by * software when a Copper PHY is used because autonegotiation is managed * by the PHY rather than the MAC. Software must also configure these * bits when link is forced on a fiber connection. *****************************************************************************/int32_te1000_force_mac_fc(struct e1000_hw *hw){ uint32_t ctrl; DEBUGFUNC("e1000_force_mac_fc"); /* Get the current configuration of the Device Control Register */ ctrl = E1000_READ_REG(hw, CTRL); /* Because we didn't get link via the internal auto-negotiation * mechanism (we either forced link or we got link via PHY * auto-neg), we have to manually enable/disable transmit an * receive flow control. * * The "Case" statement below enables/disable flow control * according to the "hw->fc" parameter. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled * 1: Rx flow control is enabled (we can receive pause * frames but not send pause frames). * 2: Tx flow control is enabled (we can send pause frames * frames but we do not rec
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -