Commit 0ba13995 authored by Xu Liang's avatar Xu Liang Committed by David S. Miller
Browse files

net: phy: mxl-gpy: enhance delay time required by loopback disable function



GPY2xx devices need 3 seconds to fully switch out of loopback mode
before it can safely re-enter loopback mode. Implement timeout mechanism
to guarantee 3 seconds waited before re-enter loopback mode.

Signed-off-by: default avatarXu Liang <lxu@maxlinear.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9bdf4489
Loading
Loading
Loading
Loading
+29 −6
Original line number Diff line number Diff line
@@ -107,6 +107,13 @@ struct gpy_priv {

	u8 fw_major;
	u8 fw_minor;

	/* It takes 3 seconds to fully switch out of loopback mode before
	 * it can safely re-enter loopback mode. Record the time when
	 * loopback is disabled. Check and wait if necessary before loopback
	 * is enabled.
	 */
	u64 lb_dis_to;
};

static const struct {
@@ -769,18 +776,34 @@ static void gpy_get_wol(struct phy_device *phydev,

static int gpy_loopback(struct phy_device *phydev, bool enable)
{
	struct gpy_priv *priv = phydev->priv;
	u16 set = 0;
	int ret;

	ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
			 enable ? BMCR_LOOPBACK : 0);
	if (!ret) {
		/* It takes some time for PHY device to switch
		 * into/out-of loopback mode.
	if (enable) {
		u64 now = get_jiffies_64();

		/* wait until 3 seconds from last disable */
		if (time_before64(now, priv->lb_dis_to))
			msleep(jiffies64_to_msecs(priv->lb_dis_to - now));

		set = BMCR_LOOPBACK;
	}

	ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, set);
	if (ret <= 0)
		return ret;

	if (enable) {
		/* It takes some time for PHY device to switch into
		 * loopback mode.
		 */
		msleep(100);
	} else {
		priv->lb_dis_to = get_jiffies_64() + HZ * 3;
	}

	return ret;
	return 0;
}

static int gpy115_loopback(struct phy_device *phydev, bool enable)