Skip to content

Commit 7b103aa

Browse files
dangowrtPaolo Abeni
authored andcommitted
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. In order to not hold RTNL during the 10ms of waiting schedule delayed work to take care of clearing the bit asynchronously, which is similar to the self-clearing behavior. Fixes: 2233593 ("net: dsa: add driver for MaxLinear GSW1xx switch family") Reported-by: Rasmus Villemoes <ravi@prevas.dk> Signed-off-by: Daniel Golle <daniel@makrotopia.org> Link: https://patch.msgid.link/76745fceb5a3f53088110fb7a96acf88434088ca.1765241054.git.daniel@makrotopia.org Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 651b253 commit 7b103aa

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

drivers/net/dsa/lantiq/mxl-gsw1xx.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111

1212
#include <linux/bits.h>
1313
#include <linux/delay.h>
14+
#include <linux/jiffies.h>
1415
#include <linux/module.h>
1516
#include <linux/of_device.h>
1617
#include <linux/of_mdio.h>
1718
#include <linux/regmap.h>
19+
#include <linux/workqueue.h>
1820
#include <net/dsa.h>
1921

2022
#include "lantiq_gswip.h"
@@ -29,6 +31,7 @@ struct gsw1xx_priv {
2931
struct regmap *clk;
3032
struct regmap *shell;
3133
struct phylink_pcs pcs;
34+
struct delayed_work clear_raneg;
3235
phy_interface_t tbi_interface;
3336
struct gswip_priv gswip;
3437
};
@@ -145,7 +148,9 @@ static void gsw1xx_pcs_disable(struct phylink_pcs *pcs)
145148
{
146149
struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs);
147150

148-
/* Assert SGMII shell reset */
151+
cancel_delayed_work_sync(&priv->clear_raneg);
152+
153+
/* Assert SGMII shell reset (will also clear RANEG bit) */
149154
regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
150155
GSW1XX_RST_REQ_SGMII_SHELL);
151156

@@ -428,12 +433,29 @@ static int gsw1xx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
428433
return 0;
429434
}
430435

436+
static void gsw1xx_pcs_clear_raneg(struct work_struct *work)
437+
{
438+
struct gsw1xx_priv *priv =
439+
container_of(work, struct gsw1xx_priv, clear_raneg.work);
440+
441+
regmap_clear_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL,
442+
GSW1XX_SGMII_TBI_ANEGCTL_RANEG);
443+
}
444+
431445
static void gsw1xx_pcs_an_restart(struct phylink_pcs *pcs)
432446
{
433447
struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs);
434448

449+
cancel_delayed_work_sync(&priv->clear_raneg);
450+
435451
regmap_set_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL,
436452
GSW1XX_SGMII_TBI_ANEGCTL_RANEG);
453+
454+
/* despite being documented as self-clearing, the RANEG bit
455+
* sometimes remains set, preventing auto-negotiation from happening.
456+
* MaxLinear advises to manually clear the bit after 10ms.
457+
*/
458+
schedule_delayed_work(&priv->clear_raneg, msecs_to_jiffies(10));
437459
}
438460

439461
static void gsw1xx_pcs_link_up(struct phylink_pcs *pcs,
@@ -636,6 +658,8 @@ static int gsw1xx_probe(struct mdio_device *mdiodev)
636658
if (ret)
637659
return ret;
638660

661+
INIT_DELAYED_WORK(&priv->clear_raneg, gsw1xx_pcs_clear_raneg);
662+
639663
ret = gswip_probe_common(&priv->gswip, version);
640664
if (ret)
641665
return ret;
@@ -648,23 +672,31 @@ static int gsw1xx_probe(struct mdio_device *mdiodev)
648672
static void gsw1xx_remove(struct mdio_device *mdiodev)
649673
{
650674
struct gswip_priv *priv = dev_get_drvdata(&mdiodev->dev);
675+
struct gsw1xx_priv *gsw1xx_priv;
651676

652677
if (!priv)
653678
return;
654679

655680
dsa_unregister_switch(priv->ds);
681+
682+
gsw1xx_priv = container_of(priv, struct gsw1xx_priv, gswip);
683+
cancel_delayed_work_sync(&gsw1xx_priv->clear_raneg);
656684
}
657685

658686
static void gsw1xx_shutdown(struct mdio_device *mdiodev)
659687
{
660688
struct gswip_priv *priv = dev_get_drvdata(&mdiodev->dev);
689+
struct gsw1xx_priv *gsw1xx_priv;
661690

662691
if (!priv)
663692
return;
664693

665694
dsa_switch_shutdown(priv->ds);
666695

667696
dev_set_drvdata(&mdiodev->dev, NULL);
697+
698+
gsw1xx_priv = container_of(priv, struct gsw1xx_priv, gswip);
699+
cancel_delayed_work_sync(&gsw1xx_priv->clear_raneg);
668700
}
669701

670702
static const struct gswip_hw_info gsw12x_data = {

0 commit comments

Comments
 (0)