summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale/fec_main.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-03-31 10:46:21 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-10-17 14:35:21 +0100
commitdbd69f5aeb1ae857c76daf1f0abeaa39015a6886 (patch)
treecd3b4fd2b3d3fb153dff3de648ef9d7315a1defc /drivers/net/ethernet/freescale/fec_main.c
parentada950bc676bbcd7140f1422e700e183b376f2ab (diff)
net: fec: add locking for MDIO bus access
Both fec_restart() and fec_stop() both perform a reset of the FEC. This reset can result in an in-process MDIO transfer being terminated, which can lead to the MDIO read/write functions timing out. Add some locking to prevent this occuring. We can't use a spinlock for this as the MDIO accessor functions use wait_for_completion_timeout(), which sleeps. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f786485acf63..f67e83967a15 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1075,12 +1075,14 @@ static void fec_enet_timeout_work(struct work_struct *work)
rtnl_lock();
if (netif_device_present(ndev) || netif_running(ndev)) {
+ mutex_lock(&fep->mutex);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_restart(ndev);
netif_wake_queue(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
+ mutex_unlock(&fep->mutex);
}
rtnl_unlock();
}
@@ -1568,20 +1570,24 @@ static void fec_enet_adjust_link(struct net_device *ndev)
/* if any of the above changed restart the FEC */
if (status_change) {
+ mutex_lock(&fep->mutex);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_restart(ndev);
netif_wake_queue(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
+ mutex_unlock(&fep->mutex);
}
} else {
if (fep->link) {
+ mutex_lock(&fep->mutex);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_stop(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
+ mutex_unlock(&fep->mutex);
fep->link = phy_dev->link;
status_change = 1;
}
@@ -1594,15 +1600,23 @@ static void fec_enet_adjust_link(struct net_device *ndev)
static unsigned long fec_enet_mdio_op(struct fec_enet_private *fep,
unsigned data)
{
+ unsigned long time_left;
+
fep->mii_timeout = 0;
init_completion(&fep->mdio_done);
+ mutex_lock(&fep->mutex);
+
/* start operation */
writel(data, fep->hwp + FEC_MII_DATA);
/* wait for end of transfer */
- return wait_for_completion_timeout(&fep->mdio_done,
+ time_left = wait_for_completion_timeout(&fep->mdio_done,
usecs_to_jiffies(FEC_MII_TIMEOUT));
+
+ mutex_unlock(&fep->mutex);
+
+ return time_left;
}
static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
@@ -2039,6 +2053,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
fep->pause_mode = fep->pause_flag;
if (netif_running(ndev)) {
+ mutex_lock(&fep->mutex);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_stop(ndev);
@@ -2046,6 +2061,7 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
netif_wake_queue(ndev);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
+ mutex_unlock(&fep->mutex);
}
}
}
@@ -2318,7 +2334,9 @@ fec_enet_open(struct net_device *ndev)
return ret;
}
+ mutex_lock(&fep->mutex);
fec_restart(ndev);
+ mutex_unlock(&fep->mutex);
napi_enable(&fep->napi);
phy_start(fep->phy_dev);
netif_start_queue(ndev);
@@ -2335,7 +2353,9 @@ fec_enet_close(struct net_device *ndev)
if (netif_device_present(ndev)) {
napi_disable(&fep->napi);
netif_tx_disable(ndev);
+ mutex_lock(&fep->mutex);
fec_stop(ndev);
+ mutex_unlock(&fep->mutex);
}
phy_disconnect(fep->phy_dev);
@@ -2492,6 +2512,7 @@ static int fec_set_features(struct net_device *netdev,
/* Quiesce the device if necessary */
if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
+ mutex_lock(&fep->mutex);
napi_disable(&fep->napi);
netif_tx_lock_bh(netdev);
fec_stop(netdev);
@@ -2524,6 +2545,7 @@ static int fec_set_features(struct net_device *netdev,
netif_wake_queue(netdev);
netif_tx_unlock_bh(netdev);
napi_enable(&fep->napi);
+ mutex_unlock(&fep->mutex);
}
return 0;
@@ -2710,6 +2732,8 @@ fec_probe(struct platform_device *pdev)
/* setup board info structure */
fep = netdev_priv(ndev);
+ mutex_init(&fep->mutex);
+
#if !defined(CONFIG_M5272)
/* default enable pause frame auto negotiation */
if (pdev->id_entry &&
@@ -2895,7 +2919,9 @@ static int __maybe_unused fec_suspend(struct device *dev)
netif_tx_lock_bh(ndev);
netif_device_detach(ndev);
netif_tx_unlock_bh(ndev);
+ mutex_lock(&fep->mutex);
fec_stop(ndev);
+ mutex_unlock(&fep->mutex);
}
rtnl_unlock();
@@ -2927,7 +2953,9 @@ static int __maybe_unused fec_resume(struct device *dev)
rtnl_lock();
if (netif_running(ndev)) {
+ mutex_lock(&fep->mutex);
fec_restart(ndev);
+ mutex_unlock(&fep->mutex);
netif_tx_lock_bh(ndev);
netif_device_attach(ndev);
netif_tx_unlock_bh(ndev);