aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2011-11-04 05:14:59 -0400
committerDavid S. Miller <davem@davemloft.net>2011-11-04 17:31:47 -0400
commitb9e454826f22e17d1945bd282834c87aef8d0f95 (patch)
treee90abb4a6f8bc8bdb67b1b4bacd030bfad15b9ed /drivers
parent78f94dc7b10d98cf4cf8498d98581500d910c6b7 (diff)
tg3: Fix 4k tx bd segmentation code
The new 4k tx bd segmentation code had a bug in the error cleanup path. If the driver did not map all the physical fragments, the abort path would wind up advancing the producer index beyond the point where the setup code stopped. This would ultimately turn into a tx recovery error where the driver would expect the skb pointer to be set when it isn't. This patch fixes the problem, and then makes the code a little easier to understand. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c47
1 files changed, 24 insertions, 23 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 35901630a65..507b73b979f 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -6444,31 +6444,26 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget,
6444 hwbug = 1; 6444 hwbug = 1;
6445 6445
6446 if (tg3_flag(tp, 4K_FIFO_LIMIT)) { 6446 if (tg3_flag(tp, 4K_FIFO_LIMIT)) {
6447 u32 prvidx = *entry;
6447 u32 tmp_flag = flags & ~TXD_FLAG_END; 6448 u32 tmp_flag = flags & ~TXD_FLAG_END;
6448 while (len > TG3_TX_BD_DMA_MAX) { 6449 while (len > TG3_TX_BD_DMA_MAX && *budget) {
6449 u32 frag_len = TG3_TX_BD_DMA_MAX; 6450 u32 frag_len = TG3_TX_BD_DMA_MAX;
6450 len -= TG3_TX_BD_DMA_MAX; 6451 len -= TG3_TX_BD_DMA_MAX;
6451 6452
6452 if (len) { 6453 /* Avoid the 8byte DMA problem */
6453 tnapi->tx_buffers[*entry].fragmented = true; 6454 if (len <= 8) {
6454 /* Avoid the 8byte DMA problem */ 6455 len += TG3_TX_BD_DMA_MAX / 2;
6455 if (len <= 8) { 6456 frag_len = TG3_TX_BD_DMA_MAX / 2;
6456 len += TG3_TX_BD_DMA_MAX / 2;
6457 frag_len = TG3_TX_BD_DMA_MAX / 2;
6458 }
6459 } else
6460 tmp_flag = flags;
6461
6462 if (*budget) {
6463 tg3_tx_set_bd(&tnapi->tx_ring[*entry], map,
6464 frag_len, tmp_flag, mss, vlan);
6465 (*budget)--;
6466 *entry = NEXT_TX(*entry);
6467 } else {
6468 hwbug = 1;
6469 break;
6470 } 6457 }
6471 6458
6459 tnapi->tx_buffers[*entry].fragmented = true;
6460
6461 tg3_tx_set_bd(&tnapi->tx_ring[*entry], map,
6462 frag_len, tmp_flag, mss, vlan);
6463 *budget -= 1;
6464 prvidx = *entry;
6465 *entry = NEXT_TX(*entry);
6466
6472 map += frag_len; 6467 map += frag_len;
6473 } 6468 }
6474 6469
@@ -6476,10 +6471,11 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget,
6476 if (*budget) { 6471 if (*budget) {
6477 tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, 6472 tg3_tx_set_bd(&tnapi->tx_ring[*entry], map,
6478 len, flags, mss, vlan); 6473 len, flags, mss, vlan);
6479 (*budget)--; 6474 *budget -= 1;
6480 *entry = NEXT_TX(*entry); 6475 *entry = NEXT_TX(*entry);
6481 } else { 6476 } else {
6482 hwbug = 1; 6477 hwbug = 1;
6478 tnapi->tx_buffers[prvidx].fragmented = false;
6483 } 6479 }
6484 } 6480 }
6485 } else { 6481 } else {
@@ -6561,6 +6557,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
6561 dev_kfree_skb(new_skb); 6557 dev_kfree_skb(new_skb);
6562 ret = -1; 6558 ret = -1;
6563 } else { 6559 } else {
6560 u32 save_entry = *entry;
6561
6564 base_flags |= TXD_FLAG_END; 6562 base_flags |= TXD_FLAG_END;
6565 6563
6566 tnapi->tx_buffers[*entry].skb = new_skb; 6564 tnapi->tx_buffers[*entry].skb = new_skb;
@@ -6570,7 +6568,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
6570 if (tg3_tx_frag_set(tnapi, entry, budget, new_addr, 6568 if (tg3_tx_frag_set(tnapi, entry, budget, new_addr,
6571 new_skb->len, base_flags, 6569 new_skb->len, base_flags,
6572 mss, vlan)) { 6570 mss, vlan)) {
6573 tg3_tx_skb_unmap(tnapi, *entry, 0); 6571 tg3_tx_skb_unmap(tnapi, save_entry, 0);
6574 dev_kfree_skb(new_skb); 6572 dev_kfree_skb(new_skb);
6575 ret = -1; 6573 ret = -1;
6576 } 6574 }
@@ -6786,11 +6784,14 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
6786 if (dma_mapping_error(&tp->pdev->dev, mapping)) 6784 if (dma_mapping_error(&tp->pdev->dev, mapping))
6787 goto dma_error; 6785 goto dma_error;
6788 6786
6789 if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, 6787 if (!budget ||
6788 tg3_tx_frag_set(tnapi, &entry, &budget, mapping,
6790 len, base_flags | 6789 len, base_flags |
6791 ((i == last) ? TXD_FLAG_END : 0), 6790 ((i == last) ? TXD_FLAG_END : 0),
6792 tmp_mss, vlan)) 6791 tmp_mss, vlan)) {
6793 would_hit_hwbug = 1; 6792 would_hit_hwbug = 1;
6793 break;
6794 }
6794 } 6795 }
6795 } 6796 }
6796 6797