Merge branch 'phy_reset'

Florian Fainelli says:

====================
net: phy: consolidate PHY reset

This patchset consolidates the PHY reset through the MII BMCR
register by using a central place were this is done.

This patchset resumes the work Kyle Moffett started here:
https://lkml.org/lkml/2011/10/20/301

Note that at this point, drivers doing funky things after issuing
a PHY reset using phy_init_hw() will still suffer from PHY state
machine problems, this will be taken care of later on.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2013-12-09 20:39:05 -05:00
commit 65be6291c8
10 changed files with 82 additions and 63 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
@ -317,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:
@ -360,11 +362,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)
ret = phy_init_hw(phydev);
break;
case SIOCSHWTSTAMP:
@ -376,7 +375,7 @@ int phy_mii_ioctl(struct phy_device *phydev,
return -EOPNOTSUPP;
}
return 0;
return ret;
}
EXPORT_SYMBOL(phy_mii_ioctl);

View File

@ -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
@ -839,6 +893,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 +908,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 +918,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)

View File

@ -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;