diff options
author | Xiaotian Feng <xtfeng@gmail.com> | 2012-11-13 14:47:36 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-14 21:50:10 -0500 |
commit | 71c6c837a0fe9d291e0764503f09dac0fec59ce1 (patch) | |
tree | 64fc5d4c2cf468c841050bed08774bd254d5edbf /drivers | |
parent | b2942004fb5c9f3304b77e187b8a1977b3626c9b (diff) |
drivers/net: fix tasklet misuse issue
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/jme.c | 28 | ||||
-rw-r--r-- | drivers/net/ethernet/micrel/ksz884x.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 12 |
3 files changed, 18 insertions, 38 deletions
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 92317e9c0f73..60ac46f4ac08 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c | |||
@@ -1860,10 +1860,14 @@ jme_open(struct net_device *netdev) | |||
1860 | jme_clear_pm(jme); | 1860 | jme_clear_pm(jme); |
1861 | JME_NAPI_ENABLE(jme); | 1861 | JME_NAPI_ENABLE(jme); |
1862 | 1862 | ||
1863 | tasklet_enable(&jme->linkch_task); | 1863 | tasklet_init(&jme->linkch_task, jme_link_change_tasklet, |
1864 | tasklet_enable(&jme->txclean_task); | 1864 | (unsigned long) jme); |
1865 | tasklet_hi_enable(&jme->rxclean_task); | 1865 | tasklet_init(&jme->txclean_task, jme_tx_clean_tasklet, |
1866 | tasklet_hi_enable(&jme->rxempty_task); | 1866 | (unsigned long) jme); |
1867 | tasklet_init(&jme->rxclean_task, jme_rx_clean_tasklet, | ||
1868 | (unsigned long) jme); | ||
1869 | tasklet_init(&jme->rxempty_task, jme_rx_empty_tasklet, | ||
1870 | (unsigned long) jme); | ||
1867 | 1871 | ||
1868 | rc = jme_request_irq(jme); | 1872 | rc = jme_request_irq(jme); |
1869 | if (rc) | 1873 | if (rc) |
@@ -3079,22 +3083,6 @@ jme_init_one(struct pci_dev *pdev, | |||
3079 | tasklet_init(&jme->pcc_task, | 3083 | tasklet_init(&jme->pcc_task, |
3080 | jme_pcc_tasklet, | 3084 | jme_pcc_tasklet, |
3081 | (unsigned long) jme); | 3085 | (unsigned long) jme); |
3082 | tasklet_init(&jme->linkch_task, | ||
3083 | jme_link_change_tasklet, | ||
3084 | (unsigned long) jme); | ||
3085 | tasklet_init(&jme->txclean_task, | ||
3086 | jme_tx_clean_tasklet, | ||
3087 | (unsigned long) jme); | ||
3088 | tasklet_init(&jme->rxclean_task, | ||
3089 | jme_rx_clean_tasklet, | ||
3090 | (unsigned long) jme); | ||
3091 | tasklet_init(&jme->rxempty_task, | ||
3092 | jme_rx_empty_tasklet, | ||
3093 | (unsigned long) jme); | ||
3094 | tasklet_disable_nosync(&jme->linkch_task); | ||
3095 | tasklet_disable_nosync(&jme->txclean_task); | ||
3096 | tasklet_disable_nosync(&jme->rxclean_task); | ||
3097 | tasklet_disable_nosync(&jme->rxempty_task); | ||
3098 | jme->dpi.cur = PCC_P1; | 3086 | jme->dpi.cur = PCC_P1; |
3099 | 3087 | ||
3100 | jme->reg_ghc = 0; | 3088 | jme->reg_ghc = 0; |
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index e558edd1cb6c..69e01977a1dd 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c | |||
@@ -5459,8 +5459,10 @@ static int prepare_hardware(struct net_device *dev) | |||
5459 | rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev); | 5459 | rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev); |
5460 | if (rc) | 5460 | if (rc) |
5461 | return rc; | 5461 | return rc; |
5462 | tasklet_enable(&hw_priv->rx_tasklet); | 5462 | tasklet_init(&hw_priv->rx_tasklet, rx_proc_task, |
5463 | tasklet_enable(&hw_priv->tx_tasklet); | 5463 | (unsigned long) hw_priv); |
5464 | tasklet_init(&hw_priv->tx_tasklet, tx_proc_task, | ||
5465 | (unsigned long) hw_priv); | ||
5464 | 5466 | ||
5465 | hw->promiscuous = 0; | 5467 | hw->promiscuous = 0; |
5466 | hw->all_multi = 0; | 5468 | hw->all_multi = 0; |
@@ -7033,16 +7035,6 @@ static int __devinit pcidev_init(struct pci_dev *pdev, | |||
7033 | spin_lock_init(&hw_priv->hwlock); | 7035 | spin_lock_init(&hw_priv->hwlock); |
7034 | mutex_init(&hw_priv->lock); | 7036 | mutex_init(&hw_priv->lock); |
7035 | 7037 | ||
7036 | /* tasklet is enabled. */ | ||
7037 | tasklet_init(&hw_priv->rx_tasklet, rx_proc_task, | ||
7038 | (unsigned long) hw_priv); | ||
7039 | tasklet_init(&hw_priv->tx_tasklet, tx_proc_task, | ||
7040 | (unsigned long) hw_priv); | ||
7041 | |||
7042 | /* tasklet_enable will decrement the atomic counter. */ | ||
7043 | tasklet_disable(&hw_priv->rx_tasklet); | ||
7044 | tasklet_disable(&hw_priv->tx_tasklet); | ||
7045 | |||
7046 | for (i = 0; i < TOTAL_PORT_NUM; i++) | 7038 | for (i = 0; i < TOTAL_PORT_NUM; i++) |
7047 | init_waitqueue_head(&hw_priv->counter[i].counter); | 7039 | init_waitqueue_head(&hw_priv->counter[i].counter); |
7048 | 7040 | ||
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 1d04754a6637..77e6db9dcfed 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c | |||
@@ -942,6 +942,10 @@ static int axienet_open(struct net_device *ndev) | |||
942 | phy_start(lp->phy_dev); | 942 | phy_start(lp->phy_dev); |
943 | } | 943 | } |
944 | 944 | ||
945 | /* Enable tasklets for Axi DMA error handling */ | ||
946 | tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler, | ||
947 | (unsigned long) lp); | ||
948 | |||
945 | /* Enable interrupts for Axi DMA Tx */ | 949 | /* Enable interrupts for Axi DMA Tx */ |
946 | ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev); | 950 | ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev); |
947 | if (ret) | 951 | if (ret) |
@@ -950,8 +954,7 @@ static int axienet_open(struct net_device *ndev) | |||
950 | ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev); | 954 | ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev); |
951 | if (ret) | 955 | if (ret) |
952 | goto err_rx_irq; | 956 | goto err_rx_irq; |
953 | /* Enable tasklets for Axi DMA error handling */ | 957 | |
954 | tasklet_enable(&lp->dma_err_tasklet); | ||
955 | return 0; | 958 | return 0; |
956 | 959 | ||
957 | err_rx_irq: | 960 | err_rx_irq: |
@@ -960,6 +963,7 @@ err_tx_irq: | |||
960 | if (lp->phy_dev) | 963 | if (lp->phy_dev) |
961 | phy_disconnect(lp->phy_dev); | 964 | phy_disconnect(lp->phy_dev); |
962 | lp->phy_dev = NULL; | 965 | lp->phy_dev = NULL; |
966 | tasklet_kill(&lp->dma_err_tasklet); | ||
963 | dev_err(lp->dev, "request_irq() failed\n"); | 967 | dev_err(lp->dev, "request_irq() failed\n"); |
964 | return ret; | 968 | return ret; |
965 | } | 969 | } |
@@ -1613,10 +1617,6 @@ static int __devinit axienet_of_probe(struct platform_device *op) | |||
1613 | goto err_iounmap_2; | 1617 | goto err_iounmap_2; |
1614 | } | 1618 | } |
1615 | 1619 | ||
1616 | tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler, | ||
1617 | (unsigned long) lp); | ||
1618 | tasklet_disable(&lp->dma_err_tasklet); | ||
1619 | |||
1620 | return 0; | 1620 | return 0; |
1621 | 1621 | ||
1622 | err_iounmap_2: | 1622 | err_iounmap_2: |