Patchwork [2/2] net/smsc911x: Check if PHY is in operational mode before software reset

login
register
mail settings
Submitter Javier Martinez Canillas
Date Jan. 2, 2012, 5:08 p.m.
Message ID <1325524131-14585-2-git-send-email-martinez.javier@gmail.com>
Download mbox | patch
Permalink /patch/133875/
State Changes Requested
Delegated to: David Miller
Headers show

Comments

Javier Martinez Canillas - Jan. 2, 2012, 5:08 p.m.
SMSC LAN generation 4 chips integrate an IEEE 802.3 ethernet physical layer.
The PHY driver for this integrated chip enable an energy detect power-down mode.
When the PHY is in a power-down mode, it prevents the MAC portion chip to be
software reseted.

That means that if we compile the kernel with the configuration option SMSC_PHY
enabled and try to bring the network interface up without an cable plug-ed the
PHY will be in a low power mode and the software reset will fail returning -EIO
to user-space:

root@igep00x0:~# ifconfig eth0 up
ifconfig: SIOCSIFFLAGS: Input/output error

This patch disable the energy detect power-down mode before trying to software
reset the LAN chip and re-enables after it was reseted successfully.

Signed-off-by: Javier Martinez Canillas <martinez.javier@gmail.com>
---
 drivers/net/ethernet/smsc/smsc911x.c |   88 ++++++++++++++++++++++++++++++++++
 1 files changed, 88 insertions(+), 0 deletions(-)
David Miller - Jan. 3, 2012, 6:46 p.m.
From: Javier Martinez Canillas <martinez.javier@gmail.com>
Date: Mon,  2 Jan 2012 18:08:51 +0100

> +	/* If energy is detected the PHY is already awake so is not necessary
> +	 * to disable the energy detect power-down mode. */
 ...
> +	/* LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that
> +	 * are initialized in a Energy Detect Power-Down mode that prevents
> +	 * the MAC chip to be software reseted. So we have to wakeup the PHY
> +	 * before */

Format these comments correctly:

	/* Like this.
	 * See?
	 */

	/* Not like this.
	 * Ok? */

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Javier Martinez Canillas - Jan. 3, 2012, 11:30 p.m.
On Tue, Jan 3, 2012 at 7:46 PM, David Miller <davem@davemloft.net> wrote:
> From: Javier Martinez Canillas <martinez.javier@gmail.com>
> Date: Mon,  2 Jan 2012 18:08:51 +0100
>
>> +     /* If energy is detected the PHY is already awake so is not necessary
>> +      * to disable the energy detect power-down mode. */
>  ...
>> +     /* LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that
>> +      * are initialized in a Energy Detect Power-Down mode that prevents
>> +      * the MAC chip to be software reseted. So we have to wakeup the PHY
>> +      * before */
>
> Format these comments correctly:
>
>        /* Like this.
>         * See?
>         */
>
>        /* Not like this.
>         * Ok? */
>

Ok, will resend with the right style.

Besides these coding style issues, does the patch looks good to you?

Best regards,
David Miller - Jan. 4, 2012, 1:18 a.m.
From: Javier Martinez Canillas <martinez.javier@gmail.com>
Date: Wed, 4 Jan 2012 00:30:23 +0100

> Besides these coding style issues, does the patch looks good to you?

It looked fine.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 8843071..2a63e11 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -1243,10 +1243,88 @@  static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
 	spin_unlock(&pdata->mac_lock);
 }
 
+static int smsc911x_phy_disable_energy_detect(struct smsc911x_data *pdata)
+{
+	int rc = 0;
+
+	if (!pdata->phy_dev)
+		return rc;
+
+	rc = phy_read(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS);
+
+	if (rc < 0) {
+		SMSC_WARN(pdata, drv, "Failed reading PHY control reg");
+		return rc;
+	}
+
+	/* If energy is detected the PHY is already awake so is not necessary
+	 * to disable the energy detect power-down mode. */
+	if ((rc & MII_LAN83C185_EDPWRDOWN) &&
+	    !(rc & MII_LAN83C185_ENERGYON)) {
+		/* Disable energy detect mode for this SMSC Transceivers */
+		rc = phy_write(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS,
+			       rc & (~MII_LAN83C185_EDPWRDOWN));
+
+		if (rc < 0) {
+			SMSC_WARN(pdata, drv, "Failed writing PHY control reg");
+			return rc;
+		}
+
+		mdelay(1);
+	}
+
+	return 0;
+}
+
+static int smsc911x_phy_enable_energy_detect(struct smsc911x_data *pdata)
+{
+	int rc = 0;
+
+	if (!pdata->phy_dev)
+		return rc;
+
+	rc = phy_read(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS);
+
+	if (rc < 0) {
+		SMSC_WARN(pdata, drv, "Failed reading PHY control reg");
+		return rc;
+	}
+
+	/* Only enable if energy detect mode is already disabled */
+	if (!(rc & MII_LAN83C185_EDPWRDOWN)) {
+		mdelay(100);
+		/* Enable energy detect mode for this SMSC Transceivers */
+		rc = phy_write(pdata->phy_dev, MII_LAN83C185_CTRL_STATUS,
+			       rc | MII_LAN83C185_EDPWRDOWN);
+
+		if (rc < 0) {
+			SMSC_WARN(pdata, drv, "Failed writing PHY control reg");
+			return rc;
+		}
+
+		mdelay(1);
+	}
+	return 0;
+}
+
 static int smsc911x_soft_reset(struct smsc911x_data *pdata)
 {
 	unsigned int timeout;
 	unsigned int temp;
+	int ret;
+
+	/* LAN9210/LAN9211/LAN9220/LAN9221 chips have an internal PHY that
+	 * are initialized in a Energy Detect Power-Down mode that prevents
+	 * the MAC chip to be software reseted. So we have to wakeup the PHY
+	 * before */
+	if (pdata->generation == 4) {
+		ret = smsc911x_phy_disable_energy_detect(pdata);
+
+		if (ret) {
+			SMSC_WARN(pdata, drv, "Failed to wakeup the PHY chip");
+			return ret;
+		}
+	}
 
 	/* Reset the LAN911x */
 	smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_);
@@ -1260,6 +1338,16 @@  static int smsc911x_soft_reset(struct smsc911x_data *pdata)
 		SMSC_WARN(pdata, drv, "Failed to complete reset");
 		return -EIO;
 	}
+
+	if (pdata->generation == 4) {
+		ret = smsc911x_phy_enable_energy_detect(pdata);
+
+		if (ret) {
+			SMSC_WARN(pdata, drv, "Failed to wakeup the PHY chip");
+			return ret;
+		}
+	}
+
 	return 0;
 }