diff --git a/packages/linux/patches/3.9.6/linux-701-fix-r8169.patch b/packages/linux/patches/3.9.6/linux-701-fix-r8169.patch new file mode 100644 index 0000000000..5c1244c887 --- /dev/null +++ b/packages/linux/patches/3.9.6/linux-701-fix-r8169.patch @@ -0,0 +1,110 @@ +From b423e9ae49d78ea3f53b131c8d5a6087aed16fd6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?fran=C3=A7ois=20romieu?= +Date: Sat, 18 May 2013 01:24:46 +0000 +Subject: [PATCH] r8169: fix offloaded tx checksum for small packets. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +8168evl offloaded checksums are wrong since commit +e5195c1f31f399289347e043d6abf3ffa80f0005 ("r8169: fix 8168evl frame padding.") +pads small packets to 60 bytes (without ethernet checksum). Typical symptoms +appear as UDP checksums which are wrong by the count of added bytes. + +It isn't worth compensating. Let the driver checksum. + +Due to the skb length changes, TSO code is moved before the Tx descriptor gets +written. + +Signed-off-by: Francois Romieu +Tested-by: Holger Hoffstätte +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/realtek/r8169.c | 41 ++++++++++++++++++++++++------------ + 1 file changed, 27 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c +index 79c520b..393f961 100644 +--- a/drivers/net/ethernet/realtek/r8169.c ++++ b/drivers/net/ethernet/realtek/r8169.c +@@ -5856,7 +5856,20 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb, + return -EIO; + } + +-static inline void rtl8169_tso_csum(struct rtl8169_private *tp, ++static bool rtl_skb_pad(struct sk_buff *skb) ++{ ++ if (skb_padto(skb, ETH_ZLEN)) ++ return false; ++ skb_put(skb, ETH_ZLEN - skb->len); ++ return true; ++} ++ ++static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb) ++{ ++ return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34; ++} ++ ++static inline bool rtl8169_tso_csum(struct rtl8169_private *tp, + struct sk_buff *skb, u32 *opts) + { + const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version; +@@ -5869,13 +5882,20 @@ static inline void rtl8169_tso_csum(struct rtl8169_private *tp, + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + const struct iphdr *ip = ip_hdr(skb); + ++ if (unlikely(rtl_test_hw_pad_bug(tp, skb))) ++ return skb_checksum_help(skb) == 0 && rtl_skb_pad(skb); ++ + if (ip->protocol == IPPROTO_TCP) + opts[offset] |= info->checksum.tcp; + else if (ip->protocol == IPPROTO_UDP) + opts[offset] |= info->checksum.udp; + else + WARN_ON_ONCE(1); ++ } else { ++ if (unlikely(rtl_test_hw_pad_bug(tp, skb))) ++ return rtl_skb_pad(skb); + } ++ return true; + } + + static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, +@@ -5896,17 +5916,15 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + goto err_stop_0; + } + +- /* 8168evl does not automatically pad to minimum length. */ +- if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 && +- skb->len < ETH_ZLEN)) { +- if (skb_padto(skb, ETH_ZLEN)) +- goto err_update_stats; +- skb_put(skb, ETH_ZLEN - skb->len); +- } +- + if (unlikely(le32_to_cpu(txd->opts1) & DescOwn)) + goto err_stop_0; + ++ opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); ++ opts[0] = DescOwn; ++ ++ if (!rtl8169_tso_csum(tp, skb, opts)) ++ goto err_update_stats; ++ + len = skb_headlen(skb); + mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(d, mapping))) { +@@ -5918,11 +5936,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, + tp->tx_skb[entry].len = len; + txd->addr = cpu_to_le64(mapping); + +- opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); +- opts[0] = DescOwn; +- +- rtl8169_tso_csum(tp, skb, opts); +- + frags = rtl8169_xmit_frags(tp, skb, opts); + if (frags < 0) + goto err_dma_1; +-- +1.8.1.6