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 | |
| 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>
| -rw-r--r-- | drivers/net/tg3.c | 66 | ||||
| -rw-r--r-- | drivers/net/tg3.h | 7 |
2 files changed, 47 insertions, 26 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) |
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 3ecf356cfb08..f9c81baca8d8 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h | |||
| @@ -2203,7 +2203,6 @@ struct tg3 { | |||
| 2203 | #define TG3_FLG2_PCI_EXPRESS 0x00000200 | 2203 | #define TG3_FLG2_PCI_EXPRESS 0x00000200 |
| 2204 | #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 | 2204 | #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 |
| 2205 | #define TG3_FLG2_HW_AUTONEG 0x00000800 | 2205 | #define TG3_FLG2_HW_AUTONEG 0x00000800 |
| 2206 | #define TG3_FLG2_PHY_JUST_INITTED 0x00001000 | ||
| 2207 | #define TG3_FLG2_PHY_SERDES 0x00002000 | 2206 | #define TG3_FLG2_PHY_SERDES 0x00002000 |
| 2208 | #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 | 2207 | #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 |
| 2209 | #define TG3_FLG2_FLASH 0x00008000 | 2208 | #define TG3_FLG2_FLASH 0x00008000 |
| @@ -2236,6 +2235,12 @@ struct tg3 { | |||
| 2236 | u16 asf_counter; | 2235 | u16 asf_counter; |
| 2237 | u16 asf_multiplier; | 2236 | u16 asf_multiplier; |
| 2238 | 2237 | ||
| 2238 | /* 1 second counter for transient serdes link events */ | ||
| 2239 | u32 serdes_counter; | ||
| 2240 | #define SERDES_AN_TIMEOUT_5704S 2 | ||
| 2241 | #define SERDES_PARALLEL_DET_TIMEOUT 1 | ||
| 2242 | #define SERDES_AN_TIMEOUT_5714S 1 | ||
| 2243 | |||
| 2239 | struct tg3_link_config link_config; | 2244 | struct tg3_link_config link_config; |
| 2240 | struct tg3_bufmgr_config bufmgr_config; | 2245 | struct tg3_bufmgr_config bufmgr_config; |
| 2241 | 2246 | ||
