Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 22335939ec90 ("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>

authored by

Daniel Golle and committed by
Paolo Abeni
7b103aaf 651b253b

+33 -1
+33 -1
drivers/net/dsa/lantiq/mxl-gsw1xx.c
··· 11 11 12 12 #include <linux/bits.h> 13 13 #include <linux/delay.h> 14 + #include <linux/jiffies.h> 14 15 #include <linux/module.h> 15 16 #include <linux/of_device.h> 16 17 #include <linux/of_mdio.h> 17 18 #include <linux/regmap.h> 19 + #include <linux/workqueue.h> 18 20 #include <net/dsa.h> 19 21 20 22 #include "lantiq_gswip.h" ··· 31 29 struct regmap *clk; 32 30 struct regmap *shell; 33 31 struct phylink_pcs pcs; 32 + struct delayed_work clear_raneg; 34 33 phy_interface_t tbi_interface; 35 34 struct gswip_priv gswip; 36 35 }; ··· 148 145 { 149 146 struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs); 150 147 151 - /* Assert SGMII shell reset */ 148 + cancel_delayed_work_sync(&priv->clear_raneg); 149 + 150 + /* Assert SGMII shell reset (will also clear RANEG bit) */ 152 151 regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ, 153 152 GSW1XX_RST_REQ_SGMII_SHELL); 154 153 ··· 433 428 return 0; 434 429 } 435 430 431 + static void gsw1xx_pcs_clear_raneg(struct work_struct *work) 432 + { 433 + struct gsw1xx_priv *priv = 434 + container_of(work, struct gsw1xx_priv, clear_raneg.work); 435 + 436 + regmap_clear_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL, 437 + GSW1XX_SGMII_TBI_ANEGCTL_RANEG); 438 + } 439 + 436 440 static void gsw1xx_pcs_an_restart(struct phylink_pcs *pcs) 437 441 { 438 442 struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs); 439 443 444 + cancel_delayed_work_sync(&priv->clear_raneg); 445 + 440 446 regmap_set_bits(priv->sgmii, GSW1XX_SGMII_TBI_ANEGCTL, 441 447 GSW1XX_SGMII_TBI_ANEGCTL_RANEG); 448 + 449 + /* despite being documented as self-clearing, the RANEG bit 450 + * sometimes remains set, preventing auto-negotiation from happening. 451 + * MaxLinear advises to manually clear the bit after 10ms. 452 + */ 453 + schedule_delayed_work(&priv->clear_raneg, msecs_to_jiffies(10)); 442 454 } 443 455 444 456 static void gsw1xx_pcs_link_up(struct phylink_pcs *pcs, ··· 658 636 if (ret) 659 637 return ret; 660 638 639 + INIT_DELAYED_WORK(&priv->clear_raneg, gsw1xx_pcs_clear_raneg); 640 + 661 641 ret = gswip_probe_common(&priv->gswip, version); 662 642 if (ret) 663 643 return ret; ··· 672 648 static void gsw1xx_remove(struct mdio_device *mdiodev) 673 649 { 674 650 struct gswip_priv *priv = dev_get_drvdata(&mdiodev->dev); 651 + struct gsw1xx_priv *gsw1xx_priv; 675 652 676 653 if (!priv) 677 654 return; 678 655 679 656 dsa_unregister_switch(priv->ds); 657 + 658 + gsw1xx_priv = container_of(priv, struct gsw1xx_priv, gswip); 659 + cancel_delayed_work_sync(&gsw1xx_priv->clear_raneg); 680 660 } 681 661 682 662 static void gsw1xx_shutdown(struct mdio_device *mdiodev) 683 663 { 684 664 struct gswip_priv *priv = dev_get_drvdata(&mdiodev->dev); 665 + struct gsw1xx_priv *gsw1xx_priv; 685 666 686 667 if (!priv) 687 668 return; ··· 694 665 dsa_switch_shutdown(priv->ds); 695 666 696 667 dev_set_drvdata(&mdiodev->dev, NULL); 668 + 669 + gsw1xx_priv = container_of(priv, struct gsw1xx_priv, gswip); 670 + cancel_delayed_work_sync(&gsw1xx_priv->clear_raneg); 697 671 } 698 672 699 673 static const struct gswip_hw_info gsw12x_data = {