From df8944cf5cd3794c46e95e0404038376ee7f8dda Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:46 +0000 Subject: tg3: Reintroduce tg3_tx_ring_info The following patches will require the use of an additional flag in the ring_info structure. The use of this flag is tx path specific, so this patch defines a specialized ring_info structure. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 803576568154..3708159548fc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4824,7 +4824,7 @@ static void tg3_tx(struct tg3_napi *tnapi) txq = netdev_get_tx_queue(tp->dev, index); while (sw_idx != hw_idx) { - struct ring_info *ri = &tnapi->tx_buffers[sw_idx]; + struct tg3_tx_ring_info *ri = &tnapi->tx_buffers[sw_idx]; struct sk_buff *skb = ri->skb; int i, tx_bug = 0; @@ -5929,7 +5929,7 @@ static void tg3_skb_error_unmap(struct tg3_napi *tnapi, { int i; u32 entry = tnapi->tx_prod; - struct ring_info *txb = &tnapi->tx_buffers[entry]; + struct tg3_tx_ring_info *txb = &tnapi->tx_buffers[entry]; pci_unmap_single(tnapi->tp->pdev, dma_unmap_addr(txb, mapping), @@ -6603,7 +6603,7 @@ static void tg3_free_rings(struct tg3 *tp) continue; for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct ring_info *txp; + struct tg3_tx_ring_info *txp; struct sk_buff *skb; unsigned int k; @@ -6762,9 +6762,9 @@ static int tg3_alloc_consistent(struct tg3 *tp) */ if ((!i && !tg3_flag(tp, ENABLE_TSS)) || (i && tg3_flag(tp, ENABLE_TSS))) { - tnapi->tx_buffers = kzalloc(sizeof(struct ring_info) * - TG3_TX_RING_SIZE, - GFP_KERNEL); + tnapi->tx_buffers = kzalloc( + sizeof(struct tg3_tx_ring_info) * + TG3_TX_RING_SIZE, GFP_KERNEL); if (!tnapi->tx_buffers) goto err_out; -- cgit v1.2.3 From 92cd3a17ce9c719abb4c28dee3438e0c641f8de4 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:47 +0000 Subject: tg3: Simplify tx bd assignments In the following patches, the process the driver will use to assign skb fragments to transmit BDs will get more complicated. To prepare for that new code, this patch seeks to simplify how transmit BDs are populated. It does this by separating the code that assigns the BD members from the logic that controls how the fields are set. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 76 +++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 39 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3708159548fc..8dfde34b2415 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5901,27 +5901,16 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, #endif } -static void tg3_set_txd(struct tg3_napi *tnapi, int entry, - dma_addr_t mapping, int len, u32 flags, - u32 mss_and_is_end) +static inline void tg3_tx_set_bd(struct tg3_napi *tnapi, u32 entry, + dma_addr_t mapping, u32 len, u32 flags, + u32 mss, u32 vlan) { - struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry]; - int is_end = (mss_and_is_end & 0x1); - u32 mss = (mss_and_is_end >> 1); - u32 vlan_tag = 0; + struct tg3_tx_buffer_desc *txbd = &tnapi->tx_ring[entry]; - if (is_end) - flags |= TXD_FLAG_END; - if (flags & TXD_FLAG_VLAN) { - vlan_tag = flags >> 16; - flags &= 0xffff; - } - vlan_tag |= (mss << TXD_MSS_SHIFT); - - txd->addr_hi = ((u64) mapping >> 32); - txd->addr_lo = ((u64) mapping & 0xffffffff); - txd->len_flags = (len << TXD_LEN_SHIFT) | flags; - txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; + txbd->addr_hi = ((u64) mapping >> 32); + txbd->addr_lo = ((u64) mapping & 0xffffffff); + txbd->len_flags = (len << TXD_LEN_SHIFT) | (flags & 0x0000ffff); + txbd->vlan_tag = (mss << TXD_MSS_SHIFT) | (vlan << TXD_VLAN_TAG_SHIFT); } static void tg3_skb_error_unmap(struct tg3_napi *tnapi, @@ -5950,7 +5939,7 @@ static void tg3_skb_error_unmap(struct tg3_napi *tnapi, /* Workaround 4GB and 40-bit hardware DMA bugs. */ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, struct sk_buff *skb, - u32 base_flags, u32 mss) + u32 base_flags, u32 mss, u32 vlan) { struct tg3 *tp = tnapi->tp; struct sk_buff *new_skb; @@ -5988,12 +5977,14 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, ret = -1; dev_kfree_skb(new_skb); } else { + base_flags |= TXD_FLAG_END; + tnapi->tx_buffers[entry].skb = new_skb; dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, new_addr); - tg3_set_txd(tnapi, entry, new_addr, new_skb->len, - base_flags, 1 | (mss << 1)); + tg3_tx_set_bd(tnapi, entry, new_addr, new_skb->len, + base_flags, mss, vlan); } } @@ -6051,7 +6042,7 @@ tg3_tso_bug_end: static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); - u32 len, entry, base_flags, mss; + u32 len, entry, base_flags, mss, vlan = 0; int i = -1, would_hit_hwbug; dma_addr_t mapping; struct tg3_napi *tnapi; @@ -6153,9 +6144,12 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - if (vlan_tx_tag_present(skb)) - base_flags |= (TXD_FLAG_VLAN | - (vlan_tx_tag_get(skb) << 16)); +#ifdef BCM_KERNEL_SUPPORTS_8021Q + if (vlan_tx_tag_present(skb)) { + base_flags |= TXD_FLAG_VLAN; + vlan = vlan_tx_tag_get(skb); + } +#endif if (tg3_flag(tp, USE_JUMBO_BDFLAG) && !mss && skb->len > VLAN_ETH_FRAME_LEN) @@ -6186,13 +6180,21 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tg3_flag(tp, 5701_DMA_BUG)) would_hit_hwbug = 1; - tg3_set_txd(tnapi, entry, mapping, len, base_flags, - (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); + tg3_tx_set_bd(tnapi, entry, mapping, len, base_flags | + ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), + mss, vlan); entry = NEXT_TX(entry); /* Now loop through additional data fragments, and queue them. */ if (skb_shinfo(skb)->nr_frags > 0) { + u32 tmp_mss = mss; + + if (!tg3_flag(tp, HW_TSO_1) && + !tg3_flag(tp, HW_TSO_2) && + !tg3_flag(tp, HW_TSO_3)) + tmp_mss = 0; + last = skb_shinfo(skb)->nr_frags - 1; for (i = 0; i <= last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -6219,14 +6221,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tg3_40bit_overflow_test(tp, mapping, len)) would_hit_hwbug = 1; - if (tg3_flag(tp, HW_TSO_1) || - tg3_flag(tp, HW_TSO_2) || - tg3_flag(tp, HW_TSO_3)) - tg3_set_txd(tnapi, entry, mapping, len, - base_flags, (i == last)|(mss << 1)); - else - tg3_set_txd(tnapi, entry, mapping, len, - base_flags, (i == last)); + tg3_tx_set_bd(tnapi, entry, mapping, len, base_flags | + ((i == last) ? TXD_FLAG_END : 0), + tmp_mss, vlan); entry = NEXT_TX(entry); } @@ -6238,7 +6235,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) /* If the workaround fails due to memory/mapping * failure, silently drop this packet. */ - if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, mss)) + if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, + mss, vlan)) goto out_unlock; entry = NEXT_TX(tnapi->tx_prod); @@ -11370,8 +11368,8 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) rx_start_idx = rnapi->hw_status->idx[0].rx_producer; - tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, - base_flags, (mss << 1) | 1); + tg3_tx_set_bd(tnapi, tnapi->tx_prod, map, tx_len, + base_flags | TXD_FLAG_END, mss, 0); tnapi->tx_prod++; -- cgit v1.2.3 From 13350ea78bd687a229af0f6052d2f45aa50a6524 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:48 +0000 Subject: tg3: Remove short DMA check for 1st fragment The first fragment of an skb should always be greater than 8 bytes. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 8dfde34b2415..0f5bcf79d727 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6168,9 +6168,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = 0; - if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8) - would_hit_hwbug = 1; - if (tg3_4g_overflow_test(mapping, len)) would_hit_hwbug = 1; -- cgit v1.2.3 From 0d681b27b0efc962a3038a316e78373de7bfe1ce Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:49 +0000 Subject: tg3: Generalize tg3_skb_error_unmap() In the following patches, unmapping skb fragments will get just as complicated as mapping them. This patch generalizes tg3_skb_error_unmap() and makes it the one-stop-shop for skb unmapping. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 48 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0f5bcf79d727..3f69f1ace267 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5913,13 +5913,15 @@ static inline void tg3_tx_set_bd(struct tg3_napi *tnapi, u32 entry, txbd->vlan_tag = (mss << TXD_MSS_SHIFT) | (vlan << TXD_VLAN_TAG_SHIFT); } -static void tg3_skb_error_unmap(struct tg3_napi *tnapi, - struct sk_buff *skb, int last) +static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) { int i; - u32 entry = tnapi->tx_prod; + struct sk_buff *skb; struct tg3_tx_ring_info *txb = &tnapi->tx_buffers[entry]; + skb = txb->skb; + txb->skb = NULL; + pci_unmap_single(tnapi->tp->pdev, dma_unmap_addr(txb, mapping), skb_headlen(skb), @@ -6227,7 +6229,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (would_hit_hwbug) { - tg3_skb_error_unmap(tnapi, skb, i); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i); /* If the workaround fails due to memory/mapping * failure, silently drop this packet. @@ -6264,7 +6266,7 @@ out_unlock: return NETDEV_TX_OK; dma_error: - tg3_skb_error_unmap(tnapi, skb, i); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i); dev_kfree_skb(skb); tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; return NETDEV_TX_OK; @@ -6597,35 +6599,13 @@ static void tg3_free_rings(struct tg3 *tp) if (!tnapi->tx_buffers) continue; - for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct tg3_tx_ring_info *txp; - struct sk_buff *skb; - unsigned int k; + for (i = 0; i < TG3_TX_RING_SIZE; i++) { + struct sk_buff *skb = tnapi->tx_buffers[i].skb; - txp = &tnapi->tx_buffers[i]; - skb = txp->skb; - - if (skb == NULL) { - i++; + if (!skb) continue; - } - pci_unmap_single(tp->pdev, - dma_unmap_addr(txp, mapping), - skb_headlen(skb), - PCI_DMA_TODEVICE); - txp->skb = NULL; - - i++; - - for (k = 0; k < skb_shinfo(skb)->nr_frags; k++) { - txp = &tnapi->tx_buffers[i & (TG3_TX_RING_SIZE - 1)]; - pci_unmap_page(tp->pdev, - dma_unmap_addr(txp, mapping), - skb_shinfo(skb)->frags[k].size, - PCI_DMA_TODEVICE); - i++; - } + tg3_tx_skb_unmap(tnapi, i, skb_shinfo(skb)->nr_frags); dev_kfree_skb_any(skb); } @@ -11358,6 +11338,10 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) return -EIO; } + val = tnapi->tx_prod; + tnapi->tx_buffers[val].skb = skb; + dma_unmap_addr_set(&tnapi->tx_buffers[val], mapping, map); + tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | rnapi->coal_now); @@ -11389,7 +11373,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) break; } - pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod - 1, 0); dev_kfree_skb(skb); if (tx_idx != tnapi->tx_prod) -- cgit v1.2.3 From e01ee14d499e5d09c0a9db0cac2545a018849e3d Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:50 +0000 Subject: tg3: Add partial fragment unmapping code The following patches are going to break skb fragments into smaller sizes. This patch attempts to make the change easier to digest by only addressing the skb teardown portion. The patch modifies the driver to skip over any BDs that have a flag set that indicates the BD isn't the beginning of an skb fragment. Such BDs were a result of segmentation and do not need a pci_unmap_page() call. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 26 ++++++++++++++++++++++++++ drivers/net/tg3.h | 1 + 2 files changed, 27 insertions(+) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3f69f1ace267..90b68a229745 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4840,6 +4840,12 @@ static void tg3_tx(struct tg3_napi *tnapi) ri->skb = NULL; + while (ri->fragmented) { + ri->fragmented = false; + sw_idx = NEXT_TX(sw_idx); + ri = &tnapi->tx_buffers[sw_idx]; + } + sw_idx = NEXT_TX(sw_idx); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { @@ -4851,6 +4857,13 @@ static void tg3_tx(struct tg3_napi *tnapi) dma_unmap_addr(ri, mapping), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); + + while (ri->fragmented) { + ri->fragmented = false; + sw_idx = NEXT_TX(sw_idx); + ri = &tnapi->tx_buffers[sw_idx]; + } + sw_idx = NEXT_TX(sw_idx); } @@ -5926,6 +5939,13 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) dma_unmap_addr(txb, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); + + while (txb->fragmented) { + txb->fragmented = false; + entry = NEXT_TX(entry); + txb = &tnapi->tx_buffers[entry]; + } + for (i = 0; i < last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -5935,6 +5955,12 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) pci_unmap_page(tnapi->tp->pdev, dma_unmap_addr(txb, mapping), frag->size, PCI_DMA_TODEVICE); + + while (txb->fragmented) { + txb->fragmented = false; + entry = NEXT_TX(entry); + txb = &tnapi->tx_buffers[entry]; + } } } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index f6986ca50d80..466dd7add12b 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2655,6 +2655,7 @@ struct ring_info { struct tg3_tx_ring_info { struct sk_buff *skb; DEFINE_DMA_UNMAP_ADDR(mapping); + bool fragmented; }; struct tg3_link_config { -- cgit v1.2.3 From d1a3b7377d3b6a01ec5f70adb32173b13233aabf Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:51 +0000 Subject: tg3: Consolidate code that calls tg3_tx_set_bd() This patch consolidates all code that populates tx BDs into a single routine. Setting tx BDs needs to be more carefully controlled to see if workarounds need to be applied. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 79 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 37 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 90b68a229745..7f816a0ee421 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5914,18 +5914,37 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, #endif } -static inline void tg3_tx_set_bd(struct tg3_napi *tnapi, u32 entry, +static inline void tg3_tx_set_bd(struct tg3_tx_buffer_desc *txbd, dma_addr_t mapping, u32 len, u32 flags, u32 mss, u32 vlan) { - struct tg3_tx_buffer_desc *txbd = &tnapi->tx_ring[entry]; - txbd->addr_hi = ((u64) mapping >> 32); txbd->addr_lo = ((u64) mapping & 0xffffffff); txbd->len_flags = (len << TXD_LEN_SHIFT) | (flags & 0x0000ffff); txbd->vlan_tag = (mss << TXD_MSS_SHIFT) | (vlan << TXD_VLAN_TAG_SHIFT); } +static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 entry, + dma_addr_t map, u32 len, u32 flags, + u32 mss, u32 vlan) +{ + struct tg3 *tp = tnapi->tp; + bool hwbug = false; + + if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8) + hwbug = 1; + + if (tg3_4g_overflow_test(map, len)) + hwbug = 1; + + if (tg3_40bit_overflow_test(tp, map, len)) + hwbug = 1; + + tg3_tx_set_bd(&tnapi->tx_ring[entry], map, len, flags, mss, vlan); + + return hwbug; +} + static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) { int i; @@ -5993,17 +6012,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, PCI_DMA_TODEVICE); /* Make sure the mapping succeeded */ if (pci_dma_mapping_error(tp->pdev, new_addr)) { - ret = -1; dev_kfree_skb(new_skb); - - /* Make sure new skb does not cross any 4G boundaries. - * Drop the packet if it does. - */ - } else if (tg3_4g_overflow_test(new_addr, new_skb->len)) { - pci_unmap_single(tp->pdev, new_addr, new_skb->len, - PCI_DMA_TODEVICE); ret = -1; - dev_kfree_skb(new_skb); } else { base_flags |= TXD_FLAG_END; @@ -6011,8 +6021,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, new_addr); - tg3_tx_set_bd(tnapi, entry, new_addr, new_skb->len, - base_flags, mss, vlan); + if (tg3_tx_frag_set(tnapi, entry, new_addr, + new_skb->len, base_flags, + mss, vlan)) { + tg3_tx_skb_unmap(tnapi, entry, 0); + dev_kfree_skb(new_skb); + ret = -1; + } } } @@ -6196,18 +6211,13 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = 0; - if (tg3_4g_overflow_test(mapping, len)) - would_hit_hwbug = 1; - - if (tg3_40bit_overflow_test(tp, mapping, len)) - would_hit_hwbug = 1; - if (tg3_flag(tp, 5701_DMA_BUG)) would_hit_hwbug = 1; - tg3_tx_set_bd(tnapi, entry, mapping, len, base_flags | - ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), - mss, vlan); + if (tg3_tx_frag_set(tnapi, entry, mapping, len, base_flags | + ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), + mss, vlan)) + would_hit_hwbug = 1; entry = NEXT_TX(entry); @@ -6236,20 +6246,11 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (pci_dma_mapping_error(tp->pdev, mapping)) goto dma_error; - if (tg3_flag(tp, SHORT_DMA_BUG) && - len <= 8) - would_hit_hwbug = 1; - - if (tg3_4g_overflow_test(mapping, len)) - would_hit_hwbug = 1; - - if (tg3_40bit_overflow_test(tp, mapping, len)) + if (tg3_tx_frag_set(tnapi, entry, mapping, len, + base_flags | ((i == last) ? TXD_FLAG_END : 0), + tmp_mss, vlan)) would_hit_hwbug = 1; - tg3_tx_set_bd(tnapi, entry, mapping, len, base_flags | - ((i == last) ? TXD_FLAG_END : 0), - tmp_mss, vlan); - entry = NEXT_TX(entry); } } @@ -11375,8 +11376,12 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) rx_start_idx = rnapi->hw_status->idx[0].rx_producer; - tg3_tx_set_bd(tnapi, tnapi->tx_prod, map, tx_len, - base_flags | TXD_FLAG_END, mss, 0); + if (tg3_tx_frag_set(tnapi, tnapi->tx_prod, map, tx_len, + base_flags | TXD_FLAG_END, mss, 0)) { + tnapi->tx_buffers[val].skb = NULL; + dev_kfree_skb(skb); + return -EIO; + } tnapi->tx_prod++; -- cgit v1.2.3 From 84b67b27e9531e9a70c9e8cd952d66c55f4d0ddb Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:52 +0000 Subject: tg3: Add tx BD budgeting code As the driver breaks large skb fragments into smaller submissions to the hardware, there is a new danger that BDs might get exhausted before all fragments have been mapped. This patch adds code to make sure tx BDs aren't oversubscribed and flag the condition if it happens. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7f816a0ee421..b93ba3d2192a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5924,7 +5924,7 @@ static inline void tg3_tx_set_bd(struct tg3_tx_buffer_desc *txbd, txbd->vlan_tag = (mss << TXD_MSS_SHIFT) | (vlan << TXD_VLAN_TAG_SHIFT); } -static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 entry, +static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, dma_addr_t map, u32 len, u32 flags, u32 mss, u32 vlan) { @@ -5940,7 +5940,14 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 entry, if (tg3_40bit_overflow_test(tp, map, len)) hwbug = 1; - tg3_tx_set_bd(&tnapi->tx_ring[entry], map, len, flags, mss, vlan); + if (*budget) { + tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, + len, flags, mss, vlan); + (*budget)--; + } else + hwbug = 1; + + *entry = NEXT_TX(*entry); return hwbug; } @@ -5986,12 +5993,12 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) /* Workaround 4GB and 40-bit hardware DMA bugs. */ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, struct sk_buff *skb, + u32 *entry, u32 *budget, u32 base_flags, u32 mss, u32 vlan) { struct tg3 *tp = tnapi->tp; struct sk_buff *new_skb; dma_addr_t new_addr = 0; - u32 entry = tnapi->tx_prod; int ret = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) @@ -6017,14 +6024,14 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, } else { base_flags |= TXD_FLAG_END; - tnapi->tx_buffers[entry].skb = new_skb; - dma_unmap_addr_set(&tnapi->tx_buffers[entry], + tnapi->tx_buffers[*entry].skb = new_skb; + dma_unmap_addr_set(&tnapi->tx_buffers[*entry], mapping, new_addr); - if (tg3_tx_frag_set(tnapi, entry, new_addr, + if (tg3_tx_frag_set(tnapi, entry, budget, new_addr, new_skb->len, base_flags, mss, vlan)) { - tg3_tx_skb_unmap(tnapi, entry, 0); + tg3_tx_skb_unmap(tnapi, *entry, 0); dev_kfree_skb(new_skb); ret = -1; } @@ -6086,6 +6093,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss, vlan = 0; + u32 budget; int i = -1, would_hit_hwbug; dma_addr_t mapping; struct tg3_napi *tnapi; @@ -6097,12 +6105,14 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tg3_flag(tp, ENABLE_TSS)) tnapi++; + budget = tg3_tx_avail(tnapi); + /* We are running in BH disabled context with netif_tx_lock * and TX reclaim runs via tp->napi.poll inside of a software * interrupt. Furthermore, IRQ processing runs lockless so we have * no IRQ context deadlocks to worry about either. Rejoice! */ - if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(budget <= (skb_shinfo(skb)->nr_frags + 1))) { if (!netif_tx_queue_stopped(txq)) { netif_tx_stop_queue(txq); @@ -6214,13 +6224,11 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tg3_flag(tp, 5701_DMA_BUG)) would_hit_hwbug = 1; - if (tg3_tx_frag_set(tnapi, entry, mapping, len, base_flags | + if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, len, base_flags | ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), mss, vlan)) would_hit_hwbug = 1; - entry = NEXT_TX(entry); - /* Now loop through additional data fragments, and queue them. */ if (skb_shinfo(skb)->nr_frags > 0) { u32 tmp_mss = mss; @@ -6246,12 +6254,11 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (pci_dma_mapping_error(tp->pdev, mapping)) goto dma_error; - if (tg3_tx_frag_set(tnapi, entry, mapping, len, - base_flags | ((i == last) ? TXD_FLAG_END : 0), + if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, + len, base_flags | + ((i == last) ? TXD_FLAG_END : 0), tmp_mss, vlan)) would_hit_hwbug = 1; - - entry = NEXT_TX(entry); } } @@ -6261,11 +6268,11 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) /* If the workaround fails due to memory/mapping * failure, silently drop this packet. */ - if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, - mss, vlan)) + entry = tnapi->tx_prod; + budget = tg3_tx_avail(tnapi); + if (tigon3_dma_hwbug_workaround(tnapi, skb, &entry, &budget, + base_flags, mss, vlan)) goto out_unlock; - - entry = NEXT_TX(tnapi->tx_prod); } skb_tx_timestamp(skb); @@ -11206,6 +11213,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) { u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val; + u32 budget; struct sk_buff *skb, *rx_skb; u8 *tx_data; dma_addr_t map; @@ -11376,7 +11384,8 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) rx_start_idx = rnapi->hw_status->idx[0].rx_producer; - if (tg3_tx_frag_set(tnapi, tnapi->tx_prod, map, tx_len, + budget = tg3_tx_avail(tnapi); + if (tg3_tx_frag_set(tnapi, &val, &budget, map, tx_len, base_flags | TXD_FLAG_END, mss, 0)) { tnapi->tx_buffers[val].skb = NULL; dev_kfree_skb(skb); -- cgit v1.2.3 From e31aa9870627106aebddd280aab8ecb2f493246a Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:53 +0000 Subject: tg3: Break larger frags into 4k chunks for 5719 The 5719 has bug where RDMAs larger than 4k can cause problems. This patch works around the problem by dividing larger DMA requests into something the hardware can handle. Signed-off-by: Matt Carlson Reviewed-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++------ drivers/net/tg3.h | 1 + 2 files changed, 47 insertions(+), 6 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b93ba3d2192a..c77a39d6cd15 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -190,6 +190,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) /* minimum number of free TX descriptors required to wake up TX process */ #define TG3_TX_WAKEUP_THRESH(tnapi) ((tnapi)->tx_pending / 4) +#define TG3_TX_BD_DMA_MAX 4096 #define TG3_RAW_IP_ALIGN 2 @@ -5940,14 +5941,50 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, if (tg3_40bit_overflow_test(tp, map, len)) hwbug = 1; - if (*budget) { + if (tg3_flag(tp, 4K_FIFO_LIMIT)) { + u32 tmp_flag = flags & ~TXD_FLAG_END; + while (len > TG3_TX_BD_DMA_MAX) { + u32 frag_len = TG3_TX_BD_DMA_MAX; + len -= TG3_TX_BD_DMA_MAX; + + if (len) { + tnapi->tx_buffers[*entry].fragmented = true; + /* Avoid the 8byte DMA problem */ + if (len <= 8) { + len += TG3_TX_BD_DMA_MAX / 2; + frag_len = TG3_TX_BD_DMA_MAX / 2; + } + } else + tmp_flag = flags; + + if (*budget) { + tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, + frag_len, tmp_flag, mss, vlan); + (*budget)--; + *entry = NEXT_TX(*entry); + } else { + hwbug = 1; + break; + } + + map += frag_len; + } + + if (len) { + if (*budget) { + tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, + len, flags, mss, vlan); + (*budget)--; + *entry = NEXT_TX(*entry); + } else { + hwbug = 1; + } + } + } else { tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, len, flags, mss, vlan); - (*budget)--; - } else - hwbug = 1; - - *entry = NEXT_TX(*entry); + *entry = NEXT_TX(*entry); + } return hwbug; } @@ -13899,6 +13936,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tg3_flag(tp, 5755_PLUS)) tg3_flag_set(tp, SHORT_DMA_BUG); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + tg3_flag_set(tp, 4K_FIFO_LIMIT); + if (tg3_flag(tp, 5717_PLUS)) tg3_flag_set(tp, LRG_PROD_RING_CAP); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 466dd7add12b..2ea456dd5880 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2905,6 +2905,7 @@ enum TG3_FLAGS { TG3_FLAG_57765_PLUS, TG3_FLAG_APE_HAS_NCSI, TG3_FLAG_5717_PLUS, + TG3_FLAG_4K_FIFO_LIMIT, /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */ TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */ -- cgit v1.2.3 From a051294423b015c5c89f2ed78f7fe0893b775098 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Wed, 27 Jul 2011 14:20:54 +0000 Subject: tg3: Remove 5719 jumbo frames and TSO blocks The A0 revision of this chip is the only device that requires these features to be disabled. Signed-off-by: Matt Carlson Signed-off-by: David S. Miller --- drivers/net/tg3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/tg3.c') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c77a39d6cd15..dc3fbf61910b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8406,7 +8406,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) /* Program the jumbo buffer descriptor ring control * blocks on those devices that have them. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 || (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) { if (tg3_flag(tp, JUMBO_RING_ENABLE)) { @@ -13873,7 +13873,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_flag_set(tp, 5705_PLUS); /* Determine TSO capabilities */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) + if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) ; /* Do nothing. HW bug. */ else if (tg3_flag(tp, 57765_PLUS)) tg3_flag_set(tp, HW_TSO_3); @@ -13943,7 +13943,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_flag_set(tp, LRG_PROD_RING_CAP); if (tg3_flag(tp, 57765_PLUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719) + tp->pci_chip_rev_id != CHIPREV_ID_5719_A0) tg3_flag_set(tp, USE_JUMBO_BDFLAG); if (!tg3_flag(tp, 5705_PLUS) || -- cgit v1.2.3