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

Commit 2712168f authored by Matt Carlson's avatar Matt Carlson Committed by David S. Miller
Browse files

tg3: Allow phylib flowctrl changes anytime



This patch loosens the restriction that the phylib interface must be up
and running to change the flow control parameters.

Signed-off-by: default avatarMatt Carlson <mcarlson@broadcom.com>
Reviewed-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a4153d40
Loading
Loading
Loading
Loading
+52 −42
Original line number Diff line number Diff line
@@ -10093,56 +10093,66 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
	int err = 0;

	if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
		if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
			return -EAGAIN;

		if (epause->autoneg) {
		u32 newadv;
		struct phy_device *phydev;

		phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];

		if (!(phydev->supported & SUPPORTED_Pause) ||
		    (!(phydev->supported & SUPPORTED_Asym_Pause) &&
		     ((epause->rx_pause && !epause->tx_pause) ||
		      (!epause->rx_pause && epause->tx_pause))))
			return -EINVAL;

		tp->link_config.flowctrl = 0;
		if (epause->rx_pause) {
				if (epause->tx_pause)
			tp->link_config.flowctrl |= FLOW_CTRL_RX;

			if (epause->tx_pause) {
				tp->link_config.flowctrl |= FLOW_CTRL_TX;
				newadv = ADVERTISED_Pause;
				else
			} else
				newadv = ADVERTISED_Pause |
					 ADVERTISED_Asym_Pause;
		} else if (epause->tx_pause) {
			tp->link_config.flowctrl |= FLOW_CTRL_TX;
			newadv = ADVERTISED_Asym_Pause;
		} else
			newadv = 0;

		if (epause->autoneg)
			tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
		else
			tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;

		if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
			u32 oldadv = phydev->advertising &
					     (ADVERTISED_Pause |
					      ADVERTISED_Asym_Pause);
				     (ADVERTISED_Pause | ADVERTISED_Asym_Pause);
			if (oldadv != newadv) {
				phydev->advertising &=
					~(ADVERTISED_Pause |
					  ADVERTISED_Asym_Pause);
				phydev->advertising |= newadv;
					err = phy_start_aneg(phydev);
				if (phydev->autoneg) {
					/*
					 * Always renegotiate the link to
					 * inform our link partner of our
					 * flow control settings, even if the
					 * flow control is forced.  Let
					 * tg3_adjust_link() do the final
					 * flow control setup.
					 */
					return phy_start_aneg(phydev);
				}
			} else {
				tp->link_config.advertising &=
						~(ADVERTISED_Pause |
						  ADVERTISED_Asym_Pause);
				tp->link_config.advertising |= newadv;
			}
		} else {
			if (epause->rx_pause)
				tp->link_config.flowctrl |= FLOW_CTRL_RX;
			else
				tp->link_config.flowctrl &= ~FLOW_CTRL_RX;

			if (epause->tx_pause)
				tp->link_config.flowctrl |= FLOW_CTRL_TX;
			else
				tp->link_config.flowctrl &= ~FLOW_CTRL_TX;

			if (netif_running(dev))
			if (!epause->autoneg)
				tg3_setup_flow_control(tp, 0, 0);
		} else {
			tp->link_config.orig_advertising &=
					~(ADVERTISED_Pause |
					  ADVERTISED_Asym_Pause);
			tp->link_config.orig_advertising |= newadv;
		}
	} else {
		int irq_sync = 0;