]> err.no Git - linux-2.6/commitdiff
[TG3]: Improve 5704S autoneg.
authorMichael Chan <mchan@broadcom.com>
Wed, 27 Sep 2006 22:59:15 +0000 (15:59 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Fri, 29 Sep 2006 01:01:34 +0000 (18:01 -0700)
Improve 5704S autoneg logic by using a serdes_counter field to keep
track of the transient states.  This eliminates a 200 msec busy
loop in the code.  Autoneg will take its course without the driver
busy waiting for it to finish.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tg3.c
drivers/net/tg3.h

index aaf45b907a786aaa9028e60fcf6d38668653ad6d..4eef798fbb7bc5749e12a20e04001a3bb070ad0a 100644 (file)
@@ -2406,24 +2406,27 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
        expected_sg_dig_ctrl |= (1 << 12);
 
        if (sg_dig_ctrl != expected_sg_dig_ctrl) {
+               if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+                   tp->serdes_counter &&
+                   ((mac_status & (MAC_STATUS_PCS_SYNCED |
+                                   MAC_STATUS_RCVD_CFG)) ==
+                    MAC_STATUS_PCS_SYNCED)) {
+                       tp->serdes_counter--;
+                       current_link_up = 1;
+                       goto out;
+               }
+restart_autoneg:
                if (workaround)
                        tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
                tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
                udelay(5);
                tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
 
-               tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+               tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
+               tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
        } else if (mac_status & (MAC_STATUS_PCS_SYNCED |
                                 MAC_STATUS_SIGNAL_DET)) {
-               int i;
-
-               /* Giver time to negotiate (~200ms) */
-               for (i = 0; i < 40000; i++) {
-                       sg_dig_status = tr32(SG_DIG_STATUS);
-                       if (sg_dig_status & (0x3))
-                               break;
-                       udelay(5);
-               }
+               sg_dig_status = tr32(SG_DIG_STATUS);
                mac_status = tr32(MAC_STATUS);
 
                if ((sg_dig_status & (1 << 1)) &&
@@ -2439,10 +2442,11 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 
                        tg3_setup_flow_control(tp, local_adv, remote_adv);
                        current_link_up = 1;
-                       tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+                       tp->serdes_counter = 0;
+                       tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
                } else if (!(sg_dig_status & (1 << 1))) {
-                       if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED)
-                               tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+                       if (tp->serdes_counter)
+                               tp->serdes_counter--;
                        else {
                                if (workaround) {
                                        u32 val = serdes_cfg;
@@ -2466,9 +2470,17 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
                                    !(mac_status & MAC_STATUS_RCVD_CFG)) {
                                        tg3_setup_flow_control(tp, 0, 0);
                                        current_link_up = 1;
-                               }
+                                       tp->tg3_flags2 |=
+                                               TG3_FLG2_PARALLEL_DETECT;
+                                       tp->serdes_counter =
+                                               SERDES_PARALLEL_DET_TIMEOUT;
+                               } else
+                                       goto restart_autoneg;
                        }
                }
+       } else {
+               tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
+               tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
        }
 
 out:
@@ -2599,14 +2611,16 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
                                    MAC_STATUS_CFG_CHANGED));
                udelay(5);
                if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
-                                        MAC_STATUS_CFG_CHANGED)) == 0)
+                                        MAC_STATUS_CFG_CHANGED |
+                                        MAC_STATUS_LNKSTATE_CHANGED)) == 0)
                        break;
        }
 
        mac_status = tr32(MAC_STATUS);
        if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
                current_link_up = 0;
-               if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+               if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+                   tp->serdes_counter == 0) {
                        tw32_f(MAC_MODE, (tp->mac_mode |
                                          MAC_MODE_SEND_CONFIGS));
                        udelay(1);
@@ -2711,7 +2725,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                        tg3_writephy(tp, MII_BMCR, bmcr);
 
                        tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
-                       tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+                       tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
                        tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
 
                        return err;
@@ -2816,9 +2830,9 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 
 static void tg3_serdes_parallel_detect(struct tg3 *tp)
 {
-       if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) {
+       if (tp->serdes_counter) {
                /* Give autoneg time to complete. */
-               tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+               tp->serdes_counter--;
                return;
        }
        if (!netif_carrier_ok(tp->dev) &&
@@ -6660,12 +6674,14 @@ static void tg3_timer(unsigned long __opaque)
                                need_setup = 1;
                        }
                        if (need_setup) {
-                               tw32_f(MAC_MODE,
-                                    (tp->mac_mode &
-                                     ~MAC_MODE_PORT_MODE_MASK));
-                               udelay(40);
-                               tw32_f(MAC_MODE, tp->mac_mode);
-                               udelay(40);
+                               if (!tp->serdes_counter) {
+                                       tw32_f(MAC_MODE,
+                                            (tp->mac_mode &
+                                             ~MAC_MODE_PORT_MODE_MASK));
+                                       udelay(40);
+                                       tw32_f(MAC_MODE, tp->mac_mode);
+                                       udelay(40);
+                               }
                                tg3_setup_phy(tp, 0);
                        }
                } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
index 3ecf356cfb082e17cc17875aec9eaf0c7e5b3cbb..f9c81baca8d88cfba95a659690505741c7e9df3c 100644 (file)
@@ -2203,7 +2203,6 @@ struct tg3 {
 #define TG3_FLG2_PCI_EXPRESS           0x00000200
 #define TG3_FLG2_ASF_NEW_HANDSHAKE     0x00000400
 #define TG3_FLG2_HW_AUTONEG            0x00000800
-#define TG3_FLG2_PHY_JUST_INITTED      0x00001000
 #define TG3_FLG2_PHY_SERDES            0x00002000
 #define TG3_FLG2_CAPACITIVE_COUPLING   0x00004000
 #define TG3_FLG2_FLASH                 0x00008000
@@ -2236,6 +2235,12 @@ struct tg3 {
        u16                             asf_counter;
        u16                             asf_multiplier;
 
+       /* 1 second counter for transient serdes link events */
+       u32                             serdes_counter;
+#define SERDES_AN_TIMEOUT_5704S                2
+#define SERDES_PARALLEL_DET_TIMEOUT    1
+#define SERDES_AN_TIMEOUT_5714S                1
+
        struct tg3_link_config          link_config;
        struct tg3_bufmgr_config        bufmgr_config;