[TG3]: Add 1000T & 1000X flowctl adv helpers
This patch adds two functions designed to convert abstract TX & RX flow control parameters to 1000-BaseT and 1000-BaseX autonegotiation advertisements. Code that uses standard definitions which statically advertises TX & RX flow control has been replaced with code that configures the advertisements based on administrator dictated preferences. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
95937268b7
Коммит
ba4d07a848
|
@ -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)
|
static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
|
||||||
{
|
{
|
||||||
u8 cap = 0;
|
u8 cap = 0;
|
||||||
|
@ -1764,7 +1796,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
|
||||||
~(ADVERTISED_1000baseT_Half |
|
~(ADVERTISED_1000baseT_Half |
|
||||||
ADVERTISED_1000baseT_Full);
|
ADVERTISED_1000baseT_Full);
|
||||||
|
|
||||||
new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
|
new_adv = ADVERTISE_CSMA;
|
||||||
if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
|
if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
|
||||||
new_adv |= ADVERTISE_10HALF;
|
new_adv |= ADVERTISE_10HALF;
|
||||||
if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
|
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;
|
new_adv |= ADVERTISE_100HALF;
|
||||||
if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
|
if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
|
||||||
new_adv |= ADVERTISE_100FULL;
|
new_adv |= ADVERTISE_100FULL;
|
||||||
|
|
||||||
|
new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
|
||||||
|
|
||||||
tg3_writephy(tp, MII_ADVERTISE, new_adv);
|
tg3_writephy(tp, MII_ADVERTISE, new_adv);
|
||||||
|
|
||||||
if (tp->link_config.advertising &
|
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);
|
tg3_writephy(tp, MII_TG3_CTRL, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
|
||||||
|
new_adv |= ADVERTISE_CSMA;
|
||||||
|
|
||||||
/* Asking for a specific link mode. */
|
/* Asking for a specific link mode. */
|
||||||
if (tp->link_config.speed == SPEED_1000) {
|
if (tp->link_config.speed == SPEED_1000) {
|
||||||
new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
|
|
||||||
tg3_writephy(tp, MII_ADVERTISE, new_adv);
|
tg3_writephy(tp, MII_ADVERTISE, new_adv);
|
||||||
|
|
||||||
if (tp->link_config.duplex == DUPLEX_FULL)
|
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)
|
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
|
||||||
new_adv |= (MII_TG3_CTRL_AS_MASTER |
|
new_adv |= (MII_TG3_CTRL_AS_MASTER |
|
||||||
MII_TG3_CTRL_ENABLE_AS_MASTER);
|
MII_TG3_CTRL_ENABLE_AS_MASTER);
|
||||||
tg3_writephy(tp, MII_TG3_CTRL, new_adv);
|
|
||||||
} else {
|
} 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.speed == SPEED_100) {
|
||||||
if (tp->link_config.duplex == DUPLEX_FULL)
|
if (tp->link_config.duplex == DUPLEX_FULL)
|
||||||
new_adv |= ADVERTISE_100FULL;
|
new_adv |= ADVERTISE_100FULL;
|
||||||
|
@ -1822,7 +1855,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
|
||||||
new_adv |= ADVERTISE_10HALF;
|
new_adv |= ADVERTISE_10HALF;
|
||||||
}
|
}
|
||||||
tg3_writephy(tp, MII_ADVERTISE, new_adv);
|
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 &&
|
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))
|
if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
|
||||||
local_adv = 0;
|
local_adv = 0;
|
||||||
local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
|
|
||||||
|
|
||||||
if (tg3_readphy(tp, MII_LPA, &remote_adv))
|
if (tg3_readphy(tp, MII_LPA, &remote_adv))
|
||||||
remote_adv = 0;
|
remote_adv = 0;
|
||||||
|
|
||||||
remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
|
/* If we are not advertising what has been requested,
|
||||||
|
* bring the link down and reconfigure.
|
||||||
/* If we are not advertising full pause capability,
|
|
||||||
* something is wrong. 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;
|
current_link_up = 0;
|
||||||
} else {
|
} else {
|
||||||
tg3_setup_flow_control(tp, local_adv, remote_adv);
|
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_1000XPSE_ASYM |
|
||||||
ADVERTISE_SLCT);
|
ADVERTISE_SLCT);
|
||||||
|
|
||||||
/* Always advertise symmetric PAUSE just like copper */
|
new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
|
||||||
new_adv |= ADVERTISE_1000XPAUSE;
|
|
||||||
|
|
||||||
if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
|
if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
|
||||||
new_adv |= ADVERTISE_1000XHALF;
|
new_adv |= ADVERTISE_1000XHALF;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче