From 114002bc1af6c63de4c003f8c5d3ca0bb430d987 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:30 -0800 Subject: [PATCH 1/9] net: phy: report link partner features through ethtool The PHY library already reads the MII_STAT1000 and MII_LPA registers in genphy_read_status(), so extend it to also populate the PHY device link partner advertised features such that we can feed this back into ethtool when asked for it in phy_ethtool_gset(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 1 + drivers/net/phy/phy_device.c | 6 ++++++ include/linux/phy.h | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 36c6994436b7c..05cb8fe742f91 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -289,6 +289,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; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index d6447b3f7409d..6db36595eac9b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -839,6 +839,8 @@ int genphy_read_status(struct phy_device *phydev) if (err) return err; + phydev->lp_advertising = 0; + if (AUTONEG_ENABLE == phydev->autoneg) { if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { @@ -852,6 +854,8 @@ int genphy_read_status(struct phy_device *phydev) if (adv < 0) return adv; + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb); lpagb &= adv << 2; } @@ -860,6 +864,8 @@ int genphy_read_status(struct phy_device *phydev) if (lpa < 0) return lpa; + phydev->lp_advertising |= mii_lpa_to_ethtool_lpa_t(lpa); + adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) diff --git a/include/linux/phy.h b/include/linux/phy.h index 7ff751ae6f0ab..90a666e0884b9 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -287,8 +287,8 @@ struct phy_c45_device_ids { * adjust_state: Callback for the enet driver to respond to * changes in the state machine. * - * speed, duplex, pause, supported, advertising, and - * autoneg are used like in mii_if_info + * speed, duplex, pause, supported, advertising, lp_advertising, + * and autoneg are used like in mii_if_info * * interrupts currently only supports enabled or disabled, * but could be changed in the future to support enabling @@ -340,6 +340,7 @@ struct phy_device { /* See mii.h for more info */ u32 supported; u32 advertising; + u32 lp_advertising; int autoneg; From 2613f95f614b39681f77a5036046ea395e306e28 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:31 -0800 Subject: [PATCH 2/9] net: phy: use phy_init_hw instead of open-coding it Use phy_init_hw() instead of open-coding it in phy_mii_ioctl(), this improves consistenty and makes sure that we will not duplicate the same routine somewhere else. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 05cb8fe742f91..5d7101b3b604e 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -361,11 +361,8 @@ 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); - } + val & BMCR_RESET) + phy_init_hw(phydev); break; case SIOCSHWTSTAMP: From f0528ce7a43d51090b45cf27c53e4b343facaade Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:32 -0800 Subject: [PATCH 3/9] net: greth: use phy_read_status() In case the greth driver is bound to anything but the Generic PHY driver or the PHY has a special read_status callback implemented, unexpected things will happen. Make sure we that we use phy_read_status() which does the proper abstraction of calling the driver specific read_status() callback for a given PHY. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/aeroflex/greth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index e066945551445..b20cbf0323e0f 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1361,7 +1361,7 @@ static int greth_mdio_init(struct greth_private *greth) timeout = jiffies + 6*HZ; while (!phy_aneg_done(greth->phy) && time_before(jiffies, timeout)) { } - genphy_read_status(greth->phy); + phy_read_status(greth->phy); greth_link_change(greth->netdev); } From 06d87cec73d883690f690e72da498e7f0334f9bc Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:33 -0800 Subject: [PATCH 4/9] net: bfin_mac: do not reset PHY after phy_start() The PHY is already reset during driver probing, and this manual reset after calling phy_start() will wipe out board-specific PHY fixups and driver specific configuration initialization. Remove that explicit PHY reset. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/adi/bfin_mac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c index 0d4f295798798..c0f68dcd1dc12 100644 --- a/drivers/net/ethernet/adi/bfin_mac.c +++ b/drivers/net/ethernet/adi/bfin_mac.c @@ -1557,7 +1557,6 @@ static int bfin_mac_open(struct net_device *dev) return ret; phy_start(lp->phydev); - phy_write(lp->phydev, MII_BMCR, BMCR_RESET); setup_system_regs(dev); setup_mac_addr(dev->dev_addr); From 87aa9f9c61ad56d505641681812e92ad976f8608 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:34 -0800 Subject: [PATCH 5/9] net: phy: consolidate PHY reset in phy_init_hw() There are quite a lot of drivers touching a PHY device MII_BMCR register to reset the PHY without taking care of: 1) ensuring that BMCR_RESET is cleared after a given timeout 2) the PHY state machine resuming to the proper state and re-applying potentially changed settings such as auto-negotiation Introduce phy_poll_reset() which will take care of polling the MII_BMCR for the BMCR_RESET bit to be cleared after a given timeout or return a timeout error code. In order to make sure the PHY is in a correct state, phy_init_hw() first issues a software reset through MII_BMCR and then applies any fixups. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/networking/phy.txt | 3 +- drivers/net/phy/phy.c | 5 +-- drivers/net/phy/phy_device.c | 56 +++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index d5b1a39352453..ebf2707194029 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt @@ -255,7 +255,8 @@ Writing a PHY driver config_init: configures PHY into a sane state after a reset. For instance, a Davicom PHY requires descrambling disabled. - probe: Does any setup needed by the driver + probe: Allocate phy->priv, optionally refuse to bind. + PHY may not have been reset or had fixups run yet. suspend/resume: power management config_aneg: Changes the speed/duplex/negotiation settings read_status: Reads the current speed/duplex/negotiation settings diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5d7101b3b604e..e3dd69100da88 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -318,6 +318,7 @@ int phy_mii_ioctl(struct phy_device *phydev, { struct mii_ioctl_data *mii_data = if_mii(ifr); u16 val = mii_data->val_in; + int ret = 0; switch (cmd) { case SIOCGMIIPHY: @@ -362,7 +363,7 @@ int phy_mii_ioctl(struct phy_device *phydev, if (mii_data->reg_num == MII_BMCR && val & BMCR_RESET) - phy_init_hw(phydev); + ret = phy_init_hw(phydev); break; case SIOCSHWTSTAMP: @@ -374,7 +375,7 @@ int phy_mii_ioctl(struct phy_device *phydev, return -EOPNOTSUPP; } - return 0; + return ret; } EXPORT_SYMBOL(phy_mii_ioctl); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6db36595eac9b..5a619f0dcf73c 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -364,7 +364,11 @@ int phy_device_register(struct phy_device *phydev) 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) { @@ -497,6 +501,47 @@ void phy_disconnect(struct phy_device *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 +549,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 From 7cd1463664c2a15721ff4ccfb61d4d970815cb3d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:35 -0800 Subject: [PATCH 6/9] net: mv643xx_eth: use phy_init_hw to reset PHY Instead of open-coding a PHY reset through the MII BMCR register, use phy_init_hw() which does that for us and will also make sure that PHY fixups are applied if required. We also remove a call to phy_reset() due to the following sequence of calls in the driver: phy_scan() -> phy_connect() -> phy_connect_direct() -> phy_attach_direct() -> phy_init_hw() and we only have a call to phy_init() after phy_scan(). Signed-off-by: Florian Fainelli Tested-by: Sebastian Hesselbarth Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mv643xx_eth.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index fa905052fbf4c..b3d9327f78b91 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2066,23 +2066,6 @@ static inline void oom_timer_wrapper(unsigned long data) napi_schedule(&mp->napi); } -static void phy_reset(struct mv643xx_eth_private *mp) -{ - int data; - - data = phy_read(mp->phy, MII_BMCR); - if (data < 0) - return; - - data |= BMCR_RESET; - if (phy_write(mp->phy, MII_BMCR, data) < 0) - return; - - do { - data = phy_read(mp->phy, MII_BMCR); - } while (data >= 0 && data & BMCR_RESET); -} - static void port_start(struct mv643xx_eth_private *mp) { u32 pscr; @@ -2095,7 +2078,7 @@ static void port_start(struct mv643xx_eth_private *mp) struct ethtool_cmd cmd; mv643xx_eth_get_settings(mp->dev, &cmd); - phy_reset(mp); + phy_init_hw(mp->phy); mv643xx_eth_set_settings(mp->dev, &cmd); } @@ -2763,8 +2746,6 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex) { struct phy_device *phy = mp->phy; - phy_reset(mp); - if (speed == 0) { phy->autoneg = AUTONEG_ENABLE; phy->speed = 0; From 78de53f05c58784e366b9115575058a5815c89d6 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:36 -0800 Subject: [PATCH 7/9] net: pxa168_eth: use phy_init_hw for PHY reset Instead of open-coding a PHY reset through the MII BMCR register, use phy_init_hw() which does this for us and ensures that PHY device fixups are also applied. We also remove a call to ethernet_phy_reset() which is now unncessary since phy_attach() calls phy_attach_direct() which in turns calls phy_init_hw(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/pxa168_eth.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 2ad32417a52cd..452e81de33dec 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -320,23 +320,6 @@ static void ethernet_phy_set_addr(struct pxa168_eth_private *pep, int phy_addr) wrl(pep, PHY_ADDRESS, reg_data); } -static void ethernet_phy_reset(struct pxa168_eth_private *pep) -{ - int data; - - data = phy_read(pep->phy, MII_BMCR); - if (data < 0) - return; - - data |= BMCR_RESET; - if (phy_write(pep->phy, MII_BMCR, data) < 0) - return; - - do { - data = phy_read(pep->phy, MII_BMCR); - } while (data >= 0 && data & BMCR_RESET); -} - static void rxq_refill(struct net_device *dev) { struct pxa168_eth_private *pep = netdev_priv(dev); @@ -645,7 +628,7 @@ static void eth_port_start(struct net_device *dev) struct ethtool_cmd cmd; pxa168_get_settings(pep->dev, &cmd); - ethernet_phy_reset(pep); + phy_init_hw(pep->phy); pxa168_set_settings(pep->dev, &cmd); } @@ -1382,7 +1365,6 @@ static struct phy_device *phy_scan(struct pxa168_eth_private *pep, int phy_addr) static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex) { struct phy_device *phy = pep->phy; - ethernet_phy_reset(pep); phy_attach(pep->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_MII); From 01b0114e068480226bc22fea18c3bccbd815ce8b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:37 -0800 Subject: [PATCH 8/9] net: tc35815: use phy_init_hw for PHY reset Instead of open-coding the PHY reset through MII BMCR, use phy_init_hw() which does that for us and also makes sure that any PHY specific fixups are applied. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/toshiba/tc35815.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c index 1322546d92ac9..f6b3212ec339e 100644 --- a/drivers/net/ethernet/toshiba/tc35815.c +++ b/drivers/net/ethernet/toshiba/tc35815.c @@ -1170,19 +1170,12 @@ static int tc35815_tx_full(struct net_device *dev) static void tc35815_restart(struct net_device *dev) { struct tc35815_local *lp = netdev_priv(dev); + int ret; if (lp->phy_dev) { - int timeout; - - phy_write(lp->phy_dev, MII_BMCR, BMCR_RESET); - timeout = 100; - while (--timeout) { - if (!(phy_read(lp->phy_dev, MII_BMCR) & BMCR_RESET)) - break; - udelay(1); - } - if (!timeout) - printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); + ret = phy_init_hw(lp->phy_dev); + if (ret) + printk(KERN_ERR "%s: PHY init failed.\n", dev->name); } spin_lock_bh(&lp->rx_lock); From 0c9eb5b931c3da3a79faa889b903dc7bd318203c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:38 -0800 Subject: [PATCH 9/9] net: sh_eth: do not issue a wild PHY reset through BMCR The sh_eth driver issues an uncontrolled PHY reset through the MII register BMCR but fails to wait for the reset to complete, and will also implicitely wipe out all possible PHY fixups applied. Use phy_init_hw() which remedies both problems. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index d256ce19d4de1..6761dde7007a0 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1704,7 +1704,10 @@ static int sh_eth_phy_start(struct net_device *ndev) return ret; /* reset phy - this also wakes it from PDOWN */ - phy_write(mdp->phydev, MII_BMCR, BMCR_RESET); + ret = phy_init_hw(mdp->phydev); + if (ret) + return ret; + phy_start(mdp->phydev); return 0;