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: Stephen Hemmminger <shemminger@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
7a7b518151
commit
da4c1ff475
@ -1766,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
|
||||
{
|
||||
struct sky2_hw *hw = sky2->hw;
|
||||
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);
|
||||
|
||||
if (lpa & PHY_M_AN_RF) {
|
||||
printk(KERN_ERR PFX "%s: remote fault", sky2->netdev->name);
|
||||
return -1;
|
||||
@ -1784,20 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
|
||||
sky2->speed = sky2_phy_speed(hw, aux);
|
||||
sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
|
||||
|
||||
/* Pause bits are offset (9..8) */
|
||||
if (hw->chip_id == CHIP_ID_YUKON_XL
|
||||
|| hw->chip_id == CHIP_ID_YUKON_EC_U
|
||||
|| hw->chip_id == CHIP_ID_YUKON_EX)
|
||||
aux >>= 6;
|
||||
/* Since the pause result bits seem to in different positions on
|
||||
* different chips. look at registers.
|
||||
*/
|
||||
if (!sky2_is_copper(hw)) {
|
||||
/* 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,
|
||||
aux & PHY_M_PS_TX_P_EN);
|
||||
if (advert & ADVERTISE_1000XPAUSE)
|
||||
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
|
||||
&& !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
|
||||
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);
|
||||
else
|
||||
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
|
||||
|
Loading…
Reference in New Issue
Block a user