diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/dp83867.c | 13 | ||||
-rw-r--r-- | drivers/net/phy/fixed_phy.c | 30 | ||||
-rw-r--r-- | drivers/net/phy/lxt.c | 22 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 82 | ||||
-rw-r--r-- | drivers/net/phy/mdio-mux.c | 10 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 10 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 34 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 105 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 5 | ||||
-rw-r--r-- | drivers/net/phy/smsc.c | 17 |
10 files changed, 236 insertions, 92 deletions
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 2afa61b51..91177a4a3 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -57,6 +57,7 @@ /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_PHYCR_FIFO_DEPTH_MASK (3 << 14) /* RGMIIDCTL bits */ #define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 @@ -133,8 +134,8 @@ static int dp83867_of_init(struct phy_device *phydev) static int dp83867_config_init(struct phy_device *phydev) { struct dp83867_private *dp83867; - int ret; - u16 val, delay; + int ret, val; + u16 delay; if (!phydev->priv) { dp83867 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83867), @@ -151,8 +152,12 @@ static int dp83867_config_init(struct phy_device *phydev) } if (phy_interface_is_rgmii(phydev)) { - ret = phy_write(phydev, MII_DP83867_PHYCTRL, - (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); + val = phy_read(phydev, MII_DP83867_PHYCTRL); + if (val < 0) + return val; + val &= ~DP83867_PHYCR_FIFO_DEPTH_MASK; + val |= (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT); + ret = phy_write(phydev, MII_DP83867_PHYCTRL, val); if (ret) return ret; } diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index fc07a8866..9ec7f7353 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/gpio.h> +#include <linux/idr.h> #define MII_REGS_NUM 29 @@ -255,7 +256,8 @@ int fixed_phy_add(unsigned int irq, int phy_addr, memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM); - fmb->mii_bus->irq[phy_addr] = irq; + if (irq != PHY_POLL) + fmb->mii_bus->irq[phy_addr] = irq; fp->addr = phy_addr; fp->status = *status; @@ -285,6 +287,8 @@ err_regs: } EXPORT_SYMBOL_GPL(fixed_phy_add); +static DEFINE_IDA(phy_fixed_ida); + static void fixed_phy_del(int phy_addr) { struct fixed_mdio_bus *fmb = &platform_fmb; @@ -296,14 +300,12 @@ static void fixed_phy_del(int phy_addr) if (gpio_is_valid(fp->link_gpio)) gpio_free(fp->link_gpio); kfree(fp); + ida_simple_remove(&phy_fixed_ida, phy_addr); return; } } } -static int phy_fixed_addr; -static DEFINE_SPINLOCK(phy_fixed_addr_lock); - struct phy_device *fixed_phy_register(unsigned int irq, struct fixed_phy_status *status, int link_gpio, @@ -314,21 +316,22 @@ struct phy_device *fixed_phy_register(unsigned int irq, int phy_addr; int ret; + if (!fmb->mii_bus || fmb->mii_bus->state != MDIOBUS_REGISTERED) + return ERR_PTR(-EPROBE_DEFER); + /* Get the next available PHY address, up to PHY_MAX_ADDR */ - spin_lock(&phy_fixed_addr_lock); - if (phy_fixed_addr == PHY_MAX_ADDR) { - spin_unlock(&phy_fixed_addr_lock); - return ERR_PTR(-ENOSPC); - } - phy_addr = phy_fixed_addr++; - spin_unlock(&phy_fixed_addr_lock); + phy_addr = ida_simple_get(&phy_fixed_ida, 0, PHY_MAX_ADDR, GFP_KERNEL); + if (phy_addr < 0) + return ERR_PTR(phy_addr); ret = fixed_phy_add(irq, phy_addr, status, link_gpio); - if (ret < 0) + if (ret < 0) { + ida_simple_remove(&phy_fixed_ida, phy_addr); return ERR_PTR(ret); + } phy = get_phy_device(fmb->mii_bus, phy_addr, false); - if (!phy || IS_ERR(phy)) { + if (IS_ERR(phy)) { fixed_phy_del(phy_addr); return ERR_PTR(-EINVAL); } @@ -430,6 +433,7 @@ static void __exit fixed_mdio_bus_exit(void) list_del(&fp->node); kfree(fp); } + ida_destroy(&phy_fixed_ida); } module_exit(fixed_mdio_bus_exit); diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index f6078376e..b9fde1bcf 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -80,23 +80,15 @@ static int lxt970_ack_interrupt(struct phy_device *phydev) static int lxt970_config_intr(struct phy_device *phydev) { - int err; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN); + return phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN); else - err = phy_write(phydev, MII_LXT970_IER, 0); - - return err; + return phy_write(phydev, MII_LXT970_IER, 0); } static int lxt970_config_init(struct phy_device *phydev) { - int err; - - err = phy_write(phydev, MII_LXT970_CONFIG, 0); - - return err; + return phy_write(phydev, MII_LXT970_CONFIG, 0); } @@ -112,14 +104,10 @@ static int lxt971_ack_interrupt(struct phy_device *phydev) static int lxt971_config_intr(struct phy_device *phydev) { - int err; - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) - err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN); + return phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN); else - err = phy_write(phydev, MII_LXT971_IER, 0); - - return err; + return phy_write(phydev, MII_LXT971_IER, 0); } /* diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 280e8795b..ec2c1eee6 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -285,6 +285,48 @@ static int marvell_config_aneg(struct phy_device *phydev) return 0; } +static int m88e1111_config_aneg(struct phy_device *phydev) +{ + int err; + + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation + */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + + err = marvell_set_polarity(phydev, phydev->mdix); + if (err < 0) + return err; + + err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL, + MII_M1111_PHY_LED_DIRECT); + if (err < 0) + return err; + + err = genphy_config_aneg(phydev); + if (err < 0) + return err; + + if (phydev->autoneg != AUTONEG_ENABLE) { + int bmcr; + + /* A write to speed/duplex bits (that is performed by + * genphy_config_aneg() call above) must be followed by + * a software reset. Otherwise, the write has no effect. + */ + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET); + if (err < 0) + return err; + } + + return 0; +} + #ifdef CONFIG_OF_MDIO /* * Set and/or override some configuration registers based on the @@ -407,15 +449,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) if (err < 0) return err; - oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); - - phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); - phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF); - phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); - - err = genphy_config_aneg(phydev); - - return err; + return genphy_config_aneg(phydev); } static int m88e1318_config_aneg(struct phy_device *phydev) @@ -636,6 +670,28 @@ static int m88e1111_config_init(struct phy_device *phydev) return phy_write(phydev, MII_BMCR, BMCR_RESET); } +static int m88e1121_config_init(struct phy_device *phydev) +{ + int err, oldpage; + + oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE); + + err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); + if (err < 0) + return err; + + /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ + err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, + MII_88E1121_PHY_LED_DEF); + if (err < 0) + return err; + + phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage); + + /* Set marvell,reg-init configuration from device tree */ + return marvell_config_init(phydev); +} + static int m88e1510_config_init(struct phy_device *phydev) { int err; @@ -668,7 +724,7 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; } - return marvell_config_init(phydev); + return m88e1121_config_init(phydev); } static int m88e1118_config_aneg(struct phy_device *phydev) @@ -1161,7 +1217,7 @@ static struct phy_driver marvell_drivers[] = { .flags = PHY_HAS_INTERRUPT, .probe = marvell_probe, .config_init = &m88e1111_config_init, - .config_aneg = &marvell_config_aneg, + .config_aneg = &m88e1111_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, @@ -1196,7 +1252,7 @@ static struct phy_driver marvell_drivers[] = { .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, .probe = marvell_probe, - .config_init = &marvell_config_init, + .config_init = &m88e1121_config_init, .config_aneg = &m88e1121_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, @@ -1215,7 +1271,7 @@ static struct phy_driver marvell_drivers[] = { .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, .probe = marvell_probe, - .config_init = &marvell_config_init, + .config_init = &m88e1121_config_init, .config_aneg = &m88e1318_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 308ade0eb..5c81d6faf 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -45,13 +45,7 @@ static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum) struct mdio_mux_parent_bus *pb = cb->parent; int r; - /* In theory multiple mdio_mux could be stacked, thus creating - * more than a single level of nesting. But in practice, - * SINGLE_DEPTH_NESTING will cover the vast majority of use - * cases. We use it, instead of trying to handle the general - * case. - */ - mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING); + mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX); r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); if (r) goto out; @@ -76,7 +70,7 @@ static int mdio_mux_write(struct mii_bus *bus, int phy_id, int r; - mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING); + mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX); r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data); if (r) goto out; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 0cba64f1e..09deef4be 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -333,7 +333,7 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) struct phy_device *phydev; phydev = mdiobus_scan(bus, i); - if (IS_ERR(phydev)) { + if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) { err = PTR_ERR(phydev); goto error; } @@ -419,7 +419,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) int err; phydev = get_phy_device(bus, addr, false); - if (IS_ERR(phydev) || phydev == NULL) + if (IS_ERR(phydev)) return phydev; /* @@ -431,7 +431,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) err = phy_device_register(phydev); if (err) { phy_device_free(phydev); - return NULL; + return ERR_PTR(-ENODEV); } return phydev; @@ -457,7 +457,7 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum) BUG_ON(in_interrupt()); - mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING); + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); retval = bus->read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); @@ -509,7 +509,7 @@ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val) BUG_ON(in_interrupt()); - mutex_lock_nested(&bus->mdio_lock, SINGLE_DEPTH_NESTING); + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); err = bus->write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 4516c8a4f..5a8fefc25 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -726,7 +726,7 @@ static int kszphy_probe(struct phy_device *phydev) static struct phy_driver ksphy_driver[] = { { .phy_id = PHY_ID_KS8737, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KS8737", .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, @@ -781,7 +781,7 @@ static struct phy_driver ksphy_driver[] = { .resume = genphy_resume, }, { .phy_id = PHY_ID_KSZ8041, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8041", .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), @@ -800,7 +800,7 @@ static struct phy_driver ksphy_driver[] = { .resume = genphy_resume, }, { .phy_id = PHY_ID_KSZ8041RNLI, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8041RNLI", .features = PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause, @@ -819,7 +819,7 @@ static struct phy_driver ksphy_driver[] = { .resume = genphy_resume, }, { .phy_id = PHY_ID_KSZ8051, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8051", .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), @@ -857,7 +857,7 @@ static struct phy_driver ksphy_driver[] = { }, { .phy_id = PHY_ID_KSZ8081, .name = "Micrel KSZ8081 or KSZ8091", - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz8081_type, @@ -875,7 +875,7 @@ static struct phy_driver ksphy_driver[] = { }, { .phy_id = PHY_ID_KSZ8061, .name = "Micrel KSZ8061", - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, @@ -909,7 +909,7 @@ static struct phy_driver ksphy_driver[] = { .write_mmd_indirect = ksz9021_wr_mmd_phyreg, }, { .phy_id = PHY_ID_KSZ9031, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ9031 Gigabit PHY", .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, @@ -926,7 +926,7 @@ static struct phy_driver ksphy_driver[] = { .resume = genphy_resume, }, { .phy_id = PHY_ID_KSZ8873MLL, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8873MLL Switch", .features = (SUPPORTED_Pause | SUPPORTED_Asym_Pause), .flags = PHY_HAS_MAGICANEG, @@ -940,7 +940,7 @@ static struct phy_driver ksphy_driver[] = { .resume = genphy_resume, }, { .phy_id = PHY_ID_KSZ886X, - .phy_id_mask = 0x00fffff0, + .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ886X Switch", .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, @@ -962,17 +962,17 @@ MODULE_LICENSE("GPL"); static struct mdio_device_id __maybe_unused micrel_tbl[] = { { PHY_ID_KSZ9021, 0x000ffffe }, - { PHY_ID_KSZ9031, 0x00fffff0 }, + { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ8001, 0x00ffffff }, - { PHY_ID_KS8737, 0x00fffff0 }, + { PHY_ID_KS8737, MICREL_PHY_ID_MASK }, { PHY_ID_KSZ8021, 0x00ffffff }, { PHY_ID_KSZ8031, 0x00ffffff }, - { PHY_ID_KSZ8041, 0x00fffff0 }, - { PHY_ID_KSZ8051, 0x00fffff0 }, - { PHY_ID_KSZ8061, 0x00fffff0 }, - { PHY_ID_KSZ8081, 0x00fffff0 }, - { PHY_ID_KSZ8873MLL, 0x00fffff0 }, - { PHY_ID_KSZ886X, 0x00fffff0 }, + { PHY_ID_KSZ8041, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ8051, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ8061, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ8081, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ8873MLL, MICREL_PHY_ID_MASK }, + { PHY_ID_KSZ886X, MICREL_PHY_ID_MASK }, { } }; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 445fc5aef..c5dc2c363 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -362,6 +362,60 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) } EXPORT_SYMBOL(phy_ethtool_sset); +int phy_ethtool_ksettings_set(struct phy_device *phydev, + const struct ethtool_link_ksettings *cmd) +{ + u8 autoneg = cmd->base.autoneg; + u8 duplex = cmd->base.duplex; + u32 speed = cmd->base.speed; + u32 advertising; + + if (cmd->base.phy_address != phydev->mdio.addr) + return -EINVAL; + + ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising); + + /* We make sure that we don't pass unsupported values in to the PHY */ + advertising &= phydev->supported; + + /* Verify the settings we care about. */ + if (autoneg != AUTONEG_ENABLE && autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (autoneg == AUTONEG_ENABLE && advertising == 0) + return -EINVAL; + + if (autoneg == AUTONEG_DISABLE && + ((speed != SPEED_1000 && + speed != SPEED_100 && + speed != SPEED_10) || + (duplex != DUPLEX_HALF && + duplex != DUPLEX_FULL))) + return -EINVAL; + + phydev->autoneg = autoneg; + + phydev->speed = speed; + + phydev->advertising = advertising; + + if (autoneg == AUTONEG_ENABLE) + phydev->advertising |= ADVERTISED_Autoneg; + else + phydev->advertising &= ~ADVERTISED_Autoneg; + + phydev->duplex = duplex; + + phydev->mdix = cmd->base.eth_tp_mdix_ctrl; + + /* Restart the PHY */ + phy_start_aneg(phydev); + + return 0; +} +EXPORT_SYMBOL(phy_ethtool_ksettings_set); + int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) { cmd->supported = phydev->supported; @@ -385,6 +439,33 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) } EXPORT_SYMBOL(phy_ethtool_gset); +int phy_ethtool_ksettings_get(struct phy_device *phydev, + struct ethtool_link_ksettings *cmd) +{ + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + phydev->supported); + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + phydev->advertising); + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, + phydev->lp_advertising); + + cmd->base.speed = phydev->speed; + cmd->base.duplex = phydev->duplex; + if (phydev->interface == PHY_INTERFACE_MODE_MOCA) + cmd->base.port = PORT_BNC; + else + cmd->base.port = PORT_MII; + + cmd->base.phy_address = phydev->mdio.addr; + cmd->base.autoneg = phydev->autoneg; + cmd->base.eth_tp_mdix_ctrl = phydev->mdix; + + return 0; +} +EXPORT_SYMBOL(phy_ethtool_ksettings_get); + /** * phy_mii_ioctl - generic PHY MII ioctl interface * @phydev: the phy_device struct @@ -1268,3 +1349,27 @@ void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) phydev->drv->get_wol(phydev, wol); } EXPORT_SYMBOL(phy_ethtool_get_wol); + +int phy_ethtool_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *cmd) +{ + struct phy_device *phydev = ndev->phydev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_ksettings_get(phydev, cmd); +} +EXPORT_SYMBOL(phy_ethtool_get_link_ksettings); + +int phy_ethtool_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd) +{ + struct phy_device *phydev = ndev->phydev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_ksettings_set(phydev, cmd); +} +EXPORT_SYMBOL(phy_ethtool_set_link_ksettings); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index e551f3a89..e977ba931 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -529,7 +529,7 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) /* If the phy_id is mostly Fs, there is no device there */ if ((phy_id & 0x1fffffff) == 0x1fffffff) - return NULL; + return ERR_PTR(-ENODEV); return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids); } @@ -1123,8 +1123,9 @@ static int genphy_config_advert(struct phy_device *phydev) */ int genphy_setup_forced(struct phy_device *phydev) { - int ctl = 0; + int ctl = phy_read(phydev, MII_BMCR); + ctl &= BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN; phydev->pause = 0; phydev->asym_pause = 0; diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 2e21e9366..b62c4aaee 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -75,22 +75,13 @@ static int smsc_phy_reset(struct phy_device *phydev) * in all capable mode before using it. */ if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) { - int timeout = 50000; - - /* set "all capable" mode and reset the phy */ + /* set "all capable" mode */ rc |= MII_LAN83C185_MODE_ALL; phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc); - phy_write(phydev, MII_BMCR, BMCR_RESET); - - /* wait end of reset (max 500 ms) */ - do { - udelay(10); - if (timeout-- == 0) - return -1; - rc = phy_read(phydev, MII_BMCR); - } while (rc & BMCR_RESET); } - return 0; + + /* reset the phy */ + return genphy_soft_reset(phydev); } static int lan911x_config_init(struct phy_device *phydev) |