From: Joe Damato <joe@dama.to>
To: netdev@vger.kernel.org, Michael Chan <michael.chan@broadcom.com>,
Pavan Chebbi <pavan.chebbi@broadcom.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Joe Damato <joe@dama.to>
Cc: edumazet@google.com, horms@kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH net 2/2] bnxt_en: Pad short SW USO segments to BNXT_MIN_PKT_SIZE
Date: Thu, 8 Oct 2026 12:11:12 -0700 [thread overview]
Message-ID: <20261008191114.3736826-3-joe@dama.to> (raw)
In-Reply-To: <20261008191114.3736826-1-joe@dama.to>
Each SW USO segment is hdr_len + seg_payload bytes. With IPv4, hdr_len
is 42 bytes, so a segment carrying less than 10 bytes of UDP payload is
sent shorter than BNXT_MIN_PKT_SIZE. This happens with a short last
segment (e.g. gso_size 1400 and 1405 bytes of payload) or with a
gso_size below 10 bytes.
Fix the short last segment in bnxt_sw_udp_gso_xmit(): zero the pad
bytes after the header in the segment's inline header slot and add a
pad BD pointing at them after the payload BDs. Only the last segment
can need padding, and its pad BD fits within the existing bound in
bds_needed and BNXT_SW_USO_MAX_DESCS, since payload BDs are at most
num_segs + nr_frags.
If gso_size itself is too small, every segment would need a pad BD,
exceeding the descriptor bound. This case is unlikely, so
bnxt_features_check() clears GSO features for these skbs and the stack
segments them instead; bnxt_start_xmit() then pads each segment.
Fixes: cc5d90667db8 ("net: bnxt: Implement software USO")
Cc: stable@vger.kernel.org
Signed-off-by: Joe Damato <joe@dama.to>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 12 ++++++++++
drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c | 23 +++++++++++++++++--
drivers/net/ethernet/broadcom/bnxt/bnxt_gso.h | 15 ++++++++++++
3 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 15a8349ccf7b..d766dd469797 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -14268,6 +14268,18 @@ static netdev_features_t bnxt_features_check(struct sk_buff *skb,
u8 *l4_proto;
features = vlan_features_check(skb, features);
+
+ /* SW USO pads at most the last segment; let the stack segment skbs
+ * where every segment would be shorter than BNXT_MIN_PKT_SIZE.
+ */
+ if (skb_is_gso(skb) &&
+ (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) &&
+ !(bp->flags & BNXT_FLAG_UDP_GSO_CAP) &&
+ bnxt_sw_gso_pad_len(skb_transport_offset(skb) +
+ sizeof(struct udphdr),
+ skb_shinfo(skb)->gso_size))
+ features &= ~NETIF_F_GSO_MASK;
+
switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
if (!skb->encapsulation)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
index ef04c9d08066..f87e02ef3033 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
@@ -82,11 +82,14 @@ int bnxt_sw_udp_gso_xmit(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
if (unlikely(num_segs <= 1))
goto drop;
+ if (unlikely(bnxt_sw_gso_pad_len(hdr_len, mss)))
+ goto drop;
+
/* Upper bound on the number of descriptors needed.
*
* Each segment uses 1 long BD + 1 ext BD + payload BDs, which is
* at most num_segs + nr_frags (each frag boundary crossing adds at
- * most 1 extra BD).
+ * most 1 extra BD). The last segment may need 1 pad BD.
*/
bds_needed = 3 * num_segs + skb_shinfo(skb)->nr_frags + 1;
@@ -133,12 +136,14 @@ int bnxt_sw_udp_gso_xmit(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
dma_addr_t dma_addr;
struct tx_bd *txbd;
struct udphdr *uh;
+ unsigned int pad;
void *this_hdr;
int bd_count;
bool last;
u32 flags;
last = (i == num_segs - 1);
+ pad = bnxt_sw_gso_pad_len(hdr_len, seg_payload);
offset = slot * TSO_HEADER_SIZE;
this_hdr = txr->tx_inline_buf + offset;
this_hdr_dma = txr->tx_inline_dma + offset;
@@ -156,10 +161,18 @@ int bnxt_sw_udp_gso_xmit(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
iph->check = 0;
}
+ /* Pad bytes follow the header in the inline slot. Zero them
+ * so stale header bytes from an earlier packet are not sent.
+ */
+ if (pad)
+ memset(this_hdr + hdr_len, 0, pad);
+
dma_sync_single_for_device(&pdev->dev, this_hdr_dma,
- hdr_len, DMA_TO_DEVICE);
+ hdr_len + pad, DMA_TO_DEVICE);
bd_count = tso_dma_map_count(&map, seg_payload);
+ if (pad)
+ bd_count++;
tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
@@ -222,6 +235,12 @@ int bnxt_sw_udp_gso_xmit(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
seg_payload -= chunk_len;
}
+ if (pad) {
+ prod = NEXT_TX(prod);
+ txbd = bnxt_sw_gso_data_bd(bp, txr, prod,
+ this_hdr_dma + hdr_len, pad);
+ }
+
txbd->tx_bd_len_flags_type |=
cpu_to_le32(TX_BD_FLAGS_PACKET_END);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.h
index 77d9af97cc22..5916ee08c0e6 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.h
@@ -19,10 +19,25 @@
* Each segment: 1 long BD + 1 ext BD + payload BDs.
* Total payload BDs across all segs <= num_segs + nr_frags (each frag
* boundary crossing adds at most 1 extra BD).
+ * The last segment may need 1 pad BD (see bnxt_sw_gso_pad_len()).
* So: 3 * max_segs + MAX_SKB_FRAGS + 1 = 3 * 64 + 17 + 1 = 210.
*/
#define BNXT_SW_USO_MAX_DESCS (3 * BNXT_SW_USO_MAX_SEGS + MAX_SKB_FRAGS + 1)
+/* Bytes of padding needed to bring a segment carrying @seg_payload bytes
+ * up to BNXT_MIN_PKT_SIZE, or 0 if no padding is needed.
+ */
+static inline unsigned int bnxt_sw_gso_pad_len(unsigned int hdr_len,
+ unsigned int seg_payload)
+{
+ unsigned int len = hdr_len + seg_payload;
+
+ if (len < BNXT_MIN_PKT_SIZE)
+ return BNXT_MIN_PKT_SIZE - len;
+ else
+ return 0;
+}
+
static inline u16 bnxt_inline_avail(struct bnxt_tx_ring_info *txr)
{
return BNXT_SW_USO_MAX_SEGS -
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-08 19:11 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 19:11 [PATCH net 0/2] bnxt_en: Fix SW USO padding Joe Damato
2026-10-08 19:11 ` [PATCH net 1/2] bnxt_en: Add helper to fill SW USO payload BDs Joe Damato
2026-10-08 19:11 ` Joe Damato [this message]
2026-10-09 5:26 ` [PATCH net 2/2] bnxt_en: Pad short SW USO segments to BNXT_MIN_PKT_SIZE Michael Chan
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=20261008191114.3736826-3-joe@dama.to \
--to=joe@dama.to \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.chan@broadcom.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pavan.chebbi@broadcom.com \
--cc=stable@vger.kernel.org \
/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