Skip to content

Commit

Permalink
net: ethernet: mediatek: avoid race condition during the reset process
Browse files Browse the repository at this point in the history
add the protection of the race condition between
the reset process and hardware access happening
on the related callbacks.

Signed-off-by: Sean Wang <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
moore-bros authored and davem330 committed Sep 16, 2016
1 parent 2a8307a commit dce6fa4
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
36 changes: 36 additions & 0 deletions drivers/net/ethernet/mediatek/mtk_eth_soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ static void mtk_phy_link_adjust(struct net_device *dev)
MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN |
MAC_MCR_BACKPR_EN;

if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return;

switch (mac->phy_dev->speed) {
case SPEED_1000:
mcr |= MAC_MCR_SPEED_1000;
Expand Down Expand Up @@ -370,6 +373,9 @@ static int mtk_set_mac_address(struct net_device *dev, void *p)
if (ret)
return ret;

if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY;

spin_lock_bh(&mac->hw->page_lock);
mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1],
MTK_GDMA_MAC_ADRH(mac->id));
Expand Down Expand Up @@ -770,6 +776,9 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
spin_lock(&eth->page_lock);

if (unlikely(test_bit(MTK_RESETTING, &eth->state)))
goto drop;

tx_num = mtk_cal_txd_req(skb);
if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
mtk_stop_queue(eth);
Expand Down Expand Up @@ -842,6 +851,9 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,

netdev = eth->netdev[mac];

if (unlikely(test_bit(MTK_RESETTING, &eth->state)))
goto release_desc;

/* alloc new buffer */
new_data = napi_alloc_frag(ring->frag_size);
if (unlikely(!new_data)) {
Expand Down Expand Up @@ -1576,13 +1588,20 @@ static void mtk_pending_work(struct work_struct *work)

rtnl_lock();

dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__);

while (test_and_set_bit_lock(MTK_RESETTING, &eth->state))
cpu_relax();

dev_dbg(eth->dev, "[%s][%d] mtk_stop starts\n", __func__, __LINE__);
/* stop all devices to make sure that dma is properly shut down */
for (i = 0; i < MTK_MAC_COUNT; i++) {
if (!eth->netdev[i])
continue;
mtk_stop(eth->netdev[i]);
__set_bit(i, &restart);
}
dev_dbg(eth->dev, "[%s][%d] mtk_stop ends\n", __func__, __LINE__);

/* restart underlying hardware such as power, clock, pin mux
* and the connected phy
Expand Down Expand Up @@ -1615,6 +1634,11 @@ static void mtk_pending_work(struct work_struct *work)
dev_close(eth->netdev[i]);
}
}

dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__);

clear_bit_unlock(MTK_RESETTING, &eth->state);

rtnl_unlock();
}

Expand Down Expand Up @@ -1659,6 +1683,9 @@ static int mtk_get_settings(struct net_device *dev,
struct mtk_mac *mac = netdev_priv(dev);
int err;

if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY;

err = phy_read_status(mac->phy_dev);
if (err)
return -ENODEV;
Expand Down Expand Up @@ -1709,6 +1736,9 @@ static int mtk_nway_reset(struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);

if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY;

return genphy_restart_aneg(mac->phy_dev);
}

Expand All @@ -1717,6 +1747,9 @@ static u32 mtk_get_link(struct net_device *dev)
struct mtk_mac *mac = netdev_priv(dev);
int err;

if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return -EBUSY;

err = genphy_update_link(mac->phy_dev);
if (err)
return ethtool_op_get_link(dev);
Expand Down Expand Up @@ -1757,6 +1790,9 @@ static void mtk_get_ethtool_stats(struct net_device *dev,
unsigned int start;
int i;

if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state)))
return;

if (netif_running(dev) && netif_device_present(dev)) {
if (spin_trylock(&hwstats->stats_lock)) {
mtk_stats_update_mac(mac);
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/mediatek/mtk_eth_soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ enum mtk_clks_map {
};

enum mtk_dev_state {
MTK_HW_INIT
MTK_HW_INIT,
MTK_RESETTING
};

/* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at
Expand Down

0 comments on commit dce6fa4

Please sign in to comment.