diff options
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r-- | drivers/net/tg3.c | 62 |
1 files changed, 48 insertions, 14 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b571b20..5b83a54 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1612,6 +1612,38 @@ static void tg3_link_report(struct tg3 *tp) } } +static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_PAUSE_CAP; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_PAUSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + else + miireg = 0; + + return miireg; +} + +static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_1000XPAUSE; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_1000XPSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; + else + miireg = 0; + + return miireg; +} + static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) { u8 cap = 0; @@ -1764,7 +1796,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) ~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); - new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + new_adv = ADVERTISE_CSMA; if (tp->link_config.advertising & ADVERTISED_10baseT_Half) new_adv |= ADVERTISE_10HALF; if (tp->link_config.advertising & ADVERTISED_10baseT_Full) @@ -1773,6 +1805,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp) new_adv |= ADVERTISE_100HALF; if (tp->link_config.advertising & ADVERTISED_100baseT_Full) new_adv |= ADVERTISE_100FULL; + + new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); + tg3_writephy(tp, MII_ADVERTISE, new_adv); if (tp->link_config.advertising & @@ -1792,9 +1827,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp) tg3_writephy(tp, MII_TG3_CTRL, 0); } } else { + new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); + new_adv |= ADVERTISE_CSMA; + /* Asking for a specific link mode. */ if (tp->link_config.speed == SPEED_1000) { - new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; tg3_writephy(tp, MII_ADVERTISE, new_adv); if (tp->link_config.duplex == DUPLEX_FULL) @@ -1805,11 +1842,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) new_adv |= (MII_TG3_CTRL_AS_MASTER | MII_TG3_CTRL_ENABLE_AS_MASTER); - tg3_writephy(tp, MII_TG3_CTRL, new_adv); } else { - tg3_writephy(tp, MII_TG3_CTRL, 0); - - new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; if (tp->link_config.speed == SPEED_100) { if (tp->link_config.duplex == DUPLEX_FULL) new_adv |= ADVERTISE_100FULL; @@ -1822,7 +1855,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp) new_adv |= ADVERTISE_10HALF; } tg3_writephy(tp, MII_ADVERTISE, new_adv); + + new_adv = 0; } + + tg3_writephy(tp, MII_TG3_CTRL, new_adv); } if (tp->link_config.autoneg == AUTONEG_DISABLE && @@ -2118,17 +2155,15 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) if (tg3_readphy(tp, MII_ADVERTISE, &local_adv)) local_adv = 0; - local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); if (tg3_readphy(tp, MII_LPA, &remote_adv)) remote_adv = 0; - remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM); - - /* If we are not advertising full pause capability, - * something is wrong. Bring the link down and reconfigure. + /* If we are not advertising what has been requested, + * bring the link down and reconfigure. */ - if (local_adv != ADVERTISE_PAUSE_CAP) { + if (local_adv != + tg3_advert_flowctrl_1000T(tp->link_config.flowctrl)) { current_link_up = 0; } else { tg3_setup_flow_control(tp, local_adv, remote_adv); @@ -2973,8 +3008,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) ADVERTISE_1000XPSE_ASYM | ADVERTISE_SLCT); - /* Always advertise symmetric PAUSE just like copper */ - new_adv |= ADVERTISE_1000XPAUSE; + new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl); if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) new_adv |= ADVERTISE_1000XHALF; |