aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorPeter Korsgaard <peter@korsgaard.com>2013-12-16 05:35:35 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-09 15:24:22 -0500
commit5fd93067a1e7bc8ce6a889816d2b4c2d19a2e970 (patch)
tree2bfddfeb1ff90283ca3d869ae88cca18ce4f2312 /drivers/net/usb
parent1552c3d8e10d1113d55237f3dd0d65c0a3501632 (diff)
dm9601: work around tx fifo sync issue on dm962x
commit 4263c86dca5198da6bd3ad826d0b2304fbe25776 upstream. Certain dm962x revisions contain an bug, where if a USB bulk transfer retry (E.G. if bulk crc mismatch) happens right after a transfer with odd or maxpacket length, the internal tx hardware fifo gets out of sync causing the interface to stop working. Work around it by adding up to 3 bytes of padding to ensure this situation cannot trigger. This workaround also means we never pass multiple-of-maxpacket size skb's to usbnet, so the length adjustment to handle usbnet's padding of those can be removed. Reported-by: Joseph Chang <joseph_chang@davicom.com.tw> Signed-off-by: Peter Korsgaard <peter@korsgaard.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/dm9601.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 732a926e3f51..c0bfc818c701 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -473,7 +473,7 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
473static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 473static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
474 gfp_t flags) 474 gfp_t flags)
475{ 475{
476 int len; 476 int len, pad;
477 477
478 /* format: 478 /* format:
479 b1: packet length low 479 b1: packet length low
@@ -481,12 +481,23 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
481 b3..n: packet data 481 b3..n: packet data
482 */ 482 */
483 483
484 len = skb->len; 484 len = skb->len + DM_TX_OVERHEAD;
485
486 /* workaround for dm962x errata with tx fifo getting out of
487 * sync if a USB bulk transfer retry happens right after a
488 * packet with odd / maxpacket length by adding up to 3 bytes
489 * padding.
490 */
491 while ((len & 1) || !(len % dev->maxpacket))
492 len++;
485 493
486 if (skb_headroom(skb) < DM_TX_OVERHEAD) { 494 len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */
495 pad = len - skb->len;
496
497 if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) {
487 struct sk_buff *skb2; 498 struct sk_buff *skb2;
488 499
489 skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); 500 skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags);
490 dev_kfree_skb_any(skb); 501 dev_kfree_skb_any(skb);
491 skb = skb2; 502 skb = skb2;
492 if (!skb) 503 if (!skb)
@@ -495,10 +506,10 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
495 506
496 __skb_push(skb, DM_TX_OVERHEAD); 507 __skb_push(skb, DM_TX_OVERHEAD);
497 508
498 /* usbnet adds padding if length is a multiple of packet size 509 if (pad) {
499 if so, adjust length value in header */ 510 memset(skb->data + skb->len, 0, pad);
500 if ((skb->len % dev->maxpacket) == 0) 511 __skb_put(skb, pad);
501 len++; 512 }
502 513
503 skb->data[0] = len; 514 skb->data[0] = len;
504 skb->data[1] = len >> 8; 515 skb->data[1] = len >> 8;