Patchwork fix mv643xx_eth for disabled autoneg

login
register
mail settings
Submitter Phil Sutter
Date March 6, 2013, 5:49 p.m.
Message ID <1362592142-4049-1-git-send-email-phil.sutter@viprinet.com>
Download mbox | patch
Permalink /patch/225561/
State Accepted
Delegated to: David Miller
Headers show

Comments

Phil Sutter - March 6, 2013, 5:49 p.m.
When autoneg has been disabled in the PHY (Marvell 88E1118 here), auto
negotiation between MAC and PHY seem non-functional anymore. The only
way I found to workaround this is to manually configure the MAC with the
settings sent to the PHY earlier.

Signed-off-by: Phil Sutter <phil.sutter@viprinet.com>
---
 drivers/net/ethernet/marvell/mv643xx_eth.c |   55 ++++++++++++++++++++++++++--
 1 files changed, 51 insertions(+), 4 deletions(-)
David Miller - March 7, 2013, 9:18 p.m.
From: Phil Sutter <phil.sutter@viprinet.com>
Date: Wed,  6 Mar 2013 18:49:02 +0100

> When autoneg has been disabled in the PHY (Marvell 88E1118 here), auto
> negotiation between MAC and PHY seem non-functional anymore. The only
> way I found to workaround this is to manually configure the MAC with the
> settings sent to the PHY earlier.
> 
> Signed-off-by: Phil Sutter <phil.sutter@viprinet.com>

Applied, thanks.
--
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
Phil Sutter - March 20, 2013, 11:49 a.m.
On Wed, Mar 06, 2013 at 06:49:02PM +0100, Phil Sutter wrote:
> When autoneg has been disabled in the PHY (Marvell 88E1118 here), auto
> negotiation between MAC and PHY seem non-functional anymore. The only
> way I found to workaround this is to manually configure the MAC with the
> settings sent to the PHY earlier.

And still, this is somehow broken for turned off autoneg. Not a DoS
anymore, but it seems like one can not disable duplex autoneg. No matter
what duplex settings I configure on each side, communication is still
possible.

Do you have any idea what could be missing or how to furtherly track
down the problem? Could this even be a bug in the hardware?

Best wishes, Phil
--
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/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 5e1ca0f..5435833 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -1082,6 +1082,45 @@  static void txq_set_fixed_prio_mode(struct tx_queue *txq)
 
 
 /* mii management interface *************************************************/
+static void mv643xx_adjust_pscr(struct mv643xx_eth_private *mp)
+{
+	u32 pscr = rdlp(mp, PORT_SERIAL_CONTROL);
+	u32 autoneg_disable = FORCE_LINK_PASS |
+	             DISABLE_AUTO_NEG_SPEED_GMII |
+		     DISABLE_AUTO_NEG_FOR_FLOW_CTRL |
+		     DISABLE_AUTO_NEG_FOR_DUPLEX;
+
+	if (mp->phy->autoneg == AUTONEG_ENABLE) {
+		/* enable auto negotiation */
+		pscr &= ~autoneg_disable;
+		goto out_write;
+	}
+
+	pscr |= autoneg_disable;
+
+	if (mp->phy->speed == SPEED_1000) {
+		/* force gigabit, half duplex not supported */
+		pscr |= SET_GMII_SPEED_TO_1000;
+		pscr |= SET_FULL_DUPLEX_MODE;
+		goto out_write;
+	}
+
+	pscr &= ~SET_GMII_SPEED_TO_1000;
+
+	if (mp->phy->speed == SPEED_100)
+		pscr |= SET_MII_SPEED_TO_100;
+	else
+		pscr &= ~SET_MII_SPEED_TO_100;
+
+	if (mp->phy->duplex == DUPLEX_FULL)
+		pscr |= SET_FULL_DUPLEX_MODE;
+	else
+		pscr &= ~SET_FULL_DUPLEX_MODE;
+
+out_write:
+	wrlp(mp, PORT_SERIAL_CONTROL, pscr);
+}
+
 static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id)
 {
 	struct mv643xx_eth_shared_private *msp = dev_id;
@@ -1500,6 +1539,7 @@  static int
 mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
+	int ret;
 
 	if (mp->phy == NULL)
 		return -EINVAL;
@@ -1509,7 +1549,10 @@  mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 	 */
 	cmd->advertising &= ~ADVERTISED_1000baseT_Half;
 
-	return phy_ethtool_sset(mp->phy, cmd);
+	ret = phy_ethtool_sset(mp->phy, cmd);
+	if (!ret)
+		mv643xx_adjust_pscr(mp);
+	return ret;
 }
 
 static void mv643xx_eth_get_drvinfo(struct net_device *dev,
@@ -2448,11 +2491,15 @@  static int mv643xx_eth_stop(struct net_device *dev)
 static int mv643xx_eth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct mv643xx_eth_private *mp = netdev_priv(dev);
+	int ret;
 
-	if (mp->phy != NULL)
-		return phy_mii_ioctl(mp->phy, ifr, cmd);
+	if (mp->phy == NULL)
+		return -ENOTSUPP;
 
-	return -EOPNOTSUPP;
+	ret = phy_mii_ioctl(mp->phy, ifr, cmd);
+	if (!ret)
+		mv643xx_adjust_pscr(mp);
+	return ret;
 }
 
 static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu)