Skip to content

Commit

Permalink
r8169: work around RTL8125 UDP hw bug
Browse files Browse the repository at this point in the history
It was reported that on RTL8125 network breaks under heavy UDP load,
e.g. torrent traffic ([0], from comment 27). Realtek confirmed a hw bug
and provided me with a test version of the r8125 driver including a
workaround. Tests confirmed that the workaround fixes the issue.
I modified the original version of the workaround to meet mainline
code style.

[0] https://bugzilla.kernel.org/show_bug.cgi?id=209839

v2:
- rebased to net
v3:
- make rtl_skb_is_udp() more robust and use skb_header_pointer()
  to access the ip(v6) header
v4:
- remove dependency on ptp_classify.h
- replace magic number with offsetof(struct udphdr, len)

Fixes: f1bce4a ("r8169: add support for RTL8125")
Tested-by: xplo <xplo.bn@gmail.com>
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Link: https://lore.kernel.org/r/6e453d49-1801-e6de-d5f7-d7e6c7526c8f@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Heiner Kallweit authored and Jakub Kicinski committed Jan 30, 2021
1 parent 0136563 commit 8d520b4
Showing 1 changed file with 65 additions and 6 deletions.
71 changes: 65 additions & 6 deletions drivers/net/ethernet/realtek/r8169_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4046,17 +4046,72 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
return -EIO;
}

static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp)
static bool rtl_skb_is_udp(struct sk_buff *skb)
{
int no = skb_network_offset(skb);
struct ipv6hdr *i6h, _i6h;
struct iphdr *ih, _ih;

switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih);
return ih && ih->protocol == IPPROTO_UDP;
case htons(ETH_P_IPV6):
i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h);
return i6h && i6h->nexthdr == IPPROTO_UDP;
default:
return false;
}
}

#define RTL_MIN_PATCH_LEN 47

/* see rtl8125_get_patch_pad_len() in r8125 vendor driver */
static unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp,
struct sk_buff *skb)
{
unsigned int padto = 0, len = skb->len;

if (rtl_is_8125(tp) && len < 128 + RTL_MIN_PATCH_LEN &&
rtl_skb_is_udp(skb) && skb_transport_header_was_set(skb)) {
unsigned int trans_data_len = skb_tail_pointer(skb) -
skb_transport_header(skb);

if (trans_data_len >= offsetof(struct udphdr, len) &&
trans_data_len < RTL_MIN_PATCH_LEN) {
u16 dest = ntohs(udp_hdr(skb)->dest);

/* dest is a standard PTP port */
if (dest == 319 || dest == 320)
padto = len + RTL_MIN_PATCH_LEN - trans_data_len;
}

if (trans_data_len < sizeof(struct udphdr))
padto = max_t(unsigned int, padto,
len + sizeof(struct udphdr) - trans_data_len);
}

return padto;
}

static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp,
struct sk_buff *skb)
{
unsigned int padto;

padto = rtl8125_quirk_udp_padto(tp, skb);

switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_34:
case RTL_GIGA_MAC_VER_60:
case RTL_GIGA_MAC_VER_61:
case RTL_GIGA_MAC_VER_63:
return true;
padto = max_t(unsigned int, padto, ETH_ZLEN);
default:
return false;
break;
}

return padto;
}

static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
Expand Down Expand Up @@ -4128,9 +4183,10 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,

opts[1] |= transport_offset << TCPHO_SHIFT;
} else {
if (unlikely(skb->len < ETH_ZLEN && rtl_test_hw_pad_bug(tp)))
/* eth_skb_pad would free the skb on error */
return !__skb_put_padto(skb, ETH_ZLEN, false);
unsigned int padto = rtl_quirk_packet_padto(tp, skb);

/* skb_padto would free the skb on error */
return !__skb_put_padto(skb, padto, false);
}

return true;
Expand Down Expand Up @@ -4307,6 +4363,9 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
if (skb->len < ETH_ZLEN)
features &= ~NETIF_F_CSUM_MASK;

if (rtl_quirk_packet_padto(tp, skb))
features &= ~NETIF_F_CSUM_MASK;

if (transport_offset > TCPHO_MAX &&
rtl_chip_supports_csum_v2(tp))
features &= ~NETIF_F_CSUM_MASK;
Expand Down

0 comments on commit 8d520b4

Please sign in to comment.