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

Commit c1ce2f77 authored by Lendacky, Thomas's avatar Lendacky, Thomas Committed by David S. Miller
Browse files

amd-xgbe: Fix flow control setting logic



The flow control negotiation logic is flawed and does not properly
advertise and process auto-negotiation of the flow control settings.
Update the flow control support to properly set the flow control
auto-negotiation settings and process the results approrpriately.

Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 34bfff40
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -782,8 +782,6 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
{
	pdata->phy_link = -1;
	pdata->phy_speed = SPEED_UNKNOWN;
	pdata->phy_tx_pause = pdata->tx_pause;
	pdata->phy_rx_pause = pdata->rx_pause;

	return pdata->phy_if.phy_reset(pdata);
}
+17 −12
Original line number Diff line number Diff line
@@ -247,9 +247,9 @@ static void xgbe_get_pauseparam(struct net_device *netdev,

	DBGPR("-->xgbe_get_pauseparam\n");

	pause->autoneg = pdata->pause_autoneg;
	pause->tx_pause = pdata->tx_pause;
	pause->rx_pause = pdata->rx_pause;
	pause->autoneg = pdata->phy.pause_autoneg;
	pause->tx_pause = pdata->phy.tx_pause;
	pause->rx_pause = pdata->phy.rx_pause;

	DBGPR("<--xgbe_get_pauseparam\n");
}
@@ -265,19 +265,24 @@ static int xgbe_set_pauseparam(struct net_device *netdev,
	DBGPR("  autoneg = %d, tx_pause = %d, rx_pause = %d\n",
	      pause->autoneg, pause->tx_pause, pause->rx_pause);

	pdata->pause_autoneg = pause->autoneg;
	if (pause->autoneg) {
		pdata->phy.advertising |= ADVERTISED_Pause;
		pdata->phy.advertising |= ADVERTISED_Asym_Pause;
	if (pause->autoneg && (pdata->phy.autoneg != AUTONEG_ENABLE))
		return -EINVAL;

	pdata->phy.pause_autoneg = pause->autoneg;
	pdata->phy.tx_pause = pause->tx_pause;
	pdata->phy.rx_pause = pause->rx_pause;

	} else {
	pdata->phy.advertising &= ~ADVERTISED_Pause;
	pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;

		pdata->tx_pause = pause->tx_pause;
		pdata->rx_pause = pause->rx_pause;
	if (pause->rx_pause) {
		pdata->phy.advertising |= ADVERTISED_Pause;
		pdata->phy.advertising |= ADVERTISED_Asym_Pause;
	}

	if (pause->tx_pause)
		pdata->phy.advertising ^= ADVERTISED_Asym_Pause;

	if (netif_running(netdev))
		ret = pdata->phy_if.phy_config_aneg(pdata);

+51 −22
Original line number Diff line number Diff line
@@ -737,6 +737,18 @@ static void xgbe_an_init(struct xgbe_prv_data *pdata)
	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
}

static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
{
	if (pdata->tx_pause && pdata->rx_pause)
		return "rx/tx";
	else if (pdata->rx_pause)
		return "rx";
	else if (pdata->tx_pause)
		return "tx";
	else
		return "off";
}

static const char *xgbe_phy_speed_string(int speed)
{
	switch (speed) {
@@ -760,7 +772,7 @@ static void xgbe_phy_print_status(struct xgbe_prv_data *pdata)
			    "Link is Up - %s/%s - flow control %s\n",
			    xgbe_phy_speed_string(pdata->phy.speed),
			    pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
			    pdata->phy.pause ? "rx/tx" : "off");
			    xgbe_phy_fc_string(pdata));
	else
		netdev_info(pdata->netdev, "Link is Down\n");
}
@@ -771,24 +783,18 @@ static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)

	if (pdata->phy.link) {
		/* Flow control support */
		if (pdata->pause_autoneg) {
			if (pdata->phy.pause || pdata->phy.asym_pause) {
				pdata->tx_pause = 1;
				pdata->rx_pause = 1;
			} else {
				pdata->tx_pause = 0;
				pdata->rx_pause = 0;
			}
		}
		pdata->pause_autoneg = pdata->phy.pause_autoneg;

		if (pdata->tx_pause != pdata->phy_tx_pause) {
		if (pdata->tx_pause != pdata->phy.tx_pause) {
			new_state = 1;
			pdata->hw_if.config_tx_flow_control(pdata);
			pdata->phy_tx_pause = pdata->tx_pause;
			pdata->tx_pause = pdata->phy.tx_pause;
		}

		if (pdata->rx_pause != pdata->phy_rx_pause) {
		if (pdata->rx_pause != pdata->phy.rx_pause) {
			new_state = 1;
			pdata->hw_if.config_rx_flow_control(pdata);
			pdata->phy_rx_pause = pdata->rx_pause;
			pdata->rx_pause = pdata->phy.rx_pause;
		}

		/* Speed support */
@@ -835,9 +841,6 @@ static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
	if (pdata->phy.duplex != DUPLEX_FULL)
		return -EINVAL;

	pdata->phy.pause = 0;
	pdata->phy.asym_pause = 0;

	return 0;
}

@@ -933,8 +936,6 @@ static void xgbe_phy_status_force(struct xgbe_prv_data *pdata)
		}
	}
	pdata->phy.duplex = DUPLEX_FULL;
	pdata->phy.pause = 0;
	pdata->phy.asym_pause = 0;
}

