In commit 
175c0dff, drivers uses tasklet_kill to avoid put disabled tasklet
on the tasklet vec. But some of the drivers uses tasklet_init & tasklet_disable
in the driver init code, then tasklet_enable when it is opened. This makes
tasklet_enable on a killed tasklet and make ksoftirqd crazy then. Normally,
drivers should use tasklet_init/tasklet_kill on device open/remove, and use
tasklet_disable/tasklet_enable on device suspend/resume.
Reported-by: Peter Wu <lekensteyn@gmail.com>
Tested-by: Peter Wu <lekensteyn@gmail.com>
Signed-off-by: Xiaotian Feng <dannyfeng@tencent.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
        jme_clear_pm(jme);
        JME_NAPI_ENABLE(jme);
 
-       tasklet_enable(&jme->linkch_task);
-       tasklet_enable(&jme->txclean_task);
-       tasklet_hi_enable(&jme->rxclean_task);
-       tasklet_hi_enable(&jme->rxempty_task);
+       tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
+                    (unsigned long) jme);
+       tasklet_init(&jme->txclean_task, jme_tx_clean_tasklet,
+                    (unsigned long) jme);
+       tasklet_init(&jme->rxclean_task, jme_rx_clean_tasklet,
+                    (unsigned long) jme);
+       tasklet_init(&jme->rxempty_task, jme_rx_empty_tasklet,
+                    (unsigned long) jme);
 
        rc = jme_request_irq(jme);
        if (rc)
        tasklet_init(&jme->pcc_task,
                     jme_pcc_tasklet,
                     (unsigned long) jme);
-       tasklet_init(&jme->linkch_task,
-                    jme_link_change_tasklet,
-                    (unsigned long) jme);
-       tasklet_init(&jme->txclean_task,
-                    jme_tx_clean_tasklet,
-                    (unsigned long) jme);
-       tasklet_init(&jme->rxclean_task,
-                    jme_rx_clean_tasklet,
-                    (unsigned long) jme);
-       tasklet_init(&jme->rxempty_task,
-                    jme_rx_empty_tasklet,
-                    (unsigned long) jme);
-       tasklet_disable_nosync(&jme->linkch_task);
-       tasklet_disable_nosync(&jme->txclean_task);
-       tasklet_disable_nosync(&jme->rxclean_task);
-       tasklet_disable_nosync(&jme->rxempty_task);
        jme->dpi.cur = PCC_P1;
 
        jme->reg_ghc = 0;
 
        rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
        if (rc)
                return rc;
-       tasklet_enable(&hw_priv->rx_tasklet);
-       tasklet_enable(&hw_priv->tx_tasklet);
+       tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
+                    (unsigned long) hw_priv);
+       tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
+                    (unsigned long) hw_priv);
 
        hw->promiscuous = 0;
        hw->all_multi = 0;
        spin_lock_init(&hw_priv->hwlock);
        mutex_init(&hw_priv->lock);
 
-       /* tasklet is enabled. */
-       tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
-               (unsigned long) hw_priv);
-       tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
-               (unsigned long) hw_priv);
-
-       /* tasklet_enable will decrement the atomic counter. */
-       tasklet_disable(&hw_priv->rx_tasklet);
-       tasklet_disable(&hw_priv->tx_tasklet);
-
        for (i = 0; i < TOTAL_PORT_NUM; i++)
                init_waitqueue_head(&hw_priv->counter[i].counter);
 
 
                phy_start(lp->phy_dev);
        }
 
+       /* Enable tasklets for Axi DMA error handling */
+       tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
+                    (unsigned long) lp);
+
        /* Enable interrupts for Axi DMA Tx */
        ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
        if (ret)
        ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
        if (ret)
                goto err_rx_irq;
-       /* Enable tasklets for Axi DMA error handling */
-       tasklet_enable(&lp->dma_err_tasklet);
+
        return 0;
 
 err_rx_irq:
        if (lp->phy_dev)
                phy_disconnect(lp->phy_dev);
        lp->phy_dev = NULL;
+       tasklet_kill(&lp->dma_err_tasklet);
        dev_err(lp->dev, "request_irq() failed\n");
        return ret;
 }
                goto err_iounmap_2;
        }
 
-       tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
-                    (unsigned long) lp);
-       tasklet_disable(&lp->dma_err_tasklet);
-
        return 0;
 
 err_iounmap_2: