aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tg3.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2006-09-27 18:59:15 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-28 21:01:34 -0400
commit3d3ebe741b2c06fe3df67739d09f6ef0e25ee41a (patch)
treef9112f5b5beac57673a26563a3a50517c5c96798 /drivers/net/tg3.c
parent6ac59344ef25d5f0ebadb5663cf700d25d2a3886 (diff)
[TG3]: Improve 5704S autoneg.
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>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r--drivers/net/tg3.c66
1 files changed, 41 insertions, 25 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index aaf45b907a78..4eef798fbb7b 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -2406,24 +2406,27 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
2406 expected_sg_dig_ctrl |= (1 << 12); 2406 expected_sg_dig_ctrl |= (1 << 12);
2407 2407
2408 if (sg_dig_ctrl != expected_sg_dig_ctrl) { 2408 if (sg_dig_ctrl != expected_sg_dig_ctrl) {
2409 if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
2410 tp->serdes_counter &&
2411 ((mac_status & (MAC_STATUS_PCS_SYNCED |
2412 MAC_STATUS_RCVD_CFG)) ==
2413 MAC_STATUS_PCS_SYNCED)) {
2414 tp->serdes_counter--;
2415 current_link_up = 1;
2416 goto out;
2417 }
2418restart_autoneg:
2409 if (workaround) 2419 if (workaround)
2410 tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000); 2420 tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
2411 tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30)); 2421 tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
2412 udelay(5); 2422 udelay(5);
2413 tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl); 2423 tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
2414 2424
2415 tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED; 2425 tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
2426 tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
2416 } else if (mac_status & (MAC_STATUS_PCS_SYNCED | 2427 } else if (mac_status & (MAC_STATUS_PCS_SYNCED |
2417 MAC_STATUS_SIGNAL_DET)) { 2428 MAC_STATUS_SIGNAL_DET)) {
2418 int i; 2429 sg_dig_status = tr32(SG_DIG_STATUS);
2419
2420 /* Giver time to negotiate (~200ms) */
2421 for (i = 0; i < 40000; i++) {
2422 sg_dig_status = tr32(SG_DIG_STATUS);
2423 if (sg_dig_status & (0x3))
2424 break;
2425 udelay(5);
2426 }
2427 mac_status = tr32(MAC_STATUS); 2430 mac_status = tr32(MAC_STATUS);
2428 2431
2429 if ((sg_dig_status & (1 << 1)) && 2432 if ((sg_dig_status & (1 << 1)) &&
@@ -2439,10 +2442,11 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
2439 2442
2440 tg3_setup_flow_control(tp, local_adv, remote_adv); 2443 tg3_setup_flow_control(tp, local_adv, remote_adv);
2441 current_link_up = 1; 2444 current_link_up = 1;
2442 tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; 2445 tp->serdes_counter = 0;
2446 tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
2443 } else if (!(sg_dig_status & (1 << 1))) { 2447 } else if (!(sg_dig_status & (1 << 1))) {
2444 if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) 2448 if (tp->serdes_counter)
2445 tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; 2449 tp->serdes_counter--;
2446 else { 2450 else {
2447 if (workaround) { 2451 if (workaround) {
2448 u32 val = serdes_cfg; 2452 u32 val = serdes_cfg;
@@ -2466,9 +2470,17 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
2466 !(mac_status & MAC_STATUS_RCVD_CFG)) { 2470 !(mac_status & MAC_STATUS_RCVD_CFG)) {
2467 tg3_setup_flow_control(tp, 0, 0); 2471 tg3_setup_flow_control(tp, 0, 0);
2468 current_link_up = 1; 2472 current_link_up = 1;
2469 } 2473 tp->tg3_flags2 |=
2474 TG3_FLG2_PARALLEL_DETECT;
2475 tp->serdes_counter =
2476 SERDES_PARALLEL_DET_TIMEOUT;
2477 } else
2478 goto restart_autoneg;
2470 } 2479 }
2471 } 2480 }
2481 } else {
2482 tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
2483 tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
2472 } 2484 }
2473 2485
2474out: 2486out:
@@ -2599,14 +2611,16 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
2599 MAC_STATUS_CFG_CHANGED)); 2611 MAC_STATUS_CFG_CHANGED));
2600 udelay(5); 2612 udelay(5);
2601 if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | 2613 if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
2602 MAC_STATUS_CFG_CHANGED)) == 0) 2614 MAC_STATUS_CFG_CHANGED |
2615 MAC_STATUS_LNKSTATE_CHANGED)) == 0)
2603 break; 2616 break;
2604 } 2617 }
2605 2618
2606 mac_status = tr32(MAC_STATUS); 2619 mac_status = tr32(MAC_STATUS);
2607 if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) { 2620 if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
2608 current_link_up = 0; 2621 current_link_up = 0;
2609 if (tp->link_config.autoneg == AUTONEG_ENABLE) { 2622 if (tp->link_config.autoneg == AUTONEG_ENABLE &&
2623 tp->serdes_counter == 0) {
2610 tw32_f(MAC_MODE, (tp->mac_mode | 2624 tw32_f(MAC_MODE, (tp->mac_mode |
2611 MAC_MODE_SEND_CONFIGS)); 2625 MAC_MODE_SEND_CONFIGS));
2612 udelay(1); 2626 udelay(1);
@@ -2711,7 +2725,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
2711 tg3_writephy(tp, MII_BMCR, bmcr); 2725 tg3_writephy(tp, MII_BMCR, bmcr);
2712 2726
2713 tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); 2727 tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
2714 tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED; 2728 tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
2715 tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; 2729 tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
2716 2730
2717 return err; 2731 return err;
@@ -2816,9 +2830,9 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
2816 2830
2817static void tg3_serdes_parallel_detect(struct tg3 *tp) 2831static void tg3_serdes_parallel_detect(struct tg3 *tp)
2818{ 2832{
2819 if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) { 2833 if (tp->serdes_counter) {
2820 /* Give autoneg time to complete. */ 2834 /* Give autoneg time to complete. */
2821 tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; 2835 tp->serdes_counter--;
2822 return; 2836 return;
2823 } 2837 }
2824 if (!netif_carrier_ok(tp->dev) && 2838 if (!netif_carrier_ok(tp->dev) &&
@@ -6660,12 +6674,14 @@ static void tg3_timer(unsigned long __opaque)
6660 need_setup = 1; 6674 need_setup = 1;
6661 } 6675 }
6662 if (need_setup) { 6676 if (need_setup) {
6663 tw32_f(MAC_MODE, 6677 if (!tp->serdes_counter) {
6664 (tp->mac_mode & 6678 tw32_f(MAC_MODE,
6665 ~MAC_MODE_PORT_MODE_MASK)); 6679 (tp->mac_mode &
6666 udelay(40); 6680 ~MAC_MODE_PORT_MODE_MASK));
6667 tw32_f(MAC_MODE, tp->mac_mode); 6681 udelay(40);
6668 udelay(40); 6682 tw32_f(MAC_MODE, tp->mac_mode);
6683 udelay(40);
6684 }
6669 tg3_setup_phy(tp, 0); 6685 tg3_setup_phy(tp, 0);
6670 } 6686 }
6671 } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) 6687 } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)