diff options
| author | Michael Chan <mchan@broadcom.com> | 2010-06-01 11:05:36 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-06-02 05:26:40 -0400 |
| commit | f048fa9c8686119c3858a463cab6121dced7c0bf (patch) | |
| tree | c68dd0cc095559c348c8916b6e3372b4e0610e9a | |
| parent | fafeeb6c80e3842c6dc19d05de09a23f23eef0d8 (diff) | |
bnx2: Fix hang during rmmod bnx2.
The regression is caused by:
commit 4327ba435a56ada13eedf3eb332e583c7a0586a9
bnx2: Fix netpoll crash.
If ->open() and ->close() are called multiple times, the same napi structs
will be added to dev->napi_list multiple times, corrupting the dev->napi_list.
This causes free_netdev() to hang during rmmod.
We fix this by calling netif_napi_del() during ->close().
Also, bnx2_init_napi() must not be in the __devinit section since it is
called by ->open().
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/bnx2.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 188e356c30a3..949d7a9dcf92 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
| @@ -247,6 +247,7 @@ static const struct flash_spec flash_5709 = { | |||
| 247 | MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); | 247 | MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); |
| 248 | 248 | ||
| 249 | static void bnx2_init_napi(struct bnx2 *bp); | 249 | static void bnx2_init_napi(struct bnx2 *bp); |
| 250 | static void bnx2_del_napi(struct bnx2 *bp); | ||
| 250 | 251 | ||
| 251 | static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) | 252 | static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) |
| 252 | { | 253 | { |
| @@ -6270,6 +6271,7 @@ open_err: | |||
| 6270 | bnx2_free_skbs(bp); | 6271 | bnx2_free_skbs(bp); |
| 6271 | bnx2_free_irq(bp); | 6272 | bnx2_free_irq(bp); |
| 6272 | bnx2_free_mem(bp); | 6273 | bnx2_free_mem(bp); |
| 6274 | bnx2_del_napi(bp); | ||
| 6273 | return rc; | 6275 | return rc; |
| 6274 | } | 6276 | } |
| 6275 | 6277 | ||
| @@ -6537,6 +6539,7 @@ bnx2_close(struct net_device *dev) | |||
| 6537 | bnx2_free_irq(bp); | 6539 | bnx2_free_irq(bp); |
| 6538 | bnx2_free_skbs(bp); | 6540 | bnx2_free_skbs(bp); |
| 6539 | bnx2_free_mem(bp); | 6541 | bnx2_free_mem(bp); |
| 6542 | bnx2_del_napi(bp); | ||
| 6540 | bp->link_up = 0; | 6543 | bp->link_up = 0; |
| 6541 | netif_carrier_off(bp->dev); | 6544 | netif_carrier_off(bp->dev); |
| 6542 | bnx2_set_power_state(bp, PCI_D3hot); | 6545 | bnx2_set_power_state(bp, PCI_D3hot); |
| @@ -8227,7 +8230,16 @@ bnx2_bus_string(struct bnx2 *bp, char *str) | |||
| 8227 | return str; | 8230 | return str; |
| 8228 | } | 8231 | } |
| 8229 | 8232 | ||
| 8230 | static void __devinit | 8233 | static void |
| 8234 | bnx2_del_napi(struct bnx2 *bp) | ||
| 8235 | { | ||
| 8236 | int i; | ||
| 8237 | |||
| 8238 | for (i = 0; i < bp->irq_nvecs; i++) | ||
| 8239 | netif_napi_del(&bp->bnx2_napi[i].napi); | ||
| 8240 | } | ||
| 8241 | |||
| 8242 | static void | ||
| 8231 | bnx2_init_napi(struct bnx2 *bp) | 8243 | bnx2_init_napi(struct bnx2 *bp) |
| 8232 | { | 8244 | { |
| 8233 | int i; | 8245 | int i; |
