Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f952fce authored by Yuusuke Ashizuka's avatar Yuusuke Ashizuka Committed by Greg Kroah-Hartman
Browse files

ravb: Fixed to be able to unload modules



[ Upstream commit 1838d6c62f57836639bd3d83e7855e0ee4f6defc ]

When this driver is built as a module, I cannot rmmod it after insmoding
it.
This is because that this driver calls ravb_mdio_init() at the time of
probe, and module->refcnt is incremented by alloc_mdio_bitbang() called
after that.
Therefore, even if ifup is not performed, the driver is in use and rmmod
cannot be performed.

$ lsmod
Module                  Size  Used by
ravb                   40960  1
$ rmmod ravb
rmmod: ERROR: Module ravb is in use

Call ravb_mdio_init() at open and free_mdio_bitbang() at close, thereby
rmmod is possible in the ifdown state.

Fixes: c156633f ("Renesas Ethernet AVB driver proper")
Signed-off-by: default avatarYuusuke Ashizuka <ashiduka@fujitsu.com>
Reviewed-by: default avatarSergei Shtylyov <sergei.shtylyov@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent fe46ff0c
Loading
Loading
Loading
Loading
+55 −55
Original line number Diff line number Diff line
@@ -1336,6 +1336,51 @@ static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
	return error;
}

/* MDIO bus init function */
static int ravb_mdio_init(struct ravb_private *priv)
{
	struct platform_device *pdev = priv->pdev;
	struct device *dev = &pdev->dev;
	int error;

	/* Bitbang init */
	priv->mdiobb.ops = &bb_ops;

	/* MII controller setting */
	priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
	if (!priv->mii_bus)
		return -ENOMEM;

	/* Hook up MII support for ethtool */
	priv->mii_bus->name = "ravb_mii";
	priv->mii_bus->parent = dev;
	snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
		 pdev->name, pdev->id);

	/* Register MDIO bus */
	error = of_mdiobus_register(priv->mii_bus, dev->of_node);
	if (error)
		goto out_free_bus;

	return 0;

out_free_bus:
	free_mdio_bitbang(priv->mii_bus);
	return error;
}

/* MDIO bus release function */
static int ravb_mdio_release(struct ravb_private *priv)
{
	/* Unregister mdio bus */
	mdiobus_unregister(priv->mii_bus);

	/* Free bitbang info */
	free_mdio_bitbang(priv->mii_bus);

	return 0;
}

/* Network device open function for Ethernet AVB */
static int ravb_open(struct net_device *ndev)
{
@@ -1344,6 +1389,13 @@ static int ravb_open(struct net_device *ndev)
	struct device *dev = &pdev->dev;
	int error;

	/* MDIO bus init */
	error = ravb_mdio_init(priv);
	if (error) {
		netdev_err(ndev, "failed to initialize MDIO\n");
		return error;
	}

	napi_enable(&priv->napi[RAVB_BE]);
	napi_enable(&priv->napi[RAVB_NC]);

@@ -1421,6 +1473,7 @@ static int ravb_open(struct net_device *ndev)
out_napi_off:
	napi_disable(&priv->napi[RAVB_NC]);
	napi_disable(&priv->napi[RAVB_BE]);
	ravb_mdio_release(priv);
	return error;
}

@@ -1718,6 +1771,8 @@ static int ravb_close(struct net_device *ndev)
	ravb_ring_free(ndev, RAVB_BE);
	ravb_ring_free(ndev, RAVB_NC);

	ravb_mdio_release(priv);

	return 0;
}

@@ -1820,51 +1875,6 @@ static const struct net_device_ops ravb_netdev_ops = {
	.ndo_change_mtu		= eth_change_mtu,
};

/* MDIO bus init function */
static int ravb_mdio_init(struct ravb_private *priv)
{
	struct platform_device *pdev = priv->pdev;
	struct device *dev = &pdev->dev;
	int error;

	/* Bitbang init */
	priv->mdiobb.ops = &bb_ops;

	/* MII controller setting */
	priv->mii_bus = alloc_mdio_bitbang(&priv->mdiobb);
	if (!priv->mii_bus)
		return -ENOMEM;

	/* Hook up MII support for ethtool */
	priv->mii_bus->name = "ravb_mii";
	priv->mii_bus->parent = dev;
	snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
		 pdev->name, pdev->id);

	/* Register MDIO bus */
	error = of_mdiobus_register(priv->mii_bus, dev->of_node);
	if (error)
		goto out_free_bus;

	return 0;

out_free_bus:
	free_mdio_bitbang(priv->mii_bus);
	return error;
}

/* MDIO bus release function */
static int ravb_mdio_release(struct ravb_private *priv)
{
	/* Unregister mdio bus */
	mdiobus_unregister(priv->mii_bus);

	/* Free bitbang info */
	free_mdio_bitbang(priv->mii_bus);

	return 0;
}

static const struct of_device_id ravb_match_table[] = {
	{ .compatible = "renesas,etheravb-r8a7790", .data = (void *)RCAR_GEN2 },
	{ .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 },
@@ -2069,13 +2079,6 @@ static int ravb_probe(struct platform_device *pdev)
		eth_hw_addr_random(ndev);
	}

	/* MDIO bus init */
	error = ravb_mdio_init(priv);
	if (error) {
		dev_err(&pdev->dev, "failed to initialize MDIO\n");
		goto out_dma_free;
	}

	netif_napi_add(ndev, &priv->napi[RAVB_BE], ravb_poll, 64);
	netif_napi_add(ndev, &priv->napi[RAVB_NC], ravb_poll, 64);

@@ -2095,8 +2098,6 @@ static int ravb_probe(struct platform_device *pdev)
out_napi_del:
	netif_napi_del(&priv->napi[RAVB_NC]);
	netif_napi_del(&priv->napi[RAVB_BE]);
	ravb_mdio_release(priv);
out_dma_free:
	dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
			  priv->desc_bat_dma);

@@ -2129,7 +2130,6 @@ static int ravb_remove(struct platform_device *pdev)
	unregister_netdev(ndev);
	netif_napi_del(&priv->napi[RAVB_NC]);
	netif_napi_del(&priv->napi[RAVB_BE]);
	ravb_mdio_release(priv);
	pm_runtime_disable(&pdev->dev);
	free_netdev(ndev);
	platform_set_drvdata(pdev, NULL);