Commit 3d3ebe74 authored by Michael Chan's avatar Michael Chan Committed by David S. Miller

[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: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6ac59344
...@@ -2406,24 +2406,27 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) ...@@ -2406,24 +2406,27 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
expected_sg_dig_ctrl |= (1 << 12); expected_sg_dig_ctrl |= (1 << 12);
if (sg_dig_ctrl != expected_sg_dig_ctrl) { 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) if (workaround)
tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000); tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30)); tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
udelay(5); udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl); 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 | } else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) { MAC_STATUS_SIGNAL_DET)) {
int i;
/* Giver time to negotiate (~200ms) */
for (i = 0; i < 40000; i++) {
sg_dig_status = tr32(SG_DIG_STATUS); sg_dig_status = tr32(SG_DIG_STATUS);
if (sg_dig_status & (0x3))
break;
udelay(5);
}
mac_status = tr32(MAC_STATUS); mac_status = tr32(MAC_STATUS);
if ((sg_dig_status & (1 << 1)) && if ((sg_dig_status & (1 << 1)) &&
...@@ -2439,10 +2442,11 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) ...@@ -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); tg3_setup_flow_control(tp, local_adv, remote_adv);
current_link_up = 1; 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))) { } else if (!(sg_dig_status & (1 << 1))) {
if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) if (tp->serdes_counter)
tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; tp->serdes_counter--;
else { else {
if (workaround) { if (workaround) {
u32 val = serdes_cfg; u32 val = serdes_cfg;
...@@ -2466,9 +2470,17 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) ...@@ -2466,9 +2470,17 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
!(mac_status & MAC_STATUS_RCVD_CFG)) { !(mac_status & MAC_STATUS_RCVD_CFG)) {
tg3_setup_flow_control(tp, 0, 0); tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1; 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: out:
...@@ -2599,14 +2611,16 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) ...@@ -2599,14 +2611,16 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
MAC_STATUS_CFG_CHANGED)); MAC_STATUS_CFG_CHANGED));
udelay(5); udelay(5);
if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED)) == 0) MAC_STATUS_CFG_CHANGED |
MAC_STATUS_LNKSTATE_CHANGED)) == 0)
break; break;
} }
mac_status = tr32(MAC_STATUS); mac_status = tr32(MAC_STATUS);
if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) { if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
current_link_up = 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 | tw32_f(MAC_MODE, (tp->mac_mode |
MAC_MODE_SEND_CONFIGS)); MAC_MODE_SEND_CONFIGS));
udelay(1); udelay(1);
...@@ -2711,7 +2725,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) ...@@ -2711,7 +2725,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
tg3_writephy(tp, MII_BMCR, bmcr); tg3_writephy(tp, MII_BMCR, bmcr);
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); 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; tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
return err; return err;
...@@ -2816,9 +2830,9 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) ...@@ -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) 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. */ /* Give autoneg time to complete. */
tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED; tp->serdes_counter--;
return; return;
} }
if (!netif_carrier_ok(tp->dev) && if (!netif_carrier_ok(tp->dev) &&
...@@ -6660,12 +6674,14 @@ static void tg3_timer(unsigned long __opaque) ...@@ -6660,12 +6674,14 @@ static void tg3_timer(unsigned long __opaque)
need_setup = 1; need_setup = 1;
} }
if (need_setup) { if (need_setup) {
if (!tp->serdes_counter) {
tw32_f(MAC_MODE, tw32_f(MAC_MODE,
(tp->mac_mode & (tp->mac_mode &
~MAC_MODE_PORT_MODE_MASK)); ~MAC_MODE_PORT_MODE_MASK));
udelay(40); udelay(40);
tw32_f(MAC_MODE, tp->mac_mode); tw32_f(MAC_MODE, tp->mac_mode);
udelay(40); udelay(40);
}
tg3_setup_phy(tp, 0); tg3_setup_phy(tp, 0);
} }
} else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
......
...@@ -2203,7 +2203,6 @@ struct tg3 { ...@@ -2203,7 +2203,6 @@ struct tg3 {
#define TG3_FLG2_PCI_EXPRESS 0x00000200 #define TG3_FLG2_PCI_EXPRESS 0x00000200
#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400 #define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400
#define TG3_FLG2_HW_AUTONEG 0x00000800 #define TG3_FLG2_HW_AUTONEG 0x00000800
#define TG3_FLG2_PHY_JUST_INITTED 0x00001000
#define TG3_FLG2_PHY_SERDES 0x00002000 #define TG3_FLG2_PHY_SERDES 0x00002000
#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000
#define TG3_FLG2_FLASH 0x00008000 #define TG3_FLG2_FLASH 0x00008000
...@@ -2236,6 +2235,12 @@ struct tg3 { ...@@ -2236,6 +2235,12 @@ struct tg3 {
u16 asf_counter; u16 asf_counter;
u16 asf_multiplier; 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_link_config link_config;
struct tg3_bufmgr_config bufmgr_config; struct tg3_bufmgr_config bufmgr_config;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment