PHYLIB: Locking fixes for PHY I/O potentially sleeping
[safe/jmp/linux-2.6] / drivers / net / phy / mdio_bus.c
index 5e81494..6e9f619 100644 (file)
@@ -13,9 +13,7 @@
  * option) any later version.
  *
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
@@ -29,7 +27,6 @@
 #include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-/* mdiobus_register 
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
  *
- * description: Called by a bus driver to bring up all the PHYs
- *   on a given bus, and attach them to the bus
+ * Description: Called by a bus driver to bring up all the PHYs
+ *   on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
  */
 int mdiobus_register(struct mii_bus *bus)
 {
        int i;
        int err = 0;
 
-       spin_lock_init(&bus->mdio_lock);
+       mutex_init(&bus->mdio_lock);
 
        if (NULL == bus || NULL == bus->name ||
                        NULL == bus->read ||
@@ -61,6 +62,11 @@ int mdiobus_register(struct mii_bus *bus)
        for (i = 0; i < PHY_MAX_ADDR; i++) {
                struct phy_device *phydev;
 
+               if (bus->phy_mask & (1 << i)) {
+                       bus->phy_map[i] = NULL;
+                       continue;
+               }
+
                phydev = get_phy_device(bus, i);
 
                if (IS_ERR(phydev))
@@ -79,15 +85,18 @@ int mdiobus_register(struct mii_bus *bus)
 
                        phydev->dev.parent = bus->dev;
                        phydev->dev.bus = &mdio_bus_type;
-                       sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i);
+                       snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, i);
 
                        phydev->bus = bus;
 
                        err = device_register(&phydev->dev);
 
-                       if (err)
+                       if (err) {
                                printk(KERN_ERR "phy %d failed to register\n",
                                                i);
+                               phy_device_free(phydev);
+                               phydev = NULL;
+                       }
                }
 
                bus->phy_map[i] = phydev;
@@ -104,25 +113,27 @@ void mdiobus_unregister(struct mii_bus *bus)
        int i;
 
        for (i = 0; i < PHY_MAX_ADDR; i++) {
-               if (bus->phy_map[i]) {
+               if (bus->phy_map[i])
                        device_unregister(&bus->phy_map[i]->dev);
-                       kfree(bus->phy_map[i]);
-               }
        }
 }
 EXPORT_SYMBOL(mdiobus_unregister);
 
-/* mdio_bus_match
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
  *
- * description: Given a PHY device, and a PHY driver, return 1 if
- *   the driver supports the device.  Otherwise, return 0
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ *   the driver supports the device.  Otherwise, return 0.
  */
 static int mdio_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct phy_device *phydev = to_phy_device(dev);
        struct phy_driver *phydrv = to_phy_driver(drv);
 
-       return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask));
+       return ((phydrv->phy_id & phydrv->phy_id_mask) ==
+               (phydev->phy_id & phydrv->phy_id_mask));
 }
 
 /* Suspend and resume.  Copied from platform_suspend and
@@ -133,13 +144,9 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state)
        int ret = 0;
        struct device_driver *drv = dev->driver;
 
-       if (drv && drv->suspend) {
-               ret = drv->suspend(dev, state, SUSPEND_DISABLE);
-               if (ret == 0)
-                       ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE);
-               if (ret == 0)
-                       ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN);
-       }
+       if (drv && drv->suspend)
+               ret = drv->suspend(dev, state);
+
        return ret;
 }
 
@@ -148,13 +155,9 @@ static int mdio_bus_resume(struct device * dev)
        int ret = 0;
        struct device_driver *drv = dev->driver;
 
-       if (drv && drv->resume) {
-               ret = drv->resume(dev, RESUME_POWER_ON);
-               if (ret == 0)
-                       ret = drv->resume(dev, RESUME_RESTORE_STATE);
-               if (ret == 0)
-                       ret = drv->resume(dev, RESUME_ENABLE);
-       }
+       if (drv && drv->resume)
+               ret = drv->resume(dev);
+
        return ret;
 }
 
@@ -164,13 +167,14 @@ struct bus_type mdio_bus_type = {
        .suspend        = mdio_bus_suspend,
        .resume         = mdio_bus_resume,
 };
+EXPORT_SYMBOL(mdio_bus_type);
 
 int __init mdio_bus_init(void)
 {
        return bus_register(&mdio_bus_type);
 }
 
-void __exit mdio_bus_exit(void)
+void mdio_bus_exit(void)
 {
        bus_unregister(&mdio_bus_type);
 }