FAILED: patch "[PATCH] net/mlx5e: do not HW-GRO coalesce small frames" failed to apply to 6.12-stable tree
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x e2466392a0b8496000e12181cb1ee1535eb0da25
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090309-detergent-handgrip-7f4e@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e2466392a0b8496000e12181cb1ee1535eb0da25 Mon Sep 17 00:00:00 2001
From: Glenn Judd <[email protected]>
Date: Sun, 16 Aug 2026 09:42:59 +0300
Subject: [PATCH] net/mlx5e: do not HW-GRO coalesce small frames
When hardware GRO (SHAMPO) coalesces a small IPv4/TCP segment that was padded up to the 60-byte minimum Ethernet frame, the trailing padding is folded into the merged payload causing padding to be delivered to the user as payload.
Detecting and reproducing the issue: the selftest tools/testing/selftests/drivers/net/gro.py subtest hw_ipv4_data_lrg_1byte sends {100, 1} expecting to receive {101}. In current code, it receives {106} (100 + 1 payload + 5 pad) instead.
This patch avoids giving the user padding as payload by simply not coalescing small packets (which fails the subtest; the same approach and behavior as sw gro). This gains code simplicity at the cost of more computation (passing an extra skb up the stack) for small packets that could be coalesced.
The threshold is chosen as ETH_ZLEN + 2 * VLAN_HLEN. This is the largest frame that may still contain minimum-frame padding (+ 2 VLAN tags), so anything larger is safe to consider for coalesce. (We do not include ETH_FCS_LEN in that threshold computation as netdev_fix_features() drops NETIF_F_GRO_HW whenever NETIF_F_RXFCS is set, so retained FCS can't reach this path.)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +5 -0
@@ -2263,6 +2263,11 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq data_offset = wqe_offset & (page_size -1 ); page_idx = wqe_offset >> rq->mpwqe.page_shift; +if (unlikely (cqe_bcnt <=ETH_ZLEN +2 *VLAN_HLEN )) { + match = false; + flush = true; + } +if (*skb && !(match &&mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt, page_size))) {
Sasha Levin
maintainerPATCH 1/2 net/mlx5e: SHAMPO, Always calculate page size
From: Dragos Tatulea <[email protected]>
[ Upstream commit dff1c3164a69284ac9fedb1c25d4c008139e9fb8 ]
Adapt the rx path in SHAMPO mode to calculate page size based on configured page_shift when dealing with payload data.
This is necessary as an upcoming patch will add support for using different page sizes.
This change has no functional changes.
Stable-dep-of: e2466392a0b8 ("net/mlx5e: do not HW-GRO coalesce small frames")
--- .../net/ethernet/mellanox/mlx5/core/en_rx.c | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +22 -12
@@ -1983,11 +1983,14 @@ mlx5e_shampo_fill_skb_data(struct sk_buff *skb, struct mlx5e_rq *rq,struct mlx5e_frag_page *frag_page, u32 data_bcnt, u32 data_offset) { + u32 page_size = BIT(rq->mpwqe.page_shift); +net_prefetchw (skb->data); do { /* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */ - u32 pg_consumed_bytes = min_t(u32, PAGE_SIZE - data_offset, data_bcnt); + u32 pg_consumed_bytes = min_t(u32, page_size - data_offset, + data_bcnt); unsigned int truesize = pg_consumed_bytes; mlx5e_add_skb_frag(rq, skb, frag_page, data_offset,
@@ -2008,6 +2011,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wu16 headlen =min_t (u16,MLX5E_RX_MAX_HEAD , cqe_bcnt);struct mlx5e_frag_page *head_page = frag_page;struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf; +u32 page_size =BIT (rq->mpwqe.page_shift);u32 frag_offset = head_offset;u32 byte_cnt = cqe_bcnt;struct skb_shared_info *sinfo;
@@ -2051,9 +2055,9 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w linear_hr =skb_headroom (skb); linear_data_len = headlen; linear_frame_sz =MLX5_SKB_FRAG_SZ (skb_end_offset (skb)); -if (unlikely (frag_offset >=PAGE_SIZE )) { +if (unlikely (frag_offset >= page_size)) { frag_page++; - frag_offset -=PAGE_SIZE ; + frag_offset -= page_size; } }
@@ -2065,7 +2069,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wwhile (byte_cnt) {/* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */ pg_consumed_bytes = -min_t (u32,PAGE_SIZE - frag_offset, byte_cnt); +min_t (u32, page_size - frag_offset, byte_cnt);if (test_bit (MLX5E_RQ_STATE_SHAMPO , &rq->state)) truesize += pg_consumed_bytes;
@@ -2102,7 +2106,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w nr_frags_free = old_nr_frags - sinfo->nr_frags;if (unlikely (nr_frags_free)) { frag_page -= nr_frags_free; - truesize -= (nr_frags_free -1 ) *PAGE_SIZE + + truesize -= (nr_frags_free -1 ) * page_size +ALIGN (pg_consumed_bytes,BIT (rq->mpwqe.log_stride_sz)); }
@@ -2311,15 +2315,16 @@ mlx5e_shampo_flush_skb(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, bool match) rq->hw_gro_data->skb =NULL ; } -static bool -mlx5e_hw_gro_skb_has_enough_space (struct sk_buff *skb,u16 data_bcnt) +static bool mlx5e_hw_gro_skb_has_enough_space (struct sk_buff *skb, +u16 data_bcnt, +u32 page_size) {int nr_frags =skb_shinfo (skb)->nr_frags; -if (PAGE_SIZE >=GRO_LEGACY_MAX_SIZE ) +if (page_size >=GRO_LEGACY_MAX_SIZE )return skb->len + data_bcnt <=GRO_LEGACY_MAX_SIZE ;else -return PAGE_SIZE * nr_frags + data_bcnt <=GRO_LEGACY_MAX_SIZE ; +return page_size * nr_frags + data_bcnt <=GRO_LEGACY_MAX_SIZE ; }static void mlx5e_handle_rx_cqe_mpwrq_shampo (struct mlx5e_rq *rq,struct mlx5_cqe64 *cqe)
@@ -2328,18 +2333,19 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqu16 header_index =mlx5e_shampo_get_cqe_header_index (rq, cqe);u32 wqe_offset =be32_to_cpu (cqe->shampo.data_offset);u16 cstrides =mpwrq_get_cqe_consumed_strides (cqe); -u32 data_offset = wqe_offset & (PAGE_SIZE -1 );u32 cqe_bcnt =mpwrq_get_cqe_byte_cnt (cqe);u16 wqe_id =be16_to_cpu (cqe->wqe_id); -u32 page_idx = wqe_offset >>PAGE_SHIFT ;u16 head_size = cqe->shampo.header_size;struct sk_buff **skb = &rq->hw_gro_data->skb;bool flush = cqe->shampo.flush;bool match = cqe->shampo.match; +u32 page_size =BIT (rq->mpwqe.page_shift);struct mlx5e_rq_stats *stats = rq->stats;struct mlx5e_rx_wqe_ll *wqe;struct mlx5e_mpw_info *wi;struct mlx5_wq_ll *wq; +u32 data_offset; +u32 page_idx; wi =mlx5e_get_mpw_info (rq, wqe_id); wi->consumed_strides += cstrides;
@@ -2355,7 +2361,11 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq goto mpwrq_cqe_out; } -if (*skb && (!match || !(mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt)))) { + data_offset = wqe_offset & (page_size -1 ); + page_idx = wqe_offset >> rq->mpwqe.page_shift; +if (*skb && + !(match &&mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt, + page_size))) { match = false;mlx5e_shampo_flush_skb (rq, cqe, match); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 net/mlx5e: do not HW-GRO coalesce small frames
From: Glenn Judd <[email protected]>
[ Upstream commit e2466392a0b8496000e12181cb1ee1535eb0da25 ]
When hardware GRO (SHAMPO) coalesces a small IPv4/TCP segment that was padded up to the 60-byte minimum Ethernet frame, the trailing padding is folded into the merged payload causing padding to be delivered to the user as payload.
Detecting and reproducing the issue: the selftest tools/testing/selftests/drivers/net/gro.py subtest hw_ipv4_data_lrg_1byte sends {100, 1} expecting to receive {101}. In current code, it receives {106} (100 + 1 payload + 5 pad) instead.
This patch avoids giving the user padding as payload by simply not coalescing small packets (which fails the subtest; the same approach and behavior as sw gro). This gains code simplicity at the cost of more computation (passing an extra skb up the stack) for small packets that could be coalesced.
The threshold is chosen as ETH_ZLEN + 2 * VLAN_HLEN. This is the largest frame that may still contain minimum-frame padding (+ 2 VLAN tags), so anything larger is safe to consider for coalesce. (We do not include ETH_FCS_LEN in that threshold computation as netdev_fix_features() drops NETIF_F_GRO_HW whenever NETIF_F_RXFCS is set, so retained FCS can't reach this path.)
--- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +5 -0
@@ -2363,6 +2363,11 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq data_offset = wqe_offset & (page_size -1 ); page_idx = wqe_offset >> rq->mpwqe.page_shift; +if (unlikely (cqe_bcnt <=ETH_ZLEN +2 *VLAN_HLEN )) { + match = false; + flush = true; + } +if (*skb && !(match &&mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt, page_size))) {
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 1/2 net/mlx5e: SHAMPO, Always calculate page size
In reply to [email protected]From: Dragos Tatulea <[email protected]>
[ Upstream commit dff1c3164a69284ac9fedb1c25d4c008139e9fb8 ]
Adapt the rx path in SHAMPO mode to calculate page size based on configured page_shift when dealing with payload data.
This is necessary as an upcoming patch will add support for using different page sizes.
This change has no functional changes.
Stable-dep-of: e2466392a0b8 ("net/mlx5e: do not HW-GRO coalesce small frames")
--- .../net/ethernet/mellanox/mlx5/core/en_rx.c | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +22 -12
@@ -1983,11 +1983,14 @@ mlx5e_shampo_fill_skb_data(struct sk_buff *skb, struct mlx5e_rq *rq,struct mlx5e_frag_page *frag_page, u32 data_bcnt, u32 data_offset) { + u32 page_size = BIT(rq->mpwqe.page_shift); +net_prefetchw (skb->data); do { /* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */ - u32 pg_consumed_bytes = min_t(u32, PAGE_SIZE - data_offset, data_bcnt); + u32 pg_consumed_bytes = min_t(u32, page_size - data_offset, + data_bcnt); unsigned int truesize = pg_consumed_bytes; mlx5e_add_skb_frag(rq, skb, frag_page, data_offset,
@@ -2008,6 +2011,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wu16 headlen =min_t (u16,MLX5E_RX_MAX_HEAD , cqe_bcnt);struct mlx5e_frag_page *head_page = frag_page;struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf; +u32 page_size =BIT (rq->mpwqe.page_shift);u32 frag_offset = head_offset;u32 byte_cnt = cqe_bcnt;struct skb_shared_info *sinfo;
@@ -2051,9 +2055,9 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w linear_hr =skb_headroom (skb); linear_data_len = headlen; linear_frame_sz =MLX5_SKB_FRAG_SZ (skb_end_offset (skb)); -if (unlikely (frag_offset >=PAGE_SIZE )) { +if (unlikely (frag_offset >= page_size)) { frag_page++; - frag_offset -=PAGE_SIZE ; + frag_offset -= page_size; } }
@@ -2065,7 +2069,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wwhile (byte_cnt) {/* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */ pg_consumed_bytes = -min_t (u32,PAGE_SIZE - frag_offset, byte_cnt); +min_t (u32, page_size - frag_offset, byte_cnt);if (test_bit (MLX5E_RQ_STATE_SHAMPO , &rq->state)) truesize += pg_consumed_bytes;
@@ -2102,7 +2106,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w nr_frags_free = old_nr_frags - sinfo->nr_frags;if (unlikely (nr_frags_free)) { frag_page -= nr_frags_free; - truesize -= (nr_frags_free -1 ) *PAGE_SIZE + + truesize -= (nr_frags_free -1 ) * page_size +ALIGN (pg_consumed_bytes,BIT (rq->mpwqe.log_stride_sz)); }
@@ -2311,15 +2315,16 @@ mlx5e_shampo_flush_skb(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe, bool match) rq->hw_gro_data->skb =NULL ; } -static bool -mlx5e_hw_gro_skb_has_enough_space (struct sk_buff *skb,u16 data_bcnt) +static bool mlx5e_hw_gro_skb_has_enough_space (struct sk_buff *skb, +u16 data_bcnt, +u32 page_size) {int nr_frags =skb_shinfo (skb)->nr_frags; -if (PAGE_SIZE >=GRO_LEGACY_MAX_SIZE ) +if (page_size >=GRO_LEGACY_MAX_SIZE )return skb->len + data_bcnt <=GRO_LEGACY_MAX_SIZE ;else -return PAGE_SIZE * nr_frags + data_bcnt <=GRO_LEGACY_MAX_SIZE ; +return page_size * nr_frags + data_bcnt <=GRO_LEGACY_MAX_SIZE ; }static void mlx5e_handle_rx_cqe_mpwrq_shampo (struct mlx5e_rq *rq,struct mlx5_cqe64 *cqe)
@@ -2328,18 +2333,19 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cqu16 header_index =mlx5e_shampo_get_cqe_header_index (rq, cqe);u32 wqe_offset =be32_to_cpu (cqe->shampo.data_offset);u16 cstrides =mpwrq_get_cqe_consumed_strides (cqe); -u32 data_offset = wqe_offset & (PAGE_SIZE -1 );u32 cqe_bcnt =mpwrq_get_cqe_byte_cnt (cqe);u16 wqe_id =be16_to_cpu (cqe->wqe_id); -u32 page_idx = wqe_offset >>PAGE_SHIFT ;u16 head_size = cqe->shampo.header_size;struct sk_buff **skb = &rq->hw_gro_data->skb;bool flush = cqe->shampo.flush;bool match = cqe->shampo.match; +u32 page_size =BIT (rq->mpwqe.page_shift);struct mlx5e_rq_stats *stats = rq->stats;struct mlx5e_rx_wqe_ll *wqe;struct mlx5e_mpw_info *wi;struct mlx5_wq_ll *wq; +u32 data_offset; +u32 page_idx; wi =mlx5e_get_mpw_info (rq, wqe_id); wi->consumed_strides += cstrides;
@@ -2355,7 +2361,11 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq goto mpwrq_cqe_out; } -if (*skb && (!match || !(mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt)))) { + data_offset = wqe_offset & (page_size -1 ); + page_idx = wqe_offset >> rq->mpwqe.page_shift; +if (*skb && + !(match &&mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt, + page_size))) { match = false;mlx5e_shampo_flush_skb (rq, cqe, match); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 net/mlx5e: do not HW-GRO coalesce small frames
From: Glenn Judd <[email protected]>
[ Upstream commit e2466392a0b8496000e12181cb1ee1535eb0da25 ]
When hardware GRO (SHAMPO) coalesces a small IPv4/TCP segment that was padded up to the 60-byte minimum Ethernet frame, the trailing padding is folded into the merged payload causing padding to be delivered to the user as payload.
Detecting and reproducing the issue: the selftest tools/testing/selftests/drivers/net/gro.py subtest hw_ipv4_data_lrg_1byte sends {100, 1} expecting to receive {101}. In current code, it receives {106} (100 + 1 payload + 5 pad) instead.
This patch avoids giving the user padding as payload by simply not coalescing small packets (which fails the subtest; the same approach and behavior as sw gro). This gains code simplicity at the cost of more computation (passing an extra skb up the stack) for small packets that could be coalesced.
The threshold is chosen as ETH_ZLEN + 2 * VLAN_HLEN. This is the largest frame that may still contain minimum-frame padding (+ 2 VLAN tags), so anything larger is safe to consider for coalesce. (We do not include ETH_FCS_LEN in that threshold computation as netdev_fix_features() drops NETIF_F_GRO_HW whenever NETIF_F_RXFCS is set, so retained FCS can't reach this path.)
--- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +5 -0
@@ -2363,6 +2363,11 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq data_offset = wqe_offset & (page_size -1 ); page_idx = wqe_offset >> rq->mpwqe.page_shift; +if (unlikely (cqe_bcnt <=ETH_ZLEN +2 *VLAN_HLEN )) { + match = false; + flush = true; + } +if (*skb && !(match &&mlx5e_hw_gro_skb_has_enough_space (*skb, data_bcnt, page_size))) {
Signature · 1 line
2.53.0