aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/niu.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-01-05 02:54:06 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-09 02:29:56 -0500
commit3ebebccf89b1b6e4fec4de05b245d6c459f27ce8 (patch)
tree2f69bd73412f9a986c739e87326ebcc5cf4e68af /drivers/net/niu.c
parent792dd90f114a48c210c566f3642b26f699702cb7 (diff)
[NIU]: Fix potentially stuck TCP socket send queues.
It is possible for the TX ring to have packets sit in it for unbounded amounts of time. The only way to defer TX interrupts in the chip is to periodically set "mark" bits, when processing of a TX descriptor with the mark bit set is complete it triggers the interrupt for the TX queue's LDG. A consequence of this kind of scheme is that if packet flow suddenly stops, the remaining TX packets will just sit there. If this happens, since those packets could be charged to TCP socket send queues, such sockets could get stuck. The simplest solution is to divorce the socket ownership of the packet once the device takes the SKB, by using skb_orphan() in niu_start_xmit(). In hindsight, it would have been much nicer if the chip provided two interrupt sources for TX (like basically every other ethernet chip does). Namely, keep the "mark" bit, but also signal the LDG when the TX queue becomes completely empty. That way there is no need to have a deadlock breaker like this. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r--drivers/net/niu.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index babb1ef37e34..ac361642567a 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -5208,7 +5208,8 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev)
5208 } 5208 }
5209 kfree_skb(skb); 5209 kfree_skb(skb);
5210 skb = skb_new; 5210 skb = skb_new;
5211 } 5211 } else
5212 skb_orphan(skb);
5212 5213
5213 align = ((unsigned long) skb->data & (16 - 1)); 5214 align = ((unsigned long) skb->data & (16 - 1));
5214 headroom = align + sizeof(struct tx_pkt_hdr); 5215 headroom = align + sizeof(struct tx_pkt_hdr);