summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2016-12-07 07:54:43 +0300
committerDavid S. Miller <davem@davemloft.net>2016-12-07 21:27:14 +0300
commitec988ad78ed6d184a7f4ca6b8e962b0e8f1de461 (patch)
treeabd95e56d38d8c2e4ab6c83b3391896291365bf5
parenta50af86dd49ee1851d1ccf06dd0019c05b95e297 (diff)
downloadlinux-ec988ad78ed6d184a7f4ca6b8e962b0e8f1de461.tar.xz
phy: Don't increment MDIO bus refcount unless it's a different owner
Commit 3e3aaf649416 ("phy: fix mdiobus module safety") fixed the way we dealt with MDIO bus module reference count, but sort of introduced a regression in that, if an Ethernet driver registers its own MDIO bus driver, as is common, we will end up with the Ethernet driver's module->refnct set to 1, thus preventing this driver from any removal. Fix this by comparing the network device's device driver owner against the MDIO bus driver owner, and only if they are different, increment the MDIO bus module refcount. Fixes: 3e3aaf649416 ("phy: fix mdiobus module safety") Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/phy_device.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 1a4bf8acad78..c4ceb082e970 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -857,11 +857,17 @@ EXPORT_SYMBOL(phy_attached_print);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
+ struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus = phydev->mdio.bus;
struct device *d = &phydev->mdio.dev;
int err;
- if (!try_module_get(bus->owner)) {
+ /* For Ethernet device drivers that register their own MDIO bus, we
+ * will have bus->owner match ndev_mod, so we do not want to increment
+ * our own module->refcnt here, otherwise we would not be able to
+ * unload later on.
+ */
+ if (ndev_owner != bus->owner && !try_module_get(bus->owner)) {
dev_err(&dev->dev, "failed to get the bus module\n");
return -EIO;
}
@@ -921,7 +927,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
error:
put_device(d);
- module_put(bus->owner);
+ if (ndev_owner != bus->owner)
+ module_put(bus->owner);
return err;
}
EXPORT_SYMBOL(phy_attach_direct);
@@ -971,6 +978,8 @@ EXPORT_SYMBOL(phy_attach);
*/
void phy_detach(struct phy_device *phydev)
{
+ struct net_device *dev = phydev->attached_dev;
+ struct module *ndev_owner = dev->dev.parent->driver->owner;
struct mii_bus *bus;
int i;
@@ -998,7 +1007,8 @@ void phy_detach(struct phy_device *phydev)
bus = phydev->mdio.bus;
put_device(&phydev->mdio.dev);
- module_put(bus->owner);
+ if (ndev_owner != bus->owner)
+ module_put(bus->owner);
}
EXPORT_SYMBOL(phy_detach);