From patchwork Mon Dec 16 10:35:35 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Korsgaard X-Patchwork-Id: 301618 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 0A41A2C009B for ; Mon, 16 Dec 2013 21:35:55 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753318Ab3LPKfv (ORCPT ); Mon, 16 Dec 2013 05:35:51 -0500 Received: from mail-ee0-f53.google.com ([74.125.83.53]:36197 "EHLO mail-ee0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753306Ab3LPKfu (ORCPT ); Mon, 16 Dec 2013 05:35:50 -0500 Received: by mail-ee0-f53.google.com with SMTP id b57so2132550eek.12 for ; Mon, 16 Dec 2013 02:35:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=4cA/a1L5PlyNfN7IUqaQAtButjnO2AwGgGtYgQHDEpM=; b=t09nm+atu3HcJvC0ahF9AcfsNC9OKEFkp6bZoRc6iVl7y5FNYBbTsaVbMieayN2wyB Q4RKL+Yb5FBOed3GR0SdbDvmwzMnZ7WpPuY3OL3lUdxUPw4KmK0JhBavg4yVVw/IJr7B eGdQY9fliH5cvKgpyBMUI5n1kwOTjNbRt+LvxFkGipjWryTKfu41DwZZWQXXvCP0H+ll lcS/wuYu2/n7NCyCET+eCi8V4h2Vjm4uCGFHdF6mQIKK/pAaxQohBtO5KQPEebMZIed9 n2qc+y8dI08wtNpRrk5UlWXPW5LmFLZyjsDK5/J+Ul24gyZU/aTgccG71sCtJwd4XjwK vmWA== X-Received: by 10.15.23.206 with SMTP id h54mr16071299eeu.17.1387190148976; Mon, 16 Dec 2013 02:35:48 -0800 (PST) Received: from dell.be.48ers.dk ([91.183.168.190]) by mx.google.com with ESMTPSA id m1sm40667742eeg.0.2013.12.16.02.35.46 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 16 Dec 2013 02:35:47 -0800 (PST) Received: from peko by dell.be.48ers.dk with local (Exim 4.80) (envelope-from ) id 1VsVWb-0004S1-Gq; Mon, 16 Dec 2013 11:35:45 +0100 From: Peter Korsgaard To: netdev@vger.kernel.org, davem@davemloft.net Cc: joseph_chang@davicom.com.tw, Peter Korsgaard , Subject: [PATCH 4/4] dm9601: work around tx fifo sync issue on dm962x Date: Mon, 16 Dec 2013 11:35:35 +0100 Message-Id: <1387190135-17052-5-git-send-email-peter@korsgaard.com> X-Mailer: git-send-email 1.8.5.1 In-Reply-To: <1387190135-17052-1-git-send-email-peter@korsgaard.com> References: <1387190135-17052-1-git-send-email-peter@korsgaard.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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. Cc: Reported-by: Joseph Chang Signed-off-by: Peter Korsgaard --- drivers/net/usb/dm9601.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index ca99c35..14aa48f 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) static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { - int len; + int len, pad; /* format: 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 */ - 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; - 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); skb = skb2; 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); - /* 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[1] = len >> 8;