Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+31 −11
Original line number Original line Diff line number Diff line
@@ -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)
	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);