diff options
Diffstat (limited to 'drivers/net/usb/smsc95xx.c')
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index d222d7e25273..3135af63d378 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/usb.h> | 28 | #include <linux/usb.h> |
29 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
30 | #include <linux/usb/usbnet.h> | 30 | #include <linux/usb/usbnet.h> |
31 | #include <linux/slab.h> | ||
31 | #include "smsc95xx.h" | 32 | #include "smsc95xx.h" |
32 | 33 | ||
33 | #define SMSC_CHIPNAME "smsc95xx" | 34 | #define SMSC_CHIPNAME "smsc95xx" |
@@ -1189,9 +1190,21 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, | |||
1189 | } | 1190 | } |
1190 | 1191 | ||
1191 | if (csum) { | 1192 | if (csum) { |
1192 | u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); | 1193 | if (skb->len <= 45) { |
1193 | skb_push(skb, 4); | 1194 | /* workaround - hardware tx checksum does not work |
1194 | memcpy(skb->data, &csum_preamble, 4); | 1195 | * properly with extremely small packets */ |
1196 | long csstart = skb->csum_start - skb_headroom(skb); | ||
1197 | __wsum calc = csum_partial(skb->data + csstart, | ||
1198 | skb->len - csstart, 0); | ||
1199 | *((__sum16 *)(skb->data + csstart | ||
1200 | + skb->csum_offset)) = csum_fold(calc); | ||
1201 | |||
1202 | csum = false; | ||
1203 | } else { | ||
1204 | u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); | ||
1205 | skb_push(skb, 4); | ||
1206 | memcpy(skb->data, &csum_preamble, 4); | ||
1207 | } | ||
1195 | } | 1208 | } |
1196 | 1209 | ||
1197 | skb_push(skb, 4); | 1210 | skb_push(skb, 4); |