Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92c6b8d1 authored by Matt Carlson's avatar Matt Carlson Committed by David S. Miller
Browse files

tg3: Fix 5906 transmit hangs



The 5906 has trouble with fragments that are less than 8 bytes in size.
This patch works around the problem by pivoting the 5906's transmit
routine to tg3_start_xmit_dma_bug() and introducing a new SHORT_DMA_BUG
flag that enables code to detect and react to the problematic condition.

Signed-off-by: default avatarMatt Carlson <mcarlson@broadcom.com>
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0e1406dd
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -5393,7 +5393,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
	mss = 0;
	if ((mss = skb_shinfo(skb)->gso_size) != 0) {
		struct iphdr *iph;
		int tcp_opt_len, ip_tcp_len, hdr_len;
		u32 tcp_opt_len, ip_tcp_len, hdr_len;

		if (skb_header_cloned(skb) &&
		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -5424,8 +5424,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
								 IPPROTO_TCP,
								 0);

		if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
		    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
		if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)
			mss |= hdr_len << 9;
		else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) ||
			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
			if (tcp_opt_len || iph->ihl > 5) {
				int tsflags;

@@ -5460,6 +5462,9 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,

	would_hit_hwbug = 0;

	if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8)
		would_hit_hwbug = 1;

	if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) &&
	    tg3_4g_overflow_test(mapping, len))
		would_hit_hwbug = 1;
@@ -5489,6 +5494,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,

			tnapi->tx_buffers[entry].skb = NULL;

			if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) &&
			    len <= 8)
				would_hit_hwbug = 1;

			if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) &&
			    tg3_4g_overflow_test(mapping, len))
				would_hit_hwbug = 1;
@@ -12625,9 +12634,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
	}

	if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) {
		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
			tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG;
		else {
			tp->tg3_flags3 |= TG3_FLG3_4G_DMA_BNDRY_BUG;
			tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG;
		}
	}

	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
	     (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
@@ -13987,8 +14000,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
		goto err_out_iounmap;
	}

	if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
	if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
		dev->netdev_ops = &tg3_netdev_ops;
	else
		dev->netdev_ops = &tg3_netdev_ops_dma_bug;
+1 −0
Original line number Diff line number Diff line
@@ -2761,6 +2761,7 @@ struct tg3 {
#define TG3_FLG3_ENABLE_RSS		0x00020000
#define TG3_FLG3_4G_DMA_BNDRY_BUG	0x00080000
#define TG3_FLG3_40BIT_DMA_LIMIT_BUG	0x00100000
#define TG3_FLG3_SHORT_DMA_BUG		0x00200000

	struct timer_list		timer;
	u16				timer_counter;