Commit 45456e38 authored by Gerhard Engleder's avatar Gerhard Engleder Committed by Paolo Abeni
Browse files

net: phy: Allow loopback speed selection for PHY drivers



PHY drivers support loopback mode, but it is not possible to select the
speed of the loopback mode. The speed is chosen by the set_loopback()
operation of the PHY driver. Same is valid for genphy_loopback().

There are PHYs that support loopback with different speeds. Extend
set_loopback() to make loopback speed selection possible.

Signed-off-by: default avatarGerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250312203010.47429-2-gerhard@engleder-embedded.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 3d97da0e
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -215,8 +215,11 @@ static int adin_resume(struct phy_device *phydev)
	return adin_set_powerdown_mode(phydev, false);
}

static int adin_set_loopback(struct phy_device *phydev, bool enable)
static int adin_set_loopback(struct phy_device *phydev, bool enable, int speed)
{
	if (enable && speed)
		return -EOPNOTSUPP;

	if (enable)
		return phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_10T1L_CTRL,
					BMCR_LOOPBACK);
+4 −1
Original line number Diff line number Diff line
@@ -1009,8 +1009,11 @@ static void dp83867_link_change_notify(struct phy_device *phydev)
	}
}

static int dp83867_loopback(struct phy_device *phydev, bool enable)
static int dp83867_loopback(struct phy_device *phydev, bool enable, int speed)
{
	if (enable && speed)
		return -EOPNOTSUPP;

	return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
			  enable ? BMCR_LOOPBACK : 0);
}
+7 −1
Original line number Diff line number Diff line
@@ -2131,13 +2131,19 @@ static void marvell_get_stats_simple(struct phy_device *phydev,
		data[i] = marvell_get_stat_simple(phydev, i);
}

static int m88e1510_loopback(struct phy_device *phydev, bool enable)
static int m88e1510_loopback(struct phy_device *phydev, bool enable, int speed)
{
	int err;

	if (enable) {
		u16 bmcr_ctl, mscr2_ctl = 0;

		if (speed == SPEED_10 || speed == SPEED_100 ||
		    speed == SPEED_1000)
			phydev->speed = speed;
		else if (speed)
			return -EINVAL;

		bmcr_ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);

		err = phy_write(phydev, MII_BMCR, bmcr_ctl);
+7 −4
Original line number Diff line number Diff line
@@ -813,7 +813,7 @@ static void gpy_get_wol(struct phy_device *phydev,
	wol->wolopts = priv->wolopts;
}

static int gpy_loopback(struct phy_device *phydev, bool enable)
static int gpy_loopback(struct phy_device *phydev, bool enable, int speed)
{
	struct gpy_priv *priv = phydev->priv;
	u16 set = 0;
@@ -822,6 +822,9 @@ static int gpy_loopback(struct phy_device *phydev, bool enable)
	if (enable) {
		u64 now = get_jiffies_64();

		if (speed)
			return -EOPNOTSUPP;

		/* wait until 3 seconds from last disable */
		if (time_before64(now, priv->lb_dis_to))
			msleep(jiffies64_to_msecs(priv->lb_dis_to - now));
@@ -845,15 +848,15 @@ static int gpy_loopback(struct phy_device *phydev, bool enable)
	return 0;
}

static int gpy115_loopback(struct phy_device *phydev, bool enable)
static int gpy115_loopback(struct phy_device *phydev, bool enable, int speed)
{
	struct gpy_priv *priv = phydev->priv;

	if (enable)
		return gpy_loopback(phydev, enable);
		return gpy_loopback(phydev, enable, speed);

	if (priv->fw_minor > 0x76)
		return gpy_loopback(phydev, 0);
		return gpy_loopback(phydev, 0, 0);

	return genphy_soft_reset(phydev);
}
+4 −1
Original line number Diff line number Diff line
@@ -1228,8 +1228,11 @@ int gen10g_config_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(gen10g_config_aneg);

int genphy_c45_loopback(struct phy_device *phydev, bool enable)
int genphy_c45_loopback(struct phy_device *phydev, bool enable, int speed)
{
	if (enable && speed)
		return -EOPNOTSUPP;

	return phy_modify_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1,
			      MDIO_PCS_CTRL1_LOOPBACK,
			      enable ? MDIO_PCS_CTRL1_LOOPBACK : 0);
Loading