summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Zapolskiy <vladimir_zapolskiy@mentor.com>2018-07-04 11:14:51 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-08-24 14:12:37 +0300
commitfb96d97a4af4007bf72ca42d9067092b74f5929f (patch)
tree2a9e38c10844ee89b7a7b8c8a52c120c1e4a5b4e
parent354077c09b58d119fd7dfef976711adfe9aaf8d5 (diff)
downloadlinux-fb96d97a4af4007bf72ca42d9067092b74f5929f.tar.xz
ravb: fix invalid context bug while changing link options by ethtool
[ Upstream commit 05925e52a7d379192a5fdff2c33710f573190ead ] The change fixes sleep in atomic context bug, which is encountered every time when link settings are changed by ethtool. Since commit 35b5f6b1a82b ("PHYLIB: Locking fixes for PHY I/O potentially sleeping") phy_start_aneg() function utilizes a mutex to serialize changes to phy state, however that helper function is called in atomic context under a grabbed spinlock, because phy_start_aneg() is called by phy_ethtool_ksettings_set() and by replaced phy_ethtool_sset() helpers from phylib. Now duplex mode setting is enforced in ravb_adjust_link() only, also now RX/TX is disabled when link is put down or modifications to E-MAC registers ECMR and GECMR are expected for both cases of checked and ignored link status pin state from E-MAC interrupt handler. Fixes: c156633f1353 ("Renesas Ethernet AVB driver proper") Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com> Reviewed-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c49
1 files changed, 15 insertions, 34 deletions
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 316db1fd371d..307ecd500dac 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -955,6 +955,13 @@ static void ravb_adjust_link(struct net_device *ndev)
struct ravb_private *priv = netdev_priv(ndev);
struct phy_device *phydev = ndev->phydev;
bool new_state = false;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Disable TX and RX right over here, if E-MAC change is ignored */
+ if (priv->no_avb_link)
+ ravb_rcv_snd_disable(ndev);
if (phydev->link) {
if (phydev->duplex != priv->duplex) {
@@ -972,18 +979,21 @@ static void ravb_adjust_link(struct net_device *ndev)
ravb_modify(ndev, ECMR, ECMR_TXF, 0);
new_state = true;
priv->link = phydev->link;
- if (priv->no_avb_link)
- ravb_rcv_snd_enable(ndev);
}
} else if (priv->link) {
new_state = true;
priv->link = 0;
priv->speed = 0;
priv->duplex = -1;
- if (priv->no_avb_link)
- ravb_rcv_snd_disable(ndev);
}
+ /* Enable TX and RX right over here, if E-MAC change is ignored */
+ if (priv->no_avb_link && phydev->link)
+ ravb_rcv_snd_enable(ndev);
+
+ mmiowb();
+ spin_unlock_irqrestore(&priv->lock, flags);
+
if (new_state && netif_msg_link(priv))
phy_print_status(phydev);
}
@@ -1085,39 +1095,10 @@ static int ravb_get_link_ksettings(struct net_device *ndev,
static int ravb_set_link_ksettings(struct net_device *ndev,
const struct ethtool_link_ksettings *cmd)
{
- struct ravb_private *priv = netdev_priv(ndev);
- unsigned long flags;
- int error;
-
if (!ndev->phydev)
return -ENODEV;
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Disable TX and RX */
- ravb_rcv_snd_disable(ndev);
-
- error = phy_ethtool_ksettings_set(ndev->phydev, cmd);
- if (error)
- goto error_exit;
-
- if (cmd->base.duplex == DUPLEX_FULL)
- priv->duplex = 1;
- else
- priv->duplex = 0;
-
- ravb_set_duplex(ndev);
-
-error_exit:
- mdelay(1);
-
- /* Enable TX and RX */
- ravb_rcv_snd_enable(ndev);
-
- mmiowb();
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return error;
+ return phy_ethtool_ksettings_set(ndev->phydev, cmd);
}
static int ravb_nway_reset(struct net_device *ndev)