[<prev] [next>] [day] [month] [year] [list]
Message-ID: <ab836f5d36e3f00cd8e2fb3e647b7204b5b6c990.1764898074.git.daniel@makrotopia.org>
Date: Fri, 5 Dec 2025 01:32:20 +0000
From: Daniel Golle <daniel@...rotopia.org>
To: Hauke Mehrtens <hauke@...ke-m.de>, Andrew Lunn <andrew@...n.ch>,
Vladimir Oltean <olteanv@...il.com>,
"David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
Russell King <linux@...linux.org.uk>,
Daniel Golle <daniel@...rotopia.org>, netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Cc: Rasmus Villemoes <ravi@...vas.dk>,
"Benny (Ying-Tsan) Weng" <yweng@...linear.com>,
John Crispin <john@...ozen.org>
Subject: [PATCH net] net: dsa: mxl-gsw1xx: manually clear RANEG bit
Despite being documented as self-clearing, the RANEG bit sometimes
remains set, preventing auto-negotiation from happening.
Manually clear the RANEG bit after 10ms as advised by MaxLinear, using
delayed_work emulating the asynchronous self-clearing behavior.
Fixes: 22335939ec90 ("net: dsa: add driver for MaxLinear GSW1xx switch family")
Reported-by: Rasmus Villemoes <ravi@...vas.dk>
Suggested-by: "Benny (Ying-Tsan) Weng" <yweng@...linear.com>
Signed-off-by: Daniel Golle <daniel@...rotopia.org>
---
drivers/net/dsa/lantiq/mxl-gsw1xx.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/net/dsa/lantiq/mxl-gsw1xx.c b/drivers/net/dsa/lantiq/mxl-gsw1xx.c
index cf33a16fd183b..91304d3c1ca9b 100644
--- a/drivers/net/dsa/lantiq/mxl-gsw1xx.c
+++ b/drivers/net/dsa/lantiq/mxl-gsw1xx.c
@@ -11,10 +11,12 @@
#include <linux/bits.h>
#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/regmap.h>
+#include <linux/workqueue.h>
#include <net/dsa.h>
#include "lantiq_gswip.h"
@@ -29,6 +31,7 @@ struct gsw1xx_priv {
struct regmap *clk;
struct regmap *shell;
struct phylink_pcs pcs;
+ struct delayed_work clear_raneg;
phy_interface_t tbi_interface;
struct gswip_priv gswip;
};
@@ -145,6 +148,8 @@ static void gsw1xx_pcs_disable(struct phylink_pcs *pcs)
{
struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs);
+ cancel_delayed_work_sync(&priv->clear_raneg);
+
/* Assert SGMII shell reset */
regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
GSW1XX_RST_REQ_SGMII_SHELL);
@@ -428,12 +433,27 @@ static int gsw1xx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
return 0;
}
+static void gsw1xx_pcs_clear_raneg(struct work_struct *work)
+{
+ struct gsw1xx_priv *priv =
+ container_of(work, struct gsw1xx_priv, clear_raneg.work);
+
+ regmap_clear_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL,
+ GSW1XX_SGMII_TBI_ANEGCTL_RANEG);
+}
+
static void gsw1xx_pcs_an_restart(struct phylink_pcs *pcs)
{
struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs);
regmap_set_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL,
GSW1XX_SGMII_TBI_ANEGCTL_RANEG);
+
+ /* despite being documented as self-clearing, the RANEG bit
+ * sometimes remains set, preventing auto-negotiation from happening.
+ * MaxLinear advises to manually clear the bit after 10ms.
+ */
+ schedule_delayed_work(&priv->clear_raneg, msecs_to_jiffies(10));
}
static void gsw1xx_pcs_link_up(struct phylink_pcs *pcs,
@@ -636,6 +656,8 @@ static int gsw1xx_probe(struct mdio_device *mdiodev)
if (ret)
return ret;
+ INIT_DELAYED_WORK(&priv->clear_raneg, gsw1xx_pcs_clear_raneg);
+
ret = gswip_probe_common(&priv->gswip, version);
if (ret)
return ret;
--
2.52.0
Powered by blists - more mailing lists