diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-03-31 10:46:21 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-10-17 14:35:21 +0100 |
commit | dbd69f5aeb1ae857c76daf1f0abeaa39015a6886 (patch) | |
tree | cd3b4fd2b3d3fb153dff3de648ef9d7315a1defc /drivers/net/ethernet/freescale/fec_main.c | |
parent | ada950bc676bbcd7140f1422e700e183b376f2ab (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.c | 30 |
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); |