diff options
author | Eilon Greenstein <eilong@broadcom.com> | 2009-01-15 00:22:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-01-15 11:28:10 -0500 |
commit | 1cf167f27ad2720af11ee8aa350009342f909e70 (patch) | |
tree | 3733c5516e5518cdab133895e515cc4355a216e0 /drivers/net | |
parent | c53a6ee88b0a91bd012ef1b7988c0b93dae6f24d (diff) |
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: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/bnx2x.h | 2 | ||||
-rw-r--r-- | drivers/net/bnx2x_main.c | 20 |
2 files changed, 16 insertions, 6 deletions
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index fd705d1295a7..96a8889afbe1 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h | |||
@@ -811,7 +811,7 @@ struct bnx2x { | |||
811 | int pm_cap; | 811 | int pm_cap; |
812 | int pcie_cap; | 812 | int pcie_cap; |
813 | 813 | ||
814 | struct work_struct sp_task; | 814 | struct delayed_work sp_task; |
815 | struct work_struct reset_task; | 815 | struct work_struct reset_task; |
816 | 816 | ||
817 | struct timer_list timer; | 817 | struct timer_list timer; |
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 4be05847f86f..cc6ffba74592 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c | |||
@@ -95,6 +95,7 @@ MODULE_PARM_DESC(debug, "default debug msglevel"); | |||
95 | module_param(use_multi, int, 0); | 95 | module_param(use_multi, int, 0); |
96 | MODULE_PARM_DESC(use_multi, "use per-CPU queues"); | 96 | MODULE_PARM_DESC(use_multi, "use per-CPU queues"); |
97 | #endif | 97 | #endif |
98 | static struct workqueue_struct *bnx2x_wq; | ||
98 | 99 | ||
99 | enum bnx2x_board_type { | 100 | enum bnx2x_board_type { |
100 | BCM57710 = 0, | 101 | BCM57710 = 0, |
@@ -671,7 +672,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw) | |||
671 | synchronize_irq(bp->pdev->irq); | 672 | synchronize_irq(bp->pdev->irq); |
672 | 673 | ||
673 | /* make sure sp_task is not running */ | 674 | /* make sure sp_task is not running */ |
674 | cancel_work_sync(&bp->sp_task); | 675 | cancel_delayed_work(&bp->sp_task); |
676 | flush_workqueue(bnx2x_wq); | ||
675 | } | 677 | } |
676 | 678 | ||
677 | /* fast path */ | 679 | /* fast path */ |
@@ -1660,7 +1662,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) | |||
1660 | 1662 | ||
1661 | 1663 | ||
1662 | if (unlikely(status & 0x1)) { | 1664 | if (unlikely(status & 0x1)) { |
1663 | schedule_work(&bp->sp_task); | 1665 | queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); |
1664 | 1666 | ||
1665 | status &= ~0x1; | 1667 | status &= ~0x1; |
1666 | if (!status) | 1668 | if (!status) |
@@ -2820,7 +2822,7 @@ static void bnx2x_attn_int(struct bnx2x *bp) | |||
2820 | 2822 | ||
2821 | static void bnx2x_sp_task(struct work_struct *work) | 2823 | static void bnx2x_sp_task(struct work_struct *work) |
2822 | { | 2824 | { |
2823 | struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); | 2825 | struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work); |
2824 | u16 status; | 2826 | u16 status; |
2825 | 2827 | ||
2826 | 2828 | ||
@@ -2875,7 +2877,7 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) | |||
2875 | return IRQ_HANDLED; | 2877 | return IRQ_HANDLED; |
2876 | #endif | 2878 | #endif |
2877 | 2879 | ||
2878 | schedule_work(&bp->sp_task); | 2880 | queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); |
2879 | 2881 | ||
2880 | return IRQ_HANDLED; | 2882 | return IRQ_HANDLED; |
2881 | } | 2883 | } |
@@ -7501,7 +7503,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) | |||
7501 | 7503 | ||
7502 | mutex_init(&bp->port.phy_mutex); | 7504 | mutex_init(&bp->port.phy_mutex); |
7503 | 7505 | ||
7504 | INIT_WORK(&bp->sp_task, bnx2x_sp_task); | 7506 | INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); |
7505 | INIT_WORK(&bp->reset_task, bnx2x_reset_task); | 7507 | INIT_WORK(&bp->reset_task, bnx2x_reset_task); |
7506 | 7508 | ||
7507 | rc = bnx2x_get_hwinfo(bp); | 7509 | rc = bnx2x_get_hwinfo(bp); |
@@ -10519,12 +10521,20 @@ static struct pci_driver bnx2x_pci_driver = { | |||
10519 | 10521 | ||
10520 | static int __init bnx2x_init(void) | 10522 | static int __init bnx2x_init(void) |
10521 | { | 10523 | { |
10524 | bnx2x_wq = create_singlethread_workqueue("bnx2x"); | ||
10525 | if (bnx2x_wq == NULL) { | ||
10526 | printk(KERN_ERR PFX "Cannot create workqueue\n"); | ||
10527 | return -ENOMEM; | ||
10528 | } | ||
10529 | |||
10522 | return pci_register_driver(&bnx2x_pci_driver); | 10530 | return pci_register_driver(&bnx2x_pci_driver); |
10523 | } | 10531 | } |
10524 | 10532 | ||
10525 | static void __exit bnx2x_cleanup(void) | 10533 | static void __exit bnx2x_cleanup(void) |
10526 | { | 10534 | { |
10527 | pci_unregister_driver(&bnx2x_pci_driver); | 10535 | pci_unregister_driver(&bnx2x_pci_driver); |
10536 | |||
10537 | destroy_workqueue(bnx2x_wq); | ||
10528 | } | 10538 | } |
10529 | 10539 | ||
10530 | module_init(bnx2x_init); | 10540 | module_init(bnx2x_init); |