aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Glendinning <steve.glendinning@smsc.com>2010-03-18 22:18:41 -0700
committerDavid S. Miller <davem@davemloft.net>2010-03-18 22:18:41 -0700
commit11bc3088373e913f165a8652601c6f8b8dc4aea2 (patch)
tree5a82487caf4de60681ac0bd743bfeba4851254b8
parent0ecad5a262923967147e2d1725e277a2a5fbcdd4 (diff)
smsc95xx: Fix tx checksum offload for small packets
TX checksum offload does not work properly when transmitting UDP packets with 0, 1 or 2 bytes of data. This patch works around the problem by calculating checksums for these packets in the driver. Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/usb/smsc95xx.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index d222d7e2527..73f9a31cf94 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1189,9 +1189,21 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
}
if (csum) {
- u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
- skb_push(skb, 4);
- memcpy(skb->data, &csum_preamble, 4);
+ if (skb->len <= 45) {
+ /* workaround - hardware tx checksum does not work
+ * properly with extremely small packets */
+ long csstart = skb->csum_start - skb_headroom(skb);
+ __wsum calc = csum_partial(skb->data + csstart,
+ skb->len - csstart, 0);
+ *((__sum16 *)(skb->data + csstart
+ + skb->csum_offset)) = csum_fold(calc);
+
+ csum = false;
+ } else {
+ u32 csum_preamble = smsc95xx_calc_csum_preamble(skb);
+ skb_push(skb, 4);
+ memcpy(skb->data, &csum_preamble, 4);
+ }
}
skb_push(skb, 4);