Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
To: netdev-bot+sashiko@kernel.org
Cc: maxime.chevallier@bootlin.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, peppe.cavallaro@st.com,
	alexandre.torgue@st.com, netdev@vger.kernel.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH net] net: stmmac: fix TX descriptor availability check for TSO traffic
Date: Thu, 10 Sep 2026 15:08:17 +0200	[thread overview]
Message-ID: <aqKrwW62rHjVzb5h@lore-desk> (raw)
In-Reply-To: <178903370842.219967.14155724625684562557@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 10132 bytes --]

> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider:
> 
> Critical: 0 · High: 1 (1) · Medium: 0 · Low: 0 (1)
> 
> - [High] stmmac_tso_xmit() now demands the exact descriptor count
>   returned by stmmac_tso_get_num_desc() (stmmac_main.c:4543-4544) but…
> 
> Pre-existing issues:
> - [High] proto_hdr_len in stmmac_tso_xmit() is declared as u8
>   (stmmac_main.c:4524) but is assigned the size_t result of…
> - [Low] The stmmac_tso_xmit() kernel-doc states "mss is fixed when enable
>   tso, so w/o programming the TDES3 ctx field." (stmmac_main.c:4512),…
> 
> --
> 
> net: stmmac: fix TX descriptor availability check for TSO traffic
> 
> This replaces the (skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE + 1
> estimate in stmmac_tso_xmit() with stmmac_tso_get_num_desc(), which counts
> the header descriptor, the linear payload, every fragment and the MSS
> context descriptor. The new count is then used for the free descriptor
> check before the ring is programmed.
> 
> A few questions below.
> 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > index 24656b35350b1..3566b33bc34e5 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > @@ -4454,6 +4454,26 @@ static bool stmmac_tso_valid_packet(struct sk_buff *skb)
> >  	       header_len + gso_size < 16383;
> >  }
> >  
> > +static int stmmac_tso_get_num_desc(struct stmmac_tx_queue *tx_q,
> > +				   struct sk_buff *skb, u32 pay_len)
> > +{
> > +	int i, ndesc = 1;
> > +
> > +	/* head payload */
> > +	ndesc += DIV_ROUND_UP(pay_len, TSO_MAX_BUFF_SIZE);
> > +	/* frag payload */
> > +	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
> > +		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
> > +
> > +		ndesc += DIV_ROUND_UP(skb_frag_size(frag),
> > +				      TSO_MAX_BUFF_SIZE);
> > +	}
> > +	/* MSS update requires a new descriptor */
> > +	ndesc += !!(skb_shinfo(skb)->gso_size != tx_q->mss);
> 
> [Severity: Low]
> This is a pre-existing issue and not introduced by this patch, but the new
> comment here now contradicts the stmmac_tso_xmit() kernel-doc that follows
> a few lines below, which still says:
> 
> 	 * mss is fixed when enable tso, so w/o programming the TDES3 ctx field.
> 
> stmmac_tso_xmit() does program a context descriptor whenever the skb MSS
> differs from the cached queue MSS:
> 
> 	if (mss != tx_q->mss) {
> 		...
> 		stmmac_set_mss(priv, mss_desc, mss);
> 		tx_q->mss = mss;
> 		tx_q->cur_tx = STMMAC_NEXT_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
> 
> Would it make sense to drop or update that kernel-doc sentence while
> touching this area?

As pointed out by Sashiko, this issue is not introduced by this patch and it
can be fixed with a dedicated patch.

> 
> > +
> > +	return ndesc;
> > +}
> > +
> >  /**
> >   *  stmmac_tso_xmit - Tx entry point of the driver for oversized frames (TSO)
> >   *  @skb : the socket buffer
> > @@ -4497,10 +4517,10 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
> >  	struct stmmac_priv *priv = netdev_priv(dev);
> >  	unsigned int first_entry, entry, tx_packets;
> >  	struct stmmac_txq_stats *txq_stats;
> > +	int i, first_tx, nfrags, ndesc;
> >  	struct stmmac_tx_queue *tx_q;
> >  	bool set_ic, is_last_segment;
> >  	u32 pay_len, mss, queue;
> > -	int i, first_tx, nfrags;
> >  	u8 proto_hdr_len, hdr;
> >  	dma_addr_t des;
> >  
> > @@ -4513,14 +4533,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
> >  
> >  	/* Compute header lengths */
> >  	proto_hdr_len = stmmac_tso_header_size(skb);
> > +	pay_len = skb_headlen(skb) - proto_hdr_len; /* no frags */
> 
> [Severity: High]
> This isn't a bug introduced by this patch, but the new pay_len computation
> inherits an existing truncation. proto_hdr_len is declared u8 while
> stmmac_tso_header_size() returns a size_t (skb_transport_offset() +
> sizeof(struct udphdr), or skb_tcp_all_headers()), and
> stmmac_tso_valid_packet() explicitly admits headers up to 1023 bytes into
> the hardware TSO path:
> 
> 	return header_len <= 1023 && gso_size >= 64 &&
> 	       header_len + gso_size < 16383;
> 
> For a header of 256..1023 bytes the store wraps modulo 256 (486 becomes
> 230, 256 becomes 0). The truncated value then defines the hardware
> contract, both for the payload start address:
> 
> 	stmmac_tso_allocator(priv, &entry, des + proto_hdr_len, pay_len,
> 			     (nfrags == 0), queue);
> 
> and for the descriptor lengths:
> 
> 	stmmac_prepare_tso_tx_desc(priv, first, 1, proto_hdr_len, 0, 1,
> 				   is_last_segment, hdr / 4,
> 				   skb->len - proto_hdr_len);
> 
> so the tail of the real header is handed to the engine as TCP/UDP payload
> while TDES3 declares more payload than the following descriptors describe
> (a header of exactly 256 also yields a zero length buffer1 with TSE set).
> A TCP over IPv6 socket carrying a few hundred bytes of sticky
> destination/hop-by-hop options makes skb_tcp_all_headers() exceed 255 while
> staying under 1023, so such an skb reaches stmmac_tso_xmit().
> 
> For the new pay_len the error biases upward, so the ring accounting stays
> safe, but should proto_hdr_len be widened to unsigned int (or size_t) since
> this patch now builds the descriptor count on it too?

