Commit 9bc045c6 authored by Enric Balletbo i Serra's avatar Enric Balletbo i Serra Committed by Luis Henriques

smsc911x: power-up phydev before doing a software reset.

commit ccf899a2 upstream.

With commit be9dad1f ("net: phy: suspend phydev when going
to HALTED"), the PHY device will be put in a low-power mode using
BMCR_PDOWN if the the interface is set down. The smsc911x driver does
a software_reset opening the device driver (ndo_open). In such case,
the PHY must be powered-up before access to any register and before
calling the software_reset function. Otherwise, as the PHY is powered
down the software reset fails and the interface can not be enabled
again.

This patch fixes this scenario that is easy to reproduce setting down
the network interface and setting up again.

    $ ifconfig eth0 down
    $ ifconfig eth0 up
    ifconfig: SIOCSIFFLAGS: Input/output error
Signed-off-by: default avatarEnric Balletbo i Serra <eballetbo@iseebcn.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 1b1a5bb6
...@@ -1342,6 +1342,42 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) ...@@ -1342,6 +1342,42 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
spin_unlock(&pdata->mac_lock); spin_unlock(&pdata->mac_lock);
} }
static int smsc911x_phy_general_power_up(struct smsc911x_data *pdata)
{
int rc = 0;
if (!pdata->phy_dev)
return rc;
/* If the internal PHY is in General Power-Down mode, all, except the
* management interface, is powered-down and stays in that condition as
* long as Phy register bit 0.11 is HIGH.
*
* In that case, clear the bit 0.11, so the PHY powers up and we can
* access to the phy registers.
*/
rc = phy_read(pdata->phy_dev, MII_BMCR);
if (rc < 0) {
SMSC_WARN(pdata, drv, "Failed reading PHY control reg");
return rc;
}
/* If the PHY general power-down bit is not set is not necessary to
* disable the general power down-mode.
*/
if (rc & BMCR_PDOWN) {
rc = phy_write(pdata->phy_dev, MII_BMCR, rc & ~BMCR_PDOWN);
if (rc < 0) {
SMSC_WARN(pdata, drv, "Failed writing PHY control reg");
return rc;
}
usleep_range(1000, 1500);
}
return 0;
}
static int smsc911x_phy_disable_energy_detect(struct smsc911x_data *pdata) static int smsc911x_phy_disable_energy_detect(struct smsc911x_data *pdata)
{ {
int rc = 0; int rc = 0;
...@@ -1414,6 +1450,16 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata) ...@@ -1414,6 +1450,16 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata)
unsigned int temp; unsigned int temp;
int ret; int ret;
/*
* Make sure to power-up the PHY chip before doing a reset, otherwise
* the reset fails.
*/
ret = smsc911x_phy_general_power_up(pdata);
if (ret) {
SMSC_WARN(pdata, drv, "Failed to power-up the PHY chip");
return ret;
}
/* /*
* LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that * LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that
* are initialized in a Energy Detect Power-Down mode that prevents * are initialized in a Energy Detect Power-Down mode that prevents
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment