summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2025-06-03 16:11:14 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:31:13 +0300
commit6f7c7e07cd279f8d4d1eb3c887b6477df1273c09 (patch)
treefb3f6dba77eca4600ee4295cc173337802b47ec4
parentdf01b42941eda1c8a2d1685f6e986df5490af762 (diff)
downloadlinux-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.c53
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);