From 4fd5f812c23c7deee6425f4a318e85c317cd1d6c Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Tue, 26 Aug 2008 13:08:46 +0200 Subject: phylib: allow incremental scanning of an mii bus This patch splits the bus scanning code in mdiobus_register() off into a separate function, and makes this function available for calling from external code. This allows incrementally scanning an mii bus, e.g. as information about which addresses are 'safe' to scan becomes available. Signed-off-by: Lennert Buytenhek Acked-by: Andy Fleming --- drivers/net/phy/mdio_bus.c | 89 +++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 41 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 94e0b7ed76f..e7508c10887 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -60,49 +60,14 @@ int mdiobus_register(struct mii_bus *bus) bus->reset(bus); for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *phydev; + bus->phy_map[i] = NULL; + if ((bus->phy_mask & (1 << i)) == 0) { + struct phy_device *phydev; - if (bus->phy_mask & (1 << i)) { - bus->phy_map[i] = NULL; - continue; + phydev = mdiobus_scan(bus, i); + if (IS_ERR(phydev)) + err = PTR_ERR(phydev); } - - phydev = get_phy_device(bus, i); - - if (IS_ERR(phydev)) - return PTR_ERR(phydev); - - /* There's a PHY at this address - * We need to set: - * 1) IRQ - * 2) bus_id - * 3) parent - * 4) bus - * 5) mii_bus - * And, we need to register it */ - if (phydev) { - phydev->irq = bus->irq[i]; - - phydev->dev.parent = bus->dev; - phydev->dev.bus = &mdio_bus_type; - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, i); - - phydev->bus = bus; - - /* Run all of the fixups for this PHY */ - phy_scan_fixups(phydev); - - err = device_register(&phydev->dev); - - if (err) { - printk(KERN_ERR "phy %d failed to register\n", - i); - phy_device_free(phydev); - phydev = NULL; - } - } - - bus->phy_map[i] = phydev; } pr_info("%s: probed\n", bus->name); @@ -122,6 +87,48 @@ void mdiobus_unregister(struct mii_bus *bus) } EXPORT_SYMBOL(mdiobus_unregister); +struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) +{ + struct phy_device *phydev; + int err; + + phydev = get_phy_device(bus, addr); + if (IS_ERR(phydev) || phydev == NULL) + return phydev; + + /* There's a PHY at this address + * We need to set: + * 1) IRQ + * 2) bus_id + * 3) parent + * 4) bus + * 5) mii_bus + * And, we need to register it */ + + phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; + + phydev->dev.parent = bus->dev; + phydev->dev.bus = &mdio_bus_type; + snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); + + phydev->bus = bus; + + /* Run all of the fixups for this PHY */ + phy_scan_fixups(phydev); + + err = device_register(&phydev->dev); + if (err) { + printk(KERN_ERR "phy %d failed to register\n", addr); + phy_device_free(phydev); + phydev = NULL; + } + + bus->phy_map[addr] = phydev; + + return phydev; +} +EXPORT_SYMBOL(mdiobus_scan); + /** * mdio_bus_match - determine if given PHY driver supports the given PHY device * @dev: target PHY device -- cgit v1.2.3-70-g09d2 From c6d6a511d768cf7627ab54fc18f40edf85097362 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 18 Sep 2008 03:06:52 +0000 Subject: phylib: phy_mii_ioctl() fixes Make the SIOCGMIIPHY case fall through properly (it is supposed to not only return the ID of the default PHY but also to read from that PHY), and make phy_mii_ioctl() return the same error code as generic_mii_ioctl() in case of an unsupported operation. Signed-off-by: Lennert Buytenhek Acked-by: Andy Fleming Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 45cc2914d34..0433fcd0094 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -366,7 +366,8 @@ int phy_mii_ioctl(struct phy_device *phydev, switch (cmd) { case SIOCGMIIPHY: mii_data->phy_id = phydev->addr; - break; + /* fall through */ + case SIOCGMIIREG: mii_data->val_out = phy_read(phydev, mii_data->reg_num); break; @@ -413,7 +414,7 @@ int phy_mii_ioctl(struct phy_device *phydev, break; default: - return -ENOTTY; + return -EOPNOTSUPP; } return 0; -- cgit v1.2.3-70-g09d2 From 51e2a3846eab18711f4eb59cd0a4c33054e2980a Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 24 Sep 2008 10:55:46 +0000 Subject: PHY: Avoid unnecessary aneg restarts The PHY's aneg is configured and restarted whenever the link is brought up, e.g. when DHCP is started after the kernel has booted. This can take the link down for several seconds while auto-negotiation is redone. If the advertised features haven't changed, then it shouldn't be necessary to bring down the link and start auto-negotiation over again. genphy_config_advert() is enhanced to return 0 when the advertised features haven't been changed and >0 when they have been. genphy_config_aneg() then uses this information to not call genphy_restart_aneg() if there has been no change. Signed-off-by: Trent Piepho Acked-by: Andy Fleming Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 49 +++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 16a0e7de588..17162748005 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -419,13 +419,14 @@ EXPORT_SYMBOL(phy_detach); * * Description: Writes MII_ADVERTISE with the appropriate values, * after sanitizing the values to make sure we only advertise - * what is supported. + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement + * hasn't changed, and > 0 if it has changed. */ int genphy_config_advert(struct phy_device *phydev) { u32 advertise; - int adv; - int err; + int oldadv, adv; + int err, changed = 0; /* Only allow advertising what * this PHY supports */ @@ -433,7 +434,7 @@ int genphy_config_advert(struct phy_device *phydev) advertise = phydev->advertising; /* Setup standard advertisement */ - adv = phy_read(phydev, MII_ADVERTISE); + oldadv = adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) return adv; @@ -453,15 +454,18 @@ int genphy_config_advert(struct phy_device *phydev) if (advertise & ADVERTISED_Asym_Pause) adv |= ADVERTISE_PAUSE_ASYM; - err = phy_write(phydev, MII_ADVERTISE, adv); + if (adv != oldadv) { + err = phy_write(phydev, MII_ADVERTISE, adv); - if (err < 0) - return err; + if (err < 0) + return err; + changed = 1; + } /* Configure gigabit if it's supported */ if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { - adv = phy_read(phydev, MII_CTRL1000); + oldadv = adv = phy_read(phydev, MII_CTRL1000); if (adv < 0) return adv; @@ -471,13 +475,17 @@ int genphy_config_advert(struct phy_device *phydev) adv |= ADVERTISE_1000HALF; if (advertise & SUPPORTED_1000baseT_Full) adv |= ADVERTISE_1000FULL; - err = phy_write(phydev, MII_CTRL1000, adv); - if (err < 0) - return err; + if (adv != oldadv) { + err = phy_write(phydev, MII_CTRL1000, adv); + + if (err < 0) + return err; + changed = 1; + } } - return adv; + return changed; } EXPORT_SYMBOL(genphy_config_advert); @@ -561,19 +569,22 @@ int genphy_restart_aneg(struct phy_device *phydev) */ int genphy_config_aneg(struct phy_device *phydev) { - int err = 0; + int result = 0; if (AUTONEG_ENABLE == phydev->autoneg) { - err = genphy_config_advert(phydev); + int result = genphy_config_advert(phydev); - if (err < 0) - return err; + if (result < 0) /* error */ + return result; - err = genphy_restart_aneg(phydev); + /* Only restart aneg if we are advertising something different + * than we were before. */ + if (result > 0) + result = genphy_restart_aneg(phydev); } else - err = genphy_setup_forced(phydev); + result = genphy_setup_forced(phydev); - return err; + return result; } EXPORT_SYMBOL(genphy_config_aneg); -- cgit v1.2.3-70-g09d2 From 0acb28396728f42b6b1553c85d27c37513796043 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 8 Oct 2008 15:46:57 -0700 Subject: phylib: Wake PHY state machine on interrupt This way the phy layer will respond to a change in phy state immediately, instead of up to one second later when the state machine timer runs. Signed-off-by: Trent Piepho Acked-by: Andy Fleming Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 0433fcd0094..20cc82c7813 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -729,6 +729,12 @@ static void phy_change(struct work_struct *work) if (err) goto irq_enable_err; + /* Stop timer and run the state queue now. The work function for + * state_queue will start the timer up again. + */ + del_timer(&phydev->phy_timer); + schedule_work(&phydev->state_queue); + return; irq_enable_err: -- cgit v1.2.3-70-g09d2 From 18ee49ddb0d242ed1d0e273038d5e4f6de7379d3 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 1 Oct 2008 15:41:33 +0000 Subject: phylib: rename mii_bus::dev to mii_bus::parent In preparation of giving mii_bus objects a device tree presence of their own, rename struct mii_bus's ->dev argument to ->parent, since having a 'struct device *dev' that points to our parent device conflicts with introducing a 'struct device dev' representing our own device. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller Acked-by: Andy Fleming --- arch/powerpc/platforms/82xx/ep8248e.c | 2 +- arch/powerpc/platforms/pasemi/gpio_mdio.c | 2 +- drivers/net/fec_mpc52xx_phy.c | 2 +- drivers/net/fs_enet/mii-bitbang.c | 2 +- drivers/net/fs_enet/mii-fec.c | 2 +- drivers/net/gianfar_mii.c | 2 +- drivers/net/macb.c | 2 +- drivers/net/mv643xx_eth.c | 2 +- drivers/net/phy/fixed.c | 2 +- drivers/net/phy/mdio-ofgpio.c | 2 +- drivers/net/phy/mdio_bus.c | 2 +- drivers/net/sb1250-mac.c | 2 +- drivers/net/sh_eth.c | 2 +- drivers/net/tc35815.c | 2 +- drivers/net/tg3.c | 2 +- drivers/net/ucc_geth_mii.c | 2 +- include/linux/phy.h | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net/phy') diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index d5770fdf7f0..0eb6d7f6224 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -137,7 +137,7 @@ static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, bus->irq[i] = -1; bus->name = "ep8248e-mdio-bitbang"; - bus->dev = &ofdev->dev; + bus->parent = &ofdev->dev; snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); return mdiobus_register(bus); diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index ab6955412ba..798c7abe160 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -272,7 +272,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, prop = of_get_property(np, "mdio-pin", NULL); priv->mdio_pin = *prop; - new_bus->dev = dev; + new_bus->parent = dev; dev_set_drvdata(dev, new_bus); err = mdiobus_register(new_bus); diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index f5634447276..2a523308c77 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -127,7 +127,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); bus->priv = priv; - bus->dev = dev; + bus->parent = dev; dev_set_drvdata(dev, bus); /* set MII speed */ diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index be4b72f4f49..2774252c235 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -203,7 +203,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!strcmp(np->type, "ethernet-phy")) add_phy(new_bus, np); - new_bus->dev = &ofdev->dev; + new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); ret = mdiobus_register(new_bus); diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 695f74cc439..4d89a22317a 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -172,7 +172,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, if (!strcmp(np->type, "ethernet-phy")) add_phy(new_bus, np); - new_bus->dev = &ofdev->dev; + new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); ret = mdiobus_register(new_bus); diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 678f48c6911..38895b0e376 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -196,7 +196,7 @@ static int gfar_mdio_probe(struct device *dev) new_bus->irq = pdata->irq; - new_bus->dev = dev; + new_bus->parent = dev; dev_set_drvdata(dev, new_bus); /* diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 84c77f1f9a5..045361fe3d6 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -250,7 +250,7 @@ static int macb_mii_init(struct macb *bp) bp->mii_bus.reset = &macb_mdio_reset; snprintf(bp->mii_bus.id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); bp->mii_bus.priv = bp; - bp->mii_bus.dev = &bp->dev->dev; + bp->mii_bus.parent = &bp->dev->dev; pdata = bp->pdev->dev.platform_data; if (pdata) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 372811ade9f..63400815448 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2368,7 +2368,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) msp->smi_bus.read = smi_bus_read; msp->smi_bus.write = smi_bus_write, snprintf(msp->smi_bus.id, MII_BUS_ID_SIZE, "%d", pdev->id); - msp->smi_bus.dev = &pdev->dev; + msp->smi_bus.parent = &pdev->dev; msp->smi_bus.phy_mask = 0xffffffff; if (mdiobus_register(&msp->smi_bus) < 0) goto out_unmap; diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 4e07956a483..1cec8967a08 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -215,7 +215,7 @@ static int __init fixed_mdio_bus_init(void) snprintf(fmb->mii_bus.id, MII_BUS_ID_SIZE, "0"); fmb->mii_bus.name = "Fixed MDIO Bus"; - fmb->mii_bus.dev = &pdev->dev; + fmb->mii_bus.parent = &pdev->dev; fmb->mii_bus.read = &fixed_mdio_read; fmb->mii_bus.write = &fixed_mdio_write; fmb->mii_bus.irq = fmb->irqs; diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c index 7edfc0c3483..27bd4539d08 100644 --- a/drivers/net/phy/mdio-ofgpio.c +++ b/drivers/net/phy/mdio-ofgpio.c @@ -142,7 +142,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, if (!strcmp(np->type, "ethernet-phy")) add_phy(new_bus, np); - new_bus->dev = &ofdev->dev; + new_bus->parent = &ofdev->dev; dev_set_drvdata(&ofdev->dev, new_bus); ret = mdiobus_register(new_bus); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index e7508c10887..a7211a32bb4 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -107,7 +107,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) phydev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; - phydev->dev.parent = bus->dev; + phydev->dev.parent = bus->parent; phydev->dev.bus = &mdio_bus_type; snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index ce10cfa1ee5..d0ee735590b 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2378,7 +2378,7 @@ static int sbmac_init(struct platform_device *pldev, long long base) for (i = 0; i < PHY_MAX_ADDR; ++i) sc->mii_bus.irq[i] = SBMAC_PHY_INT; - sc->mii_bus.dev = &pldev->dev; + sc->mii_bus.parent = &pldev->dev; dev_set_drvdata(&pldev->dev, &sc->mii_bus); return 0; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 1c370e6aa64..1b3b7b66ffd 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1140,7 +1140,7 @@ static int sh_mdio_init(struct net_device *ndev, int id) /* Hook up MII support for ethtool */ mdp->mii_bus->name = "sh_mii"; - mdp->mii_bus->dev = &ndev->dev; + mdp->mii_bus->parent = &ndev->dev; mdp->mii_bus->id[0] = id; /* PHY IRQ */ diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 8487ace9d2e..1f2b1f2d73a 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -768,7 +768,7 @@ static int tc_mii_init(struct net_device *dev) snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "%x", (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn); lp->mii_bus.priv = dev; - lp->mii_bus.dev = &lp->pci_dev->dev; + lp->mii_bus.parent = &lp->pci_dev->dev; lp->mii_bus.irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!lp->mii_bus.irq) { err = -ENOMEM; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 123920759ef..4b8b75bcbde 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -961,7 +961,7 @@ static int tg3_mdio_init(struct tg3 *tp) snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x", (tp->pdev->bus->number << 8) | tp->pdev->devfn); mdio_bus->priv = tp; - mdio_bus->dev = &tp->pdev->dev; + mdio_bus->parent = &tp->pdev->dev; mdio_bus->read = &tg3_mdio_read; mdio_bus->write = &tg3_mdio_write; mdio_bus->reset = &tg3_mdio_reset; diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index 6d9e7ad9fda..75b72fe1f23 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -187,7 +187,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma new_bus->priv = (void __force *)regs; - new_bus->dev = device; + new_bus->parent = device; dev_set_drvdata(device, new_bus); /* Read MII management master from device tree */ diff --git a/include/linux/phy.h b/include/linux/phy.h index 5f170f5b1a3..87499bdedc6 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -99,7 +99,7 @@ struct mii_bus { */ struct mutex mdio_lock; - struct device *dev; + struct device *parent; /* list of all PHYs on bus */ struct phy_device *phy_map[PHY_MAX_ADDR]; -- cgit v1.2.3-70-g09d2 From 298cf9beb9679522de995e249eccbd82f7c51999 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 8 Oct 2008 16:29:57 -0700 Subject: phylib: move to dynamic allocation of struct mii_bus This patch introduces mdiobus_alloc() and mdiobus_free(), and makes all mdio bus drivers use these functions to allocate their struct mii_bus'es dynamically. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller Acked-by: Andy Fleming --- drivers/net/au1000_eth.c | 43 +++++++++++++++---------- drivers/net/au1000_eth.h | 2 +- drivers/net/bfin_mac.c | 31 +++++++++++------- drivers/net/bfin_mac.h | 2 +- drivers/net/cpmac.c | 51 +++++++++++++++++------------- drivers/net/fec_mpc52xx_phy.c | 6 ++-- drivers/net/fs_enet/mii-bitbang.c | 7 ++--- drivers/net/fs_enet/mii-fec.c | 6 ++-- drivers/net/gianfar_mii.c | 7 ++--- drivers/net/macb.c | 49 +++++++++++++++++------------ drivers/net/macb.h | 2 +- drivers/net/mv643xx_eth.c | 32 ++++++++++++------- drivers/net/phy/fixed.c | 29 +++++++++++------ drivers/net/phy/mdio-bitbang.c | 4 +-- drivers/net/phy/mdio-ofgpio.c | 9 +++--- drivers/net/phy/mdio_bus.c | 24 ++++++++++++++ drivers/net/sb1250-mac.c | 36 ++++++++++++--------- drivers/net/sh_eth.c | 2 +- drivers/net/tc35815.c | 45 +++++++++++++++----------- drivers/net/tg3.c | 66 ++++++++++++++++++++------------------- drivers/net/tg3.h | 2 +- drivers/net/ucc_geth_mii.c | 7 ++--- include/linux/phy.h | 2 ++ 23 files changed, 279 insertions(+), 185 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 92c16c37ff2..7b92201a7b5 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -290,7 +290,7 @@ static int mii_probe (struct net_device *dev) if(aup->mac_id == 0) { /* get PHY0 */ # if defined(AU1XXX_PHY0_ADDR) - phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus.phy_map[AU1XXX_PHY0_ADDR]; + phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus->phy_map[AU1XXX_PHY0_ADDR]; # else printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n", dev->name); @@ -298,7 +298,7 @@ static int mii_probe (struct net_device *dev) # endif /* defined(AU1XXX_PHY0_ADDR) */ } else if (aup->mac_id == 1) { /* get PHY1 */ # if defined(AU1XXX_PHY1_ADDR) - phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus.phy_map[AU1XXX_PHY1_ADDR]; + phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus->phy_map[AU1XXX_PHY1_ADDR]; # else printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n", dev->name); @@ -311,8 +311,8 @@ static int mii_probe (struct net_device *dev) /* find the first (lowest address) PHY on the current MAC's MII bus */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) - if (aup->mii_bus.phy_map[phy_addr]) { - phydev = aup->mii_bus.phy_map[phy_addr]; + if (aup->mii_bus->phy_map[phy_addr]) { + phydev = aup->mii_bus->phy_map[phy_addr]; # if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR) break; /* break out with first one found */ # endif @@ -331,7 +331,7 @@ static int mii_probe (struct net_device *dev) * the MAC0 MII bus */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { struct phy_device *const tmp_phydev = - au_macs[0]->mii_bus.phy_map[phy_addr]; + au_macs[0]->mii_bus->phy_map[phy_addr]; if (!tmp_phydev) continue; /* no PHY here... */ @@ -698,28 +698,32 @@ static struct net_device * au1000_probe(int port_num) *aup->enable = 0; aup->mac_enabled = 0; - aup->mii_bus.priv = dev; - aup->mii_bus.read = mdiobus_read; - aup->mii_bus.write = mdiobus_write; - aup->mii_bus.reset = mdiobus_reset; - aup->mii_bus.name = "au1000_eth_mii"; - snprintf(aup->mii_bus.id, MII_BUS_ID_SIZE, "%x", aup->mac_id); - aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + aup->mii_bus = mdiobus_alloc(); + if (aup->mii_bus == NULL) + goto err_out; + + aup->mii_bus->priv = dev; + aup->mii_bus->read = mdiobus_read; + aup->mii_bus->write = mdiobus_write; + aup->mii_bus->reset = mdiobus_reset; + aup->mii_bus->name = "au1000_eth_mii"; + snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id); + aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for(i = 0; i < PHY_MAX_ADDR; ++i) - aup->mii_bus.irq[i] = PHY_POLL; + aup->mii_bus->irq[i] = PHY_POLL; /* if known, set corresponding PHY IRQs */ #if defined(AU1XXX_PHY_STATIC_CONFIG) # if defined(AU1XXX_PHY0_IRQ) if (AU1XXX_PHY0_BUSID == aup->mac_id) - aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ; + aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ; # endif # if defined(AU1XXX_PHY1_IRQ) if (AU1XXX_PHY1_BUSID == aup->mac_id) - aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ; + aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ; # endif #endif - mdiobus_register(&aup->mii_bus); + mdiobus_register(aup->mii_bus); if (mii_probe(dev) != 0) { goto err_out; @@ -775,6 +779,11 @@ static struct net_device * au1000_probe(int port_num) return dev; err_out: + if (aup->mii_bus != NULL) { + mdiobus_unregister(aup->mii_bus); + mdiobus_free(aup->mii_bus); + } + /* here we should have a valid dev plus aup-> register addresses * so we can reset the mac properly.*/ reset_mac(dev); @@ -1005,6 +1014,8 @@ static void __exit au1000_cleanup_module(void) if (dev) { aup = (struct au1000_private *) dev->priv; unregister_netdev(dev); + mdiobus_unregister(aup->mii_bus); + mdiobus_free(aup->mii_bus); for (j = 0; j < NUM_RX_DMA; j++) if (aup->rx_db_inuse[j]) ReleaseDB(aup, aup->rx_db_inuse[j]); diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h index f3baeaa1285..824ecd5ff3a 100644 --- a/drivers/net/au1000_eth.h +++ b/drivers/net/au1000_eth.h @@ -106,7 +106,7 @@ struct au1000_private { int old_duplex; struct phy_device *phy_dev; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; /* These variables are just for quick access to certain regs addresses. */ volatile mac_reg_t *mac; /* mac registers */ diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index df896e23e2c..a0d41c5d97d 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -398,7 +398,7 @@ static int mii_probe(struct net_device *dev) /* search for connect PHY device */ for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i]; + struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i]; if (!tmp_phydev) continue; /* no PHY here... */ @@ -1058,17 +1058,21 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev) setup_mac_addr(ndev->dev_addr); /* MDIO bus initial */ - lp->mii_bus.priv = ndev; - lp->mii_bus.read = mdiobus_read; - lp->mii_bus.write = mdiobus_write; - lp->mii_bus.reset = mdiobus_reset; - lp->mii_bus.name = "bfin_mac_mdio"; - snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "0"); - lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + lp->mii_bus = mdiobus_alloc(); + if (lp->mii_bus == NULL) + goto out_err_mdiobus_alloc; + + lp->mii_bus->priv = ndev; + lp->mii_bus->read = mdiobus_read; + lp->mii_bus->write = mdiobus_write; + lp->mii_bus->reset = mdiobus_reset; + lp->mii_bus->name = "bfin_mac_mdio"; + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0"); + lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); for (i = 0; i < PHY_MAX_ADDR; ++i) - lp->mii_bus.irq[i] = PHY_POLL; + lp->mii_bus->irq[i] = PHY_POLL; - rc = mdiobus_register(&lp->mii_bus); + rc = mdiobus_register(lp->mii_bus); if (rc) { dev_err(&pdev->dev, "Cannot register MDIO bus!\n"); goto out_err_mdiobus_register; @@ -1121,8 +1125,10 @@ out_err_reg_ndev: free_irq(IRQ_MAC_RX, ndev); out_err_request_irq: out_err_mii_probe: - mdiobus_unregister(&lp->mii_bus); + mdiobus_unregister(lp->mii_bus); out_err_mdiobus_register: + mdiobus_free(lp->mii_bus); +out_err_mdiobus_alloc: peripheral_free_list(pin_req); out_err_setup_pin_mux: out_err_probe_mac: @@ -1139,7 +1145,8 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - mdiobus_unregister(&lp->mii_bus); + mdiobus_unregister(lp->mii_bus); + mdiobus_free(lp->mii_bus); unregister_netdev(ndev); diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h index beff51064ff..052b5dce3e3 100644 --- a/drivers/net/bfin_mac.h +++ b/drivers/net/bfin_mac.h @@ -66,7 +66,7 @@ struct bfin_mac_local { int old_duplex; struct phy_device *phydev; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; }; extern void bfin_get_ether_addr(char *addr); diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index ec6b0af3d46..017a5361b98 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -302,13 +302,7 @@ static int cpmac_mdio_reset(struct mii_bus *bus) static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, }; -static struct mii_bus cpmac_mii = { - .name = "cpmac-mii", - .read = cpmac_mdio_read, - .write = cpmac_mdio_write, - .reset = cpmac_mdio_reset, - .irq = mii_irqs, -}; +static struct mii_bus *cpmac_mii; static int cpmac_config(struct net_device *dev, struct ifmap *map) { @@ -1116,7 +1110,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev) for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { if (!(pdata->phy_mask & (1 << phy_id))) continue; - if (!cpmac_mii.phy_map[phy_id]) + if (!cpmac_mii->phy_map[phy_id]) continue; break; } @@ -1168,7 +1162,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev) priv->msg_enable = netif_msg_init(debug_level, 0xff); memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); - priv->phy = phy_connect(dev, cpmac_mii.phy_map[phy_id]->dev.bus_id, + priv->phy = phy_connect(dev, cpmac_mii->phy_map[phy_id]->dev.bus_id, &cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII); if (IS_ERR(priv->phy)) { if (netif_msg_drv(priv)) @@ -1216,11 +1210,22 @@ int __devinit cpmac_init(void) u32 mask; int i, res; - cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256); + cpmac_mii = mdiobus_alloc(); + if (cpmac_mii == NULL) + return -ENOMEM; + + cpmac_mii->name = "cpmac-mii"; + cpmac_mii->read = cpmac_mdio_read; + cpmac_mii->write = cpmac_mdio_write; + cpmac_mii->reset = cpmac_mdio_reset; + cpmac_mii->irq = mii_irqs; + + cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256); - if (!cpmac_mii.priv) { + if (!cpmac_mii->priv) { printk(KERN_ERR "Can't ioremap mdio registers\n"); - return -ENXIO; + res = -ENXIO; + goto fail_alloc; } #warning FIXME: unhardcode gpio&reset bits @@ -1230,10 +1235,10 @@ int __devinit cpmac_init(void) ar7_device_reset(AR7_RESET_BIT_CPMAC_HI); ar7_device_reset(AR7_RESET_BIT_EPHY); - cpmac_mii.reset(&cpmac_mii); + cpmac_mii->reset(cpmac_mii); for (i = 0; i < 300000; i++) - if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE))) + if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE))) break; else cpu_relax(); @@ -1244,10 +1249,10 @@ int __devinit cpmac_init(void) mask = 0; } - cpmac_mii.phy_mask = ~(mask | 0x80000000); - snprintf(cpmac_mii.id, MII_BUS_ID_SIZE, "0"); + cpmac_mii->phy_mask = ~(mask | 0x80000000); + snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "0"); - res = mdiobus_register(&cpmac_mii); + res = mdiobus_register(cpmac_mii); if (res) goto fail_mii; @@ -1258,10 +1263,13 @@ int __devinit cpmac_init(void) return 0; fail_cpmac: - mdiobus_unregister(&cpmac_mii); + mdiobus_unregister(cpmac_mii); fail_mii: - iounmap(cpmac_mii.priv); + iounmap(cpmac_mii->priv); + +fail_alloc: + mdiobus_free(cpmac_mii); return res; } @@ -1269,8 +1277,9 @@ fail_mii: void __devexit cpmac_exit(void) { platform_driver_unregister(&cpmac_driver); - mdiobus_unregister(&cpmac_mii); - iounmap(cpmac_mii.priv); + mdiobus_unregister(cpmac_mii); + mdiobus_free(cpmac_mii); + iounmap(cpmac_mii->priv); } module_init(cpmac_init); diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c index 2a523308c77..08e18bcb970 100644 --- a/drivers/net/fec_mpc52xx_phy.c +++ b/drivers/net/fec_mpc52xx_phy.c @@ -83,7 +83,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i int err; int i; - bus = kzalloc(sizeof(*bus), GFP_KERNEL); + bus = mdiobus_alloc(); if (bus == NULL) return -ENOMEM; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -150,7 +150,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i irq_dispose_mapping(bus->irq[i]); kfree(bus->irq); kfree(priv); - kfree(bus); + mdiobus_free(bus); return err; } @@ -171,7 +171,7 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of) irq_dispose_mapping(bus->irq[i]); kfree(priv); kfree(bus->irq); - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c index 2774252c235..49b6645d7e0 100644 --- a/drivers/net/fs_enet/mii-bitbang.c +++ b/drivers/net/fs_enet/mii-bitbang.c @@ -218,9 +218,9 @@ out_free_irqs: out_unmap_regs: iounmap(bitbang->dir); out_free_bus: - kfree(new_bus); -out_free_priv: free_mdio_bitbang(new_bus); +out_free_priv: + kfree(bitbang); out: return ret; } @@ -231,12 +231,11 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) struct bb_info *bitbang = bus->priv; mdiobus_unregister(bus); - free_mdio_bitbang(bus); dev_set_drvdata(&ofdev->dev, NULL); kfree(bus->irq); + free_mdio_bitbang(bus); iounmap(bitbang->dir); kfree(bitbang); - kfree(bus); return 0; } diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c index 4d89a22317a..28077cc1b94 100644 --- a/drivers/net/fs_enet/mii-fec.c +++ b/drivers/net/fs_enet/mii-fec.c @@ -128,7 +128,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev, struct fec_info *fec; int ret = -ENOMEM, i; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + new_bus = mdiobus_alloc(); if (!new_bus) goto out; @@ -190,7 +190,7 @@ out_res: out_fec: kfree(fec); out_mii: - kfree(new_bus); + mdiobus_free(new_bus); out: return ret; } @@ -205,7 +205,7 @@ static int fs_enet_mdio_remove(struct of_device *ofdev) kfree(bus->irq); iounmap(fec->fecp); kfree(fec); - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 38895b0e376..bf73eea9801 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -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; } diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 045361fe3d6..01f7a31bac7 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -195,8 +195,8 @@ static int macb_mii_probe(struct net_device *dev) /* find the first phy */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (bp->mii_bus.phy_map[phy_addr]) { - phydev = bp->mii_bus.phy_map[phy_addr]; + if (bp->mii_bus->phy_map[phy_addr]) { + phydev = bp->mii_bus->phy_map[phy_addr]; break; } } @@ -244,30 +244,36 @@ static int macb_mii_init(struct macb *bp) /* Enable managment port */ macb_writel(bp, NCR, MACB_BIT(MPE)); - bp->mii_bus.name = "MACB_mii_bus"; - bp->mii_bus.read = &macb_mdio_read; - bp->mii_bus.write = &macb_mdio_write; - bp->mii_bus.reset = &macb_mdio_reset; - snprintf(bp->mii_bus.id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); - bp->mii_bus.priv = bp; - bp->mii_bus.parent = &bp->dev->dev; + bp->mii_bus = mdiobus_alloc(); + if (bp->mii_bus == NULL) { + err = -ENOMEM; + goto err_out; + } + + bp->mii_bus->name = "MACB_mii_bus"; + bp->mii_bus->read = &macb_mdio_read; + bp->mii_bus->write = &macb_mdio_write; + bp->mii_bus->reset = &macb_mdio_reset; + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); + bp->mii_bus->priv = bp; + bp->mii_bus->parent = &bp->dev->dev; pdata = bp->pdev->dev.platform_data; if (pdata) - bp->mii_bus.phy_mask = pdata->phy_mask; + bp->mii_bus->phy_mask = pdata->phy_mask; - bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - if (!bp->mii_bus.irq) { + bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (!bp->mii_bus->irq) { err = -ENOMEM; - goto err_out; + goto err_out_free_mdiobus; } for (i = 0; i < PHY_MAX_ADDR; i++) - bp->mii_bus.irq[i] = PHY_POLL; + bp->mii_bus->irq[i] = PHY_POLL; - platform_set_drvdata(bp->dev, &bp->mii_bus); + platform_set_drvdata(bp->dev, bp->mii_bus); - if (mdiobus_register(&bp->mii_bus)) + if (mdiobus_register(bp->mii_bus)) goto err_out_free_mdio_irq; if (macb_mii_probe(bp->dev) != 0) { @@ -277,9 +283,11 @@ static int macb_mii_init(struct macb *bp) return 0; err_out_unregister_bus: - mdiobus_unregister(&bp->mii_bus); + mdiobus_unregister(bp->mii_bus); err_out_free_mdio_irq: - kfree(bp->mii_bus.irq); + kfree(bp->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(bp->mii_bus); err_out: return err; } @@ -1261,8 +1269,9 @@ static int __exit macb_remove(struct platform_device *pdev) bp = netdev_priv(dev); if (bp->phy_dev) phy_disconnect(bp->phy_dev); - mdiobus_unregister(&bp->mii_bus); - kfree(bp->mii_bus.irq); + mdiobus_unregister(bp->mii_bus); + kfree(bp->mii_bus->irq); + mdiobus_free(bp->mii_bus); unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(bp->regs); diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 57b85acf0d1..d3212f6db70 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -384,7 +384,7 @@ struct macb { unsigned int rx_pending, tx_pending; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; struct phy_device *phy_dev; unsigned int link; unsigned int speed; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 63400815448..d25a3025113 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -250,7 +250,7 @@ struct mv643xx_eth_shared_private { /* * Provides access to local SMI interface. */ - struct mii_bus smi_bus; + struct mii_bus *smi_bus; /* * If we have access to the error interrupt pin (which is @@ -2363,15 +2363,19 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) * Set up and register SMI bus. */ if (pd == NULL || pd->shared_smi == NULL) { - msp->smi_bus.priv = msp; - msp->smi_bus.name = "mv643xx_eth smi"; - msp->smi_bus.read = smi_bus_read; - msp->smi_bus.write = smi_bus_write, - snprintf(msp->smi_bus.id, MII_BUS_ID_SIZE, "%d", pdev->id); - msp->smi_bus.parent = &pdev->dev; - msp->smi_bus.phy_mask = 0xffffffff; - if (mdiobus_register(&msp->smi_bus) < 0) + msp->smi_bus = mdiobus_alloc(); + if (msp->smi_bus == NULL) goto out_unmap; + + msp->smi_bus->priv = msp; + msp->smi_bus->name = "mv643xx_eth smi"; + msp->smi_bus->read = smi_bus_read; + msp->smi_bus->write = smi_bus_write, + snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); + msp->smi_bus->parent = &pdev->dev; + msp->smi_bus->phy_mask = 0xffffffff; + if (mdiobus_register(msp->smi_bus) < 0) + goto out_free_mii_bus; msp->smi = msp; } else { msp->smi = platform_get_drvdata(pd->shared_smi); @@ -2411,6 +2415,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) return 0; +out_free_mii_bus: + mdiobus_free(msp->smi_bus); out_unmap: iounmap(msp->base); out_free: @@ -2424,8 +2430,10 @@ static int mv643xx_eth_shared_remove(struct platform_device *pdev) struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; - if (pd == NULL || pd->shared_smi == NULL) - mdiobus_unregister(&msp->smi_bus); + if (pd == NULL || pd->shared_smi == NULL) { + mdiobus_free(msp->smi_bus); + mdiobus_unregister(msp->smi_bus); + } if (msp->err_interrupt != NO_IRQ) free_irq(msp->err_interrupt, msp); iounmap(msp->base); @@ -2493,7 +2501,7 @@ static void set_params(struct mv643xx_eth_private *mp, static struct phy_device *phy_scan(struct mv643xx_eth_private *mp, int phy_addr) { - struct mii_bus *bus = &mp->shared->smi->smi_bus; + struct mii_bus *bus = mp->shared->smi->smi_bus; struct phy_device *phydev; int start; int num; diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 1cec8967a08..b5e13f8d5e3 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -24,7 +24,7 @@ struct fixed_mdio_bus { int irqs[PHY_MAX_ADDR]; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; struct list_head phys; }; @@ -213,19 +213,27 @@ static int __init fixed_mdio_bus_init(void) goto err_pdev; } - snprintf(fmb->mii_bus.id, MII_BUS_ID_SIZE, "0"); - fmb->mii_bus.name = "Fixed MDIO Bus"; - fmb->mii_bus.parent = &pdev->dev; - fmb->mii_bus.read = &fixed_mdio_read; - fmb->mii_bus.write = &fixed_mdio_write; - fmb->mii_bus.irq = fmb->irqs; + fmb->mii_bus = mdiobus_alloc(); + if (fmb->mii_bus == NULL) { + ret = -ENOMEM; + goto err_mdiobus_reg; + } - ret = mdiobus_register(&fmb->mii_bus); + snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0"); + fmb->mii_bus->name = "Fixed MDIO Bus"; + fmb->mii_bus->parent = &pdev->dev; + fmb->mii_bus->read = &fixed_mdio_read; + fmb->mii_bus->write = &fixed_mdio_write; + fmb->mii_bus->irq = fmb->irqs; + + ret = mdiobus_register(fmb->mii_bus); if (ret) - goto err_mdiobus_reg; + goto err_mdiobus_alloc; return 0; +err_mdiobus_alloc: + mdiobus_free(fmb->mii_bus); err_mdiobus_reg: platform_device_unregister(pdev); err_pdev: @@ -238,7 +246,8 @@ static void __exit fixed_mdio_bus_exit(void) struct fixed_mdio_bus *fmb = &platform_fmb; struct fixed_phy *fp, *tmp; - mdiobus_unregister(&fmb->mii_bus); + mdiobus_unregister(fmb->mii_bus); + mdiobus_free(fmb->mii_bus); platform_device_unregister(pdev); list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c index c01b78013dd..2576055b350 100644 --- a/drivers/net/phy/mdio-bitbang.c +++ b/drivers/net/phy/mdio-bitbang.c @@ -165,7 +165,7 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) { struct mii_bus *bus; - bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + bus = mdiobus_alloc(); if (!bus) return NULL; @@ -184,7 +184,7 @@ void free_mdio_bitbang(struct mii_bus *bus) struct mdiobb_ctrl *ctrl = bus->priv; module_put(ctrl->ops->owner); - kfree(bus); + mdiobus_free(bus); } EXPORT_SYMBOL(free_mdio_bitbang); diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c index 27bd4539d08..2ff97754e57 100644 --- a/drivers/net/phy/mdio-ofgpio.c +++ b/drivers/net/phy/mdio-ofgpio.c @@ -122,7 +122,7 @@ static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, new_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!new_bus) - goto out_free_priv; + goto out_free_bitbang; new_bus->name = "GPIO Bitbanged MII", @@ -155,9 +155,9 @@ out_free_irqs: dev_set_drvdata(&ofdev->dev, NULL); kfree(new_bus->irq); out_free_bus: - kfree(new_bus); -out_free_priv: free_mdio_bitbang(new_bus); +out_free_bitbang: + kfree(bitbang); out: return ret; } @@ -168,11 +168,10 @@ static int mdio_ofgpio_remove(struct of_device *ofdev) struct mdio_gpio_info *bitbang = bus->priv; mdiobus_unregister(bus); + kfree(bus->irq); free_mdio_bitbang(bus); dev_set_drvdata(&ofdev->dev, NULL); - kfree(bus->irq); kfree(bitbang); - kfree(bus); return 0; } diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index a7211a32bb4..d206691f15d 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -35,6 +35,18 @@ #include #include +/** + * mdiobus_alloc - allocate a mii_bus structure + * + * Description: called by a bus driver to allocate an mii_bus + * structure to fill in. + */ +struct mii_bus *mdiobus_alloc(void) +{ + return kzalloc(sizeof(struct mii_bus), GFP_KERNEL); +} +EXPORT_SYMBOL(mdiobus_alloc); + /** * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus * @bus: target mii_bus @@ -87,6 +99,18 @@ void mdiobus_unregister(struct mii_bus *bus) } EXPORT_SYMBOL(mdiobus_unregister); +/** + * mdiobus_free - free a struct mii_bus + * @bus: mii_bus to free + * + * This function frees the mii_bus. + */ +void mdiobus_free(struct mii_bus *bus) +{ + kfree(bus); +} +EXPORT_SYMBOL(mdiobus_free); + struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) { struct phy_device *phydev; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index d0ee735590b..2615d46e6e5 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -256,7 +256,7 @@ struct sbmac_softc { struct net_device *sbm_dev; /* pointer to linux device */ struct napi_struct napi; struct phy_device *phy_dev; /* the associated PHY device */ - struct mii_bus mii_bus; /* the MII bus */ + struct mii_bus *mii_bus; /* the MII bus */ int phy_irq[PHY_MAX_ADDR]; spinlock_t sbm_lock; /* spin lock */ int sbm_devflags; /* current device flags */ @@ -2348,10 +2348,17 @@ static int sbmac_init(struct platform_device *pldev, long long base) /* This is needed for PASS2 for Rx H/W checksum feature */ sbmac_set_iphdr_offset(sc); + sc->mii_bus = mdiobus_alloc(); + if (sc->mii_bus == NULL) { + sbmac_uninitctx(sc); + return -ENOMEM; + } + err = register_netdev(dev); if (err) { printk(KERN_ERR "%s.%d: unable to register netdev\n", sbmac_string, idx); + mdiobus_free(sc->mii_bus); sbmac_uninitctx(sc); return err; } @@ -2369,17 +2376,17 @@ static int sbmac_init(struct platform_device *pldev, long long base) pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n", dev->name, base, print_mac(mac, eaddr)); - sc->mii_bus.name = sbmac_mdio_string; - snprintf(sc->mii_bus.id, MII_BUS_ID_SIZE, "%x", idx); - sc->mii_bus.priv = sc; - sc->mii_bus.read = sbmac_mii_read; - sc->mii_bus.write = sbmac_mii_write; - sc->mii_bus.irq = sc->phy_irq; + sc->mii_bus->name = sbmac_mdio_string; + snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); + sc->mii_bus->priv = sc; + sc->mii_bus->read = sbmac_mii_read; + sc->mii_bus->write = sbmac_mii_write; + sc->mii_bus->irq = sc->phy_irq; for (i = 0; i < PHY_MAX_ADDR; ++i) - sc->mii_bus.irq[i] = SBMAC_PHY_INT; + sc->mii_bus->irq[i] = SBMAC_PHY_INT; - sc->mii_bus.parent = &pldev->dev; - dev_set_drvdata(&pldev->dev, &sc->mii_bus); + sc->mii_bus->parent = &pldev->dev; + dev_set_drvdata(&pldev->dev, sc->mii_bus); return 0; } @@ -2410,7 +2417,7 @@ static int sbmac_open(struct net_device *dev) /* * Probe PHY address */ - err = mdiobus_register(&sc->mii_bus); + err = mdiobus_register(sc->mii_bus); if (err) { printk(KERN_ERR "%s: unable to register MDIO bus\n", dev->name); @@ -2447,7 +2454,7 @@ static int sbmac_open(struct net_device *dev) return 0; out_unregister: - mdiobus_unregister(&sc->mii_bus); + mdiobus_unregister(sc->mii_bus); out_unirq: free_irq(dev->irq, dev); @@ -2463,7 +2470,7 @@ static int sbmac_mii_probe(struct net_device *dev) int i; for (i = 0; i < PHY_MAX_ADDR; i++) { - phy_dev = sc->mii_bus.phy_map[i]; + phy_dev = sc->mii_bus->phy_map[i]; if (phy_dev) break; } @@ -2641,7 +2648,7 @@ static int sbmac_close(struct net_device *dev) phy_disconnect(sc->phy_dev); sc->phy_dev = NULL; - mdiobus_unregister(&sc->mii_bus); + mdiobus_unregister(sc->mii_bus); free_irq(dev->irq, dev); @@ -2750,6 +2757,7 @@ static int __exit sbmac_remove(struct platform_device *pldev) unregister_netdev(dev); sbmac_uninitctx(sc); + mdiobus_free(sc->mii_bus); iounmap(sc->sbm_base); free_netdev(dev); diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 1b3b7b66ffd..b39d1cc1ef0 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1166,7 +1166,7 @@ out_free_irq: kfree(mdp->mii_bus->irq); out_free_bus: - kfree(mdp->mii_bus); + free_mdio_bitbang(mdp->mii_bus); out_free_bitbang: kfree(bitbang); diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 1f2b1f2d73a..4980b12b621 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -424,7 +424,7 @@ struct tc35815_local { */ spinlock_t lock; - struct mii_bus mii_bus; + struct mii_bus *mii_bus; struct phy_device *phy_dev; int duplex; int speed; @@ -704,13 +704,13 @@ static int tc_mii_probe(struct net_device *dev) /* find the first phy */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (lp->mii_bus.phy_map[phy_addr]) { + if (lp->mii_bus->phy_map[phy_addr]) { if (phydev) { printk(KERN_ERR "%s: multiple PHYs found\n", dev->name); return -EINVAL; } - phydev = lp->mii_bus.phy_map[phy_addr]; + phydev = lp->mii_bus->phy_map[phy_addr]; break; } } @@ -762,23 +762,29 @@ static int tc_mii_init(struct net_device *dev) int err; int i; - lp->mii_bus.name = "tc35815_mii_bus"; - lp->mii_bus.read = tc_mdio_read; - lp->mii_bus.write = tc_mdio_write; - snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "%x", - (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn); - lp->mii_bus.priv = dev; - lp->mii_bus.parent = &lp->pci_dev->dev; - lp->mii_bus.irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!lp->mii_bus.irq) { + lp->mii_bus = mdiobus_alloc(); + if (lp->mii_bus == NULL) { err = -ENOMEM; goto err_out; } + lp->mii_bus->name = "tc35815_mii_bus"; + lp->mii_bus->read = tc_mdio_read; + lp->mii_bus->write = tc_mdio_write; + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn); + lp->mii_bus->priv = dev; + lp->mii_bus->parent = &lp->pci_dev->dev; + lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!lp->mii_bus->irq) { + err = -ENOMEM; + goto err_out_free_mii_bus; + } + for (i = 0; i < PHY_MAX_ADDR; i++) - lp->mii_bus.irq[i] = PHY_POLL; + lp->mii_bus->irq[i] = PHY_POLL; - err = mdiobus_register(&lp->mii_bus); + err = mdiobus_register(lp->mii_bus); if (err) goto err_out_free_mdio_irq; err = tc_mii_probe(dev); @@ -787,9 +793,11 @@ static int tc_mii_init(struct net_device *dev) return 0; err_out_unregister_bus: - mdiobus_unregister(&lp->mii_bus); + mdiobus_unregister(lp->mii_bus); err_out_free_mdio_irq: - kfree(lp->mii_bus.irq); + kfree(lp->mii_bus->irq); +err_out_free_mii_bus; + mdiobus_free(lp->mii_bus); err_out: return err; } @@ -961,8 +969,9 @@ static void __devexit tc35815_remove_one(struct pci_dev *pdev) struct tc35815_local *lp = netdev_priv(dev); phy_disconnect(lp->phy_dev); - mdiobus_unregister(&lp->mii_bus); - kfree(lp->mii_bus.irq); + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); unregister_netdev(dev); free_netdev(dev); pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4b8b75bcbde..eb9f8f3638e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -876,7 +876,7 @@ static void tg3_mdio_config(struct tg3 *tp) { u32 val; - if (tp->mdio_bus.phy_map[PHY_ADDR]->interface != + if (tp->mdio_bus->phy_map[PHY_ADDR]->interface != PHY_INTERFACE_MODE_RGMII) return; @@ -920,9 +920,9 @@ static void tg3_mdio_config(struct tg3 *tp) static void tg3_mdio_start(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { - mutex_lock(&tp->mdio_bus.mdio_lock); + mutex_lock(&tp->mdio_bus->mdio_lock); tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; - mutex_unlock(&tp->mdio_bus.mdio_lock); + mutex_unlock(&tp->mdio_bus->mdio_lock); } tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; @@ -936,9 +936,9 @@ static void tg3_mdio_start(struct tg3 *tp) static void tg3_mdio_stop(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { - mutex_lock(&tp->mdio_bus.mdio_lock); + mutex_lock(&tp->mdio_bus->mdio_lock); tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED; - mutex_unlock(&tp->mdio_bus.mdio_lock); + mutex_unlock(&tp->mdio_bus->mdio_lock); } } @@ -947,7 +947,6 @@ static int tg3_mdio_init(struct tg3 *tp) int i; u32 reg; struct phy_device *phydev; - struct mii_bus *mdio_bus = &tp->mdio_bus; tg3_mdio_start(tp); @@ -955,21 +954,23 @@ static int tg3_mdio_init(struct tg3 *tp) (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) return 0; - memset(mdio_bus, 0, sizeof(*mdio_bus)); + tp->mdio_bus = mdiobus_alloc(); + if (tp->mdio_bus == NULL) + return -ENOMEM; - mdio_bus->name = "tg3 mdio bus"; - snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x", + tp->mdio_bus->name = "tg3 mdio bus"; + snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x", (tp->pdev->bus->number << 8) | tp->pdev->devfn); - mdio_bus->priv = tp; - mdio_bus->parent = &tp->pdev->dev; - mdio_bus->read = &tg3_mdio_read; - mdio_bus->write = &tg3_mdio_write; - mdio_bus->reset = &tg3_mdio_reset; - mdio_bus->phy_mask = ~(1 << PHY_ADDR); - mdio_bus->irq = &tp->mdio_irq[0]; + tp->mdio_bus->priv = tp; + tp->mdio_bus->parent = &tp->pdev->dev; + tp->mdio_bus->read = &tg3_mdio_read; + tp->mdio_bus->write = &tg3_mdio_write; + tp->mdio_bus->reset = &tg3_mdio_reset; + tp->mdio_bus->phy_mask = ~(1 << PHY_ADDR); + tp->mdio_bus->irq = &tp->mdio_irq[0]; for (i = 0; i < PHY_MAX_ADDR; i++) - mdio_bus->irq[i] = PHY_POLL; + tp->mdio_bus->irq[i] = PHY_POLL; /* The bus registration will look for all the PHYs on the mdio bus. * Unfortunately, it does not ensure the PHY is powered up before @@ -979,7 +980,7 @@ static int tg3_mdio_init(struct tg3 *tp) if (tg3_readphy(tp, MII_BMCR, ®) || (reg & BMCR_PDOWN)) tg3_bmcr_reset(tp); - i = mdiobus_register(mdio_bus); + i = mdiobus_register(tp->mdio_bus); if (i) { printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", tp->dev->name, i); @@ -988,7 +989,7 @@ static int tg3_mdio_init(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; switch (phydev->phy_id) { case TG3_PHY_ID_BCM50610: @@ -1014,7 +1015,8 @@ static void tg3_mdio_fini(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; - mdiobus_unregister(&tp->mdio_bus); + mdiobus_unregister(tp->mdio_bus); + mdiobus_free(tp->mdio_bus); tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED; } } @@ -1220,7 +1222,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) u32 old_tx_mode = tp->tx_mode; if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) - autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg; + autoneg = tp->mdio_bus->phy_map[PHY_ADDR]->autoneg; else autoneg = tp->link_config.autoneg; @@ -1257,7 +1259,7 @@ static void tg3_adjust_link(struct net_device *dev) u8 oldflowctrl, linkmesg = 0; u32 mac_mode, lcl_adv, rmt_adv; struct tg3 *tp = netdev_priv(dev); - struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + struct phy_device *phydev = tp->mdio_bus->phy_map[PHY_ADDR]; spin_lock(&tp->lock); @@ -1334,7 +1336,7 @@ static int tg3_phy_init(struct tg3 *tp) /* Bring the PHY back to a known state. */ tg3_bmcr_reset(tp); - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; /* Attach the MAC to the PHY. */ phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link, @@ -1367,7 +1369,7 @@ static void tg3_phy_start(struct tg3 *tp) if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; if (tp->link_config.phy_is_low_power) { tp->link_config.phy_is_low_power = 0; @@ -1387,13 +1389,13 @@ static void tg3_phy_stop(struct tg3 *tp) if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return; - phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]); + phy_stop(tp->mdio_bus->phy_map[PHY_ADDR]); } static void tg3_phy_fini(struct tg3 *tp) { if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) { - phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]); + phy_disconnect(tp->mdio_bus->phy_map[PHY_ADDR]); tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED; } } @@ -2049,7 +2051,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) struct phy_device *phydev; u32 advertising; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; tp->link_config.phy_is_low_power = 1; @@ -8954,7 +8956,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + return phy_ethtool_gset(tp->mdio_bus->phy_map[PHY_ADDR], cmd); } cmd->supported = (SUPPORTED_Autoneg); @@ -8995,7 +8997,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd); + return phy_ethtool_sset(tp->mdio_bus->phy_map[PHY_ADDR], cmd); } if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) { @@ -9143,7 +9145,7 @@ static int tg3_nway_reset(struct net_device *dev) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]); + r = phy_start_aneg(tp->mdio_bus->phy_map[PHY_ADDR]); } else { u32 bmcr; @@ -9260,7 +9262,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam u32 newadv; struct phy_device *phydev; - phydev = tp->mdio_bus.phy_map[PHY_ADDR]; + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; if (epause->rx_pause) { if (epause->tx_pause) @@ -10242,7 +10244,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)) return -EAGAIN; - return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd); + return phy_mii_ioctl(tp->mdio_bus->phy_map[PHY_ADDR], data, cmd); } switch(cmd) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6c7b5e303db..be252abe898 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2556,7 +2556,7 @@ struct tg3 { int msi_cap; int pcix_cap; - struct mii_bus mdio_bus; + struct mii_bus *mdio_bus; int mdio_irq[PHY_MAX_ADDR]; /* PHY info */ diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c index 75b72fe1f23..c001d261366 100644 --- a/drivers/net/ucc_geth_mii.c +++ b/drivers/net/ucc_geth_mii.c @@ -141,8 +141,7 @@ static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *ma struct resource res; int k, err = 0; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); - + new_bus = mdiobus_alloc(); if (NULL == new_bus) return -ENOMEM; @@ -235,7 +234,7 @@ bus_register_fail: ioremap_fail: kfree(new_bus->irq); reg_map_fail: - kfree(new_bus); + mdiobus_free(new_bus); return err; } @@ -251,7 +250,7 @@ static int uec_mdio_remove(struct of_device *ofdev) iounmap((void __iomem *)bus->priv); bus->priv = NULL; - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/include/linux/phy.h b/include/linux/phy.h index 87499bdedc6..ca4a83c4c53 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -408,8 +408,10 @@ void phy_start(struct phy_device *phydev); void phy_stop(struct phy_device *phydev); int phy_start_aneg(struct phy_device *phydev); +struct mii_bus *mdiobus_alloc(void); int mdiobus_register(struct mii_bus *bus); void mdiobus_unregister(struct mii_bus *bus); +void mdiobus_free(struct mii_bus *bus); struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); void phy_sanitize_settings(struct phy_device *phydev); -- cgit v1.2.3-70-g09d2 From 46abc02175b3c246dd5141d878f565a8725060c9 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 8 Oct 2008 16:33:40 -0700 Subject: phylib: give mdio buses a device tree presence Introduce the mdio_bus class, and give each 'struct mii_bus' its own 'struct device', so that mii_bus objects are represented in the device tree and can be found by querying the device tree. Signed-off-by: Lennert Buytenhek Acked-by: Andy Fleming Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 75 +++++++++++++++++++++++++++++++++++++++++++--- include/linux/phy.h | 8 +++++ 2 files changed, 79 insertions(+), 4 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index d206691f15d..fb4c0965b15 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -43,10 +43,34 @@ */ struct mii_bus *mdiobus_alloc(void) { - return kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + struct mii_bus *bus; + + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (bus != NULL) + bus->state = MDIOBUS_ALLOCATED; + + return bus; } EXPORT_SYMBOL(mdiobus_alloc); +/** + * mdiobus_release - mii_bus device release callback + * + * Description: called when the last reference to an mii_bus is + * dropped, to free the underlying memory. + */ +static void mdiobus_release(struct device *d) +{ + struct mii_bus *bus = to_mii_bus(d); + BUG_ON(bus->state != MDIOBUS_RELEASED); + kfree(bus); +} + +static struct class mdio_bus_class = { + .name = "mdio_bus", + .dev_release = mdiobus_release, +}; + /** * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus * @bus: target mii_bus @@ -66,6 +90,22 @@ int mdiobus_register(struct mii_bus *bus) NULL == bus->write) return -EINVAL; + BUG_ON(bus->state != MDIOBUS_ALLOCATED && + bus->state != MDIOBUS_UNREGISTERED); + + bus->dev.parent = bus->parent; + bus->dev.class = &mdio_bus_class; + bus->dev.groups = NULL; + memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE); + + err = device_register(&bus->dev); + if (err) { + printk(KERN_ERR "mii_bus %s failed to register\n", bus->id); + return -EINVAL; + } + + bus->state = MDIOBUS_REGISTERED; + mutex_init(&bus->mdio_lock); if (bus->reset) @@ -92,6 +132,10 @@ void mdiobus_unregister(struct mii_bus *bus) { int i; + BUG_ON(bus->state != MDIOBUS_REGISTERED); + bus->state = MDIOBUS_UNREGISTERED; + + device_unregister(&bus->dev); for (i = 0; i < PHY_MAX_ADDR; i++) { if (bus->phy_map[i]) device_unregister(&bus->phy_map[i]->dev); @@ -103,11 +147,24 @@ EXPORT_SYMBOL(mdiobus_unregister); * mdiobus_free - free a struct mii_bus * @bus: mii_bus to free * - * This function frees the mii_bus. + * This function releases the reference to the underlying device + * object in the mii_bus. If this is the last reference, the mii_bus + * will be freed. */ void mdiobus_free(struct mii_bus *bus) { - kfree(bus); + /* + * For compatibility with error handling in drivers. + */ + if (bus->state == MDIOBUS_ALLOCATED) { + kfree(bus); + return; + } + + BUG_ON(bus->state != MDIOBUS_UNREGISTERED); + bus->state = MDIOBUS_RELEASED; + + put_device(&bus->dev); } EXPORT_SYMBOL(mdiobus_free); @@ -205,10 +262,20 @@ EXPORT_SYMBOL(mdio_bus_type); int __init mdio_bus_init(void) { - return bus_register(&mdio_bus_type); + int ret; + + ret = class_register(&mdio_bus_class); + if (!ret) { + ret = bus_register(&mdio_bus_type); + if (ret) + class_unregister(&mdio_bus_class); + } + + return ret; } void mdio_bus_exit(void) { + class_unregister(&mdio_bus_class); bus_unregister(&mdio_bus_type); } diff --git a/include/linux/phy.h b/include/linux/phy.h index ca4a83c4c53..891f27f9137 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -100,6 +100,13 @@ struct mii_bus { struct mutex mdio_lock; struct device *parent; + enum { + MDIOBUS_ALLOCATED = 1, + MDIOBUS_REGISTERED, + MDIOBUS_UNREGISTERED, + MDIOBUS_RELEASED, + } state; + struct device dev; /* list of all PHYs on bus */ struct phy_device *phy_map[PHY_MAX_ADDR]; @@ -113,6 +120,7 @@ struct mii_bus { */ int *irq; }; +#define to_mii_bus(d) container_of(d, struct mii_bus, dev) #define PHY_INTERRUPT_DISABLED 0x0 #define PHY_INTERRUPT_ENABLED 0x80000000 -- cgit v1.2.3-70-g09d2 From 2e888103295f47b8fcbf7e9bb8c5da97dd2ecd76 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 29 Sep 2008 17:12:35 +0000 Subject: phylib: add mdiobus_{read,write} Add mdiobus_{read,write} routines to allow direct reading/writing of registers on an mii bus without having to go through the PHY abstraction, and make phy_{read,write} use these primitives. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 49 ---------------------------------------------- include/linux/phy.h | 46 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 87 insertions(+), 57 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index fb4c0965b15..6671e2da0d5 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -210,6 +210,55 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) } EXPORT_SYMBOL(mdiobus_scan); +/** + * mdiobus_read - Convenience function for reading a given MII mgmt register + * @bus: the mii_bus struct + * @addr: the phy address + * @regnum: register number to read + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum) +{ + int retval; + + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); + retval = bus->read(bus, addr, regnum); + mutex_unlock(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(mdiobus_read); + +/** + * mdiobus_write - Convenience function for writing a given MII mgmt register + * @bus: the mii_bus struct + * @addr: the phy address + * @regnum: register number to write + * @val: value to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val) +{ + int err; + + BUG_ON(in_interrupt()); + + mutex_lock(&bus->mdio_lock); + err = bus->write(bus, addr, regnum, val); + mutex_unlock(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(mdiobus_write); + /** * mdio_bus_match - determine if given PHY driver supports the given PHY device * @dev: target PHY device diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 20cc82c7813..df4e6257d4a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -57,55 +57,6 @@ void phy_print_status(struct phy_device *phydev) EXPORT_SYMBOL(phy_print_status); -/** - * phy_read - Convenience function for reading a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to read - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ -int phy_read(struct phy_device *phydev, u16 regnum) -{ - int retval; - struct mii_bus *bus = phydev->bus; - - BUG_ON(in_interrupt()); - - mutex_lock(&bus->mdio_lock); - retval = bus->read(bus, phydev->addr, regnum); - mutex_unlock(&bus->mdio_lock); - - return retval; -} -EXPORT_SYMBOL(phy_read); - -/** - * phy_write - Convenience function for writing a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to write - * @val: value to write to @regnum - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ -int phy_write(struct phy_device *phydev, u16 regnum, u16 val) -{ - int err; - struct mii_bus *bus = phydev->bus; - - BUG_ON(in_interrupt()); - - mutex_lock(&bus->mdio_lock); - err = bus->write(bus, phydev->addr, regnum, val); - mutex_unlock(&bus->mdio_lock); - - return err; -} -EXPORT_SYMBOL(phy_write); - /** * phy_clear_interrupt - Ack the phy device's interrupt * @phydev: the phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index 891f27f9137..77c4ed60b98 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -122,6 +122,15 @@ struct mii_bus { }; #define to_mii_bus(d) container_of(d, struct mii_bus, dev) +struct mii_bus *mdiobus_alloc(void); +int mdiobus_register(struct mii_bus *bus); +void mdiobus_unregister(struct mii_bus *bus); +void mdiobus_free(struct mii_bus *bus); +struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); +int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum); +int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val); + + #define PHY_INTERRUPT_DISABLED 0x0 #define PHY_INTERRUPT_ENABLED 0x80000000 @@ -399,8 +408,35 @@ struct phy_fixup { int (*run)(struct phy_device *phydev); }; -int phy_read(struct phy_device *phydev, u16 regnum); -int phy_write(struct phy_device *phydev, u16 regnum, u16 val); +/** + * phy_read - Convenience function for reading a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to read + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +static inline int phy_read(struct phy_device *phydev, u16 regnum) +{ + return mdiobus_read(phydev->bus, phydev->addr, regnum); +} + +/** + * phy_write - Convenience function for writing a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to write + * @val: value to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val) +{ + return mdiobus_write(phydev->bus, phydev->addr, regnum, val); +} + int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id); struct phy_device* get_phy_device(struct mii_bus *bus, int addr); int phy_clear_interrupt(struct phy_device *phydev); @@ -416,12 +452,6 @@ void phy_start(struct phy_device *phydev); void phy_stop(struct phy_device *phydev); int phy_start_aneg(struct phy_device *phydev); -struct mii_bus *mdiobus_alloc(void); -int mdiobus_register(struct mii_bus *bus); -void mdiobus_unregister(struct mii_bus *bus); -void mdiobus_free(struct mii_bus *bus); -struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); - void phy_sanitize_settings(struct phy_device *phydev); int phy_stop_interrupts(struct phy_device *phydev); int phy_enable_interrupts(struct phy_device *phydev); -- cgit v1.2.3-70-g09d2 From ec2a5652ea53c102306f08cdf516f98e32bd4b61 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Thu, 9 Oct 2008 09:45:04 -0700 Subject: phylib: two dynamic mii_bus allocation fallout fixes 1. arch/powerpc/platforms/pasemi/gpio_mdio.c also needs to be converted over to mdiobus_{alloc,free}(). 2. drivers/net/phy/fixed.c used to embed a struct mii_bus into its struct fixed_mdio_bus and then use container_of() to go from the former to the latter. Since mii bus structures are no longer embedded, we need to do something like use the mii bus private pointer to go from mii_bus to fixed_mdio_bus instead. Signed-off-by: Lennert Buytenhek Signed-off-by: David S. Miller --- arch/powerpc/platforms/pasemi/gpio_mdio.c | 4 ++-- drivers/net/phy/fixed.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net/phy') diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index 798c7abe160..75cc165d5be 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -230,7 +230,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, if (!priv) goto out; - new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + new_bus = mdiobus_alloc(); if (!new_bus) goto out_free_priv; @@ -306,7 +306,7 @@ static int gpio_mdio_remove(struct of_device *dev) kfree(bus->priv); bus->priv = NULL; - kfree(bus); + mdiobus_free(bus); return 0; } diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index b5e13f8d5e3..cf24cc34deb 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -115,8 +115,7 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) static int fixed_mdio_read(struct mii_bus *bus, int phy_id, int reg_num) { - struct fixed_mdio_bus *fmb = container_of(bus, struct fixed_mdio_bus, - mii_bus); + struct fixed_mdio_bus *fmb = bus->priv; struct fixed_phy *fp; if (reg_num >= MII_REGS_NUM) @@ -221,6 +220,7 @@ static int __init fixed_mdio_bus_init(void) snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0"); fmb->mii_bus->name = "Fixed MDIO Bus"; + fmb->mii_bus->priv = fmb; fmb->mii_bus->parent = &pdev->dev; fmb->mii_bus->read = &fixed_mdio_read; fmb->mii_bus->write = &fixed_mdio_write; -- cgit v1.2.3-70-g09d2 From 78c36b15a02941403be5f1d28c06074f1e192079 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 13 Oct 2008 18:46:22 -0700 Subject: net/phy: add missing kernel-doc Fix kernel-doc warning, missing description: Warning(lin2627-g3-kdocfixes//drivers/net/phy/mdio_bus.c:63): No description found for parameter 'd' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 6671e2da0d5..d0ed1ef284a 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -55,6 +55,7 @@ EXPORT_SYMBOL(mdiobus_alloc); /** * mdiobus_release - mii_bus device release callback + * @d: the target struct device that contains the mii_bus * * Description: called when the last reference to an mii_bus is * dropped, to free the underlying memory. -- cgit v1.2.3-70-g09d2 From 892871dcc39c23d3e30f8c317a5bfbab74084a40 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 13 Oct 2008 18:48:09 -0700 Subject: net: export genphy_restart_aneg This patch fixes the following build error caused by commit ed94493fb38a665cebcf750dfabe8a6dd13e136f (mv643xx_eth: convert to phylib): <-- snip --> ... Building modules, stage 2. MODPOST 1280 modules ERROR: "genphy_restart_aneg" [drivers/net/mv643xx_eth.ko] undefined! ... make[2]: *** [__modpost] Error 1 <-- snip --> Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 17162748005..f11e900b437 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -557,6 +557,7 @@ int genphy_restart_aneg(struct phy_device *phydev) return ctl; } +EXPORT_SYMBOL(genphy_restart_aneg); /** -- cgit v1.2.3-70-g09d2 From 26853ab6f9a4c482be4b638477335704724d4854 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 27 Jan 2008 10:29:20 -0800 Subject: NET: convert the phy_device file to use bus_find_device_by_name The driver core now has this helper function, so might as well use it instead of forcing the phy code to roll their own version. Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/phy_device.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f11e900b437..e11b03b2b25 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -309,11 +309,6 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); -static int phy_compare_id(struct device *dev, void *data) -{ - return strcmp((char *)data, dev->bus_id) ? 0 : 1; -} - /** * phy_attach - attach a network device to a particular PHY device * @dev: network device to attach @@ -337,8 +332,7 @@ struct phy_device *phy_attach(struct net_device *dev, /* Search the list of PHY devices on the mdio bus for the * PHY with the requested name */ - d = bus_find_device(bus, NULL, (void *)bus_id, phy_compare_id); - + d = bus_find_device_by_name(bus, NULL, bus_id); if (d) { phydev = to_phy_device(d); } else { -- cgit v1.2.3-70-g09d2