Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'lan78xx-minor-fixes'

Dave Stevenson says:

====================
lan78xx minor fixes

This is a small set of patches for the Microchip LAN78xx chip,
as used in the Raspberry Pi 3B+.
The main debug/discussion was on
https://github.com/raspberrypi/linux/issues/2458

Initial symptoms were that VLANs were very unreliable.
A couple of things were found:
- firstly that the hardware timeout value set failed to
take into account the VLAN tag, so a full MTU packet
would be timed out.
- second was that regular checksum failures were being
reported. Disabling checksum offload confirmed that
the checksums were valid, and further experimentation
identified that it was only if the VLAN tags were being
passed through to the kernel that there were issues.
The hardware supports VLAN filtering and tag stripping,
therefore those have been implemented (much of the work
was already done), and the driver drops back to s/w
checksums should the choice be made not to use the h/w
VLAN stripping.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+34 -3
+34 -3
drivers/net/usb/lan78xx.c
··· 64 64 #define DEFAULT_RX_CSUM_ENABLE (true) 65 65 #define DEFAULT_TSO_CSUM_ENABLE (true) 66 66 #define DEFAULT_VLAN_FILTER_ENABLE (true) 67 + #define DEFAULT_VLAN_RX_OFFLOAD (true) 67 68 #define TX_OVERHEAD (8) 68 69 #define RXW_PADDING 2 69 70 ··· 2299 2298 if ((ll_mtu % dev->maxpacket) == 0) 2300 2299 return -EDOM; 2301 2300 2302 - ret = lan78xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN); 2301 + ret = lan78xx_set_rx_max_frame_length(dev, new_mtu + VLAN_ETH_HLEN); 2303 2302 2304 2303 netdev->mtu = new_mtu; 2305 2304 ··· 2365 2364 } 2366 2365 2367 2366 if (features & NETIF_F_HW_VLAN_CTAG_RX) 2367 + pdata->rfe_ctl |= RFE_CTL_VLAN_STRIP_; 2368 + else 2369 + pdata->rfe_ctl &= ~RFE_CTL_VLAN_STRIP_; 2370 + 2371 + if (features & NETIF_F_HW_VLAN_CTAG_FILTER) 2368 2372 pdata->rfe_ctl |= RFE_CTL_VLAN_FILTER_; 2369 2373 else 2370 2374 pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_; ··· 2593 2587 buf |= FCT_TX_CTL_EN_; 2594 2588 ret = lan78xx_write_reg(dev, FCT_TX_CTL, buf); 2595 2589 2596 - ret = lan78xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN); 2590 + ret = lan78xx_set_rx_max_frame_length(dev, 2591 + dev->net->mtu + VLAN_ETH_HLEN); 2597 2592 2598 2593 ret = lan78xx_read_reg(dev, MAC_RX, &buf); 2599 2594 buf |= MAC_RX_RXEN_; ··· 2982 2975 if (DEFAULT_TSO_CSUM_ENABLE) 2983 2976 dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG; 2984 2977 2978 + if (DEFAULT_VLAN_RX_OFFLOAD) 2979 + dev->net->features |= NETIF_F_HW_VLAN_CTAG_RX; 2980 + 2981 + if (DEFAULT_VLAN_FILTER_ENABLE) 2982 + dev->net->features |= NETIF_F_HW_VLAN_CTAG_FILTER; 2983 + 2985 2984 dev->net->hw_features = dev->net->features; 2986 2985 2987 2986 ret = lan78xx_setup_irq_domain(dev); ··· 3052 3039 struct sk_buff *skb, 3053 3040 u32 rx_cmd_a, u32 rx_cmd_b) 3054 3041 { 3042 + /* HW Checksum offload appears to be flawed if used when not stripping 3043 + * VLAN headers. Drop back to S/W checksums under these conditions. 3044 + */ 3055 3045 if (!(dev->net->features & NETIF_F_RXCSUM) || 3056 - unlikely(rx_cmd_a & RX_CMD_A_ICSM_)) { 3046 + unlikely(rx_cmd_a & RX_CMD_A_ICSM_) || 3047 + ((rx_cmd_a & RX_CMD_A_FVTG_) && 3048 + !(dev->net->features & NETIF_F_HW_VLAN_CTAG_RX))) { 3057 3049 skb->ip_summed = CHECKSUM_NONE; 3058 3050 } else { 3059 3051 skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT_)); 3060 3052 skb->ip_summed = CHECKSUM_COMPLETE; 3061 3053 } 3054 + } 3055 + 3056 + static void lan78xx_rx_vlan_offload(struct lan78xx_net *dev, 3057 + struct sk_buff *skb, 3058 + u32 rx_cmd_a, u32 rx_cmd_b) 3059 + { 3060 + if ((dev->net->features & NETIF_F_HW_VLAN_CTAG_RX) && 3061 + (rx_cmd_a & RX_CMD_A_FVTG_)) 3062 + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 3063 + (rx_cmd_b & 0xffff)); 3062 3064 } 3063 3065 3064 3066 static void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb) ··· 3140 3112 if (skb->len == size) { 3141 3113 lan78xx_rx_csum_offload(dev, skb, 3142 3114 rx_cmd_a, rx_cmd_b); 3115 + lan78xx_rx_vlan_offload(dev, skb, 3116 + rx_cmd_a, rx_cmd_b); 3143 3117 3144 3118 skb_trim(skb, skb->len - 4); /* remove fcs */ 3145 3119 skb->truesize = size + sizeof(struct sk_buff); ··· 3160 3130 skb_set_tail_pointer(skb2, size); 3161 3131 3162 3132 lan78xx_rx_csum_offload(dev, skb2, rx_cmd_a, rx_cmd_b); 3133 + lan78xx_rx_vlan_offload(dev, skb2, rx_cmd_a, rx_cmd_b); 3163 3134 3164 3135 skb_trim(skb2, skb2->len - 4); /* remove fcs */ 3165 3136 skb2->truesize = size + sizeof(struct sk_buff);