mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
net: sungem: fix rx checksum support
After commit 88078d98d1
("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>
This commit is contained in:
parent
8b26a06ad4
commit
12b03558ce
1 changed files with 12 additions and 10 deletions
|
@ -60,8 +60,7 @@
|
||||||
#include <linux/sungem_phy.h>
|
#include <linux/sungem_phy.h>
|
||||||
#include "sungem.h"
|
#include "sungem.h"
|
||||||
|
|
||||||
/* Stripping FCS is causing problems, disabled for now */
|
#define STRIP_FCS
|
||||||
#undef STRIP_FCS
|
|
||||||
|
|
||||||
#define DEFAULT_MSG (NETIF_MSG_DRV | \
|
#define DEFAULT_MSG (NETIF_MSG_DRV | \
|
||||||
NETIF_MSG_PROBE | \
|
NETIF_MSG_PROBE | \
|
||||||
|
@ -435,7 +434,7 @@ static int gem_rxmac_reset(struct gem *gp)
|
||||||
writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
|
writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
|
||||||
writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
|
writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
|
||||||
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
|
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(val, gp->regs + RXDMA_CFG);
|
||||||
if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
|
if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
|
||||||
writel(((5 & RXDMA_BLANK_IPKTS) |
|
writel(((5 & RXDMA_BLANK_IPKTS) |
|
||||||
|
@ -760,7 +759,6 @@ static int gem_rx(struct gem *gp, int work_to_do)
|
||||||
struct net_device *dev = gp->dev;
|
struct net_device *dev = gp->dev;
|
||||||
int entry, drops, work_done = 0;
|
int entry, drops, work_done = 0;
|
||||||
u32 done;
|
u32 done;
|
||||||
__sum16 csum;
|
|
||||||
|
|
||||||
if (netif_msg_rx_status(gp))
|
if (netif_msg_rx_status(gp))
|
||||||
printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
|
printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
|
||||||
|
@ -855,9 +853,13 @@ static int gem_rx(struct gem *gp, int work_to_do)
|
||||||
skb = copy_skb;
|
skb = copy_skb;
|
||||||
}
|
}
|
||||||
|
|
||||||
csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff);
|
if (likely(dev->features & NETIF_F_RXCSUM)) {
|
||||||
skb->csum = csum_unfold(csum);
|
__sum16 csum;
|
||||||
skb->ip_summed = CHECKSUM_COMPLETE;
|
|
||||||
|
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);
|
skb->protocol = eth_type_trans(skb, gp->dev);
|
||||||
|
|
||||||
napi_gro_receive(&gp->napi, skb);
|
napi_gro_receive(&gp->napi, skb);
|
||||||
|
@ -1761,7 +1763,7 @@ static void gem_init_dma(struct gem *gp)
|
||||||
writel(0, gp->regs + TXDMA_KICK);
|
writel(0, gp->regs + TXDMA_KICK);
|
||||||
|
|
||||||
val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
|
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(val, gp->regs + RXDMA_CFG);
|
||||||
|
|
||||||
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
|
writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
|
||||||
|
@ -2985,8 +2987,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
pci_set_drvdata(pdev, dev);
|
pci_set_drvdata(pdev, dev);
|
||||||
|
|
||||||
/* We can do scatter/gather and HW checksum */
|
/* We can do scatter/gather and HW checksum */
|
||||||
dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
|
dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
|
||||||
dev->features |= dev->hw_features | NETIF_F_RXCSUM;
|
dev->features = dev->hw_features;
|
||||||
if (pci_using_dac)
|
if (pci_using_dac)
|
||||||
dev->features |= NETIF_F_HIGHDMA;
|
dev->features |= NETIF_F_HIGHDMA;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue