|
@@ -473,7 +473,7 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
|
static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
|
static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
|
gfp_t flags)
|
|
gfp_t flags)
|
|
{
|
|
{
|
|
- int len;
|
|
|
|
|
|
+ int len, pad;
|
|
|
|
|
|
/* format:
|
|
/* format:
|
|
b1: packet length low
|
|
b1: packet length low
|
|
@@ -481,12 +481,23 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
|
b3..n: packet data
|
|
b3..n: packet data
|
|
*/
|
|
*/
|
|
|
|
|
|
- len = skb->len;
|
|
|
|
|
|
+ len = skb->len + DM_TX_OVERHEAD;
|
|
|
|
+
|
|
|
|
+ /* workaround for dm962x errata with tx fifo getting out of
|
|
|
|
+ * sync if a USB bulk transfer retry happens right after a
|
|
|
|
+ * packet with odd / maxpacket length by adding up to 3 bytes
|
|
|
|
+ * padding.
|
|
|
|
+ */
|
|
|
|
+ while ((len & 1) || !(len % dev->maxpacket))
|
|
|
|
+ len++;
|
|
|
|
|
|
- if (skb_headroom(skb) < DM_TX_OVERHEAD) {
|
|
|
|
|
|
+ len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */
|
|
|
|
+ pad = len - skb->len;
|
|
|
|
+
|
|
|
|
+ if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) {
|
|
struct sk_buff *skb2;
|
|
struct sk_buff *skb2;
|
|
|
|
|
|
- skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
|
|
|
|
|
|
+ skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags);
|
|
dev_kfree_skb_any(skb);
|
|
dev_kfree_skb_any(skb);
|
|
skb = skb2;
|
|
skb = skb2;
|
|
if (!skb)
|
|
if (!skb)
|
|
@@ -495,10 +506,10 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
|
|
|
|
|
|
__skb_push(skb, DM_TX_OVERHEAD);
|
|
__skb_push(skb, DM_TX_OVERHEAD);
|
|
|
|
|
|
- /* usbnet adds padding if length is a multiple of packet size
|
|
|
|
- if so, adjust length value in header */
|
|
|
|
- if ((skb->len % dev->maxpacket) == 0)
|
|
|
|
- len++;
|
|
|
|
|
|
+ if (pad) {
|
|
|
|
+ memset(skb->data + skb->len, 0, pad);
|
|
|
|
+ __skb_put(skb, pad);
|
|
|
|
+ }
|
|
|
|
|
|
skb->data[0] = len;
|
|
skb->data[0] = len;
|
|
skb->data[1] = len >> 8;
|
|
skb->data[1] = len >> 8;
|