tg3: Fix supporting flowctrl code
Subsystems (2)
PATCH 7/8 tg3: Fix supporting flowctrl code
This patch does three things. It modifies tg3_setup_flow_control() to use the administrator requested flow control settings if autonegotiation is turned off. It slightly modifies the tg3_setup_fiber_mii_phy() function to account for this new use case. And finally, it does the same for tg3_setup_copper_phy().
The copper modifications are more than a small multi-line change. The new code makes an attempt to avoid a link renegotiation if the link is active at half duplex and the only difference between the current advertised settings and requested advertised settings is the flow control advertisements.
Signed-off-by Matt Carlson <[email protected]>
Signed-off-by Michael Chan <[email protected]>
drivers/net/tg3.c +64 -43
@@ -1694,7 +1694,8 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_advu32 old_rx_mode = tp->rx_mode;u32 old_tx_mode = tp->tx_mode; -if (tp->tg3_flags &TG3_FLAG_PAUSE_AUTONEG ) { +if (tp->link_config.autoneg ==AUTONEG_ENABLE && + (tp->tg3_flags &TG3_FLAG_PAUSE_AUTONEG )) {if (tp->tg3_flags2 &TG3_FLG2_ANY_SERDES ) new_tg3_flags =tg3_resolve_flowctrl_1000X (local_adv, remote_adv);
@@ -1975,10 +1976,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)return 1 ; } +static int tg3_adv_1000T_flowctrl_ok (struct tg3 *tp,u32 *lcladv,u32 *rmtadv) +{ +u32 curadv, reqadv; + +if (tg3_readphy (tp,MII_ADVERTISE , lcladv)) +return 1 ; + + curadv = *lcladv & (ADVERTISE_PAUSE_CAP |ADVERTISE_PAUSE_ASYM ); + reqadv =tg3_advert_flowctrl_1000T (tp->link_config.flowctrl); + +if (tp->link_config.active_duplex ==DUPLEX_FULL ) { +if (curadv != reqadv) +return 0 ; + +if (tp->tg3_flags &TG3_FLAG_PAUSE_AUTONEG ) +tg3_readphy (tp,MII_LPA , rmtadv); + }else { +/* Reprogram the advertisement register, even if it +* does not affect the current link. If the link +* gets renegotiated in the future, we can save an +* additional renegotiation cycle by advertising +* it correctly in the first place. +*/ +if (curadv != reqadv) { + *lcladv &= ~(ADVERTISE_PAUSE_CAP | +ADVERTISE_PAUSE_ASYM ); +tg3_writephy (tp,MII_ADVERTISE , *lcladv | reqadv); + } + } + +return 1 ; +} +static int tg3_setup_copper_phy (struct tg3 *tp,int force_reset) {int current_link_up;u32 bmsr, dummy; +u32 lcl_adv, rmt_adv;u16 current_speed;u8 current_duplex;int i, err;
@@ -2121,54 +2156,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)udelay (10 ); } -if (tp->link_config.autoneg ==AUTONEG_ENABLE ) { -if (bmcr &BMCR_ANENABLE ) { - current_link_up =1 ; + lcl_adv =0 ; + rmt_adv =0 ; -/* Force autoneg restart if we are exiting -* low power mode. -*/ -if (!tg3_copper_is_advertising_all (tp, - tp->link_config.advertising)) - current_link_up =0 ; - }else { - current_link_up =0 ; + tp->link_config.active_speed = current_speed; + tp->link_config.active_duplex = current_duplex; + +if (tp->link_config.autoneg ==AUTONEG_ENABLE ) { +if ((bmcr &BMCR_ANENABLE ) && +tg3_copper_is_advertising_all (tp, + tp->link_config.advertising)) { +if (tg3_adv_1000T_flowctrl_ok (tp, &lcl_adv, + &rmt_adv)) + current_link_up =1 ; } }else {if (!(bmcr &BMCR_ANENABLE ) && tp->link_config.speed == current_speed && - tp->link_config.duplex == current_duplex) { + tp->link_config.duplex == current_duplex && + tp->link_config.flowctrl == + tp->link_config.active_flowctrl) { current_link_up =1 ; - }else { - current_link_up =0 ; } } - tp->link_config.active_speed = current_speed; - tp->link_config.active_duplex = current_duplex; +if (current_link_up ==1 && + tp->link_config.active_duplex ==DUPLEX_FULL ) +tg3_setup_flow_control (tp, lcl_adv, rmt_adv); } -if (current_link_up ==1 && - (tp->link_config.active_duplex ==DUPLEX_FULL ) && - (tp->link_config.autoneg ==AUTONEG_ENABLE )) { -u32 local_adv, remote_adv; - -if (tg3_readphy (tp,MII_ADVERTISE , &local_adv)) - local_adv =0 ; - -if (tg3_readphy (tp,MII_LPA , &remote_adv)) - remote_adv =0 ; - -/* If we are not advertising what has been requested, -* bring the link down and reconfigure. -*/ -if (local_adv != -tg3_advert_flowctrl_1000T (tp->link_config.flowctrl)) { - current_link_up =0 ; - }else { -tg3_setup_flow_control (tp, local_adv, remote_adv); - } - } relink:if (current_link_up ==0 || tp->link_config.phy_is_low_power) {u32 tmp;
@@ -2981,6 +2997,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)u32 bmsr, bmcr;u16 current_speed;u8 current_duplex; +u32 local_adv, remote_adv; tp->mac_mode |=MAC_MODE_PORT_MODE_GMII ;tw32_f (MAC_MODE , tp->mac_mode);
@@ -3014,7 +3031,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) err |=tg3_readphy (tp,MII_BMCR , &bmcr);if ((tp->link_config.autoneg ==AUTONEG_ENABLE ) && !force_reset && - (tp->tg3_flags2 &TG3_FLG2_PARALLEL_DETECT )) { + (tp->tg3_flags2 &TG3_FLG2_PARALLEL_DETECT ) && + tp->link_config.flowctrl == tp->link_config.active_flowctrl) {/* do nothing, just check for link up at the end */ }else if (tp->link_config.autoneg ==AUTONEG_ENABLE ) {u32 adv, new_adv;
@@ -3096,8 +3114,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)else current_duplex =DUPLEX_HALF ; + local_adv =0 ; + remote_adv =0 ; +if (bmcr &BMCR_ANENABLE ) { -u32 local_adv, remote_adv, common; +u32 common; err |=tg3_readphy (tp,MII_ADVERTISE , &local_adv); err |=tg3_readphy (tp,MII_LPA , &remote_adv);
@@ -3108,15 +3129,15 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) current_duplex =DUPLEX_FULL ; else current_duplex =DUPLEX_HALF ; - -tg3_setup_flow_control (tp, local_adv, - remote_adv); }else current_link_up =0 ; } } +if (current_link_up ==1 && current_duplex ==DUPLEX_FULL ) +tg3_setup_flow_control (tp, local_adv, remote_adv); + tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX ;if (tp->link_config.active_duplex ==DUPLEX_HALF ) tp->mac_mode |=MAC_MODE_HALF_DUPLEX ;