diff options
author | Michael Chan <mchan@broadcom.com> | 2006-09-27 18:59:15 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-28 21:01:34 -0400 |
commit | 3d3ebe741b2c06fe3df67739d09f6ef0e25ee41a (patch) | |
tree | f9112f5b5beac57673a26563a3a50517c5c96798 /drivers/net/tg3.c | |
parent | 6ac59344ef25d5f0ebadb5663cf700d25d2a3886 (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.c | 66 |
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 | } | ||
2418 | restart_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 | ||
2474 | out: | 2486 | out: |
@@ -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 | ||
2817 | static void tg3_serdes_parallel_detect(struct tg3 *tp) | 2831 | static 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) |