]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 1cf167f27ad2720af11ee8aa350009342f909e70 Mon Sep 17 00:00:00 2001 |
2 | From: Eilon Greenstein <eilong@broadcom.com> | |
3 | Date: Wed, 14 Jan 2009 21:22:18 -0800 | |
4 | Subject: bnx2x: Using singlethread work queue | |
5 | Acked-by: Karsten Keil <kkeil@novell.com> | |
6 | Reference: bnc#472500 | |
7 | ||
8 | Since slow-path events, including link update, are handled in | |
9 | work-queue, a race condition was introduced in the self-test that | |
10 | sometimes caused the link status to fail: the self-test was running | |
11 | under RTNL lock, and if the link-watch was scheduled it stoped the | |
12 | shared work-queue (waiting for the RTNL lock) and so the link update | |
13 | event was not handled until the self-test ended (releasing the RTNL | |
14 | lock) with failure (since the link status was not updated) | |
15 | ||
16 | Signed-off-by: Eilon Greenstein <eilong@broadcom.com> | |
17 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
18 | --- | |
19 | drivers/net/bnx2x.h | 2 +- | |
20 | drivers/net/bnx2x_main.c | 20 +++++++++++++++----- | |
21 | 2 files changed, 16 insertions(+), 6 deletions(-) | |
22 | ||
23 | Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h | |
24 | =================================================================== | |
25 | --- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x.h | |
26 | +++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x.h | |
27 | @@ -811,7 +811,7 @@ struct bnx2x { | |
28 | int pm_cap; | |
29 | int pcie_cap; | |
30 | ||
31 | - struct work_struct sp_task; | |
32 | + struct delayed_work sp_task; | |
33 | struct work_struct reset_task; | |
34 | ||
35 | struct timer_list timer; | |
36 | Index: linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c | |
37 | =================================================================== | |
38 | --- linux-2.6.27-bnx2x_2.orig/drivers/net/bnx2x_main.c | |
39 | +++ linux-2.6.27-bnx2x_2/drivers/net/bnx2x_main.c | |
40 | @@ -95,6 +95,7 @@ MODULE_PARM_DESC(debug, "default debug m | |
41 | module_param(use_multi, int, 0); | |
42 | MODULE_PARM_DESC(use_multi, "use per-CPU queues"); | |
43 | #endif | |
44 | +static struct workqueue_struct *bnx2x_wq; | |
45 | ||
46 | enum bnx2x_board_type { | |
47 | BCM57710 = 0, | |
48 | @@ -671,7 +672,8 @@ static void bnx2x_int_disable_sync(struc | |
49 | synchronize_irq(bp->pdev->irq); | |
50 | ||
51 | /* make sure sp_task is not running */ | |
52 | - cancel_work_sync(&bp->sp_task); | |
53 | + cancel_delayed_work(&bp->sp_task); | |
54 | + flush_workqueue(bnx2x_wq); | |
55 | } | |
56 | ||
57 | /* fast path */ | |
58 | @@ -1663,7 +1665,7 @@ static irqreturn_t bnx2x_interrupt(int i | |
59 | ||
60 | ||
61 | if (unlikely(status & 0x1)) { | |
62 | - schedule_work(&bp->sp_task); | |
63 | + queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); | |
64 | ||
65 | status &= ~0x1; | |
66 | if (!status) | |
67 | @@ -2823,7 +2825,7 @@ static void bnx2x_attn_int(struct bnx2x | |
68 | ||
69 | static void bnx2x_sp_task(struct work_struct *work) | |
70 | { | |
71 | - struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); | |
72 | + struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work); | |
73 | u16 status; | |
74 | ||
75 | ||
76 | @@ -2878,7 +2880,7 @@ static irqreturn_t bnx2x_msix_sp_int(int | |
77 | return IRQ_HANDLED; | |
78 | #endif | |
79 | ||
80 | - schedule_work(&bp->sp_task); | |
81 | + queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); | |
82 | ||
83 | return IRQ_HANDLED; | |
84 | } | |
85 | @@ -7504,7 +7506,7 @@ static int __devinit bnx2x_init_bp(struc | |
86 | ||
87 | mutex_init(&bp->port.phy_mutex); | |
88 | ||
89 | - INIT_WORK(&bp->sp_task, bnx2x_sp_task); | |
90 | + INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); | |
91 | INIT_WORK(&bp->reset_task, bnx2x_reset_task); | |
92 | ||
93 | rc = bnx2x_get_hwinfo(bp); | |
94 | @@ -10522,12 +10524,20 @@ static struct pci_driver bnx2x_pci_drive | |
95 | ||
96 | static int __init bnx2x_init(void) | |
97 | { | |
98 | + bnx2x_wq = create_singlethread_workqueue("bnx2x"); | |
99 | + if (bnx2x_wq == NULL) { | |
100 | + printk(KERN_ERR PFX "Cannot create workqueue\n"); | |
101 | + return -ENOMEM; | |
102 | + } | |
103 | + | |
104 | return pci_register_driver(&bnx2x_pci_driver); | |
105 | } | |
106 | ||
107 | static void __exit bnx2x_cleanup(void) | |
108 | { | |
109 | pci_unregister_driver(&bnx2x_pci_driver); | |
110 | + | |
111 | + destroy_workqueue(bnx2x_wq); | |
112 | } | |
113 | ||
114 | module_init(bnx2x_init); |