mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 10:01:39 -05:00
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: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
@@ -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++)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user