|
@@ -383,6 +383,24 @@ int phy_device_register(struct phy_device *phydev)
|
|
|
}
|
|
|
EXPORT_SYMBOL(phy_device_register);
|
|
|
|
|
|
+/**
|
|
|
+ * phy_device_remove - Remove a previously registered phy device from the MDIO bus
|
|
|
+ * @phydev: phy_device structure to remove
|
|
|
+ *
|
|
|
+ * This doesn't free the phy_device itself, it merely reverses the effects
|
|
|
+ * of phy_device_register(). Use phy_device_free() to free the device
|
|
|
+ * after calling this function.
|
|
|
+ */
|
|
|
+void phy_device_remove(struct phy_device *phydev)
|
|
|
+{
|
|
|
+ struct mii_bus *bus = phydev->bus;
|
|
|
+ int addr = phydev->addr;
|
|
|
+
|
|
|
+ device_del(&phydev->dev);
|
|
|
+ bus->phy_map[addr] = NULL;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(phy_device_remove);
|
|
|
+
|
|
|
/**
|
|
|
* phy_find_first - finds the first PHY device on the bus
|
|
|
* @bus: the target MII bus
|
|
@@ -578,14 +596,22 @@ EXPORT_SYMBOL(phy_init_hw);
|
|
|
* generic driver is used. The phy_device is given a ptr to
|
|
|
* the attaching device, and given a callback for link status
|
|
|
* change. The phy_device is returned to the attaching driver.
|
|
|
+ * This function takes a reference on the phy device.
|
|
|
*/
|
|
|
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
|
|
|
u32 flags, phy_interface_t interface)
|
|
|
{
|
|
|
+ struct mii_bus *bus = phydev->bus;
|
|
|
struct device *d = &phydev->dev;
|
|
|
- struct module *bus_module;
|
|
|
int err;
|
|
|
|
|
|
+ if (!try_module_get(bus->owner)) {
|
|
|
+ dev_err(&dev->dev, "failed to get the bus module\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ get_device(d);
|
|
|
+
|
|
|
/* Assume that if there is no driver, that it doesn't
|
|
|
* exist, and we should use the genphy driver.
|
|
|
*/
|
|
@@ -600,20 +626,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
|
|
|
err = device_bind_driver(d);
|
|
|
|
|
|
if (err)
|
|
|
- return err;
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
if (phydev->attached_dev) {
|
|
|
dev_err(&dev->dev, "PHY already attached\n");
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- /* Increment the bus module reference count */
|
|
|
- bus_module = phydev->bus->dev.driver ?
|
|
|
- phydev->bus->dev.driver->owner : NULL;
|
|
|
- if (!try_module_get(bus_module)) {
|
|
|
- dev_err(&dev->dev, "failed to get the bus module\n");
|
|
|
- return -EIO;
|
|
|
+ err = -EBUSY;
|
|
|
+ goto error;
|
|
|
}
|
|
|
|
|
|
phydev->attached_dev = dev;
|
|
@@ -636,6 +655,11 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
|
|
|
phy_resume(phydev);
|
|
|
|
|
|
return err;
|
|
|
+
|
|
|
+error:
|
|
|
+ put_device(d);
|
|
|
+ module_put(bus->owner);
|
|
|
+ return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(phy_attach_direct);
|
|
|
|
|
@@ -677,14 +701,15 @@ EXPORT_SYMBOL(phy_attach);
|
|
|
/**
|
|
|
* phy_detach - detach a PHY device from its network device
|
|
|
* @phydev: target phy_device struct
|
|
|
+ *
|
|
|
+ * This detaches the phy device from its network device and the phy
|
|
|
+ * driver, and drops the reference count taken in phy_attach_direct().
|
|
|
*/
|
|
|
void phy_detach(struct phy_device *phydev)
|
|
|
{
|
|
|
+ struct mii_bus *bus;
|
|
|
int i;
|
|
|
|
|
|
- if (phydev->bus->dev.driver)
|
|
|
- module_put(phydev->bus->dev.driver->owner);
|
|
|
-
|
|
|
phydev->attached_dev->phydev = NULL;
|
|
|
phydev->attached_dev = NULL;
|
|
|
phy_suspend(phydev);
|
|
@@ -700,6 +725,15 @@ void phy_detach(struct phy_device *phydev)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The phydev might go away on the put_device() below, so avoid
|
|
|
+ * a use-after-free bug by reading the underlying bus first.
|
|
|
+ */
|
|
|
+ bus = phydev->bus;
|
|
|
+
|
|
|
+ put_device(&phydev->dev);
|
|
|
+ module_put(bus->owner);
|
|
|
}
|
|
|
EXPORT_SYMBOL(phy_detach);
|
|
|
|