aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/mdio-gpio.c77
-rw-r--r--drivers/net/phy/phy.c25
-rw-r--r--drivers/net/phy/phy_device.c4
3 files changed, 61 insertions, 45 deletions
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 33984b73723..22cdd451fb8 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -30,6 +30,7 @@
#ifdef CONFIG_OF_GPIO
#include <linux/of_gpio.h>
+#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#endif
@@ -81,13 +82,12 @@ static struct mdiobb_ops mdio_gpio_ops = {
.get_mdio_data = mdio_get,
};
-static int __devinit mdio_gpio_bus_init(struct device *dev,
+static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
struct mdio_gpio_platform_data *pdata,
int bus_id)
{
struct mii_bus *new_bus;
struct mdio_gpio_info *bitbang;
- int ret = -ENOMEM;
int i;
bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
@@ -104,8 +104,6 @@ static int __devinit mdio_gpio_bus_init(struct device *dev,
new_bus->name = "GPIO Bitbanged MDIO",
- ret = -ENODEV;
-
new_bus->phy_mask = pdata->phy_mask;
new_bus->irq = pdata->irqs;
new_bus->parent = dev;
@@ -129,15 +127,8 @@ static int __devinit mdio_gpio_bus_init(struct device *dev,
dev_set_drvdata(dev, new_bus);
- ret = mdiobus_register(new_bus);
- if (ret)
- goto out_free_all;
-
- return 0;
+ return new_bus;
-out_free_all:
- dev_set_drvdata(dev, NULL);
- gpio_free(bitbang->mdio);
out_free_mdc:
gpio_free(bitbang->mdc);
out_free_bus:
@@ -145,30 +136,47 @@ out_free_bus:
out_free_bitbang:
kfree(bitbang);
out:
- return ret;
+ return NULL;
}
-static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+static void __devinit mdio_gpio_bus_deinit(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
struct mdio_gpio_info *bitbang = bus->priv;
- mdiobus_unregister(bus);
- free_mdio_bitbang(bus);
dev_set_drvdata(dev, NULL);
- gpio_free(bitbang->mdc);
gpio_free(bitbang->mdio);
+ gpio_free(bitbang->mdc);
+ free_mdio_bitbang(bus);
kfree(bitbang);
}
+static void __devexit mdio_gpio_bus_destroy(struct device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(dev);
+
+ mdiobus_unregister(bus);
+ mdio_gpio_bus_deinit(dev);
+}
+
static int __devinit mdio_gpio_probe(struct platform_device *pdev)
{
struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct mii_bus *new_bus;
+ int ret;
if (!pdata)
return -ENODEV;
- return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+ new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+ if (!new_bus)
+ return -ENODEV;
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ mdio_gpio_bus_deinit(&pdev->dev);
+
+ return ret;
}
static int __devexit mdio_gpio_remove(struct platform_device *pdev)
@@ -179,29 +187,12 @@ static int __devexit mdio_gpio_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF_GPIO
-static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
- struct device_node *np)
-{
- const u32 *data;
- int len, id, irq;
-
- data = of_get_property(np, "reg", &len);
- if (!data || len != 4)
- return;
-
- id = *data;
- pdata->phy_mask &= ~(1 << id);
-
- irq = of_irq_to_resource(np, 0, NULL);
- if (irq)
- pdata->irqs[id] = irq;
-}
static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = NULL;
struct mdio_gpio_platform_data *pdata;
+ struct mii_bus *new_bus;
int ret;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
@@ -215,14 +206,18 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
ret = of_get_gpio(ofdev->node, 1);
if (ret < 0)
- goto out_free;
+ goto out_free;
pdata->mdio = ret;
- while ((np = of_get_next_child(ofdev->node, np)))
- if (!strcmp(np->type, "ethernet-phy"))
- add_phy(pdata, np);
+ new_bus = mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+ if (!new_bus)
+ return -ENODEV;
- return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
+ ret = of_mdiobus_register(new_bus, ofdev->node);
+ if (ret)
+ mdio_gpio_bus_deinit(&ofdev->dev);
+
+ return ret;
out_free:
kfree(pdata);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 61755cbd978..eda94fcd406 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -928,13 +928,32 @@ static void phy_state_machine(struct work_struct *work)
* Otherwise, it's 0, and we're
* still waiting for AN */
if (err > 0) {
- phydev->state = PHY_RUNNING;
+ err = phy_read_status(phydev);
+ if (err)
+ break;
+
+ if (phydev->link) {
+ phydev->state = PHY_RUNNING;
+ netif_carrier_on(phydev->attached_dev);
+ } else
+ phydev->state = PHY_NOLINK;
+ phydev->adjust_link(phydev->attached_dev);
} else {
phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT;
}
- } else
- phydev->state = PHY_RUNNING;
+ } else {
+ err = phy_read_status(phydev);
+ if (err)
+ break;
+
+ if (phydev->link) {
+ phydev->state = PHY_RUNNING;
+ netif_carrier_on(phydev->attached_dev);
+ } else
+ phydev->state = PHY_NOLINK;
+ phydev->adjust_link(phydev->attached_dev);
+ }
break;
}
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index eba937c4637..b10fedd8214 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -134,8 +134,10 @@ int phy_scan_fixups(struct phy_device *phydev)
err = fixup->run(phydev);
- if (err < 0)
+ if (err < 0) {
+ mutex_unlock(&phy_fixup_lock);
return err;
+ }
}
}
mutex_unlock(&phy_fixup_lock);