diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/cicada.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/davicom.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/dp83640.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/icplus.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/lxt.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 22 | ||||
-rw-r--r-- | drivers/net/phy/mdio-gpio.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio-moxart.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio-mux-gpio.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio-mux-mmioreg.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio-octeon.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio-sun4i.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 35 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 19 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 435 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 419 | ||||
-rw-r--r-- | drivers/net/phy/spi_ks8995.c | 7 | ||||
-rw-r--r-- | drivers/net/phy/vitesse.c | 15 |
18 files changed, 536 insertions, 438 deletions
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c index 313a0377f68..b57ce0cc965 100644 --- a/drivers/net/phy/cicada.c +++ b/drivers/net/phy/cicada.c @@ -92,8 +92,8 @@ static int cis820x_config_intr(struct phy_device *phydev) { int err; - if(phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, MII_CIS8201_IMASK, + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); else err = phy_write(phydev, MII_CIS8201_IMASK, 0); diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index 383e8338ad8..d2c08f625a4 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -72,7 +72,7 @@ static int dm9161_config_intr(struct phy_device *phydev) if (temp < 0) return temp; - if(PHY_INTERRUPT_ENABLED == phydev->interrupts ) + if (PHY_INTERRUPT_ENABLED == phydev->interrupts) temp &= ~(MII_DM9161_INTR_STOP); else temp |= MII_DM9161_INTR_STOP; diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 7490b6c866e..547725fa867 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -851,8 +851,8 @@ static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); - return (rxts->msgtype == (*msgtype & 0xf) && - rxts->seqid == ntohs(*seqid)); + return rxts->msgtype == (*msgtype & 0xf) && + rxts->seqid == ntohs(*seqid); } static void dp83640_free_clocks(void) diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index b5ddd5077a8..97bf58bf493 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -48,7 +48,7 @@ MODULE_LICENSE("GPL"); static int ip175c_config_init(struct phy_device *phydev) { int err, i; - static int full_reset_performed = 0; + static int full_reset_performed; if (full_reset_performed == 0) { diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index ff2e45e9cb5..9108f319170 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -82,7 +82,7 @@ static int lxt970_config_intr(struct phy_device *phydev) { int err; - if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN); else err = phy_write(phydev, MII_LXT970_IER, 0); @@ -114,7 +114,7 @@ static int lxt971_config_intr(struct phy_device *phydev) { int err; - if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN); else err = phy_write(phydev, MII_LXT971_IER, 0); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 2e3c778ea9b..bd37e45c89c 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -894,6 +894,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -907,6 +909,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -920,6 +924,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -933,6 +939,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = {.owner = THIS_MODULE,}, }, { @@ -946,6 +954,8 @@ static struct phy_driver marvell_drivers[] = { .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, .did_interrupt = &m88e1121_did_interrupt, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -961,6 +971,8 @@ static struct phy_driver marvell_drivers[] = { .did_interrupt = &m88e1121_did_interrupt, .get_wol = &m88e1318_get_wol, .set_wol = &m88e1318_set_wol, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -974,6 +986,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -987,6 +1001,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -1000,6 +1016,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -1013,6 +1031,8 @@ static struct phy_driver marvell_drivers[] = { .read_status = &genphy_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, { @@ -1026,6 +1046,8 @@ static struct phy_driver marvell_drivers[] = { .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, .did_interrupt = &m88e1121_did_interrupt, + .resume = &genphy_resume, + .suspend = &genphy_suspend, .driver = { .owner = THIS_MODULE }, }, }; diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 8004acbef2c..e701433bf52 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -22,7 +22,6 @@ #include <linux/module.h> #include <linux/slab.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/gpio.h> diff --git a/drivers/net/phy/mdio-moxart.c b/drivers/net/phy/mdio-moxart.c index a5741cb0304..f1fc51f655d 100644 --- a/drivers/net/phy/mdio-moxart.c +++ b/drivers/net/phy/mdio-moxart.c @@ -8,7 +8,6 @@ */ #include <linux/delay.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c index d2dd9e473e2..09669516349 100644 --- a/drivers/net/phy/mdio-mux-gpio.c +++ b/drivers/net/phy/mdio-mux-gpio.c @@ -10,7 +10,6 @@ #include <linux/device.h> #include <linux/of_mdio.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/phy.h> #include <linux/mdio-mux.h> #include <linux/of_gpio.h> diff --git a/drivers/net/phy/mdio-mux-mmioreg.c b/drivers/net/phy/mdio-mux-mmioreg.c index f8e305d8da7..1656785ff33 100644 --- a/drivers/net/phy/mdio-mux-mmioreg.c +++ b/drivers/net/phy/mdio-mux-mmioreg.c @@ -15,7 +15,6 @@ #include <linux/of_address.h> #include <linux/of_mdio.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/phy.h> #include <linux/mdio-mux.h> diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index 6aee02ed97a..a51ed92fbad 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -10,7 +10,6 @@ #include <linux/of_mdio.h> #include <linux/delay.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/gfp.h> #include <linux/phy.h> #include <linux/io.h> diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c index 18969b3ad8b..bb88bc7d81f 100644 --- a/drivers/net/phy/mdio-sun4i.c +++ b/drivers/net/phy/mdio-sun4i.c @@ -13,7 +13,6 @@ */ #include <linux/delay.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 56178761ce9..930694d3a13 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -1,7 +1,4 @@ -/* - * drivers/net/phy/mdio_bus.c - * - * MDIO Bus interface +/* MDIO Bus interface * * Author: Andy Fleming * @@ -36,10 +33,10 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> +#include <linux/io.h> +#include <linux/uaccess.h> -#include <asm/io.h> #include <asm/irq.h> -#include <asm/uaccess.h> /** * mdiobus_alloc_size - allocate a mii_bus structure @@ -139,8 +136,7 @@ int mdiobus_register(struct mii_bus *bus) int i, err; if (NULL == bus || NULL == bus->name || - NULL == bus->read || - NULL == bus->write) + NULL == bus->read || NULL == bus->write) return -EINVAL; BUG_ON(bus->state != MDIOBUS_ALLOCATED && @@ -214,9 +210,7 @@ EXPORT_SYMBOL(mdiobus_unregister); */ void mdiobus_free(struct mii_bus *bus) { - /* - * For compatibility with error handling in drivers. - */ + /* For compatibility with error handling in drivers. */ if (bus->state == MDIOBUS_ALLOCATED) { kfree(bus); return; @@ -316,8 +310,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) if (phydrv->match_phy_device) return phydrv->match_phy_device(phydev); - return ((phydrv->phy_id & phydrv->phy_id_mask) == - (phydev->phy_id & phydrv->phy_id_mask)); + return (phydrv->phy_id & phydrv->phy_id_mask) == + (phydev->phy_id & phydrv->phy_id_mask); } #ifdef CONFIG_PM @@ -335,15 +329,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) if (!netdev) return true; - /* - * Don't suspend PHY if the attched netdev parent may wakeup. + /* Don't suspend PHY if the attched netdev parent may wakeup. * The parent may point to a PCI device, as in tg3 driver. */ if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) return false; - /* - * Also don't suspend PHY if the netdev itself may wakeup. This + /* Also don't suspend PHY if the netdev itself may wakeup. This * is the case for devices w/o underlaying pwr. mgmt. aware bus, * e.g. SoC devices. */ @@ -358,8 +350,7 @@ static int mdio_bus_suspend(struct device *dev) struct phy_driver *phydrv = to_phy_driver(dev->driver); struct phy_device *phydev = to_phy_device(dev); - /* - * We must stop the state machine manually, otherwise it stops out of + /* We must stop the state machine manually, otherwise it stops out of * control, possibly with the phydev->lock held. Upon resume, netdev * may call phy routines that try to grab the same lock, and that may * lead to a deadlock. @@ -388,7 +379,7 @@ static int mdio_bus_resume(struct device *dev) no_resume: if (phydev->attached_dev && phydev->adjust_link) - phy_start_machine(phydev, NULL); + phy_start_machine(phydev); return 0; } @@ -410,12 +401,12 @@ static int mdio_bus_restore(struct device *dev) phydev->link = 0; phydev->state = PHY_UP; - phy_start_machine(phydev, NULL); + phy_start_machine(phydev); return 0; } -static struct dev_pm_ops mdio_bus_pm_ops = { +static const struct dev_pm_ops mdio_bus_pm_ops = { .suspend = mdio_bus_suspend, .resume = mdio_bus_resume, .freeze = mdio_bus_suspend, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 3ae28f42086..5a8993b0caf 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -81,14 +81,14 @@ static int ksz_config_flags(struct phy_device *phydev) } static int kszphy_extended_write(struct phy_device *phydev, - u32 regnum, u16 val) + u32 regnum, u16 val) { phy_write(phydev, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | regnum); return phy_write(phydev, MII_KSZPHY_EXTREG_WRITE, val); } static int kszphy_extended_read(struct phy_device *phydev, - u32 regnum) + u32 regnum) { phy_write(phydev, MII_KSZPHY_EXTREG, regnum); return phy_read(phydev, MII_KSZPHY_EXTREG_READ); @@ -336,6 +336,21 @@ static struct phy_driver ksphy_driver[] = { .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }, { + .phy_id = PHY_ID_KSZ8041RNLI, + .phy_id_mask = 0x00fffff0, + .name = "Micrel KSZ8041RNLI", + .features = PHY_BASIC_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = kszphy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = kszphy_ack_interrupt, + .config_intr = kszphy_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = { .owner = THIS_MODULE,}, +}, { .phy_id = PHY_ID_KSZ8051, .phy_id_mask = 0x00fffff0, .name = "Micrel KSZ8051", diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 36c6994436b..19c9eca0ef2 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1,7 +1,4 @@ -/* - * drivers/net/phy/phy.c - * - * Framework for configuring and reading PHY devices +/* Framework for configuring and reading PHY devices * Based on code in sungem_phy.c and gianfar_phy.c * * Author: Andy Fleming @@ -23,7 +20,6 @@ #include <linux/errno.h> #include <linux/unistd.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -36,11 +32,11 @@ #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/mdio.h> - +#include <linux/io.h> +#include <linux/uaccess.h> #include <linux/atomic.h> -#include <asm/io.h> + #include <asm/irq.h> -#include <asm/uaccess.h> /** * phy_print_status - Convenience function to print out the current phy status @@ -48,13 +44,14 @@ */ void phy_print_status(struct phy_device *phydev) { - if (phydev->link) + if (phydev->link) { pr_info("%s - Link is Up - %d/%s\n", dev_name(&phydev->dev), phydev->speed, DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); - else + } else { pr_info("%s - Link is Down\n", dev_name(&phydev->dev)); + } } EXPORT_SYMBOL(phy_print_status); @@ -69,12 +66,10 @@ EXPORT_SYMBOL(phy_print_status); */ static int phy_clear_interrupt(struct phy_device *phydev) { - int err = 0; - if (phydev->drv->ack_interrupt) - err = phydev->drv->ack_interrupt(phydev); + return phydev->drv->ack_interrupt(phydev); - return err; + return 0; } /** @@ -86,13 +81,11 @@ static int phy_clear_interrupt(struct phy_device *phydev) */ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) { - int err = 0; - phydev->interrupts = interrupts; if (phydev->drv->config_intr) - err = phydev->drv->config_intr(phydev); + return phydev->drv->config_intr(phydev); - return err; + return 0; } @@ -106,15 +99,14 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) */ static inline int phy_aneg_done(struct phy_device *phydev) { - int retval; - - retval = phy_read(phydev, MII_BMSR); + int retval = phy_read(phydev, MII_BMSR); return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); } /* A structure for mapping a particular speed and duplex - * combination to a particular SUPPORTED and ADVERTISED value */ + * combination to a particular SUPPORTED and ADVERTISED value + */ struct phy_setting { int speed; int duplex; @@ -177,8 +169,7 @@ static inline int phy_find_setting(int speed, int duplex) int idx = 0; while (idx < ARRAY_SIZE(settings) && - (settings[idx].speed != speed || - settings[idx].duplex != duplex)) + (settings[idx].speed != speed || settings[idx].duplex != duplex)) idx++; return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; @@ -245,8 +236,7 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) if (cmd->phy_address != phydev->addr) return -EINVAL; - /* We make sure that we don't pass unsupported - * values in to the PHY */ + /* We make sure that we don't pass unsupported values in to the PHY */ cmd->advertising &= phydev->supported; /* Verify the settings we care about. */ @@ -289,6 +279,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->supported = phydev->supported; cmd->advertising = phydev->advertising; + cmd->lp_advertising = phydev->lp_advertising; ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; @@ -312,8 +303,7 @@ EXPORT_SYMBOL(phy_ethtool_gset); * PHYCONTROL layer. It changes registers without regard to * current state. Use at own risk. */ -int phy_mii_ioctl(struct phy_device *phydev, - struct ifreq *ifr, int cmd) +int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *mii_data = if_mii(ifr); u16 val = mii_data->val_in; @@ -326,25 +316,24 @@ int phy_mii_ioctl(struct phy_device *phydev, case SIOCGMIIREG: mii_data->val_out = mdiobus_read(phydev->bus, mii_data->phy_id, mii_data->reg_num); - break; + return 0; case SIOCSMIIREG: if (mii_data->phy_id == phydev->addr) { - switch(mii_data->reg_num) { + switch (mii_data->reg_num) { case MII_BMCR: - if ((val & (BMCR_RESET|BMCR_ANENABLE)) == 0) + if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) phydev->autoneg = AUTONEG_DISABLE; else phydev->autoneg = AUTONEG_ENABLE; - if ((!phydev->autoneg) && (val & BMCR_FULLDPLX)) + if (!phydev->autoneg && (val & BMCR_FULLDPLX)) phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; - if ((!phydev->autoneg) && - (val & BMCR_SPEED1000)) + if (!phydev->autoneg && (val & BMCR_SPEED1000)) phydev->speed = SPEED_1000; - else if ((!phydev->autoneg) && - (val & BMCR_SPEED100)) + else if (!phydev->autoneg && + (val & BMCR_SPEED100)) phydev->speed = SPEED_100; break; case MII_ADVERTISE: @@ -360,12 +349,9 @@ int phy_mii_ioctl(struct phy_device *phydev, mii_data->reg_num, val); if (mii_data->reg_num == MII_BMCR && - val & BMCR_RESET && - phydev->drv->config_init) { - phy_scan_fixups(phydev); - phydev->drv->config_init(phydev); - } - break; + val & BMCR_RESET) + return phy_init_hw(phydev); + return 0; case SIOCSHWTSTAMP: if (phydev->drv->hwtstamp) @@ -375,8 +361,6 @@ int phy_mii_ioctl(struct phy_device *phydev, default: return -EOPNOTSUPP; } - - return 0; } EXPORT_SYMBOL(phy_mii_ioctl); @@ -399,7 +383,6 @@ int phy_start_aneg(struct phy_device *phydev) phy_sanitize_settings(phydev); err = phydev->drv->config_aneg(phydev); - if (err < 0) goto out_unlock; @@ -419,25 +402,18 @@ out_unlock: } EXPORT_SYMBOL(phy_start_aneg); - /** * phy_start_machine - start PHY state machine tracking * @phydev: the phy_device struct - * @handler: callback function for state change notifications * * Description: The PHY infrastructure can run a state machine * which tracks whether the PHY is starting up, negotiating, * etc. This function starts the timer which tracks the state - * of the PHY. If you want to be notified when the state changes, - * pass in the callback @handler, otherwise, pass NULL. If you - * want to maintain your own state machine, do not call this - * function. + * of the PHY. If you want to maintain your own state machine, + * do not call this function. */ -void phy_start_machine(struct phy_device *phydev, - void (*handler)(struct net_device *)) +void phy_start_machine(struct phy_device *phydev) { - phydev->adjust_state = handler; - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ); } @@ -457,8 +433,6 @@ void phy_stop_machine(struct phy_device *phydev) if (phydev->state > PHY_UP) phydev->state = PHY_UP; mutex_unlock(&phydev->lock); - - phydev->adjust_state = NULL; } /** @@ -495,7 +469,8 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) /* The MDIO bus is not allowed to be written in interrupt * context, so we need to disable the irq here. A work * queue will write the PHY to disable and clear the - * interrupt, and then reenable the irq line. */ + * interrupt, and then reenable the irq line. + */ disable_irq_nosync(irq); atomic_inc(&phydev->irq_disable); @@ -510,16 +485,12 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) */ static int phy_enable_interrupts(struct phy_device *phydev) { - int err; - - err = phy_clear_interrupt(phydev); + int err = phy_clear_interrupt(phydev); if (err < 0) return err; - err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); - - return err; + return phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); } /** @@ -532,13 +503,11 @@ static int phy_disable_interrupts(struct phy_device *phydev) /* Disable PHY interrupts */ err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); - if (err) goto phy_err; /* Clear the interrupt */ err = phy_clear_interrupt(phydev); - if (err) goto phy_err; @@ -562,22 +531,16 @@ phy_err: */ int phy_start_interrupts(struct phy_device *phydev) { - int err = 0; - atomic_set(&phydev->irq_disable, 0); - if (request_irq(phydev->irq, phy_interrupt, - IRQF_SHARED, - "phy_interrupt", - phydev) < 0) { + if (request_irq(phydev->irq, phy_interrupt, 0, "phy_interrupt", + phydev) < 0) { pr_warn("%s: Can't get IRQ %d (PHY)\n", phydev->bus->name, phydev->irq); phydev->irq = PHY_POLL; return 0; } - err = phy_enable_interrupts(phydev); - - return err; + return phy_enable_interrupts(phydev); } EXPORT_SYMBOL(phy_start_interrupts); @@ -587,24 +550,20 @@ EXPORT_SYMBOL(phy_start_interrupts); */ int phy_stop_interrupts(struct phy_device *phydev) { - int err; - - err = phy_disable_interrupts(phydev); + int err = phy_disable_interrupts(phydev); if (err) phy_error(phydev); free_irq(phydev->irq, phydev); - /* - * Cannot call flush_scheduled_work() here as desired because + /* Cannot call flush_scheduled_work() here as desired because * of rtnl_lock(), but we do not really care about what would * be done, except from enable_irq(), so cancel any work * possibly pending and take care of the matter below. */ cancel_work_sync(&phydev->phy_queue); - /* - * If work indeed has been cancelled, disable_irq() will have + /* If work indeed has been cancelled, disable_irq() will have * been left unbalanced from phy_interrupt() and enable_irq() * has to be called so that other devices on the line work. */ @@ -615,14 +574,12 @@ int phy_stop_interrupts(struct phy_device *phydev) } EXPORT_SYMBOL(phy_stop_interrupts); - /** * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes * @work: work_struct that describes the work to be done */ void phy_change(struct work_struct *work) { - int err; struct phy_device *phydev = container_of(work, struct phy_device, phy_queue); @@ -630,9 +587,7 @@ void phy_change(struct work_struct *work) !phydev->drv->did_interrupt(phydev)) goto ignore; - err = phy_disable_interrupts(phydev); - - if (err) + if (phy_disable_interrupts(phydev)) goto phy_err; mutex_lock(&phydev->lock); @@ -644,16 +599,13 @@ void phy_change(struct work_struct *work) enable_irq(phydev->irq); /* Reenable interrupts */ - if (PHY_HALTED != phydev->state) - err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); - - if (err) + if (PHY_HALTED != phydev->state && + phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) goto irq_enable_err; /* reschedule state queue work to run as soon as possible */ cancel_delayed_work_sync(&phydev->state_queue); queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); - return; ignore: @@ -692,13 +644,12 @@ void phy_stop(struct phy_device *phydev) out_unlock: mutex_unlock(&phydev->lock); - /* - * Cannot call flush_scheduled_work() here as desired because + /* Cannot call flush_scheduled_work() here as desired because * of rtnl_lock(), but PHY_HALTED shall guarantee phy_change() * will not reenable interrupts. */ } - +EXPORT_SYMBOL(phy_stop); /** * phy_start - start or restart a PHY device @@ -715,20 +666,19 @@ void phy_start(struct phy_device *phydev) mutex_lock(&phydev->lock); switch (phydev->state) { - case PHY_STARTING: - phydev->state = PHY_PENDING; - break; - case PHY_READY: - phydev->state = PHY_UP; - break; - case PHY_HALTED: - phydev->state = PHY_RESUMING; - default: - break; + case PHY_STARTING: + phydev->state = PHY_PENDING; + break; + case PHY_READY: + phydev->state = PHY_UP; + break; + case PHY_HALTED: + phydev->state = PHY_RESUMING; + default: + break; } mutex_unlock(&phydev->lock); } -EXPORT_SYMBOL(phy_stop); EXPORT_SYMBOL(phy_start); /** @@ -740,160 +690,132 @@ void phy_state_machine(struct work_struct *work) struct delayed_work *dwork = to_delayed_work(work); struct phy_device *phydev = container_of(dwork, struct phy_device, state_queue); - int needs_aneg = 0; + int needs_aneg = 0, do_suspend = 0; int err = 0; mutex_lock(&phydev->lock); - if (phydev->adjust_state) - phydev->adjust_state(phydev->attached_dev); + switch (phydev->state) { + case PHY_DOWN: + case PHY_STARTING: + case PHY_READY: + case PHY_PENDING: + break; + case PHY_UP: + needs_aneg = 1; - switch(phydev->state) { - case PHY_DOWN: - case PHY_STARTING: - case PHY_READY: - case PHY_PENDING: - break; - case PHY_UP: - needs_aneg = 1; + phydev->link_timeout = PHY_AN_TIMEOUT; - phydev->link_timeout = PHY_AN_TIMEOUT; + break; + case PHY_AN: + err = phy_read_status(phydev); + if (err < 0) + break; + /* If the link is down, give up on negotiation for now */ + if (!phydev->link) { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); break; - case PHY_AN: - err = phy_read_status(phydev); + } - if (err < 0) - break; + /* Check if negotiation is done. Break if there's an error */ + err = phy_aneg_done(phydev); + if (err < 0) + break; - /* If the link is down, give up on - * negotiation for now */ - if (!phydev->link) { - phydev->state = PHY_NOLINK; - netif_carrier_off(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); - break; - } + /* If AN is done, we're running */ + if (err > 0) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); - /* Check if negotiation is done. Break - * if there's an error */ - err = phy_aneg_done(phydev); - if (err < 0) + } else if (0 == phydev->link_timeout--) { + needs_aneg = 1; + /* If we have the magic_aneg bit, we try again */ + if (phydev->drv->flags & PHY_HAS_MAGICANEG) break; - - /* If AN is done, we're running */ - if (err > 0) { - phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); - - } else if (0 == phydev->link_timeout--) { - needs_aneg = 1; - /* If we have the magic_aneg bit, - * we try again */ - if (phydev->drv->flags & PHY_HAS_MAGICANEG) - break; - } + } + break; + case PHY_NOLINK: + err = phy_read_status(phydev); + if (err) break; - case PHY_NOLINK: - err = phy_read_status(phydev); - - if (err) - break; - if (phydev->link) { - phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); - } + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + break; + case PHY_FORCING: + err = genphy_update_link(phydev); + if (err) break; - case PHY_FORCING: - err = genphy_update_link(phydev); - - if (err) - break; - if (phydev->link) { - phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - } else { - if (0 == phydev->link_timeout--) - needs_aneg = 1; - } + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + if (0 == phydev->link_timeout--) + needs_aneg = 1; + } - phydev->adjust_link(phydev->attached_dev); - break; - case PHY_RUNNING: - /* Only register a CHANGE if we are - * polling or ignoring interrupts - */ - if (!phy_interrupt_is_valid(phydev)) - phydev->state = PHY_CHANGELINK; + phydev->adjust_link(phydev->attached_dev); + break; + case PHY_RUNNING: + /* Only register a CHANGE if we are + * polling or ignoring interrupts + */ + if (!phy_interrupt_is_valid(phydev)) + phydev->state = PHY_CHANGELINK; + break; + case PHY_CHANGELINK: + err = phy_read_status(phydev); + if (err) break; - case PHY_CHANGELINK: - 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; + netif_carrier_off(phydev->attached_dev); + } - if (phydev->link) { - phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - } else { - phydev->state = PHY_NOLINK; - netif_carrier_off(phydev->attached_dev); - } + phydev->adjust_link(phydev->attached_dev); + if (phy_interrupt_is_valid(phydev)) + err = phy_config_interrupt(phydev, + PHY_INTERRUPT_ENABLED); + break; + case PHY_HALTED: + if (phydev->link) { + phydev->link = 0; + netif_carrier_off(phydev->attached_dev); phydev->adjust_link(phydev->attached_dev); - - if (phy_interrupt_is_valid(phydev)) - err = phy_config_interrupt(phydev, - PHY_INTERRUPT_ENABLED); - break; - case PHY_HALTED: - if (phydev->link) { - phydev->link = 0; - netif_carrier_off(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); - } + do_suspend = 1; + } + break; + case PHY_RESUMING: + err = phy_clear_interrupt(phydev); + if (err) break; - case PHY_RESUMING: - - err = phy_clear_interrupt(phydev); - if (err) - break; - - err = phy_config_interrupt(phydev, - PHY_INTERRUPT_ENABLED); + err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); + if (err) + break; - if (err) + if (AUTONEG_ENABLE == phydev->autoneg) { + err = phy_aneg_done(phydev); + if (err < 0) break; - if (AUTONEG_ENABLE == phydev->autoneg) { - err = phy_aneg_done(phydev); - if (err < 0) - break; - - /* err > 0 if AN is done. - * Otherwise, it's 0, and we're - * still waiting for AN */ - if (err > 0) { - 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 { + /* err > 0 if AN is done. + * Otherwise, it's 0, and we're still waiting for AN + */ + if (err > 0) { err = phy_read_status(phydev); if (err) break; @@ -901,11 +823,28 @@ void phy_state_machine(struct work_struct *work) if (phydev->link) { phydev->state = PHY_RUNNING; netif_carrier_on(phydev->attached_dev); - } else + } else { phydev->state = PHY_NOLINK; + } phydev->adjust_link(phydev->attached_dev); + } else { + phydev->state = PHY_AN; + phydev->link_timeout = PHY_AN_TIMEOUT; } - break; + } 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; } mutex_unlock(&phydev->lock); @@ -913,11 +852,14 @@ void phy_state_machine(struct work_struct *work) if (needs_aneg) err = phy_start_aneg(phydev); + if (do_suspend) + phy_suspend(phydev); + if (err < 0) phy_error(phydev); queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, - PHY_STATE_TIME * HZ); + PHY_STATE_TIME * HZ); } void phy_mac_interrupt(struct phy_device *phydev, int new_link) @@ -959,14 +901,10 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad, static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, int addr) { - u32 ret; - mmd_phy_indirect(bus, prtad, devad, addr); /* Read the content of the MMD's selected register */ - ret = bus->read(bus, addr, MII_MMD_DATA); - - return ret; + return bus->read(bus, addr, MII_MMD_DATA); } /** @@ -1006,8 +944,6 @@ static void phy_write_mmd_indirect(struct mii_bus *bus, int prtad, int devad, */ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) { - int ret = -EPROTONOSUPPORT; - /* According to 802.3az,the EEE is supported only in full duplex-mode. * Also EEE feature is active when core is operating with MII, GMII * or RGMII. @@ -1033,7 +969,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap); if (!cap) - goto eee_exit; + return -EPROTONOSUPPORT; /* Check which link settings negotiated and verify it in * the EEE advertising registers. @@ -1052,7 +988,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); idx = phy_find_setting(phydev->speed, phydev->duplex); if (!(lp & adv & settings[idx].setting)) - goto eee_exit; + return -EPROTONOSUPPORT; if (clk_stop_enable) { /* Configure the PHY to stop receiving xMII @@ -1069,11 +1005,10 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) MDIO_MMD_PCS, phydev->addr, val); } - ret = 0; /* EEE supported */ + return 0; /* EEE supported */ } -eee_exit: - return ret; + return -EPROTONOSUPPORT; } EXPORT_SYMBOL(phy_init_eee); @@ -1088,7 +1023,6 @@ int phy_get_eee_err(struct phy_device *phydev) { return phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS, phydev->addr); - } EXPORT_SYMBOL(phy_get_eee_err); @@ -1138,9 +1072,8 @@ EXPORT_SYMBOL(phy_ethtool_get_eee); */ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) { - int val; + int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised); - val = ethtool_adv_to_mmd_eee_adv_t(data->advertised); phy_write_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, MDIO_MMD_AN, phydev->addr, val); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index d6447b3f740..4b03e63639b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1,7 +1,4 @@ -/* - * drivers/net/phy/phy_device.c - * - * Framework for finding and configuring PHYs. +/* Framework for finding and configuring PHYs. * Also contains generic PHY driver * * Author: Andy Fleming @@ -33,10 +30,11 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> +#include <linux/mdio.h> +#include <linux/io.h> +#include <linux/uaccess.h> -#include <asm/io.h> #include <asm/irq.h> -#include <asm/uaccess.h> MODULE_DESCRIPTION("PHY library"); MODULE_AUTHOR("Andy Fleming"); @@ -53,31 +51,31 @@ static void phy_device_release(struct device *dev) kfree(to_phy_device(dev)); } -static struct phy_driver genphy_driver; -extern int mdio_bus_init(void); -extern void mdio_bus_exit(void); +enum genphy_driver { + GENPHY_DRV_1G, + GENPHY_DRV_10G, + GENPHY_DRV_MAX +}; + +static struct phy_driver genphy_driver[GENPHY_DRV_MAX]; static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface); - -/* - * Creates a new phy_fixup and adds it to the list +/** + * phy_register_fixup - creates a new phy_fixup and adds it to the list * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID) * @phy_uid: Used to match against phydev->phy_id (the UID of the PHY) - * It can also be PHY_ANY_UID + * It can also be PHY_ANY_UID * @phy_uid_mask: Applied to phydev->phy_id and fixup->phy_uid before - * comparison + * comparison * @run: The actual code to be run when a matching PHY is found */ int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, - int (*run)(struct phy_device *)) + int (*run)(struct phy_device *)) { - struct phy_fixup *fixup; + struct phy_fixup *fixup = kzalloc(sizeof(*fixup), GFP_KERNEL); - fixup = kzalloc(sizeof(struct phy_fixup), GFP_KERNEL); if (!fixup) return -ENOMEM; @@ -96,7 +94,7 @@ EXPORT_SYMBOL(phy_register_fixup); /* Registers a fixup to be run on any PHY with the UID in phy_uid */ int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, - int (*run)(struct phy_device *)) + int (*run)(struct phy_device *)) { return phy_register_fixup(PHY_ANY_ID, phy_uid, phy_uid_mask, run); } @@ -104,14 +102,13 @@ EXPORT_SYMBOL(phy_register_fixup_for_uid); /* Registers a fixup to be run on the PHY with id string bus_id */ int phy_register_fixup_for_id(const char *bus_id, - int (*run)(struct phy_device *)) + int (*run)(struct phy_device *)) { return phy_register_fixup(bus_id, PHY_ANY_UID, 0xffffffff, run); } EXPORT_SYMBOL(phy_register_fixup_for_id); -/* - * Returns 1 if fixup matches phydev in bus_id and phy_uid. +/* Returns 1 if fixup matches phydev in bus_id and phy_uid. * Fixups can be set to match any in one or more fields. */ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) @@ -121,7 +118,7 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) return 0; if ((fixup->phy_uid & fixup->phy_uid_mask) != - (phydev->phy_id & fixup->phy_uid_mask)) + (phydev->phy_id & fixup->phy_uid_mask)) if (fixup->phy_uid != PHY_ANY_UID) return 0; @@ -129,16 +126,14 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) } /* Runs any matching fixups for this phydev */ -int phy_scan_fixups(struct phy_device *phydev) +static int phy_scan_fixups(struct phy_device *phydev) { struct phy_fixup *fixup; mutex_lock(&phy_fixup_lock); list_for_each_entry(fixup, &phy_fixup_list, list) { if (phy_needs_fixup(phydev, fixup)) { - int err; - - err = fixup->run(phydev); + int err = fixup->run(phydev); if (err < 0) { mutex_unlock(&phy_fixup_lock); @@ -150,25 +145,24 @@ int phy_scan_fixups(struct phy_device *phydev) return 0; } -EXPORT_SYMBOL(phy_scan_fixups); struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, - bool is_c45, struct phy_c45_device_ids *c45_ids) + bool is_c45, + struct phy_c45_device_ids *c45_ids) { struct phy_device *dev; - /* We allocate the device, and initialize the - * default values */ + /* We allocate the device, and initialize the default values */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) - return (struct phy_device*) PTR_ERR((void*)-ENOMEM); + return (struct phy_device *)PTR_ERR((void *)-ENOMEM); dev->dev.release = phy_device_release; dev->speed = 0; dev->duplex = -1; - dev->pause = dev->asym_pause = 0; + dev->pause = 0; + dev->asym_pause = 0; dev->link = 1; dev->interface = PHY_INTERFACE_MODE_GMII; @@ -192,14 +186,15 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, INIT_WORK(&dev->phy_queue, phy_change); /* Request the appropriate module unconditionally; don't - bother trying to do so only if it isn't already loaded, - because that gets complicated. A hotplug event would have - done an unconditional modprobe anyway. - We don't do normal hotplug because it won't work for MDIO - -- because it relies on the device staying around for long - enough for the driver to get loaded. With MDIO, the NIC - driver will get bored and give up as soon as it finds that - there's no driver _already_ loaded. */ + * bother trying to do so only if it isn't already loaded, + * because that gets complicated. A hotplug event would have + * done an unconditional modprobe anyway. + * We don't do normal hotplug because it won't work for MDIO + * -- because it relies on the device staying around for long + * enough for the driver to get loaded. With MDIO, the NIC + * driver will get bored and give up as soon as it finds that + * there's no driver _already_ loaded. + */ request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id)); device_initialize(&dev->dev); @@ -299,10 +294,8 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, if (is_c45) return get_phy_c45_ids(bus, addr, phy_id, c45_ids); - /* Grab the bits from PHYIR1, and put them - * in the upper half */ + /* Grab the bits from PHYIR1, and put them in the upper half */ phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); - if (phy_reg < 0) return -EIO; @@ -310,7 +303,6 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, /* Grab the bits from PHYIR2, and put them in the lower half */ phy_reg = mdiobus_read(bus, addr, MII_PHYSID2); - if (phy_reg < 0) return -EIO; @@ -320,7 +312,8 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, } /** - * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * get_phy_device - reads the specified PHY device and returns its @phy_device + * struct * @bus: the target MII bus * @addr: PHY address on the MII bus * @is_c45: If true the PHY uses the 802.3 clause 45 protocol @@ -331,7 +324,6 @@ static 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, bool is_c45) { struct phy_c45_device_ids c45_ids = {0}; - struct phy_device *dev = NULL; u32 phy_id = 0; int r; @@ -343,9 +335,7 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) if ((phy_id & 0x1fffffff) == 0x1fffffff) return NULL; - dev = phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); - - return dev; + return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); } EXPORT_SYMBOL(get_phy_device); @@ -357,14 +347,17 @@ int phy_device_register(struct phy_device *phydev) { int err; - /* Don't register a phy if one is already registered at this - * address */ + /* Don't register a phy if one is already registered at this address */ if (phydev->bus->phy_map[phydev->addr]) return -EINVAL; phydev->bus->phy_map[phydev->addr] = phydev; /* Run all of the fixups for this PHY */ - phy_scan_fixups(phydev); + err = phy_init_hw(phydev); + if (err) { + pr_err("PHY %d failed to initialize\n", phydev->addr); + goto out; + } err = device_add(&phydev->dev); if (err) { @@ -409,7 +402,7 @@ EXPORT_SYMBOL(phy_find_first); * this function. */ static void phy_prepare_link(struct phy_device *phydev, - void (*handler)(struct net_device *)) + void (*handler)(struct net_device *)) { phydev->adjust_link = handler; } @@ -432,7 +425,7 @@ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, return rc; phy_prepare_link(phydev, handler); - phy_start_machine(phydev, NULL); + phy_start_machine(phydev); if (phydev->irq > 0) phy_start_interrupts(phydev); @@ -455,16 +448,17 @@ EXPORT_SYMBOL(phy_connect_direct); * choose to call only the subset of functions which provide * the desired functionality. */ -struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, - void (*handler)(struct net_device *), - phy_interface_t interface) +struct phy_device *phy_connect(struct net_device *dev, const char *bus_id, + void (*handler)(struct net_device *), + phy_interface_t interface) { struct phy_device *phydev; struct device *d; int rc; /* Search the list of PHY devices on the mdio bus for the - * PHY with the requested name */ + * PHY with the requested name + */ d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); if (!d) { pr_err("PHY %s not found\n", bus_id); @@ -481,7 +475,8 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, EXPORT_SYMBOL(phy_connect); /** - * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device + * phy_disconnect - disable interrupts, stop state machine, and detach a PHY + * device * @phydev: target phy_device struct */ void phy_disconnect(struct phy_device *phydev) @@ -490,13 +485,53 @@ void phy_disconnect(struct phy_device *phydev) phy_stop_interrupts(phydev); phy_stop_machine(phydev); - + phydev->adjust_link = NULL; phy_detach(phydev); } EXPORT_SYMBOL(phy_disconnect); +/** + * phy_poll_reset - Safely wait until a PHY reset has properly completed + * @phydev: The PHY device to poll + * + * Description: According to IEEE 802.3, Section 2, Subsection 22.2.4.1.1, as + * published in 2008, a PHY reset may take up to 0.5 seconds. The MII BMCR + * register must be polled until the BMCR_RESET bit clears. + * + * Furthermore, any attempts to write to PHY registers may have no effect + * or even generate MDIO bus errors until this is complete. + * + * Some PHYs (such as the Marvell 88E1111) don't entirely conform to the + * standard and do not fully reset after the BMCR_RESET bit is set, and may + * even *REQUIRE* a soft-reset to properly restart autonegotiation. In an + * effort to support such broken PHYs, this function is separate from the + * standard phy_init_hw() which will zero all the other bits in the BMCR + * and reapply all driver-specific and board-specific fixups. + */ +static int phy_poll_reset(struct phy_device *phydev) +{ + /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ + unsigned int retries = 12; + int ret; + + do { + msleep(50); + ret = phy_read(phydev, MII_BMCR); + if (ret < 0) + return ret; + } while (ret & BMCR_RESET && --retries); + if (ret & BMCR_RESET) + return -ETIMEDOUT; + + /* Some chips (smsc911x) may still need up to another 1ms after the + * BMCR_RESET bit is cleared before they are usable. + */ + msleep(1); + return 0; +} + int phy_init_hw(struct phy_device *phydev) { int ret; @@ -504,12 +539,21 @@ int phy_init_hw(struct phy_device *phydev) if (!phydev->drv || !phydev->drv->config_init) return 0; + ret = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (ret < 0) + return ret; + + ret = phy_poll_reset(phydev); + if (ret < 0) + return ret; + ret = phy_scan_fixups(phydev); if (ret < 0) return ret; return phydev->drv->config_init(phydev); } +EXPORT_SYMBOL(phy_init_hw); /** * phy_attach_direct - attach a network device to a given PHY device pointer @@ -520,26 +564,25 @@ int phy_init_hw(struct phy_device *phydev) * * Description: Called by drivers to attach to a particular PHY * device. The phy_device is found, and properly hooked up - * to the phy_driver. If no driver is attached, then the - * genphy_driver is used. The phy_device is given a ptr to + * to the phy_driver. If no driver is attached, then a + * 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. */ -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface) +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface) { struct device *d = &phydev->dev; int err; /* Assume that if there is no driver, that it doesn't - * exist, and we should use the genphy driver. */ + * exist, and we should use the genphy driver. + */ if (NULL == d->driver) { - if (phydev->is_c45) { - pr_err("No driver for phy %x\n", phydev->phy_id); - return -ENODEV; - } - - d->driver = &genphy_driver.driver; + if (phydev->is_c45) + d->driver = &genphy_driver[GENPHY_DRV_10G].driver; + else + d->driver = &genphy_driver[GENPHY_DRV_1G].driver; err = d->driver->probe(d); if (err >= 0) @@ -565,13 +608,17 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, /* Do initial configuration here, now that * we have certain key parameters - * (dev_flags and interface) */ + * (dev_flags and interface) + */ err = phy_init_hw(phydev); if (err) phy_detach(phydev); + phy_resume(phydev); + return err; } +EXPORT_SYMBOL(phy_attach_direct); /** * phy_attach - attach a network device to a particular PHY device @@ -582,8 +629,8 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, * Description: Same as phy_attach_direct() except that a PHY bus_id * string is passed instead of a pointer to a struct phy_device. */ -struct phy_device *phy_attach(struct net_device *dev, - const char *bus_id, phy_interface_t interface) +struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, + phy_interface_t interface) { struct bus_type *bus = &mdio_bus_type; struct phy_device *phydev; @@ -591,7 +638,8 @@ struct phy_device *phy_attach(struct net_device *dev, int rc; /* Search the list of PHY devices on the mdio bus for the - * PHY with the requested name */ + * PHY with the requested name + */ d = bus_find_device_by_name(bus, NULL, bus_id); if (!d) { pr_err("PHY %s not found\n", bus_id); @@ -613,18 +661,49 @@ EXPORT_SYMBOL(phy_attach); */ void phy_detach(struct phy_device *phydev) { + int i; phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; + phy_suspend(phydev); /* If the device had no specific driver before (i.e. - it * was using the generic driver), we unbind the device * from the generic driver so that there's a chance a - * real driver could be loaded */ - if (phydev->dev.driver == &genphy_driver.driver) - device_release_driver(&phydev->dev); + * real driver could be loaded + */ + for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) { + if (phydev->dev.driver == &genphy_driver[i].driver) { + device_release_driver(&phydev->dev); + break; + } + } } EXPORT_SYMBOL(phy_detach); +int phy_suspend(struct phy_device *phydev) +{ + struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + struct ethtool_wolinfo wol; + + /* If the device has WOL enabled, we cannot suspend the PHY */ + wol.cmd = ETHTOOL_GWOL; + phy_ethtool_get_wol(phydev, &wol); + if (wol.wolopts) + return -EBUSY; + + if (phydrv->suspend) + return phydrv->suspend(phydev); + return 0; +} + +int phy_resume(struct phy_device *phydev) +{ + struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + + if (phydrv->resume) + return phydrv->resume(phydev); + return 0; +} /* Generic PHY support and helper functions */ @@ -643,17 +722,16 @@ static int genphy_config_advert(struct phy_device *phydev) int oldadv, adv; int err, changed = 0; - /* Only allow advertising what - * this PHY supports */ + /* Only allow advertising what this PHY supports */ phydev->advertising &= phydev->supported; advertise = phydev->advertising; /* Setup standard advertisement */ - oldadv = adv = phy_read(phydev, MII_ADVERTISE); - + adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) return adv; + oldadv = adv; adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); adv |= ethtool_adv_to_mii_adv_t(advertise); @@ -668,12 +746,12 @@ static int genphy_config_advert(struct phy_device *phydev) /* Configure gigabit if it's supported */ if (phydev->supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) { - oldadv = adv = phy_read(phydev, MII_CTRL1000); - + SUPPORTED_1000baseT_Full)) { + adv = phy_read(phydev, MII_CTRL1000); if (adv < 0) return adv; + oldadv = adv; adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); adv |= ethtool_adv_to_mii_ctrl1000_t(advertise); @@ -699,10 +777,10 @@ static int genphy_config_advert(struct phy_device *phydev) */ int genphy_setup_forced(struct phy_device *phydev) { - int err; int ctl = 0; - phydev->pause = phydev->asym_pause = 0; + phydev->pause = 0; + phydev->asym_pause = 0; if (SPEED_1000 == phydev->speed) ctl |= BMCR_SPEED1000; @@ -711,10 +789,8 @@ int genphy_setup_forced(struct phy_device *phydev) if (DUPLEX_FULL == phydev->duplex) ctl |= BMCR_FULLDPLX; - - err = phy_write(phydev, MII_BMCR, ctl); - return err; + return phy_write(phydev, MII_BMCR, ctl); } EXPORT_SYMBOL(genphy_setup_forced); @@ -724,25 +800,20 @@ EXPORT_SYMBOL(genphy_setup_forced); */ int genphy_restart_aneg(struct phy_device *phydev) { - int ctl; - - ctl = phy_read(phydev, MII_BMCR); + int ctl = phy_read(phydev, MII_BMCR); if (ctl < 0) return ctl; - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + ctl |= BMCR_ANENABLE | BMCR_ANRESTART; /* Don't isolate the PHY if we're negotiating */ - ctl &= ~(BMCR_ISOLATE); + ctl &= ~BMCR_ISOLATE; - ctl = phy_write(phydev, MII_BMCR, ctl); - - return ctl; + return phy_write(phydev, MII_BMCR, ctl); } EXPORT_SYMBOL(genphy_restart_aneg); - /** * genphy_config_aneg - restart auto-negotiation or write BMCR * @phydev: target phy_device struct @@ -759,13 +830,12 @@ int genphy_config_aneg(struct phy_device *phydev) return genphy_setup_forced(phydev); result = genphy_config_advert(phydev); - if (result < 0) /* error */ return result; - if (result == 0) { /* Advertisement hasn't changed, but maybe aneg was never on to - * begin with? Or maybe phy was isolated? */ + * begin with? Or maybe phy was isolated? + */ int ctl = phy_read(phydev, MII_BMCR); if (ctl < 0) @@ -776,7 +846,8 @@ int genphy_config_aneg(struct phy_device *phydev) } /* Only restart aneg if we are advertising something different - * than we were before. */ + * than we were before. + */ if (result > 0) result = genphy_restart_aneg(phydev); @@ -784,6 +855,11 @@ int genphy_config_aneg(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_aneg); +static int gen10g_config_aneg(struct phy_device *phydev) +{ + return 0; +} + /** * genphy_update_link - update link status in @phydev * @phydev: target phy_device struct @@ -798,13 +874,11 @@ int genphy_update_link(struct phy_device *phydev) /* Do a fake read */ status = phy_read(phydev, MII_BMSR); - if (status < 0) return status; /* Read link and autonegotiation status */ status = phy_read(phydev, MII_BMSR); - if (status < 0) return status; @@ -833,35 +907,36 @@ int genphy_read_status(struct phy_device *phydev) int lpa; int lpagb = 0; - /* Update the link, but return if there - * was an error */ + /* Update the link, but return if there was an error */ err = genphy_update_link(phydev); if (err) return err; + phydev->lp_advertising = 0; + if (AUTONEG_ENABLE == phydev->autoneg) { if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { lpagb = phy_read(phydev, MII_STAT1000); - if (lpagb < 0) return lpagb; adv = phy_read(phydev, MII_CTRL1000); - if (adv < 0) return adv; + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb); lpagb &= adv << 2; } lpa = phy_read(phydev, MII_LPA); - if (lpa < 0) return lpa; - adv = phy_read(phydev, MII_ADVERTISE); + phydev->lp_advertising |= mii_lpa_to_ethtool_lpa_t(lpa); + adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) return adv; @@ -869,7 +944,8 @@ int genphy_read_status(struct phy_device *phydev) phydev->speed = SPEED_10; phydev->duplex = DUPLEX_HALF; - phydev->pause = phydev->asym_pause = 0; + phydev->pause = 0; + phydev->asym_pause = 0; if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { phydev->speed = SPEED_1000; @@ -878,19 +954,20 @@ int genphy_read_status(struct phy_device *phydev) phydev->duplex = DUPLEX_FULL; } else if (lpa & (LPA_100FULL | LPA_100HALF)) { phydev->speed = SPEED_100; - + if (lpa & LPA_100FULL) phydev->duplex = DUPLEX_FULL; } else if (lpa & LPA_10FULL) phydev->duplex = DUPLEX_FULL; - if (phydev->duplex == DUPLEX_FULL){ + if (phydev->duplex == DUPLEX_FULL) { phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; } } else { int bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) return bmcr; @@ -906,27 +983,55 @@ int genphy_read_status(struct phy_device *phydev) else phydev->speed = SPEED_10; - phydev->pause = phydev->asym_pause = 0; + phydev->pause = 0; + phydev->asym_pause = 0; } return 0; } EXPORT_SYMBOL(genphy_read_status); +static int gen10g_read_status(struct phy_device *phydev) +{ + int devad, reg; + u32 mmd_mask = phydev->c45_ids.devices_in_package; + + phydev->link = 1; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { + if (!(mmd_mask & 1)) + continue; + + /* Read twice because link state is latched and a + * read moves the current state into the register + */ + phy_read_mmd(phydev, devad, MDIO_STAT1); + reg = phy_read_mmd(phydev, devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} + static int genphy_config_init(struct phy_device *phydev) { int val; u32 features; /* For now, I'll claim that the generic driver supports - * all possible port types */ + * all possible port types + */ features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_BNC); /* Do we support autonegotiation? */ val = phy_read(phydev, MII_BMSR); - if (val < 0) return val; @@ -944,7 +1049,6 @@ static int genphy_config_init(struct phy_device *phydev) if (val & BMSR_ESTATEN) { val = phy_read(phydev, MII_ESTATUS); - if (val < 0) return val; @@ -959,6 +1063,16 @@ static int genphy_config_init(struct phy_device *phydev) return 0; } + +static int gen10g_config_init(struct phy_device *phydev) +{ + /* Temporarily just say we support everything */ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + int genphy_suspend(struct phy_device *phydev) { int value; @@ -966,7 +1080,7 @@ int genphy_suspend(struct phy_device *phydev) mutex_lock(&phydev->lock); value = phy_read(phydev, MII_BMCR); - phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN)); + phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); mutex_unlock(&phydev->lock); @@ -974,6 +1088,11 @@ int genphy_suspend(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_suspend); +static int gen10g_suspend(struct phy_device *phydev) +{ + return 0; +} + int genphy_resume(struct phy_device *phydev) { int value; @@ -981,7 +1100,7 @@ int genphy_resume(struct phy_device *phydev) mutex_lock(&phydev->lock); value = phy_read(phydev, MII_BMCR); - phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN)); + phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); mutex_unlock(&phydev->lock); @@ -989,6 +1108,11 @@ int genphy_resume(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_resume); +static int gen10g_resume(struct phy_device *phydev) +{ + return 0; +} + /** * phy_probe - probe and init a PHY device * @dev: device to probe and init @@ -999,22 +1123,18 @@ EXPORT_SYMBOL(genphy_resume); */ static int phy_probe(struct device *dev) { - struct phy_device *phydev; - struct phy_driver *phydrv; - struct device_driver *drv; + struct phy_device *phydev = to_phy_device(dev); + struct device_driver *drv = phydev->dev.driver; + struct phy_driver *phydrv = to_phy_driver(drv); int err = 0; - phydev = to_phy_device(dev); - - drv = phydev->dev.driver; - phydrv = to_phy_driver(drv); phydev->drv = phydrv; /* Disable the interrupt if the PHY doesn't support it * but the interrupt is still a valid one */ if (!(phydrv->flags & PHY_HAS_INTERRUPT) && - phy_interrupt_is_valid(phydev)) + phy_interrupt_is_valid(phydev)) phydev->irq = PHY_POLL; if (phydrv->flags & PHY_IS_INTERNAL) @@ -1024,7 +1144,8 @@ static int phy_probe(struct device *dev) /* Start out supporting everything. Eventually, * a controller will attach, and may modify one - * or both of these values */ + * or both of these values + */ phydev->supported = phydrv->features; phydev->advertising = phydrv->features; @@ -1037,14 +1158,11 @@ static int phy_probe(struct device *dev) mutex_unlock(&phydev->lock); return err; - } static int phy_remove(struct device *dev) { - struct phy_device *phydev; - - phydev = to_phy_device(dev); + struct phy_device *phydev = to_phy_device(dev); mutex_lock(&phydev->lock); phydev->state = PHY_DOWN; @@ -1071,7 +1189,6 @@ int phy_driver_register(struct phy_driver *new_driver) new_driver->driver.remove = phy_remove; retval = driver_register(&new_driver->driver); - if (retval) { pr_err("%s: Error %d in registering driver\n", new_driver->name, retval); @@ -1110,13 +1227,14 @@ EXPORT_SYMBOL(phy_driver_unregister); void phy_drivers_unregister(struct phy_driver *drv, int n) { int i; - for (i = 0; i < n; i++) { + + for (i = 0; i < n; i++) phy_driver_unregister(drv + i); - } } EXPORT_SYMBOL(phy_drivers_unregister); -static struct phy_driver genphy_driver = { +static struct phy_driver genphy_driver[] = { +{ .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, .name = "Generic PHY", @@ -1126,8 +1244,19 @@ static struct phy_driver genphy_driver = { .read_status = genphy_read_status, .suspend = genphy_suspend, .resume = genphy_resume, - .driver = {.owner= THIS_MODULE, }, -}; + .driver = { .owner = THIS_MODULE, }, +}, { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, + .read_status = gen10g_read_status, + .suspend = gen10g_suspend, + .resume = gen10g_resume, + .driver = {.owner = THIS_MODULE, }, +} }; static int __init phy_init(void) { @@ -1137,7 +1266,8 @@ static int __init phy_init(void) if (rc) return rc; - rc = phy_driver_register(&genphy_driver); + rc = phy_drivers_register(genphy_driver, + ARRAY_SIZE(genphy_driver)); if (rc) mdio_bus_exit(); @@ -1146,7 +1276,8 @@ static int __init phy_init(void) static void __exit phy_exit(void) { - phy_driver_unregister(&genphy_driver); + phy_drivers_unregister(genphy_driver, + ARRAY_SIZE(genphy_driver)); mdio_bus_exit(); } diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index f3bea134602..4cf5fb922e5 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -15,7 +15,6 @@ #include <linux/types.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/device.h> @@ -171,14 +170,14 @@ static int ks8995_write(struct ks8995_switch *ks, char *buf, static inline int ks8995_read_reg(struct ks8995_switch *ks, u8 addr, u8 *buf) { - return (ks8995_read(ks, buf, addr, 1) != 1); + return ks8995_read(ks, buf, addr, 1) != 1; } static inline int ks8995_write_reg(struct ks8995_switch *ks, u8 addr, u8 val) { char buf = val; - return (ks8995_write(ks, &buf, addr, 1) != 1); + return ks8995_write(ks, &buf, addr, 1) != 1; } /* ------------------------------------------------------------------------ */ @@ -325,7 +324,6 @@ static int ks8995_probe(struct spi_device *spi) return 0; err_drvdata: - spi_set_drvdata(spi, NULL); kfree(ks); return err; } @@ -337,7 +335,6 @@ static int ks8995_remove(struct spi_device *spi) ks8995 = spi_get_drvdata(spi); sysfs_remove_bin_file(&spi->dev.kobj, &ks8995_registers_attr); - spi_set_drvdata(spi, NULL); kfree(ks8995); return 0; diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 508e4359338..14372c65a7e 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -64,6 +64,7 @@ #define PHY_ID_VSC8234 0x000fc620 #define PHY_ID_VSC8244 0x000fc6c0 +#define PHY_ID_VSC8514 0x00070670 #define PHY_ID_VSC8574 0x000704a0 #define PHY_ID_VSC8662 0x00070660 #define PHY_ID_VSC8221 0x000fc550 @@ -131,6 +132,7 @@ static int vsc82xx_config_intr(struct phy_device *phydev) err = phy_write(phydev, MII_VSC8244_IMASK, (phydev->drv->phy_id == PHY_ID_VSC8234 || phydev->drv->phy_id == PHY_ID_VSC8244 || + phydev->drv->phy_id == PHY_ID_VSC8514 || phydev->drv->phy_id == PHY_ID_VSC8574) ? MII_VSC8244_IMASK_MASK : MII_VSC8221_IMASK_MASK); @@ -246,6 +248,18 @@ static struct phy_driver vsc82xx_driver[] = { .config_intr = &vsc82xx_config_intr, .driver = { .owner = THIS_MODULE,}, }, { + .phy_id = PHY_ID_VSC8514, + .name = "Vitesse VSC8514", + .phy_id_mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &vsc824x_config_init, + .config_aneg = &vsc82x4_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &vsc824x_ack_interrupt, + .config_intr = &vsc82xx_config_intr, + .driver = { .owner = THIS_MODULE,}, +}, { .phy_id = PHY_ID_VSC8574, .name = "Vitesse VSC8574", .phy_id_mask = 0x000ffff0, @@ -315,6 +329,7 @@ module_exit(vsc82xx_exit); static struct mdio_device_id __maybe_unused vitesse_tbl[] = { { PHY_ID_VSC8234, 0x000ffff0 }, { PHY_ID_VSC8244, 0x000fffc0 }, + { PHY_ID_VSC8514, 0x000ffff0 }, { PHY_ID_VSC8574, 0x000ffff0 }, { PHY_ID_VSC8662, 0x000ffff0 }, { PHY_ID_VSC8221, 0x000ffff0 }, |