| From foo@baz Thu Jul 19 10:08:15 CEST 2018 |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Tue, 19 Jun 2018 19:18:50 -0700 |
| Subject: net: sungem: fix rx checksum support |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit 12b03558cef6d655d0d394f5e98a6fd07c1f6c0f ] |
| |
| After commit 88078d98d1bb ("net: pskb_trim_rcsum() and CHECKSUM_COMPLETE |
| are friends"), sungem owners reported the infamous "eth0: hw csum failure" |
| message. |
| |
| CHECKSUM_COMPLETE has in fact never worked for this driver, but this |
| was masked by the fact that upper stacks had to strip the FCS, and |
| therefore skb->ip_summed was set back to CHECKSUM_NONE before |
| my recent change. |
| |
| Driver configures a number of bytes to skip when the chip computes |
| the checksum, and for some reason only half of the Ethernet header |
| was skipped. |
| |
| Then a second problem is that we should strip the FCS by default, |
| unless the driver is updated to eventually support NETIF_F_RXFCS in |
| the future. |
| |
| Finally, a driver should check if NETIF_F_RXCSUM feature is enabled |
| or not, so that the admin can turn off rx checksum if wanted. |
| |
| Many thanks to Andreas Schwab and Mathieu Malaterre for their |
| help in debugging this issue. |
| |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Reported-by: Meelis Roos <mroos@linux.ee> |
| Reported-by: Mathieu Malaterre <malat@debian.org> |
| Reported-by: Andreas Schwab <schwab@linux-m68k.org> |
| Tested-by: Andreas Schwab <schwab@linux-m68k.org> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/ethernet/sun/sungem.c | 22 ++++++++++++---------- |
| 1 file changed, 12 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/net/ethernet/sun/sungem.c |
| +++ b/drivers/net/ethernet/sun/sungem.c |
| @@ -60,8 +60,7 @@ |
| #include <linux/sungem_phy.h> |
| #include "sungem.h" |
| |
| -/* Stripping FCS is causing problems, disabled for now */ |
| -#undef STRIP_FCS |
| +#define STRIP_FCS |
| |
| #define DEFAULT_MSG (NETIF_MSG_DRV | \ |
| NETIF_MSG_PROBE | \ |
| @@ -435,7 +434,7 @@ static int gem_rxmac_reset(struct gem *g |
| writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW); |
| writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); |
| val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | |
| - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); |
| + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); |
| writel(val, gp->regs + RXDMA_CFG); |
| if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) |
| writel(((5 & RXDMA_BLANK_IPKTS) | |
| @@ -760,7 +759,6 @@ static int gem_rx(struct gem *gp, int wo |
| struct net_device *dev = gp->dev; |
| int entry, drops, work_done = 0; |
| u32 done; |
| - __sum16 csum; |
| |
| if (netif_msg_rx_status(gp)) |
| printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", |
| @@ -855,9 +853,13 @@ static int gem_rx(struct gem *gp, int wo |
| skb = copy_skb; |
| } |
| |
| - csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); |
| - skb->csum = csum_unfold(csum); |
| - skb->ip_summed = CHECKSUM_COMPLETE; |
| + if (likely(dev->features & NETIF_F_RXCSUM)) { |
| + __sum16 csum; |
| + |
| + csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); |
| + skb->csum = csum_unfold(csum); |
| + skb->ip_summed = CHECKSUM_COMPLETE; |
| + } |
| skb->protocol = eth_type_trans(skb, gp->dev); |
| |
| napi_gro_receive(&gp->napi, skb); |
| @@ -1755,7 +1757,7 @@ static void gem_init_dma(struct gem *gp) |
| writel(0, gp->regs + TXDMA_KICK); |
| |
| val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | |
| - ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); |
| + (ETH_HLEN << 13) | RXDMA_CFG_FTHRESH_128); |
| writel(val, gp->regs + RXDMA_CFG); |
| |
| writel(desc_dma >> 32, gp->regs + RXDMA_DBHI); |
| @@ -2973,8 +2975,8 @@ static int gem_init_one(struct pci_dev * |
| pci_set_drvdata(pdev, dev); |
| |
| /* We can do scatter/gather and HW checksum */ |
| - dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; |
| - dev->features |= dev->hw_features | NETIF_F_RXCSUM; |
| + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; |
| + dev->features = dev->hw_features; |
| if (pci_using_dac) |
| dev->features |= NETIF_F_HIGHDMA; |
| |