Commit 1cf167f2 authored by Eilon Greenstein's avatar Eilon Greenstein Committed by David S. Miller

bnx2x: Using singlethread work queue

Since slow-path events, including link update, are handled in
work-queue, a race condition was introduced in the self-test that
sometimes caused the link status to fail: the self-test was running
under RTNL lock, and if the link-watch was scheduled it stoped the
shared work-queue (waiting for the RTNL lock) and so the link update
event was not handled until the self-test ended (releasing the RTNL
lock) with failure (since the link status was not updated)
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c53a6ee8
...@@ -811,7 +811,7 @@ struct bnx2x { ...@@ -811,7 +811,7 @@ struct bnx2x {
int pm_cap; int pm_cap;
int pcie_cap; int pcie_cap;
struct work_struct sp_task; struct delayed_work sp_task;
struct work_struct reset_task; struct work_struct reset_task;
struct timer_list timer; struct timer_list timer;
......
...@@ -95,6 +95,7 @@ MODULE_PARM_DESC(debug, "default debug msglevel"); ...@@ -95,6 +95,7 @@ MODULE_PARM_DESC(debug, "default debug msglevel");
module_param(use_multi, int, 0); module_param(use_multi, int, 0);
MODULE_PARM_DESC(use_multi, "use per-CPU queues"); MODULE_PARM_DESC(use_multi, "use per-CPU queues");
#endif #endif
static struct workqueue_struct *bnx2x_wq;
enum bnx2x_board_type { enum bnx2x_board_type {
BCM57710 = 0, BCM57710 = 0,
...@@ -671,7 +672,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) ...@@ -671,7 +672,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
synchronize_irq(bp->pdev->irq); synchronize_irq(bp->pdev->irq);
/* make sure sp_task is not running */ /* make sure sp_task is not running */
cancel_work_sync(&bp->sp_task); cancel_delayed_work(&bp->sp_task);
flush_workqueue(bnx2x_wq);
} }
/* fast path */ /* fast path */
...@@ -1660,7 +1662,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) ...@@ -1660,7 +1662,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
if (unlikely(status & 0x1)) { if (unlikely(status & 0x1)) {
schedule_work(&bp->sp_task); queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
status &= ~0x1; status &= ~0x1;
if (!status) if (!status)
...@@ -2820,7 +2822,7 @@ static void bnx2x_attn_int(struct bnx2x *bp) ...@@ -2820,7 +2822,7 @@ static void bnx2x_attn_int(struct bnx2x *bp)
static void bnx2x_sp_task(struct work_struct *work) static void bnx2x_sp_task(struct work_struct *work)
{ {
struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
u16 status; u16 status;
...@@ -2875,7 +2877,7 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) ...@@ -2875,7 +2877,7 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
return IRQ_HANDLED; return IRQ_HANDLED;
#endif #endif
schedule_work(&bp->sp_task); queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -7501,7 +7503,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) ...@@ -7501,7 +7503,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->port.phy_mutex); mutex_init(&bp->port.phy_mutex);
INIT_WORK(&bp->sp_task, bnx2x_sp_task); INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_WORK(&bp->reset_task, bnx2x_reset_task); INIT_WORK(&bp->reset_task, bnx2x_reset_task);
rc = bnx2x_get_hwinfo(bp); rc = bnx2x_get_hwinfo(bp);
...@@ -10519,12 +10521,20 @@ static struct pci_driver bnx2x_pci_driver = { ...@@ -10519,12 +10521,20 @@ static struct pci_driver bnx2x_pci_driver = {
static int __init bnx2x_init(void) static int __init bnx2x_init(void)
{ {
bnx2x_wq = create_singlethread_workqueue("bnx2x");
if (bnx2x_wq == NULL) {
printk(KERN_ERR PFX "Cannot create workqueue\n");
return -ENOMEM;
}
return pci_register_driver(&bnx2x_pci_driver); return pci_register_driver(&bnx2x_pci_driver);
} }
static void __exit bnx2x_cleanup(void) static void __exit bnx2x_cleanup(void)
{ {
pci_unregister_driver(&bnx2x_pci_driver); pci_unregister_driver(&bnx2x_pci_driver);
destroy_workqueue(bnx2x_wq);
} }
module_init(bnx2x_init); module_init(bnx2x_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment