lan78xx minor fixes
cover 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.
Dave Stevenson (4):
net: lan78xx: Allow for VLAN headers in timeout calcs
net: lan78xx: Add support for VLAN filtering.
net: lan78xx: Add support for VLAN tag stripping.
net: lan78xx: Use s/w csum check on VLANs without tag stripping
drivers/net/usb/lan78xx.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-)
Signature · 1 line
2.7.4
PATCH 1/4 net: lan78xx: Allow for VLAN headers in timeout calcs
The frame abort timeout being set by lan78xx_set_rx_max_frame_length didn't account for any VLAN headers, resulting in very low throughput if used with tagged VLANs.
Use VLAN_ETH_HLEN instead of ETH_HLEN to correct for this.
--- drivers/net/usb/lan78xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/usb/lan78xx.c +3 -2
@@ -2298,7 +2298,7 @@ static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu)if ((ll_mtu % dev->maxpacket) ==0 )return -EDOM ; - ret =lan78xx_set_rx_max_frame_length (dev, new_mtu +ETH_HLEN ); + ret =lan78xx_set_rx_max_frame_length (dev, new_mtu +VLAN_ETH_HLEN ); netdev->mtu = new_mtu;
@@ -2587,7 +2587,8 @@ static int lan78xx_reset(struct lan78xx_net *dev) buf |=FCT_TX_CTL_EN_ ; ret =lan78xx_write_reg (dev,FCT_TX_CTL , buf); - ret =lan78xx_set_rx_max_frame_length (dev, dev->net->mtu +ETH_HLEN ); + ret =lan78xx_set_rx_max_frame_length (dev, + dev->net->mtu +VLAN_ETH_HLEN ); ret =lan78xx_read_reg (dev,MAC_RX , &buf); buf |=MAC_RX_RXEN_ ;
Signature · 1 line
2.7.4
PATCH 2/4 net: lan78xx: Add support for VLAN filtering.
In reply to Dave StevensonHW_VLAN_CTAG_FILTER was partially implemented, but not advertised to Linux.
Complete the implementation of this.
--- drivers/net/usb/lan78xx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/usb/lan78xx.c +4 -1
@@ -2363,7 +2363,7 @@ static int lan78xx_set_features(struct net_device *netdev, pdata->rfe_ctl &= ~(RFE_CTL_ICMP_COE_ |RFE_CTL_IGMP_COE_ ); } -if (features &NETIF_F_HW_VLAN_CTAG_RX ) +if (features &NETIF_F_HW_VLAN_CTAG_FILTER ) pdata->rfe_ctl |=RFE_CTL_VLAN_FILTER_ ;else pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_ ;
@@ -2976,6 +2976,9 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)if (DEFAULT_TSO_CSUM_ENABLE ) dev->net->features |=NETIF_F_TSO |NETIF_F_TSO6 |NETIF_F_SG ; +if (DEFAULT_VLAN_FILTER_ENABLE ) + dev->net->features |=NETIF_F_HW_VLAN_CTAG_FILTER ; + dev->net->hw_features = dev->net->features; ret =lan78xx_setup_irq_domain (dev);
Signature · 1 line
2.7.4
PATCH 3/4 net: lan78xx: Add support for VLAN tag stripping.
In reply to Dave StevensonThe chip supports stripping the VLAN tag and reporting it in metadata.
Complete the support for this.
--- drivers/net/usb/lan78xx.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
drivers/net/usb/lan78xx.c +22 -0
@@ -64,6 +64,7 @@#define DEFAULT_RX_CSUM_ENABLE (true)#define DEFAULT_TSO_CSUM_ENABLE (true)#define DEFAULT_VLAN_FILTER_ENABLE (true) +#define DEFAULT_VLAN_RX_OFFLOAD (true)#define TX_OVERHEAD (8)#define RXW_PADDING 2
@@ -2363,6 +2364,11 @@ static int lan78xx_set_features(struct net_device *netdev, pdata->rfe_ctl &= ~(RFE_CTL_ICMP_COE_ |RFE_CTL_IGMP_COE_ ); } +if (features &NETIF_F_HW_VLAN_CTAG_RX ) + pdata->rfe_ctl |=RFE_CTL_VLAN_STRIP_ ; +else + pdata->rfe_ctl &= ~RFE_CTL_VLAN_STRIP_ ; +if (features &NETIF_F_HW_VLAN_CTAG_FILTER ) pdata->rfe_ctl |=RFE_CTL_VLAN_FILTER_ ;else
@@ -2976,6 +2982,9 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)if (DEFAULT_TSO_CSUM_ENABLE ) dev->net->features |=NETIF_F_TSO |NETIF_F_TSO6 |NETIF_F_SG ; +if (DEFAULT_VLAN_RX_OFFLOAD ) + dev->net->features |=NETIF_F_HW_VLAN_CTAG_RX ; +if (DEFAULT_VLAN_FILTER_ENABLE ) dev->net->features |=NETIF_F_HW_VLAN_CTAG_FILTER ;
@@ -3052,6 +3061,16 @@ static void lan78xx_rx_csum_offload(struct lan78xx_net *dev, } } +static void lan78xx_rx_vlan_offload (struct lan78xx_net *dev, +struct sk_buff *skb, +u32 rx_cmd_a,u32 rx_cmd_b) +{ +if ((dev->net->features &NETIF_F_HW_VLAN_CTAG_RX ) && + (rx_cmd_a &RX_CMD_A_FVTG_ )) +__vlan_hwaccel_put_tag (skb,htons (ETH_P_8021Q ), + (rx_cmd_b &0xffff )); +} +static void lan78xx_skb_return (struct lan78xx_net *dev,struct sk_buff *skb) {int status;
@@ -3116,6 +3135,8 @@ static int lan78xx_rx(struct lan78xx_net *dev, struct sk_buff *skb)if (skb->len == size) {lan78xx_rx_csum_offload (dev, skb, rx_cmd_a, rx_cmd_b); +lan78xx_rx_vlan_offload (dev, skb, + rx_cmd_a, rx_cmd_b);skb_trim (skb, skb->len -4 );/* remove fcs */ skb->truesize = size +sizeof (struct sk_buff );
@@ -3134,6 +3155,7 @@ static int lan78xx_rx(struct lan78xx_net *dev, struct sk_buff *skb)skb_set_tail_pointer (skb2, size);lan78xx_rx_csum_offload (dev, skb2, rx_cmd_a, rx_cmd_b); +lan78xx_rx_vlan_offload (dev, skb2, rx_cmd_a, rx_cmd_b);skb_trim (skb2, skb2->len -4 );/* remove fcs */ skb2->truesize = size +sizeof (struct sk_buff );
Signature · 1 line
2.7.4
PATCH 4/4 net: lan78xx: Use s/w csum check on VLANs without tag stripping
In reply to Dave StevensonObservations of VLANs dropping packets due to invalid checksums when not offloading VLAN tag receive. With VLAN tag stripping enabled no issue is observed.
Drop back to s/w checksums if VLAN offload is disabled.
--- drivers/net/usb/lan78xx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/usb/lan78xx.c +6 -1
@@ -3052,8 +3052,13 @@ static void lan78xx_rx_csum_offload(struct lan78xx_net *dev,struct sk_buff *skb, u32 rx_cmd_a, u32 rx_cmd_b) { + /* HW Checksum offload appears to be flawed if used when not stripping + * VLAN headers. Drop back to S/W checksums under these conditions. + */ if (!(dev->net->features & NETIF_F_RXCSUM) || - unlikely(rx_cmd_a & RX_CMD_A_ICSM_)) { + unlikely(rx_cmd_a & RX_CMD_A_ICSM_) || + ((rx_cmd_a & RX_CMD_A_FVTG_) && + !(dev->net->features & NETIF_F_HW_VLAN_CTAG_RX))) { skb->ip_summed = CHECKSUM_NONE; } else { skb->csum =ntohs ((u16)(rx_cmd_b >>RX_CMD_B_CSUM_SHIFT_ ));
Signature · 1 line
2.7.4
David Miller
maintainerFrom: Dave Stevenson <[email protected]>
Date: Mon, 25 Jun 2018 15:07:11 +0100
Quoted 4 lines
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
...
Series applied, thank you.