Commit da4c1ff4 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Jeff Garzik

sky2: flow control negotiation for Yukon-FE

The Yukon-FE chip doesn't do gigabit and has a differen PHY internally.
On this chip, phy status register doesn't properly reflect the result
of flow control negotiation. To workaround the problem and avoid having
to have so much chip dependent code; compute the result of flow control
by looking at the local and remote advertised bits.
Signed-off-by: default avatarStephen Hemmminger <shemminger@linux-foundation.org>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 7a7b5181
...@@ -1766,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) ...@@ -1766,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
{ {
struct sky2_hw *hw = sky2->hw; struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port; unsigned port = sky2->port;
u16 lpa; u16 advert, lpa;
advert = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP); lpa = gm_phy_read(hw, port, PHY_MARV_AUNE_LP);
if (lpa & PHY_M_AN_RF) { if (lpa & PHY_M_AN_RF) {
printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name); printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name);
return -1; return -1;
...@@ -1784,20 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) ...@@ -1784,20 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
sky2->speed = sky2_phy_speed(hw, aux); sky2->speed = sky2_phy_speed(hw, aux);
sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
/* Pause bits are offset (9..8) */ /* Since the pause result bits seem to in different positions on
if (hw->chip_id == CHIP_ID_YUKON_XL * different chips. look at registers.
|| hw->chip_id == CHIP_ID_YUKON_EC_U */
|| hw->chip_id == CHIP_ID_YUKON_EX) if (!sky2_is_copper(hw)) {
aux >>= 6; /* Shift for bits in fiber PHY */
advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM);
lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM);
sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, if (advert & ADVERTISE_1000XPAUSE)
aux & PHY_M_PS_TX_P_EN); advert |= ADVERTISE_PAUSE_CAP;
if (advert & ADVERTISE_1000XPSE_ASYM)
advert |= ADVERTISE_PAUSE_ASYM;
if (lpa & LPA_1000XPAUSE)
lpa |= LPA_PAUSE_CAP;
if (lpa & LPA_1000XPAUSE_ASYM)
lpa |= LPA_PAUSE_ASYM;
}
sky2->flow_status = FC_NONE;
if (advert & ADVERTISE_PAUSE_CAP) {
if (lpa & LPA_PAUSE_CAP)
sky2->flow_status = FC_BOTH;
else if (advert & ADVERTISE_PAUSE_ASYM)
sky2->flow_status = FC_RX;
} else if (advert & ADVERTISE_PAUSE_ASYM) {
if ((lpa & LPA_PAUSE_CAP) && (lpa & LPA_PAUSE_ASYM))
sky2->flow_status = FC_TX;
}
if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
&& !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
sky2->flow_status = FC_NONE; sky2->flow_status = FC_NONE;
if (aux & PHY_M_PS_RX_P_EN) if (sky2->flow_status & FC_TX)
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
else else
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
......
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