static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
@@ -957,9 +958,21 @@ static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
	if (lp_reg & 0x800)
		pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause;

	ad_reg &= lp_reg;
	pdata->phy.pause = (ad_reg & 0x400) ? 1 : 0;
	pdata->phy.asym_pause = (ad_reg & 0x800) ? 1 : 0;
	if (pdata->phy.pause_autoneg) {
		/* Set flow control based on auto-negotiation result */
		pdata->phy.tx_pause = 0;
		pdata->phy.rx_pause = 0;

		if (ad_reg & lp_reg & 0x400) {
			pdata->phy.tx_pause = 1;
			pdata->phy.rx_pause = 1;
		} else if (ad_reg & lp_reg & 0x800) {
			if (ad_reg & 0x400)
				pdata->phy.rx_pause = 1;
			else if (lp_reg & 0x400)
				pdata->phy.tx_pause = 1;
		}
	}

	/* Compare Advertisement and Link Partner register 2 */
	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
@@ -1223,6 +1236,22 @@ static void xgbe_phy_init(struct xgbe_prv_data *pdata)

	pdata->phy.link = 0;

	pdata->phy.pause_autoneg = pdata->pause_autoneg;
	pdata->phy.tx_pause = pdata->tx_pause;
	pdata->phy.rx_pause = pdata->rx_pause;

	/* Fix up Flow Control advertising */
	pdata->phy.advertising &= ~ADVERTISED_Pause;
	pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;

	if (pdata->rx_pause) {
		pdata->phy.advertising |= ADVERTISED_Pause;
		pdata->phy.advertising |= ADVERTISED_Asym_Pause;
	}

	if (pdata->tx_pause)
		pdata->phy.advertising ^= ADVERTISED_Asym_Pause;

	if (netif_msg_drv(pdata))
		xgbe_dump_phy_registers(pdata);
}
+4 −4
Original line number Diff line number Diff line
@@ -539,10 +539,12 @@ struct xgbe_phy {
	int autoneg;
	int speed;
	int duplex;
	int pause;
	int asym_pause;

	int link;

	int pause_autoneg;
	int tx_pause;
	int rx_pause;
};

struct xgbe_mmc_stats {
@@ -910,8 +912,6 @@ struct xgbe_prv_data {
	phy_interface_t phy_mode;
	int phy_link;
	int phy_speed;
	unsigned int phy_tx_pause;
	unsigned int phy_rx_pause;

	/* MDIO/PHY related settings */
	struct xgbe_phy phy;