/* Set up Op-code, Phy Address, and register offset in the MDI *Controlregister.TheMACwilltakecareofinterfacingwiththe *PHYtoretrievethedesireddata.
*/ for (retry_counter = 0; retry_counter <= retry_max; retry_counter++) {
success = true;
/* Poll the ready bit to see if the MDI read completed *Increasingthetimeoutastestingshowedfailureswith *thelowertimeout
*/ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
udelay(50);
mdic = er32(MDIC); if (mdic & E1000_MDIC_READY) break;
} if (!(mdic & E1000_MDIC_READY)) {
e_dbg("MDI Read PHY Reg Address %d did not complete\n",
offset);
success = false;
} if (mdic & E1000_MDIC_ERROR) {
e_dbg("MDI Read PHY Reg Address %d Error\n", offset);
success = false;
} if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
e_dbg("MDI Read offset error - requested %d, returned %d\n",
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
success = false;
}
/* Allow some time after each MDIC transaction to avoid *readingduplicatedatainthenextMDICtransaction.
*/ if (hw->mac.type == e1000_pch2lan)
udelay(100);
if (success) {
*data = (u16)mdic; return0;
}
if (retry_counter != retry_max) {
e_dbg("Perform retry on PHY transaction...\n");
mdelay(10);
}
}
/* Set up Op-code, Phy Address, and register offset in the MDI *Controlregister.TheMACwilltakecareofinterfacingwiththe *PHYtoretrievethedesireddata.
*/ for (retry_counter = 0; retry_counter <= retry_max; retry_counter++) {
success = true;
/* Poll the ready bit to see if the MDI read completed *Increasingthetimeoutastestingshowedfailureswith *thelowertimeout
*/ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
udelay(50);
mdic = er32(MDIC); if (mdic & E1000_MDIC_READY) break;
} if (!(mdic & E1000_MDIC_READY)) {
e_dbg("MDI Write PHY Reg Address %d did not complete\n",
offset);
success = false;
} if (mdic & E1000_MDIC_ERROR) {
e_dbg("MDI Write PHY Reg Address %d Error\n", offset);
success = false;
} if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
e_dbg("MDI Write offset error - requested %d, returned %d\n",
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
success = false;
}
/* Allow some time after each MDIC transaction to avoid *readingduplicatedatainthenextMDICtransaction.
*/ if (hw->mac.type == e1000_pch2lan)
udelay(100);
if (success) return0;
if (retry_counter != retry_max) {
e_dbg("Perform retry on PHY transaction...\n");
mdelay(10);
}
}
/* Enable CRS on Tx. This must be set for half-duplex operation. */
ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val;
/* For BM PHY this bit is downshift enable */ if (phy->type != e1000_phy_bm)
phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
/* Enable downshift on BM (disabled by default) */ if (phy->type == e1000_phy_bm) { /* For 82574/82583, first disable then enable downshift */ if (phy->id == BME1000_E_PHY_ID_R2) {
phy_data &= ~BME1000_PSCR_ENABLE_DOWNSHIFT;
ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL,
phy_data); if (ret_val) return ret_val; /* Commit the changes. */
ret_val = phy->ops.commit(hw); if (ret_val) {
e_dbg("Error committing the PHY changes\n"); return ret_val;
}
}
phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
}
ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if (ret_val) return ret_val;
if ((phy->type == e1000_phy_m88) &&
(phy->revision < E1000_REVISION_4) &&
(phy->id != BME1000_E_PHY_ID_R2)) { /* Force TX_CLK in the Extended PHY Specific Control Register *to25MHzclock.
*/
ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val;
phy_data |= M88E1000_EPSCR_TX_CLK_25;
if ((phy->revision == 2) && (phy->id == M88E1111_I_PHY_ID)) { /* 82573L PHY - set the downshift counter to 5x. */
phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
} else { /* 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);
}
ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); if (ret_val) return ret_val;
}
if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) { /* Set PHY page 0, register 29 to 0x0003 */
ret_val = e1e_wphy(hw, 29, 0x0003); if (ret_val) return ret_val;
/* Set PHY page 0, register 30 to 0x0000 */
ret_val = e1e_wphy(hw, 30, 0x0000); if (ret_val) return ret_val;
}
/* Commit the changes. */ if (phy->ops.commit) {
ret_val = phy->ops.commit(hw); if (ret_val) {
e_dbg("Error committing the PHY changes\n"); return ret_val;
}
}
if (phy->type == e1000_phy_82578) {
ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val;
/* 82578 PHY - set the downshift count to 1x. */
phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); if (ret_val) return ret_val;
}
ret_val = e1000_phy_hw_reset(hw); if (ret_val) {
e_dbg("Error resetting the PHY.\n"); return ret_val;
}
/* Wait 100ms for MAC to configure PHY from NVM settings, to avoid *timeoutissueswhenLFSisenabled.
*/
msleep(100);
/* disable lplu d0 during driver init */ if (hw->phy.ops.set_d0_lplu_state) {
ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); if (ret_val) {
e_dbg("Error Disabling LPLU D0\n"); return ret_val;
}
} /* Configure mdi-mdix settings */
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data); if (ret_val) return ret_val;
data &= ~IGP01E1000_PSCR_AUTO_MDIX;
switch (phy->mdix) { case1:
data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; break; case2:
data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; break; case0: default:
data |= IGP01E1000_PSCR_AUTO_MDIX; break;
}
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data); if (ret_val) return ret_val;
/* set auto-master slave resolution settings */ if (hw->mac.autoneg) { /* when autonegotiation advertisement is only 1000Mbps then we *shoulddisableSmartSpeedandenableAutoMasterSlave *resolutionashardwaredefault.
*/ if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { /* Disable SmartSpeed */
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
&data); if (ret_val) return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
data); if (ret_val) return ret_val;
/* Set auto Master/Slave resolution process */
ret_val = e1e_rphy(hw, MII_CTRL1000, &data); if (ret_val) return ret_val;
data &= ~CTL1000_ENABLE_MASTER;
ret_val = e1e_wphy(hw, MII_CTRL1000, data); if (ret_val) return ret_val;
}
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
ret_val = e1e_rphy(hw, MII_ADVERTISE, &mii_autoneg_adv_reg); if (ret_val) return ret_val;
if (phy->autoneg_mask & ADVERTISE_1000_FULL) { /* Read the MII 1000Base-T Control Register (Address 9). */
ret_val = e1e_rphy(hw, MII_CTRL1000, &mii_1000t_ctrl_reg); if (ret_val) return ret_val;
}
/* Need to parse both autoneg_advertised and fc and set up *theappropriatePHYregisters.Firstwewillparsefor *autoneg_advertisedsoftwareoverride.Sincewecanadvertise *aplethoraofcombinations,weneedtocheckeachbit *individually.
*/
/* First we clear all the 10/100 mb speed bits in the Auto-Neg *AdvertisementRegister(Address4)andthe1000mbspeedbitsin *the1000Base-TControlRegister(Address9).
*/
mii_autoneg_adv_reg &= ~(ADVERTISE_100FULL |
ADVERTISE_100HALF |
ADVERTISE_10FULL | ADVERTISE_10HALF);
mii_1000t_ctrl_reg &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
/* Do we want to advertise 10 Mb Half Duplex? */ if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
e_dbg("Advertise 10mb Half duplex\n");
mii_autoneg_adv_reg |= ADVERTISE_10HALF;
}
/* Do we want to advertise 10 Mb Full Duplex? */ if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
e_dbg("Advertise 10mb Full duplex\n");
mii_autoneg_adv_reg |= ADVERTISE_10FULL;
}
/* Do we want to advertise 100 Mb Half Duplex? */ if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
e_dbg("Advertise 100mb Half duplex\n");
mii_autoneg_adv_reg |= ADVERTISE_100HALF;
}
/* Do we want to advertise 100 Mb Full Duplex? */ if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
e_dbg("Advertise 100mb Full duplex\n");
mii_autoneg_adv_reg |= ADVERTISE_100FULL;
}
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */ if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
e_dbg("Advertise 1000mb Half duplex request denied!\n");
/* Do we want to advertise 1000 Mb Full Duplex? */ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
e_dbg("Advertise 1000mb Full duplex\n");
mii_1000t_ctrl_reg |= ADVERTISE_1000FULL;
}
/* Check for a software override of the flow control settings, and *setupthePHYadvertisementregistersaccordingly.If *auto-negotiationisenabled,thensoftwarewillhavetosetthe *"PAUSE"bitstothecorrectvalueintheAuto-Negotiation *AdvertisementRegister(MII_ADVERTISE)andre-startauto- *negotiation. * *Thepossiblevaluesofthe"fc"parameterare: *0:Flowcontroliscompletelydisabled *1:Rxflowcontrolisenabled(wecanreceivepauseframes *butnotsendpauseframes). *2:Txflowcontrolisenabled(wecansendpauseframes *butwedonotsupportreceivingpauseframes). *3:BothRxandTxflowcontrol(symmetric)areenabled. *other:Nosoftwareoverride.Theflowcontrolconfiguration *intheEEPROMisused.
*/ switch (hw->fc.current_mode) { case e1000_fc_none: /* Flow control (Rx & Tx) is completely disabled by a *softwareover-ride.
*/
mii_autoneg_adv_reg &=
~(ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
phy->autoneg_advertised &=
~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); break; case e1000_fc_rx_pause: /* Rx Flow control is enabled, and Tx Flow control is *disabled,byasoftwareover-ride. * *Sincetherereallyisn'tawaytoadvertisethatweare *capableofRxPauseONLY,wewilladvertisethatwe *supportbothsymmetricandasymmetricRxPAUSE.Later *(ine1000e_config_fc_after_link_up)wewilldisablethe *hw'sabilitytosendPAUSEframes.
*/
mii_autoneg_adv_reg |=
(ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
phy->autoneg_advertised |=
(ADVERTISED_Pause | ADVERTISED_Asym_Pause); break; case e1000_fc_tx_pause: /* Tx Flow control is enabled, and Rx Flow control is *disabled,byasoftwareover-ride.
*/
mii_autoneg_adv_reg |= ADVERTISE_PAUSE_ASYM;
mii_autoneg_adv_reg &= ~ADVERTISE_PAUSE_CAP;
phy->autoneg_advertised |= ADVERTISED_Asym_Pause;
phy->autoneg_advertised &= ~ADVERTISED_Pause; break; case e1000_fc_full: /* Flow control (both Rx and Tx) is enabled by a software *over-ride.
*/
mii_autoneg_adv_reg |=
(ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP);
phy->autoneg_advertised |=
(ADVERTISED_Pause | ADVERTISED_Asym_Pause); break; default:
e_dbg("Flow control param set incorrectly\n"); return -E1000_ERR_CONFIG;
}
ret_val = e1e_wphy(hw, MII_ADVERTISE, mii_autoneg_adv_reg); if (ret_val) return ret_val;
/* Perform some bounds checking on the autoneg advertisement *parameter.
*/
phy->autoneg_advertised &= phy->autoneg_mask;
/* If autoneg_advertised is zero, we assume it was not defaulted *bythecallingcodesowesettoadvertisefullcapability.
*/ if (!phy->autoneg_advertised)
phy->autoneg_advertised = phy->autoneg_mask;
e_dbg("Reconfiguring auto-neg advertisement params\n");
ret_val = e1000_phy_setup_autoneg(hw); if (ret_val) {
e_dbg("Error Setting up Auto-Negotiation\n"); return ret_val;
}
e_dbg("Restarting Auto-Neg\n");
/* Restart auto-negotiation by setting the Auto Neg Enable bit and *theAutoNegRestartbitinthePHYcontrolregister.
*/
ret_val = e1e_rphy(hw, MII_BMCR, &phy_ctrl); if (ret_val) return ret_val;
/* Does the user want to wait for Auto-Neg to complete here, or *checkatalatertime(forexample,callbackroutine).
*/ if (phy->autoneg_wait_to_complete) {
ret_val = e1000_wait_autoneg(hw); if (ret_val) {
e_dbg("Error while waiting for autoneg to complete\n"); return ret_val;
}
}
if (hw->mac.autoneg) { /* Setup autoneg and flow control advertisement and perform *autonegotiation.
*/
ret_val = e1000_copper_link_autoneg(hw); if (ret_val) return ret_val;
} else { /* PHY will be set to 10H, 10F, 100H or 100F *dependingonusersettings.
*/
e_dbg("Forcing Speed and Duplex\n");
ret_val = hw->phy.ops.force_speed_duplex(hw); if (ret_val) {
e_dbg("Error Forcing Speed and Duplex\n"); return ret_val;
}
}
/* Check link status. Wait up to 100 microseconds for link to become *valid.
*/
ret_val = e1000e_phy_has_link_generic(hw, COPPER_LINK_UP_LIMIT, 10,
&link); if (ret_val) return ret_val;
if (link) {
e_dbg("Valid link established!!!\n");
hw->mac.ops.config_collision_dist(hw);
ret_val = e1000e_config_fc_after_link_up(hw);
} else {
e_dbg("Unable to establish link!!!\n");
}
ret_val = e1e_wphy(hw, MII_BMCR, phy_data); if (ret_val) return ret_val;
/* Reset the phy to commit changes. */ if (hw->phy.ops.commit) {
ret_val = hw->phy.ops.commit(hw); if (ret_val) return ret_val;
}
if (phy->autoneg_wait_to_complete) {
e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, 100000, &link); if (ret_val) return ret_val;
if (!link) { if (hw->phy.type != e1000_phy_m88) {
e_dbg("Link taking longer than expected.\n");
} else { /* We didn't get link. *ResettheDSPandcrossourfingers.
*/
ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d); if (ret_val) return ret_val;
ret_val = e1000e_phy_reset_dsp(hw); if (ret_val) return ret_val;
}
}
/* Try once more */
ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, 100000, &link); if (ret_val) return ret_val;
}
if (hw->phy.type != e1000_phy_m88) return0;
ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val;
/* Resetting the phy means we need to re-force TX_CLK in the *ExtendedPHYSpecificControlRegisterto25MHzclockfrom *theresetvalueof2.5MHz.
*/
phy_data |= M88E1000_EPSCR_TX_CLK_25;
ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); if (ret_val) return ret_val;
/* In addition, we must re-enable CRS on Tx for both half and full *duplex.
*/
ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val;
ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); if (ret_val) return ret_val;
if (!active) {
data &= ~IGP02E1000_PM_D3_LPLU;
ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); if (ret_val) return ret_val; /* LPLU and SmartSpeed are mutually exclusive. LPLU is used *duringDxstateswherethepowerconservationismost *important.Duringdriveractivityweshouldenable *SmartSpeed,soperformanceismaintained.
*/ if (phy->smart_speed == e1000_smart_speed_on) {
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
&data); if (ret_val) return ret_val;
data |= IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
data); if (ret_val) return ret_val;
} elseif (phy->smart_speed == e1000_smart_speed_off) {
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
&data); if (ret_val) return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
data); if (ret_val) return ret_val;
}
} elseif ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
(phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
(phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
data |= IGP02E1000_PM_D3_LPLU;
ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data); if (ret_val) return ret_val;
/* When LPLU is enabled, we should disable SmartSpeed */
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); if (ret_val) return ret_val;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
}
/* Polarity is determined based on the speed of *ourconnection.
*/
ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); if (ret_val) return ret_val;
if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
offset = IGP01E1000_PHY_PCS_INIT_REG;
mask = IGP01E1000_PHY_POLARITY_MASK;
} else { /* This really only applies to 10Mbps since *thereisnopolarityfor100Mbps(always0).
*/
offset = IGP01E1000_PHY_PORT_STATUS;
mask = IGP01E1000_PSSR_POLARITY_REVERSED;
}
*success = false; for (i = 0; i < iterations; i++) { /* Some PHYs require the MII_BMSR register to be read *twiceduetothelinkbitbeingsticky.Noharmdoing *itacrosstheboard.
*/
ret_val = e1e_rphy(hw, MII_BMSR, &phy_status); if (ret_val) { /* If the first read fails, another entity may have *ownershipoftheresources,waitandtryagainto *seeiftheyhaverelinquishedtheresourcesyet.
*/ if (usec_interval >= 1000)
msleep(usec_interval / 1000); else
udelay(usec_interval);
}
ret_val = e1e_rphy(hw, MII_BMSR, &phy_status); if (ret_val) break; if (phy_status & BMSR_LSTATUS) {
*success = true; break;
} if (usec_interval >= 1000)
msleep(usec_interval / 1000); else
udelay(usec_interval);
}
/* Read the AGC registers for all channels */ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data); if (ret_val) return ret_val;
/* Getting bits 15:9, which represent the combination of *coarseandfinegainvalues.Theresultisanumber *thatcanbeputintothelookuptabletoobtainthe *approximatecablelength.
*/
cur_agc_index = ((phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
IGP02E1000_AGC_LENGTH_MASK);
/* Array index bound check. */ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
(cur_agc_index == 0)) return -E1000_ERR_PHY;
/* Remove min & max AGC values from calculation. */ if (e1000_igp_2_cable_length_table[min_agc_index] >
e1000_igp_2_cable_length_table[cur_agc_index])
min_agc_index = cur_agc_index; if (e1000_igp_2_cable_length_table[max_agc_index] <
e1000_igp_2_cable_length_table[cur_agc_index])
max_agc_index = cur_agc_index;
if (phy->polarity_correction) {
ret_val = e1000_check_polarity_ife(hw); if (ret_val) return ret_val;
} else { /* Polarity is forced */
phy->cable_polarity = ((data & IFE_PSC_FORCE_POLARITY)
? e1000_rev_polarity_reversed
: e1000_rev_polarity_normal);
}
ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); if (ret_val) return ret_val;
phy->is_mdix = !!(data & IFE_PMC_MDIX_STATUS);
/* 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;
ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val;
/* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, false, false); goto release;
}
ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val;
/* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, true, false); goto release;
}
ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val;
/* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, true, false); goto release;
}
hw->phy.addr = 1;
if (offset > MAX_PHY_MULTI_PAGE_REG) { /* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
page);
ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val;
/* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, false, false); goto release;
}
hw->phy.addr = 1;
if (offset > MAX_PHY_MULTI_PAGE_REG) { /* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
page);
/* All page select, port ctrl and wakeup registers use phy address 1 */
hw->phy.addr = 1;
/* Select Port Control Registers page */
ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); if (ret_val) {
e_dbg("Could not set Port Control page\n"); return ret_val;
}
ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); if (ret_val) {
e_dbg("Could not read PHY register %d.%d\n",
BM_PORT_CTRL_PAGE, BM_WUC_ENABLE_REG); return ret_val;
}
/* Select Port Control Registers page */
ret_val = e1000_set_page_igp(hw, (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); if (ret_val) {
e_dbg("Could not set Port Control page\n"); return ret_val;
}
/* Restore 769.17 to its original value */
ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, *phy_reg); if (ret_val)
e_dbg("Could not restore PHY register %d.%d\n",
BM_PORT_CTRL_PAGE, BM_WUC_ENABLE_REG);
/* Gig must be disabled for MDIO accesses to Host Wakeup reg page */ if ((hw->mac.type == e1000_pchlan) &&
(!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
e_dbg("Attempting to access page %d while gig enabled.\n",
page);
if (!page_set) { /* Enable access to PHY wakeup registers */
ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); if (ret_val) {
e_dbg("Could not enable PHY wakeup reg access\n"); return ret_val;
}
}
/* The PHY will retain its settings across a power down/up cycle */
ret = e1e_rphy(hw, MII_BMCR, &mii_reg); if (ret) {
e_dbg("Error reading PHY register\n"); return;
}
mii_reg &= ~BMCR_PDOWN;
e1e_wphy(hw, MII_BMCR, mii_reg);
}
/* The PHY will retain its settings across a power down/up cycle */
ret = e1e_rphy(hw, MII_BMCR, &mii_reg); if (ret) {
e_dbg("Error reading PHY register\n"); return;
}
mii_reg |= BMCR_PDOWN;
e1e_wphy(hw, MII_BMCR, mii_reg);
usleep_range(1000, 2000);
}
if (!locked) {
ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val;
}
/* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, true, page_set); goto out;
}
if (!locked) {
ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val;
}
/* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) {
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, false, page_set); goto out;
}
/* This takes care of the difference with desktop vs mobile phy */
addr_reg = ((hw->phy.type == e1000_phy_82578) ?
I82578_ADDR_REG : I82577_ADDR_REG);
data_reg = addr_reg + 1;
/* All operations in this function are phy address 2 */
hw->phy.addr = 2;
/* masking with 0x3F to remove the page from offset */
ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F); if (ret_val) {
e_dbg("Could not write the Address Offset port register\n"); return ret_val;
}
/* Read or write the data value next */ if (read)
ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data); else
ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data);
if (ret_val)
e_dbg("Could not access the Data port register\n");
/* Do not apply workaround if in PHY loopback bit 14 set */
ret_val = e1e_rphy(hw, MII_BMCR, &data); if (ret_val) {
e_dbg("Error reading PHY register\n"); return ret_val;
} if (data & BMCR_LOOPBACK) return0;
/* check if link is up and at 1Gbps */
ret_val = e1e_rphy(hw, BM_CS_STATUS, &data); if (ret_val) return ret_val;
data &= (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
BM_CS_STATUS_SPEED_MASK);
if (data != (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
BM_CS_STATUS_SPEED_1000)) return0;
msleep(200);
/* flush the packets in the fifo buffer */
ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
(HV_MUX_DATA_CTRL_GEN_TO_MAC |
HV_MUX_DATA_CTRL_FORCE_SPEED)); if (ret_val) return ret_val;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.