[PATCH net-next v3 11/15] net: phy: at803x: ar8035: fix EEE support for half duplex links

From: Oleksij Rempel
Date: Mon Jan 30 2023 - 03:08:05 EST


If AR8035 is running with enabled EEE and LPI, it will not be able to
establish an 100BaseTX/Half or 1000BaseT/Half link. Similar issue we
will have with 100BaseTX/Full and LPI TX timer configured to less then
80msec.

To avoid this issue, we need to keep LPI disabled before link is
establish and enable it only we detected supported link configuration.

Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx>
---
drivers/net/phy/at803x.c | 41 +++++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 9eb4439b0afc..5ab43eb63581 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -313,6 +313,7 @@ struct at803x_priv {
u8 smarteee_lpi_tw_100m;
bool is_fiber;
bool is_1000basex;
+ bool tx_lpi_on;
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
struct regulator *vddio;
@@ -970,6 +971,8 @@ static int at803x_smarteee_config(struct phy_device *phydev, bool enable,
u16 mask = 0, val = 0;
int ret;

+ priv->tx_lpi_on = enable;
+
if (priv->flags & AT803X_DISABLE_SMARTEEE || !enable)
return phy_modify_mmd(phydev, MDIO_MMD_PCS,
AT803X_MMD3_SMARTEEE_CTL3,
@@ -1010,10 +1013,15 @@ static int at803x_smarteee_config(struct phy_device *phydev, bool enable,
if (ret)
return ret;

- val = AT803X_MMD3_SMARTEEE_CTL3_LPI_EN |
- FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH,
- FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_23_16,
- tx_lpi_timer_raw));
+ val = FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH,
+ FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_23_16,
+ tx_lpi_timer_raw));
+
+ if (phydev->state == PHY_RUNNING &&
+ phy_check_valid(phydev->speed, phydev->duplex,
+ phydev->supported_eee)) {
+ val |= AT803X_MMD3_SMARTEEE_CTL3_LPI_EN;
+ }

return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
AT803X_MMD3_SMARTEEE_CTL3_LPI_EN |
@@ -1682,7 +1690,7 @@ static int at803x_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
tx_timer_ns = tx_timer_raw * AT803X_MMD3_SMARTEEE_LPI_TIME_RESOL_NS;
data->tx_lpi_timer = DIV_ROUND_CLOSEST_ULL(tx_timer_ns, NSEC_PER_USEC);

- data->tx_lpi_enabled = !!(ret & AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
+ data->tx_lpi_enabled = priv->tx_lpi_on;

return genphy_c45_ethtool_get_eee(phydev, data);
}
@@ -1709,6 +1717,28 @@ static int at803x_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
return genphy_c45_ethtool_set_eee(phydev, data);
}

+static void at8035_link_change_notify(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+
+ if (priv->flags & AT803X_DISABLE_SMARTEEE)
+ return;
+
+ if (phydev->state == PHY_RUNNING) {
+ if (priv->tx_lpi_on && phy_check_valid(phydev->speed,
+ phydev->duplex,
+ phydev->supported_eee))
+ phy_set_bits_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_MMD3_SMARTEEE_CTL3,
+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
+ } else {
+ if (priv->tx_lpi_on)
+ phy_clear_bits_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_MMD3_SMARTEEE_CTL3,
+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
+ }
+}
+
static int qca83xx_config_init(struct phy_device *phydev)
{
u8 switch_revision;
@@ -2137,6 +2167,7 @@ static struct phy_driver at803x_driver[] = {
.cable_test_get_status = at803x_cable_test_get_status,
.get_eee = at803x_get_eee,
.set_eee = at803x_set_eee,
+ .link_change_notify = at8035_link_change_notify,
}, {
/* Qualcomm Atheros AR8030 */
.phy_id = ATH8030_PHY_ID,
--
2.30.2