gianfar: Fix race in TBI/SerDes configuration
[linux-2.6.git] / drivers / net / gianfar_mii.c
index 38895b0..0e2595d 100644 (file)
@@ -164,8 +164,7 @@ static int gfar_mdio_probe(struct device *dev)
        if (NULL == dev)
                return -EINVAL;
 
-       new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
-
+       new_bus = mdiobus_alloc();
        if (NULL == new_bus)
                return -ENOMEM;
 
@@ -242,7 +241,7 @@ static int gfar_mdio_probe(struct device *dev)
 bus_register_fail:
        iounmap(regs);
 reg_map_fail:
-       kfree(new_bus);
+       mdiobus_free(new_bus);
 
        return err;
 }
@@ -258,7 +257,7 @@ static int gfar_mdio_remove(struct device *dev)
 
        iounmap((void __iomem *)bus->priv);
        bus->priv = NULL;
-       kfree(bus);
+       mdiobus_free(bus);
 
        return 0;
 }
@@ -270,6 +269,27 @@ static struct device_driver gianfar_mdio_driver = {
        .remove = gfar_mdio_remove,
 };
 
+static int match_mdio_bus(struct device *dev, void *data)
+{
+       const struct gfar_private *priv = data;
+       const struct platform_device *pdev = to_platform_device(dev);
+
+       return !strcmp(pdev->name, gianfar_mdio_driver.name) &&
+               pdev->id == priv->einfo->mdio_bus;
+}
+
+/* Given a gfar_priv structure, find the mii_bus controlled by this device (not
+ * necessarily the same as the bus the gfar's PHY is on), if one exists.
+ * Normally only the first gianfar controls a mii_bus.  */
+struct mii_bus *gfar_get_miibus(const struct gfar_private *priv)
+{
+       /*const*/ struct device *d;
+
+       d = bus_find_device(gianfar_mdio_driver.bus, NULL, (void *)priv,
+                           match_mdio_bus);
+       return d ? dev_get_drvdata(d) : NULL;
+}
+
 int __init gfar_mdio_init(void)
 {
        return driver_register(&gianfar_mdio_driver);