📄 e1000.c
字号:
phy_data |= M88E1000_EPSCR_TX_CLK_25; /* Configure Master and Slave downshift values */ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); if (e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } /* SW Reset the PHY so all changes take effect */ ret_val = e1000_phy_reset(hw); if (ret_val < 0) { DEBUGOUT("Error Resetting the PHY\n"); return ret_val; } /* Options: * autoneg = 1 (default) * PHY will advertise value(s) parsed from * autoneg_advertised and fc * autoneg = 0 * PHY will be set to 10H, 10F, 100H, or 100F * depending on value parsed from forced_speed_duplex. */ /* Is autoneg enabled? This is enabled by default or by software override. * If so, call e1000_phy_setup_autoneg routine to parse the * autoneg_advertised and fc options. If autoneg is NOT enabled, then the * user should have provided a speed/duplex override. If so, then call * e1000_phy_force_speed_duplex to parse and set this up. */ /* Perform some bounds checking on the hw->autoneg_advertised * parameter. If this variable is zero, then set it to the default. */ hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT; /* If autoneg_advertised is zero, we assume it was not defaulted * by the calling code so we set to advertise full capability. */ if (hw->autoneg_advertised == 0) hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT; DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); ret_val = e1000_phy_setup_autoneg(hw); if (ret_val < 0) { DEBUGOUT("Error Setting up Auto-Negotiation\n"); return ret_val; } DEBUGOUT("Restarting Auto-Neg\n"); /* Restart auto-negotiation by setting the Auto Neg Enable bit and * the Auto Neg Restart bit in the PHY control register. */ if (e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); if (e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; }#if 0 /* Does the user want to wait for Auto-Neg to complete here, or * check at a later time (for example, callback routine). */ if (hw->wait_autoneg_complete) { ret_val = e1000_wait_autoneg(hw); if (ret_val < 0) { DEBUGOUT ("Error while waiting for autoneg to complete\n"); return ret_val; } }#else /* If we do not wait for autonegtation to complete I * do not see a valid link status. */ ret_val = e1000_wait_autoneg(hw); if (ret_val < 0) { DEBUGOUT("Error while waiting for autoneg to complete\n"); return ret_val; }#endif /* Check link status. Wait up to 100 microseconds for link to become * valid. */ for (i = 0; i < 10; i++) { if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } if (e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } if (phy_data & MII_SR_LINK_STATUS) { /* We have link, so we need to finish the config process: * 1) Set up the MAC to the current PHY speed/duplex * if we are on 82543. If we * are on newer silicon, we only need to configure * collision distance in the Transmit Control Register. * 2) Set up flow control on the MAC to that established with * the link partner. */ if (hw->mac_type >= e1000_82544) { e1000_config_collision_dist(hw); } else { ret_val = e1000_config_mac_to_phy(hw); if (ret_val < 0) { DEBUGOUT ("Error configuring MAC to PHY settings\n"); return ret_val; } } ret_val = e1000_config_fc_after_link_up(hw); if (ret_val < 0) { DEBUGOUT("Error Configuring Flow Control\n"); return ret_val; } DEBUGOUT("Valid link established!!!\n"); return 0; } udelay(10); } DEBUGOUT("Unable to establish link!!!\n"); return -E1000_ERR_NOLINK;}/******************************************************************************* Configures PHY autoneg and flow control advertisement settings** hw - Struct containing variables accessed by shared code******************************************************************************/static inte1000_phy_setup_autoneg(struct e1000_hw *hw){ uint16_t mii_autoneg_adv_reg; uint16_t mii_1000t_ctrl_reg; DEBUGFUNC(); /* Read the MII Auto-Neg Advertisement Register (Address 4). */ if (e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } /* Read the MII 1000Base-T Control Register (Address 9). */ if (e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } /* Need to parse both autoneg_advertised and fc and set up * the appropriate PHY registers. First we will parse for * autoneg_advertised software override. Since we can advertise * a plethora of combinations, we need to check each bit * individually. */ /* First we clear all the 10/100 mb speed bits in the Auto-Neg * Advertisement Register (Address 4) and the 1000 mb speed bits in * the 1000Base-T Control Register (Address 9). */ mii_autoneg_adv_reg &= ~REG4_SPEED_MASK; mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK; DEBUGOUT("autoneg_advertised %x\n", hw->autoneg_advertised); /* Do we want to advertise 10 Mb Half Duplex? */ if (hw->autoneg_advertised & ADVERTISE_10_HALF) { DEBUGOUT("Advertise 10mb Half duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; } /* Do we want to advertise 10 Mb Full Duplex? */ if (hw->autoneg_advertised & ADVERTISE_10_FULL) { DEBUGOUT("Advertise 10mb Full duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; } /* Do we want to advertise 100 Mb Half Duplex? */ if (hw->autoneg_advertised & ADVERTISE_100_HALF) { DEBUGOUT("Advertise 100mb Half duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; } /* Do we want to advertise 100 Mb Full Duplex? */ if (hw->autoneg_advertised & ADVERTISE_100_FULL) { DEBUGOUT("Advertise 100mb Full duplex\n"); mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; } /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ if (hw->autoneg_advertised & ADVERTISE_1000_HALF) { DEBUGOUT ("Advertise 1000mb Half duplex requested, request denied!\n"); } /* Do we want to advertise 1000 Mb Full Duplex? */ if (hw->autoneg_advertised & ADVERTISE_1000_FULL) { DEBUGOUT("Advertise 1000mb Full duplex\n"); mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; } /* Check for a software override of the flow control settings, and * setup the PHY advertisement registers accordingly. If * auto-negotiation is enabled, then software will have to set the * "PAUSE" bits to the correct value in the Auto-Negotiation * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation. * * 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 * but we do not support receiving pause frames). * 3: Both Rx and TX flow control (symmetric) are enabled. * other: No software override. The flow control configuration * in the EEPROM is used. */ switch (hw->fc) { case e1000_fc_none: /* 0 */ /* Flow control (RX & TX) is completely disabled by a * software over-ride. */ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); break; case e1000_fc_rx_pause: /* 1 */ /* RX Flow control is enabled, and TX Flow control is * disabled, by a software over-ride. */ /* Since there really isn't a way to advertise that we are * capable of RX Pause ONLY, we will advertise that we * support both symmetric and asymmetric RX PAUSE. Later * (in e1000_config_fc_after_link_up) we will disable the *hw's ability to send PAUSE frames. */ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); break; case e1000_fc_tx_pause: /* 2 */ /* TX Flow control is enabled, and RX Flow control is * disabled, by a software over-ride. */ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; break; case e1000_fc_full: /* 3 */ /* Flow control (both RX and TX) is enabled by a software * over-ride. */ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); break; default: DEBUGOUT("Flow control param set incorrectly\n"); return -E1000_ERR_CONFIG; } if (e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } DEBUGOUT("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); if (e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } return 0;}/******************************************************************************* 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.******************************************************************************/static voide1000_config_collision_dist(struct e1000_hw *hw){ uint32_t tctl; 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 inte1000_config_mac_to_phy(struct e1000_hw *hw){ uint32_t ctrl; uint16_t phy_data; DEBUGFUNC(); /* 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 (e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } 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 0;}/****************************************************************************** * 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. *****************************************************************************/static inte1000_force_mac_fc(struct e1000_hw *hw){ uint32_t ctrl; DEBUGFUNC(); /* 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 receive pause frames). * 3: Both Rx and TX flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ switch (hw->fc) { case e1000_fc_none: ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); break; case e1000_fc_rx_pause: ctrl &= (~E1000_CTRL_TFCE); ctrl |= E1000_CTRL_RFCE; break; case e1000_fc_tx_pause: ctrl &= (~E1000_CTRL_RFCE); ctrl |= E1000_CTRL_TFCE; break; case e1000_fc_full: ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -