Skip to content

Commit

Permalink
Merge branch 'dsa-shutdown'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
Make DSA switch drivers compatible with masters which unregister on shutdown

Changes in v2:
- fix build for b53_mmap
- use unregister_netdevice_many

It was reported by Lino here:

https://lore.kernel.org/netdev/20210909095324.12978-1-LinoSanfilippo@gmx.de/

that when the DSA master attempts to unregister its net_device on
shutdown, DSA should prevent that operation from succeeding because it
holds a reference to it. This hangs the shutdown process.

This issue was essentially introduced in commit 2f1e8ea ("net: dsa:
link interfaces with the DSA master to get rid of lockdep warnings").
The present series patches all DSA drivers to handle that case,
depending on whether those drivers were introduced before or after the
offending commit, a different Fixes: tag is specified for them.

The approach taken by this series solves the issue in essentially the
same way as Lino's patches, except for three key differences:

- this series takes a more minimal approach in what is done on shutdown,
  we do not attempt a full tree teardown as that is not strictly
  necessary. I might revisit this if there are compelling reasons to do
  otherwise

- this series fixes the issues for all DSA drivers, not just KSZ9897

- this series works even if the ->remove driver method gets called for
  the same device too, not just ->shutdown. This is really possible to
  happen for SPI device drivers, and potentially possible for other bus
  device drivers too.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Sep 19, 2021
2 parents 02319bf + a68e9da commit 564df7a
Show file tree
Hide file tree
Showing 38 changed files with 543 additions and 24 deletions.
21 changes: 19 additions & 2 deletions drivers/net/dsa/b53/b53_mdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,25 @@ static int b53_mdio_probe(struct mdio_device *mdiodev)
static void b53_mdio_remove(struct mdio_device *mdiodev)
{
struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);
struct dsa_switch *ds = dev->ds;

dsa_unregister_switch(ds);
if (!dev)
return;

b53_switch_remove(dev);

dev_set_drvdata(&mdiodev->dev, NULL);
}

static void b53_mdio_shutdown(struct mdio_device *mdiodev)
{
struct b53_device *dev = dev_get_drvdata(&mdiodev->dev);

if (!dev)
return;

b53_switch_shutdown(dev);

dev_set_drvdata(&mdiodev->dev, NULL);
}

static const struct of_device_id b53_of_match[] = {
Expand All @@ -373,6 +389,7 @@ MODULE_DEVICE_TABLE(of, b53_of_match);
static struct mdio_driver b53_mdio_driver = {
.probe = b53_mdio_probe,
.remove = b53_mdio_remove,
.shutdown = b53_mdio_shutdown,
.mdiodrv.driver = {
.name = "bcm53xx",
.of_match_table = b53_of_match,
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/dsa/b53/b53_mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,21 @@ static int b53_mmap_remove(struct platform_device *pdev)
if (dev)
b53_switch_remove(dev);

platform_set_drvdata(pdev, NULL);

return 0;
}

static void b53_mmap_shutdown(struct platform_device *pdev)
{
struct b53_device *dev = platform_get_drvdata(pdev);

if (dev)
b53_switch_shutdown(dev);

platform_set_drvdata(pdev, NULL);
}

static const struct of_device_id b53_mmap_of_table[] = {
{ .compatible = "brcm,bcm3384-switch" },
{ .compatible = "brcm,bcm6328-switch" },
Expand All @@ -331,6 +343,7 @@ MODULE_DEVICE_TABLE(of, b53_mmap_of_table);
static struct platform_driver b53_mmap_driver = {
.probe = b53_mmap_probe,
.remove = b53_mmap_remove,
.shutdown = b53_mmap_shutdown,
.driver = {
.name = "b53-switch",
.of_match_table = b53_mmap_of_table,
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/dsa/b53/b53_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ static inline void b53_switch_remove(struct b53_device *dev)
dsa_unregister_switch(dev->ds);
}

static inline void b53_switch_shutdown(struct b53_device *dev)
{
dsa_switch_shutdown(dev->ds);
}

#define b53_build_op(type_op_size, val_type) \
static inline int b53_##type_op_size(struct b53_device *dev, u8 page, \
u8 reg, val_type val) \
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/dsa/b53/b53_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,21 @@ static int b53_spi_remove(struct spi_device *spi)
if (dev)
b53_switch_remove(dev);

spi_set_drvdata(spi, NULL);

return 0;
}

static void b53_spi_shutdown(struct spi_device *spi)
{
struct b53_device *dev = spi_get_drvdata(spi);

if (dev)
b53_switch_shutdown(dev);

spi_set_drvdata(spi, NULL);
}

static const struct of_device_id b53_spi_of_match[] = {
{ .compatible = "brcm,bcm5325" },
{ .compatible = "brcm,bcm5365" },
Expand All @@ -344,6 +356,7 @@ static struct spi_driver b53_spi_driver = {
},
.probe = b53_spi_probe,
.remove = b53_spi_remove,
.shutdown = b53_spi_shutdown,
};

module_spi_driver(b53_spi_driver);
Expand Down
21 changes: 19 additions & 2 deletions drivers/net/dsa/b53/b53_srab.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,17 +629,34 @@ static int b53_srab_probe(struct platform_device *pdev)
static int b53_srab_remove(struct platform_device *pdev)
{
struct b53_device *dev = platform_get_drvdata(pdev);
struct b53_srab_priv *priv = dev->priv;

b53_srab_intr_set(priv, false);
if (!dev)
return 0;

b53_srab_intr_set(dev->priv, false);
b53_switch_remove(dev);

platform_set_drvdata(pdev, NULL);

return 0;
}

static void b53_srab_shutdown(struct platform_device *pdev)
{
struct b53_device *dev = platform_get_drvdata(pdev);

if (!dev)
return;

b53_switch_shutdown(dev);

platform_set_drvdata(pdev, NULL);
}

static struct platform_driver b53_srab_driver = {
.probe = b53_srab_probe,
.remove = b53_srab_remove,
.shutdown = b53_srab_shutdown,
.driver = {
.name = "b53-srab-switch",
.of_match_table = b53_srab_of_match,
Expand Down
12 changes: 12 additions & 0 deletions drivers/net/dsa/bcm_sf2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,9 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev)
{
struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);

if (!priv)
return 0;

priv->wol_ports_mask = 0;
/* Disable interrupts */
bcm_sf2_intr_disable(priv);
Expand All @@ -1523,13 +1526,18 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev)
if (priv->type == BCM7278_DEVICE_ID)
reset_control_assert(priv->rcdev);

platform_set_drvdata(pdev, NULL);

return 0;
}

static void bcm_sf2_sw_shutdown(struct platform_device *pdev)
{
struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);

if (!priv)
return;

/* For a kernel about to be kexec'd we want to keep the GPHY on for a
* successful MDIO bus scan to occur. If we did turn off the GPHY
* before (e.g: port_disable), this will also power it back on.
Expand All @@ -1538,6 +1546,10 @@ static void bcm_sf2_sw_shutdown(struct platform_device *pdev)
*/
if (priv->hw_params.num_gphy == 1)
bcm_sf2_gphy_enable_set(priv->dev->ds, true);

dsa_switch_shutdown(priv->dev->ds);

platform_set_drvdata(pdev, NULL);
}

#ifdef CONFIG_PM_SLEEP
Expand Down
22 changes: 21 additions & 1 deletion drivers/net/dsa/dsa_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,29 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev)
static void dsa_loop_drv_remove(struct mdio_device *mdiodev)
{
struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
struct dsa_loop_priv *ps = ds->priv;
struct dsa_loop_priv *ps;

if (!ds)
return;

ps = ds->priv;

dsa_unregister_switch(ds);
dev_put(ps->netdev);

dev_set_drvdata(&mdiodev->dev, NULL);
}

static void dsa_loop_drv_shutdown(struct mdio_device *mdiodev)
{
struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);

if (!ds)
return;

dsa_switch_shutdown(ds);

dev_set_drvdata(&mdiodev->dev, NULL);
}

static struct mdio_driver dsa_loop_drv = {
Expand All @@ -352,6 +371,7 @@ static struct mdio_driver dsa_loop_drv = {
},
.probe = dsa_loop_drv_probe,
.remove = dsa_loop_drv_remove,
.shutdown = dsa_loop_drv_shutdown,
};

#define NUM_FIXED_PHYS (DSA_LOOP_NUM_PORTS - 2)
Expand Down
16 changes: 16 additions & 0 deletions drivers/net/dsa/hirschmann/hellcreek.c
Original file line number Diff line number Diff line change
Expand Up @@ -1916,6 +1916,9 @@ static int hellcreek_remove(struct platform_device *pdev)
{
struct hellcreek *hellcreek = platform_get_drvdata(pdev);

if (!hellcreek)
return 0;

hellcreek_hwtstamp_free(hellcreek);
hellcreek_ptp_free(hellcreek);
dsa_unregister_switch(hellcreek->ds);
Expand All @@ -1924,6 +1927,18 @@ static int hellcreek_remove(struct platform_device *pdev)
return 0;
}

static void hellcreek_shutdown(struct platform_device *pdev)
{
struct hellcreek *hellcreek = platform_get_drvdata(pdev);

if (!hellcreek)
return;

dsa_switch_shutdown(hellcreek->ds);

platform_set_drvdata(pdev, NULL);
}

static const struct hellcreek_platform_data de1soc_r1_pdata = {
.name = "r4c30",
.num_ports = 4,
Expand All @@ -1946,6 +1961,7 @@ MODULE_DEVICE_TABLE(of, hellcreek_of_match);
static struct platform_driver hellcreek_driver = {
.probe = hellcreek_probe,
.remove = hellcreek_remove,
.shutdown = hellcreek_shutdown,
.driver = {
.name = "hellcreek",
.of_match_table = hellcreek_of_match,
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/dsa/lan9303-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,12 @@ int lan9303_remove(struct lan9303 *chip)
}
EXPORT_SYMBOL(lan9303_remove);

void lan9303_shutdown(struct lan9303 *chip)
{
dsa_switch_shutdown(chip->ds);
}
EXPORT_SYMBOL(lan9303_shutdown);

MODULE_AUTHOR("Juergen Borleis <kernel@pengutronix.de>");
MODULE_DESCRIPTION("Core driver for SMSC/Microchip LAN9303 three port ethernet switch");
MODULE_LICENSE("GPL v2");
1 change: 1 addition & 0 deletions drivers/net/dsa/lan9303.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ extern const struct lan9303_phy_ops lan9303_indirect_phy_ops;

int lan9303_probe(struct lan9303 *chip, struct device_node *np);
int lan9303_remove(struct lan9303 *chip);
void lan9303_shutdown(struct lan9303 *chip);
24 changes: 20 additions & 4 deletions drivers/net/dsa/lan9303_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,28 @@ static int lan9303_i2c_probe(struct i2c_client *client,

static int lan9303_i2c_remove(struct i2c_client *client)
{
struct lan9303_i2c *sw_dev;
struct lan9303_i2c *sw_dev = i2c_get_clientdata(client);

sw_dev = i2c_get_clientdata(client);
if (!sw_dev)
return -ENODEV;
return 0;

lan9303_remove(&sw_dev->chip);

i2c_set_clientdata(client, NULL);

return 0;
}

static void lan9303_i2c_shutdown(struct i2c_client *client)
{
struct lan9303_i2c *sw_dev = i2c_get_clientdata(client);

if (!sw_dev)
return;

lan9303_shutdown(&sw_dev->chip);

return lan9303_remove(&sw_dev->chip);
i2c_set_clientdata(client, NULL);
}

/*-------------------------------------------------------------------------*/
Expand All @@ -97,6 +112,7 @@ static struct i2c_driver lan9303_i2c_driver = {
},
.probe = lan9303_i2c_probe,
.remove = lan9303_i2c_remove,
.shutdown = lan9303_i2c_shutdown,
.id_table = lan9303_i2c_id,
};
module_i2c_driver(lan9303_i2c_driver);
Expand Down
15 changes: 15 additions & 0 deletions drivers/net/dsa/lan9303_mdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ static void lan9303_mdio_remove(struct mdio_device *mdiodev)
return;

lan9303_remove(&sw_dev->chip);

dev_set_drvdata(&mdiodev->dev, NULL);
}

static void lan9303_mdio_shutdown(struct mdio_device *mdiodev)
{
struct lan9303_mdio *sw_dev = dev_get_drvdata(&mdiodev->dev);

if (!sw_dev)
return;

lan9303_shutdown(&sw_dev->chip);

dev_set_drvdata(&mdiodev->dev, NULL);
}

/*-------------------------------------------------------------------------*/
Expand All @@ -155,6 +169,7 @@ static struct mdio_driver lan9303_mdio_driver = {
},
.probe = lan9303_mdio_probe,
.remove = lan9303_mdio_remove,
.shutdown = lan9303_mdio_shutdown,
};
mdio_module_driver(lan9303_mdio_driver);

Expand Down
18 changes: 18 additions & 0 deletions drivers/net/dsa/lantiq_gswip.c
Original file line number Diff line number Diff line change
Expand Up @@ -2184,6 +2184,9 @@ static int gswip_remove(struct platform_device *pdev)
struct gswip_priv *priv = platform_get_drvdata(pdev);
int i;

if (!priv)
return 0;

/* disable the switch */
gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);

Expand All @@ -2197,9 +2200,23 @@ static int gswip_remove(struct platform_device *pdev)
for (i = 0; i < priv->num_gphy_fw; i++)
gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);

platform_set_drvdata(pdev, NULL);

return 0;
}

static void gswip_shutdown(struct platform_device *pdev)
{
struct gswip_priv *priv = platform_get_drvdata(pdev);

if (!priv)
return;

dsa_switch_shutdown(priv->ds);

platform_set_drvdata(pdev, NULL);
}

static const struct gswip_hw_info gswip_xrx200 = {
.max_ports = 7,
.cpu_port = 6,
Expand All @@ -2223,6 +2240,7 @@ MODULE_DEVICE_TABLE(of, gswip_of_match);
static struct platform_driver gswip_driver = {
.probe = gswip_probe,
.remove = gswip_remove,
.shutdown = gswip_shutdown,
.driver = {
.name = "gswip",
.of_match_table = gswip_of_match,
Expand Down
Loading

0 comments on commit 564df7a

Please sign in to comment.