As pointed out by Sashiko, this issue is not introduced by this patch and it
can be fixed with a dedicated patch.

> 
> >  	if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
> >  		hdr = sizeof(struct udphdr);
> >  	else
> >  		hdr = tcp_hdrlen(skb);
> >  
> > -	/* Desc availability based on threshold should be enough safe */
> > -	if (unlikely(stmmac_tx_avail(priv, queue) <
> > -		(((skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE + 1)))) {
> > +	ndesc = stmmac_tso_get_num_desc(tx_q, skb, pay_len);
> > +	if (unlikely(stmmac_tx_avail(priv, queue) < ndesc)) {
> >  		if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) {
> >  			netif_tx_stop_queue(netdev_get_tx_queue(priv->dev,
> >  								queue));
> 
> [Severity: High]
> The new requirement is exact, but the TX flow control watermarks were left
> unchanged. Can this make the "Tx Ring full when queue awake" branch
> reachable for ordinary TSO traffic?
> 
> stmmac_tso_get_num_desc() returns at least nfrags + 2 for any TSO skb that
> has a linear payload, so with MAX_SKB_FRAGS = 17 plus an MSS change it asks
> for 20 descriptors, and up to roughly 23 when individual frags exceed
> TSO_MAX_BUFF_SIZE.
> 
> The tail of stmmac_tso_xmit() still stops the queue based on the old
> assumption:
> 
> 	if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) {
> 		netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
> 			  __func__);
> 		netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
> 	}
> 
> so the queue is deliberately left awake with as few as 19 free slots, while
> the next TSO skb may need more. Does that leave a window where the stack
> submits an skb that does not fit, hitting the un-ratelimited netdev_err()
> in the ndo_start_xmit hot path together with netif_tx_stop_queue() and a
> NETDEV_TX_BUSY requeue?
> 
> The non-TSO path keeps the invariant the watermark was designed for,
> stmmac_xmit() needs nfrags + 1, which is always satisfied when the queue is
> awake:
> 
> 	if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
> 
> The only place the queue is re-armed is stmmac_tx_clean():
> 
> 	if (unlikely(netif_tx_queue_stopped(netdev_get_tx_queue(priv->dev, queue))) &&
> 	    stmmac_tx_avail(priv, queue) > STMMAC_TX_THRESH(priv)) {
> 		...
> 		netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, queue));
> 
> STMMAC_TX_THRESH() is dma_tx_size / 4, which is 16 on the 64 entry ring
> stmmac_set_ringparam() accepts (DMA_MIN_TX_SIZE in common.h). On such a
> ring the wake threshold is itself below the new requirement, so can the
> queue be woken while the skb still does not fit, producing a repeating
> stop/wake/TX_BUSY cycle with repeated error logging?
> 
> Should the stop and wake watermarks be raised to the worst case TSO
> descriptor count, or the skb linearized/pushed to software GSO, as part of
> this change?

The goal of this patch is to fix the memory corruption triggered by a TSO skb
that does not fit in the tx queue available memory space.
The case described above will be managed by the new condition added at the
beginning of stmmac_tso_xmit(). I think we can change the stop/wake tx queue
watermark with a dedicated patch that we do not need to backport (I guess this
is mostly an optimization). However, if you prefer to have it in a single patch,
I will add it in this one.

> 
> >  @@ -4532,8 +4553,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
> >  		return NETDEV_TX_BUSY;
> >  	}
> 
> One more on this branch: it sets XOFF without re-checking availability and
> without arming a wake source. If the ring drains concurrently
> (dirty_tx == cur_tx, no further TX completion and no NAPI run), does the
> XOFF state persist until dev_watchdog fires ndo_tx_timeout?

I guess this corner case has not been introduced by this patch since the same
approach is present in stmmac_xmit(). I think it should be addressed with a
dedicated patch. Moreover, is the corner case fixed by the ndo_tx_timeout
callback?

Regards,
Lorenzo

> 
> Since the patch is tagged for stable, would it be worth describing the new
> NETDEV_TX_BUSY and error logging behaviour in the commit message?
> 
> >  
> > -	pay_len = skb_headlen(skb) - proto_hdr_len; /* no frags */
> > -
> >  	mss = skb_shinfo(skb)->gso_size;
> >  
> >  	/* set new MSS value if needed */
> 
> [ ... ]
> 
> -- 
> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260907-stmmac-fix-tso-nfrags-check-v1-1-328459906cdb%40oss.qualcomm.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

  reply	other threads:[~2026-09-10 13:08 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07 21:46 [PATCH net] net: stmmac: fix TX descriptor availability check for TSO traffic Lorenzo Bianconi
2026-09-10  9:48 ` netdev-bot+sashiko
2026-09-10 13:08   ` Lorenzo Bianconi [this message]
2026-09-10 15:40 ` patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aqKrwW62rHjVzb5h@lore-desk \
    --to=lorenzo.bianconi@oss.qualcomm.com \
    --cc=alexandre.torgue@foss.st.com \
    --cc=alexandre.torgue@st.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=kuba@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-stm32@st-md-mailman.stormreply.com \
    --cc=maxime.chevallier@bootlin.com \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=netdev-bot+sashiko@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=peppe.cavallaro@st.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox