mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 08:34:20 +08:00
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>
This commit is contained in:
parent
b2942004fb
commit
71c6c837a0
@ -1860,10 +1860,14 @@ jme_open(struct net_device *netdev)
|
|||||||
jme_clear_pm(jme);
|
jme_clear_pm(jme);
|
||||||
JME_NAPI_ENABLE(jme);
|
JME_NAPI_ENABLE(jme);
|
||||||
|
|
||||||
tasklet_enable(&jme->linkch_task);
|
tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
|
||||||
tasklet_enable(&jme->txclean_task);
|
(unsigned long) jme);
|
||||||
tasklet_hi_enable(&jme->rxclean_task);
|
tasklet_init(&jme->txclean_task, jme_tx_clean_tasklet,
|
||||||
tasklet_hi_enable(&jme->rxempty_task);
|
(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);
|
rc = jme_request_irq(jme);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -3079,22 +3083,6 @@ jme_init_one(struct pci_dev *pdev,
|
|||||||
tasklet_init(&jme->pcc_task,
|
tasklet_init(&jme->pcc_task,
|
||||||
jme_pcc_tasklet,
|
jme_pcc_tasklet,
|
||||||
(unsigned long) jme);
|
(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->dpi.cur = PCC_P1;
|
||||||
|
|
||||||
jme->reg_ghc = 0;
|
jme->reg_ghc = 0;
|
||||||
|
@ -5459,8 +5459,10 @@ static int prepare_hardware(struct net_device *dev)
|
|||||||
rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
|
rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
tasklet_enable(&hw_priv->rx_tasklet);
|
tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
|
||||||
tasklet_enable(&hw_priv->tx_tasklet);
|
(unsigned long) hw_priv);
|
||||||
|
tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
|
||||||
|
(unsigned long) hw_priv);
|
||||||
|
|
||||||
hw->promiscuous = 0;
|
hw->promiscuous = 0;
|
||||||
hw->all_multi = 0;
|
hw->all_multi = 0;
|
||||||
@ -7033,16 +7035,6 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
|
|||||||
spin_lock_init(&hw_priv->hwlock);
|
spin_lock_init(&hw_priv->hwlock);
|
||||||
mutex_init(&hw_priv->lock);
|
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++)
|
for (i = 0; i < TOTAL_PORT_NUM; i++)
|
||||||
init_waitqueue_head(&hw_priv->counter[i].counter);
|
init_waitqueue_head(&hw_priv->counter[i].counter);
|
||||||
|
|
||||||
|
@ -942,6 +942,10 @@ static int axienet_open(struct net_device *ndev)
|
|||||||
phy_start(lp->phy_dev);
|
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 */
|
/* Enable interrupts for Axi DMA Tx */
|
||||||
ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
|
ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -950,8 +954,7 @@ static int axienet_open(struct net_device *ndev)
|
|||||||
ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
|
ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_rx_irq;
|
goto err_rx_irq;
|
||||||
/* Enable tasklets for Axi DMA error handling */
|
|
||||||
tasklet_enable(&lp->dma_err_tasklet);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_rx_irq:
|
err_rx_irq:
|
||||||
@ -960,6 +963,7 @@ err_tx_irq:
|
|||||||
if (lp->phy_dev)
|
if (lp->phy_dev)
|
||||||
phy_disconnect(lp->phy_dev);
|
phy_disconnect(lp->phy_dev);
|
||||||
lp->phy_dev = NULL;
|
lp->phy_dev = NULL;
|
||||||
|
tasklet_kill(&lp->dma_err_tasklet);
|
||||||
dev_err(lp->dev, "request_irq() failed\n");
|
dev_err(lp->dev, "request_irq() failed\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1613,10 +1617,6 @@ static int __devinit axienet_of_probe(struct platform_device *op)
|
|||||||
goto err_iounmap_2;
|
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;
|
return 0;
|
||||||
|
|
||||||
err_iounmap_2:
|
err_iounmap_2:
|
||||||
|
Loading…
Reference in New Issue
Block a user