diff options
author | Michael Chan <mchan@broadcom.com> | 2006-07-25 19:38:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-07-25 19:38:29 -0400 |
commit | 32d8c5724b7b05c7d8f7386c49432104cc222e32 (patch) | |
tree | 6aead952a08a295135c5faf7da5ff8523a6e4616 | |
parent | b9ec6c1b917e2e43a058a78198d54aeca3d71c6f (diff) |
[TG3]: Handle tg3_init_rings() failures
Handle dev_alloc_skb() failures when initializing the RX rings.
Without proper handling, the driver will crash when using a partial
ring.
Thanks to Stephane Doyon <sdoyon@max-t.com> for reporting the bug and
providing the initial patch.
Howie Xu <howie@vmware.com> also reported the same issue.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/tg3.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 1253cec6ebdc..d66b06f2b865 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -4258,7 +4258,7 @@ static void tg3_free_rings(struct tg3 *tp) | |||
4258 | * end up in the driver. tp->{tx,}lock are held and thus | 4258 | * end up in the driver. tp->{tx,}lock are held and thus |
4259 | * we may not sleep. | 4259 | * we may not sleep. |
4260 | */ | 4260 | */ |
4261 | static void tg3_init_rings(struct tg3 *tp) | 4261 | static int tg3_init_rings(struct tg3 *tp) |
4262 | { | 4262 | { |
4263 | u32 i; | 4263 | u32 i; |
4264 | 4264 | ||
@@ -4307,18 +4307,38 @@ static void tg3_init_rings(struct tg3 *tp) | |||
4307 | 4307 | ||
4308 | /* Now allocate fresh SKBs for each rx ring. */ | 4308 | /* Now allocate fresh SKBs for each rx ring. */ |
4309 | for (i = 0; i < tp->rx_pending; i++) { | 4309 | for (i = 0; i < tp->rx_pending; i++) { |
4310 | if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, | 4310 | if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) { |
4311 | -1, i) < 0) | 4311 | printk(KERN_WARNING PFX |
4312 | "%s: Using a smaller RX standard ring, " | ||
4313 | "only %d out of %d buffers were allocated " | ||
4314 | "successfully.\n", | ||
4315 | tp->dev->name, i, tp->rx_pending); | ||
4316 | if (i == 0) | ||
4317 | return -ENOMEM; | ||
4318 | tp->rx_pending = i; | ||
4312 | break; | 4319 | break; |
4320 | } | ||
4313 | } | 4321 | } |
4314 | 4322 | ||
4315 | if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { | 4323 | if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) { |
4316 | for (i = 0; i < tp->rx_jumbo_pending; i++) { | 4324 | for (i = 0; i < tp->rx_jumbo_pending; i++) { |
4317 | if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, | 4325 | if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO, |
4318 | -1, i) < 0) | 4326 | -1, i) < 0) { |
4327 | printk(KERN_WARNING PFX | ||
4328 | "%s: Using a smaller RX jumbo ring, " | ||
4329 | "only %d out of %d buffers were " | ||
4330 | "allocated successfully.\n", | ||
4331 | tp->dev->name, i, tp->rx_jumbo_pending); | ||
4332 | if (i == 0) { | ||
4333 | tg3_free_rings(tp); | ||
4334 | return -ENOMEM; | ||
4335 | } | ||
4336 | tp->rx_jumbo_pending = i; | ||
4319 | break; | 4337 | break; |
4338 | } | ||
4320 | } | 4339 | } |
4321 | } | 4340 | } |
4341 | return 0; | ||
4322 | } | 4342 | } |
4323 | 4343 | ||
4324 | /* | 4344 | /* |
@@ -5969,7 +5989,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) | |||
5969 | * can only do this after the hardware has been | 5989 | * can only do this after the hardware has been |
5970 | * successfully reset. | 5990 | * successfully reset. |
5971 | */ | 5991 | */ |
5972 | tg3_init_rings(tp); | 5992 | err = tg3_init_rings(tp); |
5993 | if (err) | ||
5994 | return err; | ||
5973 | 5995 | ||
5974 | /* This value is determined during the probe time DMA | 5996 | /* This value is determined during the probe time DMA |
5975 | * engine test, tg3_test_dma. | 5997 | * engine test, tg3_test_dma. |