Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=ef167e27039eeaea6d3cdd5c547b082e89840bdd
Commit:     ef167e27039eeaea6d3cdd5c547b082e89840bdd
Parent:     5be73b471bbed9ca61ddfd952a2cb7701f94f034
Author:     Matt Carlson <[EMAIL PROTECTED]>
AuthorDate: Thu Dec 20 20:10:01 2007 -0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Mon Jan 28 14:59:34 2008 -0800

    [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]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 drivers/net/tg3.c |  107 +++++++++++++++++++++++++++++++---------------------
 1 files changed, 64 insertions(+), 43 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index cdade05..b2f505d 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
        u32 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;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to