aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2007-12-20 23:10:01 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:59:34 -0500
commitef167e27039eeaea6d3cdd5c547b082e89840bdd (patch)
treefd7d1b76a867472dd26ce3a866eea59e30422983 /drivers/net
parent5be73b471bbed9ca61ddfd952a2cb7701f94f034 (diff)
[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 <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tg3.c107
1 files changed, 64 insertions, 43 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index cdade05bdd07..b2f505d6ea94 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1694,7 +1694,8 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
1694 u32 old_rx_mode = tp->rx_mode; 1694 u32 old_rx_mode = tp->rx_mode;
1695 u32 old_tx_mode = tp->tx_mode; 1695 u32 old_tx_mode = tp->tx_mode;
1696 1696
1697 if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) { 1697 if (tp->link_config.autoneg == AUTONEG_ENABLE &&
1698 (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
1698 if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) 1699 if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
1699 new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv, 1700 new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
1700 remote_adv); 1701 remote_adv);
@@ -1975,10 +1976,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
1975 return 1; 1976 return 1;
1976} 1977}
1977 1978
1979static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
1980{
1981 u32 curadv, reqadv;
1982
1983 if (tg3_readphy(tp, MII_ADVERTISE, lcladv))
1984 return 1;
1985
1986 curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
1987 reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
1988
1989 if (tp->link_config.active_duplex == DUPLEX_FULL) {
1990 if (curadv != reqadv)
1991 return 0;
1992
1993 if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)
1994 tg3_readphy(tp, MII_LPA, rmtadv);
1995 } else {
1996 /* Reprogram the advertisement register, even if it
1997 * does not affect the current link. If the link
1998 * gets renegotiated in the future, we can save an
1999 * additional renegotiation cycle by advertising
2000 * it correctly in the first place.
2001 */
2002 if (curadv != reqadv) {
2003 *lcladv &= ~(ADVERTISE_PAUSE_CAP |
2004 ADVERTISE_PAUSE_ASYM);
2005 tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv);
2006 }
2007 }
2008
2009 return 1;
2010}
2011
1978static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) 2012static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
1979{ 2013{
1980 int current_link_up; 2014 int current_link_up;
1981 u32 bmsr, dummy; 2015 u32 bmsr, dummy;
2016 u32 lcl_adv, rmt_adv;
1982 u16 current_speed; 2017 u16 current_speed;
1983 u8 current_duplex; 2018 u8 current_duplex;
1984 int i, err; 2019 int i, err;
@@ -2121,54 +2156,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
2121 udelay(10); 2156 udelay(10);
2122 } 2157 }
2123 2158
2124 if (tp->link_config.autoneg == AUTONEG_ENABLE) { 2159 lcl_adv = 0;
2125 if (bmcr & BMCR_ANENABLE) { 2160 rmt_adv = 0;
2126 current_link_up = 1;
2127 2161
2128 /* Force autoneg restart if we are exiting 2162 tp->link_config.active_speed = current_speed;
2129 * low power mode. 2163 tp->link_config.active_duplex = current_duplex;
2130 */ 2164
2131 if (!tg3_copper_is_advertising_all(tp, 2165 if (tp->link_config.autoneg == AUTONEG_ENABLE) {
2132 tp->link_config.advertising)) 2166 if ((bmcr & BMCR_ANENABLE) &&
2133 current_link_up = 0; 2167 tg3_copper_is_advertising_all(tp,
2134 } else { 2168 tp->link_config.advertising)) {
2135 current_link_up = 0; 2169 if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv,
2170 &rmt_adv))
2171 current_link_up = 1;
2136 } 2172 }
2137 } else { 2173 } else {
2138 if (!(bmcr & BMCR_ANENABLE) && 2174 if (!(bmcr & BMCR_ANENABLE) &&
2139 tp->link_config.speed == current_speed && 2175 tp->link_config.speed == current_speed &&
2140 tp->link_config.duplex == current_duplex) { 2176 tp->link_config.duplex == current_duplex &&
2177 tp->link_config.flowctrl ==
2178 tp->link_config.active_flowctrl) {
2141 current_link_up = 1; 2179 current_link_up = 1;
2142 } else {
2143 current_link_up = 0;
2144 } 2180 }
2145 } 2181 }
2146 2182
2147 tp->link_config.active_speed = current_speed; 2183 if (current_link_up == 1 &&
2148 tp->link_config.active_duplex = current_duplex; 2184 tp->link_config.active_duplex == DUPLEX_FULL)
2185 tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
2149 } 2186 }
2150 2187
2151 if (current_link_up == 1 &&
2152 (tp->link_config.active_duplex == DUPLEX_FULL) &&
2153 (tp->link_config.autoneg == AUTONEG_ENABLE)) {
2154 u32 local_adv, remote_adv;
2155
2156 if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
2157 local_adv = 0;
2158
2159 if (tg3_readphy(tp, MII_LPA, &remote_adv))
2160 remote_adv = 0;
2161
2162 /* If we are not advertising what has been requested,
2163 * bring the link down and reconfigure.
2164 */
2165 if (local_adv !=
2166 tg3_advert_flowctrl_1000T(tp->link_config.flowctrl)) {
2167 current_link_up = 0;
2168 } else {
2169 tg3_setup_flow_control(tp, local_adv, remote_adv);
2170 }
2171 }
2172relink: 2188relink:
2173 if (current_link_up == 0 || tp->link_config.phy_is_low_power) { 2189 if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
2174 u32 tmp; 2190 u32 tmp;
@@ -2981,6 +2997,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
2981 u32 bmsr, bmcr; 2997 u32 bmsr, bmcr;
2982 u16 current_speed; 2998 u16 current_speed;
2983 u8 current_duplex; 2999 u8 current_duplex;
3000 u32 local_adv, remote_adv;
2984 3001
2985 tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; 3002 tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
2986 tw32_f(MAC_MODE, tp->mac_mode); 3003 tw32_f(MAC_MODE, tp->mac_mode);
@@ -3014,7 +3031,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
3014 err |= tg3_readphy(tp, MII_BMCR, &bmcr); 3031 err |= tg3_readphy(tp, MII_BMCR, &bmcr);
3015 3032
3016 if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset && 3033 if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
3017 (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) { 3034 (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
3035 tp->link_config.flowctrl == tp->link_config.active_flowctrl) {
3018 /* do nothing, just check for link up at the end */ 3036 /* do nothing, just check for link up at the end */
3019 } else if (tp->link_config.autoneg == AUTONEG_ENABLE) { 3037 } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
3020 u32 adv, new_adv; 3038 u32 adv, new_adv;
@@ -3096,8 +3114,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
3096 else 3114 else
3097 current_duplex = DUPLEX_HALF; 3115 current_duplex = DUPLEX_HALF;
3098 3116
3117 local_adv = 0;
3118 remote_adv = 0;
3119
3099 if (bmcr & BMCR_ANENABLE) { 3120 if (bmcr & BMCR_ANENABLE) {
3100 u32 local_adv, remote_adv, common; 3121 u32 common;
3101 3122
3102 err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv); 3123 err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv);
3103 err |= tg3_readphy(tp, MII_LPA, &remote_adv); 3124 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)
3108 current_duplex = DUPLEX_FULL; 3129 current_duplex = DUPLEX_FULL;
3109 else 3130 else
3110 current_duplex = DUPLEX_HALF; 3131 current_duplex = DUPLEX_HALF;
3111
3112 tg3_setup_flow_control(tp, local_adv,
3113 remote_adv);
3114 } 3132 }
3115 else 3133 else
3116 current_link_up = 0; 3134 current_link_up = 0;
3117 } 3135 }
3118 } 3136 }
3119 3137
3138 if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
3139 tg3_setup_flow_control(tp, local_adv, remote_adv);
3140
3120 tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; 3141 tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
3121 if (tp->link_config.active_duplex == DUPLEX_HALF) 3142 if (tp->link_config.active_duplex == DUPLEX_HALF)
3122 tp->mac_mode |= MAC_MODE_HALF_DUPLEX; 3143 tp->mac_mode |= MAC_MODE_HALF_DUPLEX;