📄 e1000_hw.c
字号:
uint32_t ctrl, led_ctrl; int32_t ret_val; uint16_t i; uint16_t phy_data; DEBUGFUNC("e1000_setup_copper_link"); ctrl = E1000_READ_REG(hw, CTRL); /* With 82543, we need to force speed and duplex on the MAC equal to what * the PHY speed and duplex configuration is. In addition, we need to * perform a hardware reset on the PHY to take it out of reset. */ if(hw->mac_type > e1000_82543) { ctrl |= E1000_CTRL_SLU; ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); E1000_WRITE_REG(hw, CTRL, ctrl); } else { ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU); E1000_WRITE_REG(hw, CTRL, ctrl); e1000_phy_hw_reset(hw); } /* Make sure we have a valid PHY */ ret_val = e1000_detect_gig_phy(hw); if(ret_val < 0) { DEBUGOUT("Error, did not detect valid phy.\n"); return ret_val; } DEBUGOUT1("Phy ID = %x \n", hw->phy_id); if (hw->phy_type == e1000_phy_igp) { ret_val = e1000_phy_reset(hw); if(ret_val < 0) { DEBUGOUT("Error Resetting the PHY\n"); return ret_val; } /* Wait 10ms for MAC to configure PHY from eeprom settings */ msec_delay(15); if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } /* Configure activity LED after PHY reset */ led_ctrl = E1000_READ_REG(hw, LEDCTL); led_ctrl &= IGP_ACTIVITY_LED_MASK; led_ctrl |= IGP_ACTIVITY_LED_ENABLE; if(hw->mac_type == e1000_82547) led_ctrl |= IGP_LED3_MODE; E1000_WRITE_REG(hw, LEDCTL, led_ctrl); if(hw->autoneg_advertised == ADVERTISE_1000_FULL) { /* Disable SmartSpeed */ if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED; if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } /* Set auto Master/Slave resolution process */ if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } phy_data &= ~CR_1000T_MS_ENABLE; if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } } if(e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } /* Force MDI for IGP PHY */ phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX | IGP01E1000_PSCR_FORCE_MDI_MDIX); hw->mdix = 1; if(e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } } else { /* Enable CRS on TX. This must be set for half-duplex operation. */ if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; /* Options: * MDI/MDI-X = 0 (default) * 0 - Auto for all speeds * 1 - MDI mode * 2 - MDI-X mode * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) */ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; switch (hw->mdix) { case 1: phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; break; case 2: phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; break; case 3: phy_data |= M88E1000_PSCR_AUTO_X_1000T; break; case 0: default: phy_data |= M88E1000_PSCR_AUTO_X_MODE; break; } /* Options: * disable_polarity_correction = 0 (default) * Automatic Correction for Reversed Cable Polarity * 0 - Disabled * 1 - Enabled */ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; if(hw->disable_polarity_correction == 1) phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) { DEBUGOUT("PHY Write Error\n"); return -E1000_ERR_PHY; } /* Force TX_CLK in the Extended PHY Specific Control Register * to 25MHz clock. */ if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) { DEBUGOUT("PHY Read Error\n"); return -E1000_ERR_PHY; } phy_data |= M88E1000_EPSCR_TX_CLK_25; if (hw->phy_revision < M88E1011_I_REV_4) { /* 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. */ if(hw->autoneg) { /* 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; } /* 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; } } hw->get_link_status = TRUE; } else { DEBUGOUT("Forcing speed and duplex\n"); ret_val = e1000_phy_force_speed_duplex(hw); if(ret_val < 0) { DEBUGOUT("Error Forcing Speed and Duplex\n"); return ret_val; } } /* 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 0;}/******************************************************************************* Configures PHY autoneg and flow control advertisement settings** hw - Struct containing variables accessed by shared code******************************************************************************/int32_te1000_phy_setup_autoneg(struct e1000_hw *hw){ uint16_t mii_autoneg_adv_reg; uint16_t mii_1000t_ctrl_reg; DEBUGFUNC("e1000_phy_setup_autoneg"); /* 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; DEBUGOUT1("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? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -