]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
xilinx_emacps: Fix deadlock in xemacps_reinit_for_txtimeout()
authorThomas Betker <thomas.betker@rohde-schwarz.com>
Sat, 11 May 2013 09:10:45 +0000 (11:10 +0200)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 5 Jun 2013 08:48:47 +0000 (10:48 +0200)
In xemacps_reinit_for_txtimeout(), do not hold tx_lock when calling
tasklet_disable(). If xemacps_tx_poll() starts to run between acquiring
tx_lock and tasklet_disable(), we are caught in a deadlock because
tasklet_disable() waits until xemacps_tx_poll() has finished.

Also use netif_wake_queue() instead of netif_start_queue(), and don't
forget to update ndev->trans_start.

Signed-off-by: Thomas Betker <thomas.betker@rohde-schwarz.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/net/ethernet/xilinx/xilinx_emacps.c

index c2f08094b4ab21b15b4ff3d462e9de5244142290..8e4863659063c37ae5bcf44d9f86505fe94ad625 100644 (file)
@@ -1914,9 +1914,9 @@ static void xemacps_reinit_for_txtimeout(struct work_struct *data)
        int rc;
 
        netif_stop_queue(lp->ndev);
-       spin_lock_bh(&lp->tx_lock);
        napi_disable(&lp->napi);
        tasklet_disable(&lp->tx_bdreclaim_tasklet);
+       spin_lock_bh(&lp->tx_lock);
        xemacps_reset_hw(lp);
        spin_unlock_bh(&lp->tx_lock);
 
@@ -1936,11 +1936,14 @@ static void xemacps_reinit_for_txtimeout(struct work_struct *data)
        lp->link    = 0;
        lp->speed   = 0;
        lp->duplex  = -1;
+
        if (lp->phy_dev)
                phy_start(lp->phy_dev);
+
        napi_enable(&lp->napi);
        tasklet_enable(&lp->tx_bdreclaim_tasklet);
-       netif_start_queue(lp->ndev);
+       lp->ndev->trans_start = jiffies;
+       netif_wake_queue(lp->ndev);
 }
 
 /**