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.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/tg3.h') diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 691539ba17b3..f6986ca50d80 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2652,6 +2652,11 @@ struct ring_info { DEFINE_DMA_UNMAP_ADDR(mapping); }; +struct tg3_tx_ring_info { + struct sk_buff *skb; + DEFINE_DMA_UNMAP_ADDR(mapping); +}; + struct tg3_link_config { /* Describes what we're trying to get. */ u32 advertising; @@ -2816,7 +2821,7 @@ struct tg3_napi { u32 last_tx_cons; u32 prodmbox; struct tg3_tx_buffer_desc *tx_ring; - struct ring_info *tx_buffers; + struct tg3_tx_ring_info *tx_buffers; dma_addr_t status_mapping; dma_addr_t rx_rcb_mapping; -- 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.h') 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 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.h') 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