Commit 71e6b15d authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'net-dsa-lantiq-a-bunch-of-fixes'

Daniel Golle says:

====================
net: dsa: lantiq: a bunch of fixes

This series is the continuation and result of comments received for a fix
for the SGMII restart-an bit not actually being self-clearing, which was
reported by by Rasmus Villemoes.

A closer investigation and testing the .remove and the .shutdown paths
of the mxl-gsw1xx.c and lantiq_gswip.c drivers has revealed a couple of
existing problems, which are also addressed in this series.
====================

Link: https://patch.msgid.link/cover.1765241054.git.daniel@makrotopia.org


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 7b07be1f 7b103aaf
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -444,9 +444,6 @@ static void gswip_remove(struct platform_device *pdev)
	if (!priv)
		return;

	/* disable the switch */
	gswip_disable_switch(priv);

	dsa_unregister_switch(priv->ds);

	for (i = 0; i < priv->num_gphy_fw; i++)
+0 −2
Original line number Diff line number Diff line
@@ -294,8 +294,6 @@ struct gswip_priv {
	u16 version;
};

void gswip_disable_switch(struct gswip_priv *priv);

int gswip_probe_common(struct gswip_priv *priv, u32 version);

#endif /* __LANTIQ_GSWIP_H */
+10 −9
Original line number Diff line number Diff line
@@ -752,6 +752,13 @@ static int gswip_setup(struct dsa_switch *ds)
	return 0;
}

static void gswip_teardown(struct dsa_switch *ds)
{
	struct gswip_priv *priv = ds->priv;

	regmap_clear_bits(priv->mdio, GSWIP_MDIO_GLOB, GSWIP_MDIO_GLOB_ENABLE);
}

static enum dsa_tag_protocol gswip_get_tag_protocol(struct dsa_switch *ds,
						    int port,
						    enum dsa_tag_protocol mp)
@@ -1629,6 +1636,7 @@ static const struct phylink_mac_ops gswip_phylink_mac_ops = {
static const struct dsa_switch_ops gswip_switch_ops = {
	.get_tag_protocol	= gswip_get_tag_protocol,
	.setup			= gswip_setup,
	.teardown		= gswip_teardown,
	.port_setup		= gswip_port_setup,
	.port_enable		= gswip_port_enable,
	.port_disable		= gswip_port_disable,
@@ -1656,12 +1664,6 @@ static const struct dsa_switch_ops gswip_switch_ops = {
	.port_hsr_leave		= dsa_port_simple_hsr_leave,
};

void gswip_disable_switch(struct gswip_priv *priv)
{
	regmap_clear_bits(priv->mdio, GSWIP_MDIO_GLOB, GSWIP_MDIO_GLOB_ENABLE);
}
EXPORT_SYMBOL_GPL(gswip_disable_switch);

static int gswip_validate_cpu_port(struct dsa_switch *ds)
{
	struct gswip_priv *priv = ds->priv;
@@ -1718,15 +1720,14 @@ int gswip_probe_common(struct gswip_priv *priv, u32 version)

	err = gswip_validate_cpu_port(priv->ds);
	if (err)
		goto disable_switch;
		goto unregister_switch;

	dev_info(priv->dev, "probed GSWIP version %lx mod %lx\n",
		 GSWIP_VERSION_REV(version), GSWIP_VERSION_MOD(version));

	return 0;

disable_switch:
	gswip_disable_switch(priv);
unregister_switch:
	dsa_unregister_switch(priv->ds);

	return err;
+34 −4
Original line number Diff line number Diff line
@@ -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,7 +148,9 @@ static void gsw1xx_pcs_disable(struct phylink_pcs *pcs)
{
	struct gsw1xx_priv *priv = pcs_to_gsw1xx(pcs);

	/* Assert SGMII shell reset */
	cancel_delayed_work_sync(&priv->clear_raneg);

	/* Assert SGMII shell reset (will also clear RANEG bit) */
	regmap_set_bits(priv->shell, GSW1XX_SHELL_RST_REQ,
			GSW1XX_RST_REQ_SGMII_SHELL);

@@ -428,12 +433,29 @@ 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);

	cancel_delayed_work_sync(&priv->clear_raneg);

	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 +658,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;
@@ -648,25 +672,31 @@ static int gsw1xx_probe(struct mdio_device *mdiodev)
static void gsw1xx_remove(struct mdio_device *mdiodev)
{
	struct gswip_priv *priv = dev_get_drvdata(&mdiodev->dev);
	struct gsw1xx_priv *gsw1xx_priv;

	if (!priv)
		return;

	gswip_disable_switch(priv);

	dsa_unregister_switch(priv->ds);

	gsw1xx_priv = container_of(priv, struct gsw1xx_priv, gswip);
	cancel_delayed_work_sync(&gsw1xx_priv->clear_raneg);
}

static void gsw1xx_shutdown(struct mdio_device *mdiodev)
{
	struct gswip_priv *priv = dev_get_drvdata(&mdiodev->dev);
	struct gsw1xx_priv *gsw1xx_priv;

	if (!priv)
		return;

	dsa_switch_shutdown(priv->ds);

	dev_set_drvdata(&mdiodev->dev, NULL);

	gswip_disable_switch(priv);
	gsw1xx_priv = container_of(priv, struct gsw1xx_priv, gswip);
	cancel_delayed_work_sync(&gsw1xx_priv->clear_raneg);
}

static const struct gswip_hw_info gsw12x_data = {