summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRohan G Thomas <rohan.g.thomas@altera.com>2025-09-06 10:33:31 +0800
committerJakub Kicinski <kuba@kernel.org>2025-09-09 19:30:51 -0700
commitdeb105f49879dd50d595f7f55207d6e74dec34e6 (patch)
tree28c3a5449099ad428b9a8501ff2c7a4753fbaccc
parent214da63451bbdf00cbf2347d8f264d39ae938c7e (diff)
net: phy: marvell: Fix 88e1510 downshift counter errata
The 88e1510 PHY has an erratum where the phy downshift counter is not cleared after phy being suspended(BMCR_PDOWN set) and then later resumed(BMCR_PDOWN cleared). This can cause the gigabit link to intermittently downshift to a lower speed. Disabling and re-enabling the downshift feature clears the counter, allowing the PHY to retry gigabit link negotiation up to the programmed retry count times before downshifting. This behavior has been observed on copper links. Signed-off-by: Rohan G Thomas <rohan.g.thomas@altera.com> Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Link: https://patch.msgid.link/20250906-marvell_fix-v2-1-f6efb286937f@altera.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/phy/marvell.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 623292948fa7..0ea366c1217e 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -1902,6 +1902,43 @@ error:
return err;
}
+/* m88e1510_resume
+ *
+ * The 88e1510 PHY has an erratum where the phy downshift counter is not cleared
+ * after phy being suspended(BMCR_PDOWN set) and then later resumed(BMCR_PDOWN
+ * cleared). This can cause the link to intermittently downshift to a lower speed.
+ *
+ * Disabling and re-enabling the downshift feature clears the counter, allowing
+ * the PHY to retry gigabit link negotiation up to the programmed retry count
+ * before downshifting. This behavior has been observed on copper links.
+ */
+static int m88e1510_resume(struct phy_device *phydev)
+{
+ int err;
+ u8 cnt = 0;
+
+ err = marvell_resume(phydev);
+ if (err < 0)
+ return err;
+
+ /* read downshift counter value */
+ err = m88e1011_get_downshift(phydev, &cnt);
+ if (err < 0)
+ return err;
+
+ if (cnt) {
+ /* downshift disabled */
+ err = m88e1011_set_downshift(phydev, 0);
+ if (err < 0)
+ return err;
+
+ /* downshift enabled, with previous counter value */
+ err = m88e1011_set_downshift(phydev, cnt);
+ }
+
+ return err;
+}
+
static int marvell_aneg_done(struct phy_device *phydev)
{
int retval = phy_read(phydev, MII_M1011_PHY_STATUS);
@@ -3923,7 +3960,7 @@ static struct phy_driver marvell_drivers[] = {
.handle_interrupt = marvell_handle_interrupt,
.get_wol = m88e1318_get_wol,
.set_wol = m88e1318_set_wol,
- .resume = marvell_resume,
+ .resume = m88e1510_resume,
.suspend = marvell_suspend,
.read_page = marvell_read_page,
.write_page = marvell_write_page,