diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-06-03 16:11:14 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:31:13 +0300 |
| commit | 6f7c7e07cd279f8d4d1eb3c887b6477df1273c09 (patch) | |
| tree | fb3f6dba77eca4600ee4295cc173337802b47ec4 | |
| parent | df01b42941eda1c8a2d1685f6e986df5490af762 (diff) | |
| download | linux-6f7c7e07cd279f8d4d1eb3c887b6477df1273c09.tar.gz linux-6f7c7e07cd279f8d4d1eb3c887b6477df1273c09.zip | |
net: stmmac: Fix incorrect IP-csum status report
Currently the IP checksum verification status is incorrectly set to
CHECKSUM_UNNECESSARY for all IPv4/IPv6 packets as per the
stmmac_has_ip_ethertype() method implementation. It's wrong since the Rx
COE embedded into the DW *MAC IP-cores supports the TCP/UDP/ICMP protocols
only [1,2,3,4]. From that perspective the commit c2945c435c99 ("net:
stmmac: Prevent DSA tags from breaking COE") was close to solving the
denoted problem, but didn't provide a comprehensive solution.
Since all the low-level driver sub-modules now support reporting the CSUM
verification status from Rx DMA-descriptor let's use it to correctly set
the IP-sum status in the Rx-frames SKB.
[1] DesignWare Cores Ethernet MAC Universal Databook, Revision 3.50a,
February 2009, p. 114.
[2] DesignWare Cores Ethernet MAC Universal Databook, Revision 3.73a,
October 2013, p. 189.
[3] DesignWare Cores Ethernet Quality-of-Service Databook, Revision 5.20a,
April 2020, pp. 368.
[4] DesignWare Cores XGMAC - 10G Ethernet MAC Databook, Revision 3.20a,
September 2022, p.253.
[n] ...
Fixes: c2945c435c99 ("net: stmmac: Prevent DSA tags from breaking COE")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 446439f5dbfd..d74927fbf148 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4986,6 +4986,42 @@ static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) } /** + * stmmac_get_rx_csum - Retrieve Rx CSUM status + * @priv: driver private structure + * @status: frame Rx-status + * @skb : the socket buffer + * Description : + * This function will initialize the SKB IP summed based on the Rx COE + * outcomes. + */ +static void stmmac_get_rx_csum(struct stmmac_priv *priv, int status, + struct sk_buff *skb) +{ + bool coe = priv->dev->features & NETIF_F_RXCSUM; + + /* If Rx COE wasn't synthesized into the IP-core the status may never + * have the csum_none flag. Skip the status check then to be on a safe + * side. + */ + if (!coe || (status & csum_none)) { + skb_checksum_none_assert(skb); + return; + } + + /* Rx COE feature is relatively similar on the late DW GMAC IP-cores + * (v3.30a and newer) and on the DW QoS Ether and DW XGMAC/XLGMAC/etc + * IP-cores except that the later ones support double tagged + * IP-packets: + * Rx COE type 2: C-(S-)VLAN + IPv4/IPv6 + TCP/UDP/ICMP + * Rx COE enh: 2xC-(S-)VLAN + IPv4/IPv6 + TCP/UDP/ICMP + * + * In any way the outcomes of the Rx COE work must be retrieved from + * the Rx DMA-descriptor. + */ + __skb_incr_checksum_unnecessary(skb); +} + +/** * stmmac_rx_refill - refill used skb preallocated buffers * @priv: driver private structure * @queue: RX queue index @@ -5357,11 +5393,10 @@ static struct sk_buff *stmmac_construct_skb_zc(struct stmmac_channel *ch, static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, struct dma_desc *p, struct dma_desc *np, - struct xdp_buff *xdp) + int status, struct xdp_buff *xdp) { struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue]; struct stmmac_channel *ch = &priv->channel[queue]; - int coe = priv->dev->features & NETIF_F_RXCSUM; unsigned int len = xdp->data_end - xdp->data; enum pkt_hash_types hash_type; struct sk_buff *skb; @@ -5382,10 +5417,7 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, stmmac_rx_vlan(priv->dev, skb); skb->protocol = eth_type_trans(skb, priv->dev); - if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb)) - skb_checksum_none_assert(skb); - else - skb->ip_summed = CHECKSUM_UNNECESSARY; + stmmac_get_rx_csum(priv, status, skb); if (!stmmac_get_rx_hash(priv, p, &hash, &hash_type)) skb_set_hash(skb, hash, hash_type); @@ -5598,7 +5630,7 @@ read_again: switch (res) { case STMMAC_XDP_PASS: - stmmac_dispatch_skb_zc(priv, queue, p, np, buf->xdp); + stmmac_dispatch_skb_zc(priv, queue, p, np, status, buf->xdp); xsk_buff_free(buf->xdp); break; case STMMAC_XDP_CONSUMED: @@ -5659,7 +5691,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue]; struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; struct stmmac_channel *ch = &priv->channel[queue]; - int coe = priv->dev->features & NETIF_F_RXCSUM; unsigned int count = 0, error = 0, len = 0; unsigned int next_entry = rx_q->cur_rx; enum dma_data_direction dma_dir; @@ -5892,11 +5923,7 @@ drain_data: skb->protocol = eth_type_trans(skb, priv->dev); - if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb) || - (status & csum_none)) - skb_checksum_none_assert(skb); - else - skb->ip_summed = CHECKSUM_UNNECESSARY; + stmmac_get_rx_csum(priv, status, skb); if (!stmmac_get_rx_hash(priv, p, &hash, &hash_type)) skb_set_hash(skb, hash, hash_type); |
