[TG3]: Add 1000T & 1000X flowctrl resolvers

This patch adds two new utility functions to resolve flow control.  One
function resolves flow control based on 1000-BaseT register definitions.
The other resolves flow control based on 1000-Base X register
definitions.

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:
Matt Carlson 2007-12-20 20:06:19 -08:00 committed by David S. Miller
parent 8d01862108
commit 95937268b7

View File

@ -1612,6 +1612,50 @@ static void tg3_link_report(struct tg3 *tp)
}
}
static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_PAUSE_CAP) {
if (lcladv & ADVERTISE_PAUSE_ASYM) {
if (rmtadv & LPA_PAUSE_CAP)
cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
else if (rmtadv & LPA_PAUSE_ASYM)
cap = TG3_FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_PAUSE_CAP)
cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
cap = TG3_FLOW_CTRL_TX;
}
return cap;
}
static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
if (lcladv & ADVERTISE_1000XPAUSE) {
if (lcladv & ADVERTISE_1000XPSE_ASYM) {
if (rmtadv & LPA_1000XPAUSE)
cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
else if (rmtadv & LPA_1000XPAUSE_ASYM)
cap = TG3_FLOW_CTRL_RX;
} else {
if (rmtadv & LPA_1000XPAUSE)
cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
}
} else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
cap = TG3_FLOW_CTRL_TX;
}
return cap;
}
static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
{
u8 new_tg3_flags = 0;
@ -1619,42 +1663,12 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
u32 old_tx_mode = tp->tx_mode;
if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
/* Convert 1000BaseX flow control bits to 1000BaseT
* bits before resolving flow control.
*/
if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
local_adv &= ~(ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
remote_adv &= ~(LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
if (local_adv & ADVERTISE_1000XPAUSE)
local_adv |= ADVERTISE_PAUSE_CAP;
if (local_adv & ADVERTISE_1000XPSE_ASYM)
local_adv |= ADVERTISE_PAUSE_ASYM;
if (remote_adv & LPA_1000XPAUSE)
remote_adv |= LPA_PAUSE_CAP;
if (remote_adv & LPA_1000XPAUSE_ASYM)
remote_adv |= LPA_PAUSE_ASYM;
}
if (local_adv & ADVERTISE_PAUSE_CAP) {
if (local_adv & ADVERTISE_PAUSE_ASYM) {
if (remote_adv & LPA_PAUSE_CAP)
new_tg3_flags = TG3_FLOW_CTRL_RX |
TG3_FLOW_CTRL_TX;
else if (remote_adv & LPA_PAUSE_ASYM)
new_tg3_flags = TG3_FLOW_CTRL_RX;
} else {
if (remote_adv & LPA_PAUSE_CAP)
new_tg3_flags = TG3_FLOW_CTRL_RX |
TG3_FLOW_CTRL_TX;
}
} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
if ((remote_adv & LPA_PAUSE_CAP) &&
(remote_adv & LPA_PAUSE_ASYM))
new_tg3_flags = TG3_FLOW_CTRL_TX;
}
if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
remote_adv);
else
new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
remote_adv);
} else {
new_tg3_flags = tp->link_config.flowctrl;
}