Skip to content

[rlc-8] Fix idpf tx timeout issue#921

Draft
roxanan1996 wants to merge 11 commits intorlc-8/4.18.0-553.105.1.el8_10from
{rnicolescu}/rlc-8/4.18.0-553.105.1.el8_10
Draft

[rlc-8] Fix idpf tx timeout issue#921
roxanan1996 wants to merge 11 commits intorlc-8/4.18.0-553.105.1.el8_10from
{rnicolescu}/rlc-8/4.18.0-553.105.1.el8_10

Conversation

@roxanan1996
Copy link
Contributor

@roxanan1996 roxanan1996 commented Feb 25, 2026

https://ciqinc.atlassian.net/browse/KERNEL-168

Description

Customer request to fix a tx timeout issue in c4a metal instances in
google cloud.

From mainline submission explanation:

This series fixes a stability issue in the flow scheduling Tx send/clean
path that results in a Tx timeout.

The existing guardrails in the Tx path were not sufficient to prevent
the driver from reusing completion tags that were still in flight (held
by the HW). This collision would cause the driver to erroneously clean
the wrong packet thus leaving the descriptor ring in a bad state.

The main point of this fix is to replace the flow scheduling buffer ring
with a large pool/array of buffers. The completion tag then simply is
the index into this array. The driver tracks the free tags and pulls
the next free one from a refillq. The cleaning routines simply use the
completion tag from the completion descriptor to index into the array to
quickly find the buffers to clean.

All of the code to support this is added first to ensure traffic still
passes with each patch. The final patch then removes all of the
obsolete stashing code.

COMMITS

In comparison with rlc-10 and rlc-9, the commits were trickier to apply here.
Especially commit idpf: simplify and fix splitq Tx packet rollback error path.
I decided to backport some dependency to make the backport easier.
https://lore.kernel.org/lkml/20240904154748.2114199-1-aleksander.lobakin@intel.com/
Last 2 commits from the patchset were already applied.
This patchset is part of a refactor needed for XDP support. First was this https://lore.kernel.org/lkml/20240620135347.3006818-1-aleksander.lobakin@intel.com/ for rx.
This patchset addresses only the tx conversion to libeth.
I only included the tx refactor since it is needed to address this tx timeout isssue.

The rest of the commits were similar to the ones for rlc-9/10.
Extra conflicts appeared, mainly because of this one missing
1b1b262 ("idpf: reuse libeth's definitions of parsed ptype structures")

libeth: add Tx buffer completion helpers

jira KERNEL-168
commit-author Alexander Lobakin <aleksander.lobakin@intel.com>
commit 080d72f471c86f8906845bc822051f5790d0a90d
idpf: convert to libeth Tx buffer completion

jira KERNEL-168
commit-author Alexander Lobakin <aleksander.lobakin@intel.com>
commit d9028db618a63e4bbe63eb56c0b0db2b4cb924bc
upstream-diff |
	adjusted context due to missing #include <net/libeth/rx.h>
	introduced in commit 1b1b26208515
	("idpf: reuse libeth's definitions of parsed ptype structures")
	part of "convert RX to libeth" patchset.
netdevice: add netdev_tx_reset_subqueue() shorthand

jira KERNEL-168
commit-author Alexander Lobakin <aleksander.lobakin@intel.com>
commit 3dc95a3edd0a86b4a59670b3fafcc64c7d83e2e7
idpf: refactor Tx completion routines

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 24eb35b15152ed6a2473019413b86b8f1c9714be
upstream-diff |
	adjusted context in .h file around struct idpf_compl_queue due to missing
	commit 5a816aae2d46
	("idpf: strictly assert cachelines of queue and queue vector structures")
idpf: set completion tag for "empty" bufs associated with a packet

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 4c69c77aafe74cf755af55070584b643e5c4e4d8
idpf: add support for Tx refillqs in flow scheduling mode

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit cb83b559bea39f207ee214ee2972657e8576ed18
upstream-diff |
	1. adjusted context around idpf_rx_splitq_clean function due to missing
	- 74d1412ac8f3 ("idpf: use libeth Rx buffer management for payload buffer")
	- 6ad5ff6e7282 ("libeth: convert to netmem")
	2. adjusted context around struct idpf_tx_queue members and docstring
	and did not include the libeth_cacheline_set_assert changes due to missing:
	- 5a816aae2d46 ("idpf: strictly assert cachelines of queue and queue vector structures")
	3. fix compilation issue (std=89) in idpf_tx_desc_alloc due to for loop var
	declaration
idpf: improve when to set RE bit logic

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit f2d18e16479cac7a708d77cbfb4220a9114a71fc
upstream-diff |
	adjusted context in struct idpf_tx_queue because the order
	of the fields is different due to missing
	- 5a816aae2d46 ("idpf: strictly assert cachelines of queue and queue vector structures")
idpf: simplify and fix splitq Tx packet rollback error path

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit b61dfa9bc4430ad82b96d3a7c1c485350f91b467
upstream-diff |
	adjusted context in 2 places:
	- when removing func idpf_tx_dma_map_error due to different memset
	call that uses the hardcoded struct type;
	- in func idpf_tx_splitq_frame due to missing expected
	union idpf_flex_tx_ctx_desc *ctx_desc;
	both differences were introduced in commit
	1a49cf814fe1e ("idpf: add Tx timestamp flows").
idpf: replace flow scheduling buffer ring with buffer pool

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 5f417d551324d2894168b362f2429d120ab06243
upstream-diff |
	adjusted context in:
	- ifpf_tx_splitq_frame and idpf_tx_clean_bufs;
	- struct idpf_tx_queue due to missing of some elements in the struct;
	both due to missing commit
	- 1a49cf814fe1e ("idpf: add Tx timestamp flows").
	and did not include the cacheline assert changes due to missing
	- 5a816aae2d46 ("idpf: strictly assert cachelines of queue and queue vector structures")
idpf: stop Tx if there are insufficient buffer resources

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 0c3f135e840d4a2ba4253e15d530ec61bc30718e
upstream-diff |
	adjusted conflict in idpf_tx_splitq_frame func due to missing
	1a49cf814fe1e ("idpf: add Tx timestamp flows").
idpf: remove obsolete stashing code

jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 6c4e68480238274f84aa50d54da0d9e262df6284
upstream-diff |
	- adjusted context in .h due to different order in the struct idpf_tx_queue
	- adjusted context due to missing idpf_tx_read_tstamp func;
	both are due to missing
	1a49cf814fe1e ("idpf: add Tx timestamp flows").
	- did not include libeth_cacheline_set_assert for struct idpf_tx_queue
	due to missing 5a816aae2d46
	("idpf: strictly assert cachelines of queue and queue vector structures")

BUILD

/home/rnicolescu/ciq/kernels/rlc-8-latest/kernel-src-tree
Running make mrproper...
[TIMER]{MRPROPER}: 4s
x86_64 architecture detected, copying config
'configs/kernel-x86_64.config' -> '.config'
Setting Local Version for build
CONFIG_LOCALVERSION="-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01"
Making olddefconfig
--
  HOSTLD  scripts/kconfig/conf
scripts/kconfig/conf  --olddefconfig Kconfig
#
# configuration written to .config
#
Starting Build
scripts/kconfig/conf  --syncconfig Kconfig
  SYSTBL  arch/x86/include/generated/asm/syscalls_32.h
  SYSHDR  arch/x86/include/generated/asm/unistd_32_ia32.h
  SYSTBL  arch/x86/include/generated/asm/syscalls_64.h
  HYPERCALLS arch/x86/include/generated/asm/xen-hypercalls.h
--
  LD [M]  sound/usb/usx2y/snd-usb-usx2y.ko
  LD [M]  sound/virtio/virtio_snd.ko
  LD [M]  sound/x86/snd-hdmi-lpe-audio.ko
  LD [M]  sound/xen/snd_xen_front.ko
  LD [M]  virt/lib/irqbypass.ko
[TIMER]{BUILD}: 1512s
Making Modules
  INSTALL arch/x86/crypto/blowfish-x86_64.ko
  INSTALL arch/x86/crypto/camellia-aesni-avx-x86_64.ko
  INSTALL arch/x86/crypto/camellia-aesni-avx2.ko
  INSTALL arch/x86/crypto/camellia-x86_64.ko
--
  INSTALL sound/virtio/virtio_snd.ko
  INSTALL sound/x86/snd-hdmi-lpe-audio.ko
  INSTALL sound/xen/snd_xen_front.ko
  INSTALL virt/lib/irqbypass.ko
  DEPMOD  4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+
[TIMER]{MODULES}: 10s
Making Install
sh ./arch/x86/boot/install.sh 4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+ arch/x86/boot/bzImage \
	System.map "/boot"
[TIMER]{INSTALL}: 17s
Checking kABI
kABI check passed
Setting Default Kernel to /boot/vmlinuz-4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+ and Index to 0
The default is /boot/loader/entries/6d7c5ebaf0da48f5a4e3cf1a74f29435-4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+.conf with index 0 and kernel /boot/vmlinuz-4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+
The default is /boot/loader/entries/6d7c5ebaf0da48f5a4e3cf1a74f29435-4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+.conf with index 0 and kernel /boot/vmlinuz-4.18.0-rnicolescu_rlc-8_4.18.0-553.105.1.el8_10-fe33d5dfce01+
Generating grub configuration file ...
done
Hopefully Grub2.0 took everything ... rebooting after time metrices
[TIMER]{MRPROPER}: 4s
[TIMER]{BUILD}: 1512s
[TIMER]{MODULES}: 10s
[TIMER]{INSTALL}: 17s
[TIMER]{TOTAL} 1548s
Rebooting in 10 seconds

Kselftests

./kselftest-before.log
259
./kselftest-after.log
257
Before: ./kselftest-before.log
After: ./kselftest-after.log
Diff:
-ok 15 selftests: kvm: pmu_event_filter_test
+ok 15 selftests: kvm: pmu_event_filter_test # SKIP
-ok 18 selftests: kvm: smm_test
-ok 19 selftests: kvm: state_test
-ok 20 selftests: kvm: vmx_preemption_timer_test
-ok 36 selftests: kvm: xss_msr_test # SKIP
+ok 36 selftests: kvm: xss_msr_test
-ok 39 selftests: kvm: vmx_pmu_caps_test
+ok 39 selftests: kvm: vmx_pmu_caps_test # SKIP
-ok 4 selftests: kvm: evmcs_test
+ok 51 selftests: kvm: max_guest_memory_test
+ok 54 selftests: kvm: rseq_test

Check_kernel_commits

> python3 ~/ciq/kernel-src-tree-tools/check_kernel_commits.py --repo . --pr_branch {rnicolescu}/rlc-8/4.18.0-553.105.1.el8_10 --base_branch origin/rlc-8/4.18.0-553.105.1.el8_10
All referenced commits exist upstream and have no Fixes: tags.

Run interdiff

[DIFF] PR commit 78d98f864d04 (idpf: convert to libeth Tx buffer completion) → upstream d9028db618a6
Differences found:

  ================================================================================
  *    DELTA DIFFERENCES - code changes that differ between the patches          *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
  @@ -1,8 +1,6 @@
   // SPDX-License-Identifier: GPL-2.0-only
   /* Copyright (C) 2023 Intel Corporation */
   
  -#include <net/libeth/tx.h>
  -
   #include "idpf.h"
   
   /**
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -1,8 +1,6 @@
   // SPDX-License-Identifier: GPL-2.0-only
   /* Copyright (C) 2023 Intel Corporation */
   
  -#include <net/libeth/tx.h>
  -
   #include "idpf.h"
   #include "idpf_virtchnl.h"
   
  
  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
  @@ -2,6 +2,7 @@
   /* Copyright (C) 2023 Intel Corporation */
   
   #include <net/libeth/rx.h>
  +#include <net/libeth/tx.h>
   
   #include "idpf.h"
   
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2,6 +2,7 @@
   /* Copyright (C) 2023 Intel Corporation */
   
   #include <net/libeth/rx.h>
  +#include <net/libeth/tx.h>
   
   #include "idpf.h"
   #include "idpf_virtchnl.h"
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
  @@ -2,4 +1,8 @@
   /* Copyright (C) 2023 Intel Corporation */
   
  +#include <net/libeth/rx.h>
  +
  +#include <net/libeth/tx.h>
  +
   #include "idpf.h"
   
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2,5 +1,9 @@
   /* Copyright (C) 2023 Intel Corporation */
   
  +#include <net/libeth/rx.h>
  +
  +#include <net/libeth/tx.h>
  +
   #include "idpf.h"
   #include "idpf_virtchnl.h"

[DIFF] PR commit 4a623ccb132f (idpf: refactor Tx completion routines) → upstream 24eb35b15152
Differences found:

  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -785,7 +785,7 @@
   	u32 next_to_use;
   	u32 next_to_clean;
   
  -	u32 num_completions;
  +	aligned_u64 num_completions;
   	__cacheline_group_end_aligned(read_write);
   
   	__cacheline_group_begin_aligned(cold);
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -971,4 +920,4 @@
   	u32 num_completions_pending;
   };
   
  -/**
  +static inline int idpf_q_vector_to_mem(const struct idpf_q_vector *q_vector)

[DIFF] PR commit 3d7487afc656 (idpf: add support for Tx refillqs in flow scheduling mode) → upstream cb83b559bea3
Differences found:

  ================================================================================
  *    DELTA DIFFERENCES - code changes that differ between the patches          *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -247,7 +247,6 @@
   	struct device *dev = tx_q->dev;
   	struct idpf_sw_queue *refillq;
   	int err;
  -	unsigned int i = 0;
   
   	err = idpf_tx_buf_alloc_all(tx_q);
   	if (err)
  @@ -282,7 +281,7 @@
   		goto err_alloc;
   	}
   
  -	for (i = 0; i < refillq->desc_count; i++)
  +	for (unsigned int i = 0; i < refillq->desc_count; i++)
   		refillq->ring[i] =
   			FIELD_PREP(IDPF_RFL_BI_BUFID_M, i) |
   			FIELD_PREP(IDPF_RFL_BI_GEN_M,
  
  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -3551,7 +3630,7 @@
   skip_data:
   		rx_buf->netmem = 0;
   
  -		idpf_rx_post_buf_refill(refillq, buf_id);
  +		idpf_post_buf_refill(refillq, buf_id);
   		IDPF_RX_BUMP_NTC(rxq, ntc);
   
   		/* skip if it is non EOP desc */
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -622,6 +622,7 @@
    * @cleaned_pkts: Number of packets cleaned for the above said case
    * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
    * @stash: Tx buffer stash for Flow-based scheduling mode
  + * @refillq: Pointer to refill queue
    * @compl_tag_bufid_m: Completion tag buffer id mask
    * @compl_tag_cur_gen: Used to keep track of current completion tag generation
    * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
  @@ -671,6 +672,7 @@
   
   	u16 tx_max_bufs;
   	struct idpf_txq_stash *stash;
  +	struct idpf_sw_queue *refillq;
   
   	u16 compl_tag_bufid_m;
   	u16 compl_tag_cur_gen;
  @@ -692,7 +694,7 @@
   	__cacheline_group_end_aligned(cold);
   };
   libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
  -			    112 + sizeof(struct u64_stats_sync),
  +			    120 + sizeof(struct u64_stats_sync),
   			    24);
   
   /**
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -244,4 +246,5 @@
   	struct device *dev = tx_q->dev;
   	int err;
  +	unsigned int i = 0;
   
   	err = idpf_tx_buf_alloc_all(tx_q);
  @@ -3358,4 +3417,4 @@
   		idpf_rx_post_buf_refill(refillq, buf_id);
  -
   		IDPF_RX_BUMP_NTC(rxq, ntc);
  +
   		/* skip if it is non EOP desc */
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -624,6 +619,6 @@
    * @cleaned_pkts: Number of packets cleaned for the above said case
    * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
  - * @tx_min_pkt_len: Min supported packet length
  + * @stash: Tx buffer stash for Flow-based scheduling mode
    * @compl_tag_bufid_m: Completion tag buffer id mask
  - * @compl_tag_gen_s: Completion tag generation bit
  - *	The format of the completion tag will change based on the TXQ
  + * @compl_tag_cur_gen: Used to keep track of current completion tag generation
  + * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
  @@ -743,6 +692,2 @@
   
  -	u16 tx_max_bufs;
  -	u16 tx_min_pkt_len;
  -
  -	u16 compl_tag_bufid_m;
  -	u16 compl_tag_gen_s;
  +/**

[DIFF] PR commit 2c34100e4637 (idpf: improve when to set RE bit logic) → upstream f2d18e16479c
Differences found:

  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -610,6 +610,8 @@
    * @netdev: &net_device corresponding to this queue
    * @next_to_use: Next descriptor to use
    * @next_to_clean: Next descriptor to clean
  + * @last_re: last descriptor index that RE bit was set
  + * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
    * @cleaned_bytes: Splitq only, TXQ only: When a TX completion is received on
    *		   the TX completion queue, it can be for any TXQ associated
    *		   with that completion queue. This means we can clean up to
  @@ -620,7 +622,6 @@
    *		   only once at the end of the cleaning routine.
    * @clean_budget: singleq only, queue cleaning budget
    * @cleaned_pkts: Number of packets cleaned for the above said case
  - * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
    * @stash: Tx buffer stash for Flow-based scheduling mode
    * @refillq: Pointer to refill queue
    * @compl_tag_bufid_m: Completion tag buffer id mask
  @@ -672,7 +675,6 @@
   	};
   	u16 cleaned_pkts;
   
  -	u16 tx_max_bufs;
   	struct idpf_txq_stash *stash;
   	struct idpf_sw_queue *refillq;
   
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -607,6 +607,5 @@
  - * @desc_count: Number of descriptors
  + * @netdev: &net_device corresponding to this queue
    * @next_to_use: Next descriptor to use
    * @next_to_clean: Next descriptor to clean
  - * @netdev: &net_device corresponding to this queue
    * @cleaned_bytes: Splitq only, TXQ only: When a TX completion is received on
    *		   the TX completion queue, it can be for any TXQ associated
  @@ -685,5 +622,5 @@
    * @cleaned_pkts: Number of packets cleaned for the above said case
    * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
  - * @tx_min_pkt_len: Min supported packet length
  + * @stash: Tx buffer stash for Flow-based scheduling mode
    * @refillq: Pointer to refill queue
    * @compl_tag_bufid_m: Completion tag buffer id mask
  @@ -723,4 +660,4 @@
  -	u16 desc_count;
  +	__cacheline_group_begin_aligned(read_write);
   	u16 next_to_use;
   	u16 next_to_clean;
   
  @@ -731,5 +668,5 @@
   
   	u16 tx_max_bufs;
  -	u16 tx_min_pkt_len;
  +	struct idpf_txq_stash *stash;
   	struct idpf_sw_queue *refillq;

[DIFF] PR commit 916485ec68a4 (idpf: simplify and fix splitq Tx packet rollback error path) → upstream b61dfa9bc443
Differences found:

  ================================================================================
  *    DELTA DIFFERENCES - code changes that differ between the patches          *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2287,4 +2287,55 @@
   
   /**
  + * idpf_tx_dma_map_error - handle TX DMA map errors
  + * @txq: queue to send buffer on
  + * @skb: send buffer
  + * @first: original first buffer info buffer for packet
  + * @idx: starting point on ring to unwind
  + */
  +void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb,
  +			   struct idpf_tx_buf *first, u16 idx)
  +{
  +	struct libeth_sq_napi_stats ss = { };
  +	struct libeth_cq_pp cp = {
  +		.dev	= txq->dev,
  +		.ss	= &ss,
  +	};
  +
  +	u64_stats_update_begin(&txq->stats_sync);
  +	u64_stats_inc(&txq->q_stats.dma_map_errs);
  +	u64_stats_update_end(&txq->stats_sync);
  +
  +	/* clear dma mappings for failed tx_buf map */
  +	for (;;) {
  +		struct idpf_tx_buf *tx_buf;
  +
  +		tx_buf = &txq->tx_buf[idx];
  +		libeth_tx_complete(tx_buf, &cp);
  +		if (tx_buf == first)
  +			break;
  +		if (idx == 0)
  +			idx = txq->desc_count;
  +		idx--;
  +	}
  +
  +	if (skb_is_gso(skb)) {
  +		union idpf_tx_flex_desc *tx_desc;
  +
  +		/* If we failed a DMA mapping for a TSO packet, we will have
  +		 * used one additional descriptor for a context
  +		 * descriptor. Reset that here.
  +		 */
  +		tx_desc = &txq->flex_tx[idx];
  +		memset(tx_desc, 0, sizeof(struct idpf_flex_tx_ctx_desc));
  +		if (idx == 0)
  +			idx = txq->desc_count;
  +		idx--;
  +	}
  +
  +	/* Update tail in case netdev_xmit_more was previously true */
  +	idpf_tx_buf_hw_update(txq, idx, false);
  +}
  +
  +/**
    * idpf_tx_splitq_bump_ntu - adjust NTU and generation
    * @txq: the tx ring to wrap
  @@ -2335,35 +2386,4 @@
   
   /**
  - * idpf_tx_splitq_pkt_err_unmap - Unmap buffers and bump tail in case of error
  - * @txq: Tx queue to unwind
  - * @params: pointer to splitq params struct
  - * @first: starting buffer for packet to unmap
  - */
  -static void idpf_tx_splitq_pkt_err_unmap(struct idpf_tx_queue *txq,
  -					 struct idpf_tx_splitq_params *params,
  -					 struct idpf_tx_buf *first)
  -{
  -	struct libeth_sq_napi_stats ss = { };
  -	struct idpf_tx_buf *tx_buf = first;
  -	struct libeth_cq_pp cp = {
  -		.dev    = txq->dev,
  -		.ss     = &ss,
  -	};
  -	u32 idx = 0;
  -
  -	u64_stats_update_begin(&txq->stats_sync);
  -	u64_stats_inc(&txq->q_stats.dma_map_errs);
  -	u64_stats_update_end(&txq->stats_sync);
  -
  -	do {
  -		libeth_tx_complete(tx_buf, &cp);
  -		idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
  -	} while (idpf_tx_buf_compl_tag(tx_buf) == params->compl_tag);
  -
  -	/* Update tail in case netdev_xmit_more was previously true. */
  -	idpf_tx_buf_hw_update(txq, params->prev_ntu, false);
  -}
  -
  -/**
    * idpf_tx_splitq_map - Build the Tx flex descriptor
    * @tx_q: queue to send buffer on
  
  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2339,57 +2339,6 @@
   	return count;
   }
   
  -/**
  - * idpf_tx_dma_map_error - handle TX DMA map errors
  - * @txq: queue to send buffer on
  - * @skb: send buffer
  - * @first: original first buffer info buffer for packet
  - * @idx: starting point on ring to unwind
  - */
  -void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb,
  -			   struct idpf_tx_buf *first, u16 idx)
  -{
  -	struct libeth_sq_napi_stats ss = { };
  -	struct libeth_cq_pp cp = {
  -		.dev	= txq->dev,
  -		.ss	= &ss,
  -	};
  -
  -	u64_stats_update_begin(&txq->stats_sync);
  -	u64_stats_inc(&txq->q_stats.dma_map_errs);
  -	u64_stats_update_end(&txq->stats_sync);
  -
  -	/* clear dma mappings for failed tx_buf map */
  -	for (;;) {
  -		struct idpf_tx_buf *tx_buf;
  -
  -		tx_buf = &txq->tx_buf[idx];
  -		libeth_tx_complete(tx_buf, &cp);
  -		if (tx_buf == first)
  -			break;
  -		if (idx == 0)
  -			idx = txq->desc_count;
  -		idx--;
  -	}
  -
  -	if (skb_is_gso(skb)) {
  -		union idpf_tx_flex_desc *tx_desc;
  -
  -		/* If we failed a DMA mapping for a TSO packet, we will have
  -		 * used one additional descriptor for a context
  -		 * descriptor. Reset that here.
  -		 */
  -		tx_desc = &txq->flex_tx[idx];
  -		memset(tx_desc, 0, sizeof(*tx_desc));
  -		if (idx == 0)
  -			idx = txq->desc_count;
  -		idx--;
  -	}
  -
  -	/* Update tail in case netdev_xmit_more was previously true */
  -	idpf_tx_buf_hw_update(txq, idx, false);
  -}
  -
   /**
    * idpf_tx_splitq_bump_ntu - adjust NTU and generation
    * @txq: the tx ring to wrap
  @@ -2438,6 +2387,37 @@
   	return true;
   }
   
  +/**
  + * idpf_tx_splitq_pkt_err_unmap - Unmap buffers and bump tail in case of error
  + * @txq: Tx queue to unwind
  + * @params: pointer to splitq params struct
  + * @first: starting buffer for packet to unmap
  + */
  +static void idpf_tx_splitq_pkt_err_unmap(struct idpf_tx_queue *txq,
  +					 struct idpf_tx_splitq_params *params,
  +					 struct idpf_tx_buf *first)
  +{
  +	struct libeth_sq_napi_stats ss = { };
  +	struct idpf_tx_buf *tx_buf = first;
  +	struct libeth_cq_pp cp = {
  +		.dev    = txq->dev,
  +		.ss     = &ss,
  +	};
  +	u32 idx = 0;
  +
  +	u64_stats_update_begin(&txq->stats_sync);
  +	u64_stats_inc(&txq->q_stats.dma_map_errs);
  +	u64_stats_update_end(&txq->stats_sync);
  +
  +	do {
  +		libeth_tx_complete(tx_buf, &cp);
  +		idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
  +	} while (idpf_tx_buf_compl_tag(tx_buf) == params->compl_tag);
  +
  +	/* Update tail in case netdev_xmit_more was previously true. */
  +	idpf_tx_buf_hw_update(txq, params->prev_ntu, false);
  +}
  +
   /**
    * idpf_tx_splitq_map - Build the Tx flex descriptor
    * @tx_q: queue to send buffer on
  @@ -2482,8 +2462,9 @@
   	for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
   		unsigned int max_data = IDPF_TX_MAX_DESC_DATA_ALIGNED;
   
  -		if (dma_mapping_error(tx_q->dev, dma))
  -			return idpf_tx_dma_map_error(tx_q, skb, first, i);
  +		if (unlikely(dma_mapping_error(tx_q->dev, dma)))
  +			return idpf_tx_splitq_pkt_err_unmap(tx_q, params,
  +							    first);
   
   		first->nr_frags++;
   		idpf_tx_buf_compl_tag(tx_buf) = params->compl_tag;
  @@ -2939,7 +2920,9 @@
   static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
   					struct idpf_tx_queue *tx_q)
   {
  -	struct idpf_tx_splitq_params tx_params = { };
  +	struct idpf_tx_splitq_params tx_params = {
  +		.prev_ntu = tx_q->next_to_use,
  +	};
   	union idpf_flex_tx_ctx_desc *ctx_desc;
   	struct idpf_tx_buf *first;
   	unsigned int count;
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2326,7 +2380,7 @@
   		 * descriptor. Reset that here.
   		 */
   		tx_desc = &txq->flex_tx[idx];
  -		memset(tx_desc, 0, sizeof(struct idpf_flex_tx_ctx_desc));
  +		memset(tx_desc, 0, sizeof(*tx_desc));
   		if (idx == 0)
   			idx = txq->desc_count;
   		idx--;
  @@ -2817,4 +2871,5 @@
   {
   	struct idpf_tx_splitq_params tx_params = { };
  +	union idpf_flex_tx_ctx_desc *ctx_desc;
   	struct idpf_tx_buf *first;
   	unsigned int count;

[DIFF] PR commit 1bf91468a70d (idpf: replace flow scheduling buffer ring with buffer pool) → upstream 5f417d551324
Differences found:

  ================================================================================
  *    DELTA DIFFERENCES - code changes that differ between the patches          *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -1915,11 +1915,8 @@
   		.napi	= budget,
   	};
   
  -	tx_buf = &txq->tx_buf[buf_id];
  -	if (tx_buf->type == LIBETH_SQE_SKB) {
  +	if (tx_buf->type == LIBETH_SQE_SKB)
   		libeth_tx_complete(tx_buf, &cp);
  -		idpf_post_buf_refill(txq->refillq, buf_id);
  -	}
   
   	while (idpf_tx_buf_next(tx_buf) != IDPF_TXBUF_NULL) {
   		buf_id = idpf_tx_buf_next(tx_buf);
  
  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -1962,6 +1962,7 @@
   		     idpf_tx_buf_compl_tag(tx_buf) != compl_tag))
   		return false;
   
  +	tx_buf = &txq->tx_buf[buf_id];
   	if (tx_buf->type == LIBETH_SQE_SKB) {
   		if (skb_shinfo(tx_buf->skb)->tx_flags & SKBTX_IN_PROGRESS)
   			idpf_tx_read_tstamp(txq, tx_buf->skb);
  @@ -1965,6 +1966,7 @@
   			idpf_tx_read_tstamp(txq, tx_buf->skb);
   
   		libeth_tx_complete(tx_buf, &cp);
  +		idpf_post_buf_refill(txq->refillq, buf_id);
   	}
   
   	idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
  @@ -2892,6 +2859,7 @@
   	struct idpf_tx_buf *first;
   	unsigned int count;
   	int tso, idx;
  +	u32 buf_id;
   
   	count = idpf_tx_desc_count_required(tx_q, skb);
   	if (unlikely(!count))
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -703,6 +710,7 @@
   	dma_addr_t dma;
   
   	struct idpf_q_vector *q_vector;
  +	u32 buf_pool_size;
   	__cacheline_group_end_aligned(cold);
   };
   libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
  @@ -706,7 +714,7 @@
   };
   libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
   			    120 + sizeof(struct u64_stats_sync),
  -			    24);
  +			    32);
   
   /**
    * struct idpf_buf_queue - software structure representing a buffer queue
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -1915,8 +1965,12 @@
   		     idpf_tx_buf_compl_tag(tx_buf) != compl_tag))
   		return false;
   
  -	if (tx_buf->type == LIBETH_SQE_SKB)
  +	if (tx_buf->type == LIBETH_SQE_SKB) {
  +		if (skb_shinfo(tx_buf->skb)->tx_flags & SKBTX_IN_PROGRESS)
  +			idpf_tx_read_tstamp(txq, tx_buf->skb);
  +
   		libeth_tx_complete(tx_buf, &cp);
  +	}
   
   	idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
   
  @@ -2744,4 +2798,4 @@
  -	struct idpf_flex_tx_ctx_desc *desc;
  +	union idpf_flex_tx_ctx_desc *desc;
   	int i = txq->next_to_use;
   
   	txq->tx_buf[i].type = LIBETH_SQE_CTX;
  @@ -2802,6 +2856,6 @@
   	struct idpf_tx_buf *first;
   	unsigned int count;
  -	int tso;
  +	int tso, idx;
   
   	count = idpf_tx_desc_count_required(tx_q, skb);
   	if (unlikely(!count))
  @@ -2840,4 +2962,4 @@
  -		u64_stats_update_end(&tx_q->stats_sync);
  +		idpf_tx_set_tstamp_desc(ctx_desc, idx);
   	}
   
   	/* record the location of the first descriptor for this packet */
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -692,5 +694,9 @@
   
   	struct idpf_q_vector *q_vector;
  -} ____cacheline_aligned;
  +	__cacheline_group_end_aligned(cold);
  +};
  +libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
  +			    120 + sizeof(struct u64_stats_sync),
  +			    24);
   
   /**

[DIFF] PR commit 6ed9b40baa8e (idpf: stop Tx if there are insufficient buffer resources) → upstream 0c3f135e840d
Differences found:

  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2909,7 +2926,7 @@
   	};
   	union idpf_flex_tx_ctx_desc *ctx_desc;
   	struct idpf_tx_buf *first;
  -	unsigned int count;
  +	u32 count, buf_count = 1;
   	int tso, idx;
   	u32 buf_id;
   
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -2768,7 +2821,8 @@
   	};
  +	union idpf_flex_tx_ctx_desc *ctx_desc;
   	struct idpf_tx_buf *first;
   	unsigned int count;
  -	int tso;
  +	int tso, idx;
   	u32 buf_id;
   
   	count = idpf_tx_desc_count_required(tx_q, skb);

[DIFF] PR commit fe33d5dfce01 (idpf: remove obsolete stashing code) → upstream 6c4e68480238
Differences found:

  ================================================================================
  *    DELTA DIFFERENCES - code changes that differ between the patches          *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -1557,6 +1557,82 @@
   	wake_up(&vport->sw_marker_wq);
   }
   
  +/**
  + * idpf_tx_clean_stashed_bufs - clean bufs that were stored for
  + * out of order completions
  + * @txq: queue to clean
  + * @compl_tag: completion tag of packet to clean (from completion descriptor)
  + * @cleaned: pointer to stats struct to track cleaned packets/bytes
  + * @budget: Used to determine if we are in netpoll
  + */
  +static void idpf_tx_clean_stashed_bufs(struct idpf_tx_queue *txq,
  +				       u16 compl_tag,
  +				       struct libeth_sq_napi_stats *cleaned,
  +				       int budget)
  +{
  +	struct idpf_tx_stash *stash;
  +	struct hlist_node *tmp_buf;
  +	struct libeth_cq_pp cp = {
  +		.dev	= txq->dev,
  +		.ss	= cleaned,
  +		.napi	= budget,
  +	};
  +
  +	/* Buffer completion */
  +	hash_for_each_possible_safe(txq->stash->sched_buf_hash, stash, tmp_buf,
  +				    hlist, compl_tag) {
  +		if (unlikely(idpf_tx_buf_compl_tag(&stash->buf) != compl_tag))
  +			continue;
  +
  +		hash_del(&stash->hlist);
  +		libeth_tx_complete(&stash->buf, &cp);
  +
  +		/* Push shadow buf back onto stack */
  +		idpf_buf_lifo_push(&txq->stash->buf_stack, stash);
  +	}
  +}
  +
  +/**
  + * idpf_stash_flow_sch_buffers - store buffer parameters info to be freed at a
  + * later time (only relevant for flow scheduling mode)
  + * @txq: Tx queue to clean
  + * @tx_buf: buffer to store
  + */
  +static int idpf_stash_flow_sch_buffers(struct idpf_tx_queue *txq,
  +				       struct idpf_tx_buf *tx_buf)
  +{
  +	struct idpf_tx_stash *stash;
  +
  +	if (unlikely(tx_buf->type <= LIBETH_SQE_CTX))
  +		return 0;
  +
  +	stash = idpf_buf_lifo_pop(&txq->stash->buf_stack);
  +	if (unlikely(!stash)) {
  +		net_err_ratelimited("%s: No out-of-order TX buffers left!\n",
  +				    netdev_name(txq->netdev));
  +
  +		return -ENOMEM;
  +	}
  +
  +	/* Store buffer params in shadow buffer */
  +	stash->buf.skb = tx_buf->skb;
  +	stash->buf.bytes = tx_buf->bytes;
  +	stash->buf.packets = tx_buf->packets;
  +	stash->buf.type = tx_buf->type;
  +	stash->buf.nr_frags = tx_buf->nr_frags;
  +	dma_unmap_addr_set(&stash->buf, dma, dma_unmap_addr(tx_buf, dma));
  +	dma_unmap_len_set(&stash->buf, len, dma_unmap_len(tx_buf, len));
  +	idpf_tx_buf_compl_tag(&stash->buf) = idpf_tx_buf_compl_tag(tx_buf);
  +
  +	/* Add buffer to buf_hash table to be freed later */
  +	hash_add(txq->stash->sched_buf_hash, &stash->hlist,
  +		 idpf_tx_buf_compl_tag(&stash->buf));
  +
  +	tx_buf->type = LIBETH_SQE_EMPTY;
  +
  +	return 0;
  +}
  +
   #define idpf_tx_splitq_clean_bump_ntc(txq, ntc, desc, buf)	\
   do {								\
   	if (unlikely(++(ntc) == (txq)->desc_count)) {		\
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -663,6 +663,7 @@
    * @cleaned_pkts: Number of packets cleaned for the above said case
    * @tx_min_pkt_len: Min supported packet length
    * @refillq: Pointer to refill queue
  + * @compl_tag_bufid_m: Completion tag buffer id mask
    * @compl_tag_gen_s: Completion tag generation bit
    *	The format of the completion tag will change based on the TXQ
    *	descriptor ring size so that we can maintain roughly the same level
  @@ -683,6 +684,9 @@
    *	--------------------------------
    *
    *	This gives us 8*8160 = 65280 possible unique values.
  + * @compl_tag_cur_gen: Used to keep track of current completion tag generation
  + * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
  + * @stash: Tx buffer stash for Flow-based scheduling mode
    * @stats_sync: See struct u64_stats_sync
    * @q_stats: See union idpf_tx_queue_stats
    * @q_id: Queue id
  @@ -724,8 +728,13 @@
   	u16 tx_min_pkt_len;
   	struct idpf_sw_queue *refillq;
   
  +	u16 compl_tag_bufid_m;
   	u16 compl_tag_gen_s;
   
  +	u16 compl_tag_cur_gen;
  +	u16 compl_tag_gen_max;
  +
  +	struct idpf_txq_stash *stash;
   
   	struct u64_stats_sync stats_sync;
   	struct idpf_tx_queue_stats q_stats;
  
  ################################################################################
  !    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
  ################################################################################
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -1602,87 +1462,6 @@
   	spin_unlock_bh(&tx_tstamp_caps->status_lock);
   }
   
  -/**
  - * idpf_tx_clean_stashed_bufs - clean bufs that were stored for
  - * out of order completions
  - * @txq: queue to clean
  - * @compl_tag: completion tag of packet to clean (from completion descriptor)
  - * @cleaned: pointer to stats struct to track cleaned packets/bytes
  - * @budget: Used to determine if we are in netpoll
  - */
  -static void idpf_tx_clean_stashed_bufs(struct idpf_tx_queue *txq,
  -				       u16 compl_tag,
  -				       struct libeth_sq_napi_stats *cleaned,
  -				       int budget)
  -{
  -	struct idpf_tx_stash *stash;
  -	struct hlist_node *tmp_buf;
  -	struct libeth_cq_pp cp = {
  -		.dev	= txq->dev,
  -		.ss	= cleaned,
  -		.napi	= budget,
  -	};
  -
  -	/* Buffer completion */
  -	hash_for_each_possible_safe(txq->stash->sched_buf_hash, stash, tmp_buf,
  -				    hlist, compl_tag) {
  -		if (unlikely(idpf_tx_buf_compl_tag(&stash->buf) != compl_tag))
  -			continue;
  -
  -		hash_del(&stash->hlist);
  -
  -		if (stash->buf.type == LIBETH_SQE_SKB &&
  -		    (skb_shinfo(stash->buf.skb)->tx_flags & SKBTX_IN_PROGRESS))
  -			idpf_tx_read_tstamp(txq, stash->buf.skb);
  -
  -		libeth_tx_complete(&stash->buf, &cp);
  -
  -		/* Push shadow buf back onto stack */
  -		idpf_buf_lifo_push(&txq->stash->buf_stack, stash);
  -	}
  -}
  -
  -/**
  - * idpf_stash_flow_sch_buffers - store buffer parameters info to be freed at a
  - * later time (only relevant for flow scheduling mode)
  - * @txq: Tx queue to clean
  - * @tx_buf: buffer to store
  - */
  -static int idpf_stash_flow_sch_buffers(struct idpf_tx_queue *txq,
  -				       struct idpf_tx_buf *tx_buf)
  -{
  -	struct idpf_tx_stash *stash;
  -
  -	if (unlikely(tx_buf->type <= LIBETH_SQE_CTX))
  -		return 0;
  -
  -	stash = idpf_buf_lifo_pop(&txq->stash->buf_stack);
  -	if (unlikely(!stash)) {
  -		net_err_ratelimited("%s: No out-of-order TX buffers left!\n",
  -				    netdev_name(txq->netdev));
  -
  -		return -ENOMEM;
  -	}
  -
  -	/* Store buffer params in shadow buffer */
  -	stash->buf.skb = tx_buf->skb;
  -	stash->buf.bytes = tx_buf->bytes;
  -	stash->buf.packets = tx_buf->packets;
  -	stash->buf.type = tx_buf->type;
  -	stash->buf.nr_frags = tx_buf->nr_frags;
  -	dma_unmap_addr_set(&stash->buf, dma, dma_unmap_addr(tx_buf, dma));
  -	dma_unmap_len_set(&stash->buf, len, dma_unmap_len(tx_buf, len));
  -	idpf_tx_buf_compl_tag(&stash->buf) = idpf_tx_buf_compl_tag(tx_buf);
  -
  -	/* Add buffer to buf_hash table to be freed later */
  -	hash_add(txq->stash->sched_buf_hash, &stash->hlist,
  -		 idpf_tx_buf_compl_tag(&stash->buf));
  -
  -	tx_buf->type = LIBETH_SQE_EMPTY;
  -
  -	return 0;
  -}
  -
   #define idpf_tx_splitq_clean_bump_ntc(txq, ntc, desc, buf)	\
   do {								\
   	if (unlikely(++(ntc) == (txq)->desc_count)) {		\
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -598,7 +565,6 @@
    *		   only once at the end of the cleaning routine.
    * @clean_budget: singleq only, queue cleaning budget
    * @cleaned_pkts: Number of packets cleaned for the above said case
  - * @stash: Tx buffer stash for Flow-based scheduling mode
    * @refillq: Pointer to refill queue
    * @compl_tag_bufid_m: Completion tag buffer id mask
    * @compl_tag_cur_gen: Used to keep track of current completion tag generation
  @@ -600,9 +566,6 @@
    * @cleaned_pkts: Number of packets cleaned for the above said case
    * @stash: Tx buffer stash for Flow-based scheduling mode
    * @refillq: Pointer to refill queue
  - * @compl_tag_bufid_m: Completion tag buffer id mask
  - * @compl_tag_cur_gen: Used to keep track of current completion tag generation
  - * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
    * @cached_tstamp_caps: Tx timestamp capabilities negotiated with the CP
    * @tstamp_task: Work that handles Tx timestamp read
    * @stats_sync: See struct u64_stats_sync
  @@ -633,7 +596,6 @@
   	u16 desc_count;
   
   	u16 tx_min_pkt_len;
  -	u16 compl_tag_gen_s;
   
   	struct net_device *netdev;
   	__cacheline_group_end_aligned(read_mostly);
  @@ -650,7 +612,6 @@
   	};
   	u16 cleaned_pkts;
   
  -	struct idpf_txq_stash *stash;
   	struct idpf_sw_queue *refillq;
   
   	u16 compl_tag_bufid_m;
  @@ -653,10 +614,6 @@
   	struct idpf_txq_stash *stash;
   	struct idpf_sw_queue *refillq;
   
  -	u16 compl_tag_bufid_m;
  -	u16 compl_tag_cur_gen;
  -	u16 compl_tag_gen_max;
  -
   	struct idpf_ptp_vport_tx_tstamp_caps *cached_tstamp_caps;
   	struct work_struct *tstamp_task;
   
  @@ -674,7 +631,7 @@
   	__cacheline_group_end_aligned(cold);
   };
   libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
  -			    120 + sizeof(struct u64_stats_sync),
  +			    104 + sizeof(struct u64_stats_sync),
   			    32);
   
   /**
  
  ================================================================================
  *    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
  ================================================================================
  
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
  @@ -3,4 +3,4 @@
  -#include "idpf.h"
  +#include "idpf_ptp.h"
   #include "idpf_virtchnl.h"
   
   struct idpf_tx_stash {
  @@ -1725,6 +1770,11 @@
   			continue;
   
   		hash_del(&stash->hlist);
  +
  +		if (stash->buf.type == LIBETH_SQE_SKB &&
  +		    (skb_shinfo(stash->buf.skb)->tx_flags & SKBTX_IN_PROGRESS))
  +			idpf_tx_read_tstamp(txq, stash->buf.skb);
  +
   		libeth_tx_complete(&stash->buf, &cp);
   
   		/* Push shadow buf back onto stack */
  --- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
  @@ -714,9 +663,7 @@
  - *	--------------------------------
  - *
  - *	This gives us 8*8160 = 65280 possible unique values.
  - * @compl_tag_cur_gen: Used to keep track of current completion tag generation
  - * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
  - * @stash: Tx buffer stash for Flow-based scheduling mode
  - * @stats_sync: See struct u64_stats_sync
  - * @q_stats: See union idpf_tx_queue_stats
  - * @q_id: Queue id
  +	u16 desc_count;
  +
  +	u16 tx_min_pkt_len;
  +	u16 compl_tag_gen_s;
  +
  +	struct net_device *netdev;
  +	__cacheline_group_end_aligned(read_mostly);

See each commit explanation.

roxanan1996 and others added 11 commits February 25, 2026 15:21
jira KERNEL-168
commit-author Alexander Lobakin <aleksander.lobakin@intel.com>
commit 080d72f

Software-side Tx buffers for storing DMA, frame size, skb pointers etc.
are pretty much generic and every driver defines them the same way. The
same can be said for software Tx completions -- same napi_consume_skb()s
and all that...
Add a couple simple wrappers for doing that to stop repeating the old
tale at least within the Intel code. Drivers are free to use 'priv'
member at the end of the structure.

	Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
	Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 080d72f)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Alexander Lobakin <aleksander.lobakin@intel.com>
commit d9028db
upstream-diff |
	adjusted context due to missing #include <net/libeth/rx.h>
	introduced in commit 1b1b262
	("idpf: reuse libeth's definitions of parsed ptype structures")
	part of "convert RX to libeth" patchset.

&idpf_tx_buffer is almost identical to the previous generations, as well
as the way it's handled. Moreover, relying on dma_unmap_addr() and
!!buf->skb instead of explicit defining of buffer's type was never good.
Use the newly added libeth helpers to do it properly and reduce the
copy-paste around the Tx code.

	Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
	Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit d9028db)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Alexander Lobakin <aleksander.lobakin@intel.com>
commit 3dc95a3

Add a shorthand similar to other net*_subqueue() helpers for resetting
the queue by its index w/o obtaining &netdev_tx_queue beforehand
manually.

	Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
	Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 3dc95a3)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 24eb35b
upstream-diff |
	adjusted context in .h file around struct idpf_compl_queue due to missing
	commit 5a816aa
	("idpf: strictly assert cachelines of queue and queue vector structures")

Add a mechanism to guard against stashing partial packets into the hash
table to make the driver more robust, with more efficient decision
making when cleaning.

Don't stash partial packets. This can happen when an RE (Report Event)
completion is received in flow scheduling mode, or when an out of order
RS (Report Status) completion is received. The first buffer with the skb
is stashed, but some or all of its frags are not because the stack is
out of reserve buffers. This leaves the ring in a weird state since
the frags are still on the ring.

Use the field libeth_sqe::nr_frags to track the number of
fragments/tx_bufs representing the packet. The clean routines check to
make sure there are enough reserve buffers on the stack before stashing
any part of the packet. If there are not, next_to_clean is left pointing
to the first buffer of the packet that failed to be stashed. This leaves
the whole packet on the ring, and the next time around, cleaning will
start from this packet.

An RS completion is still expected for this packet in either case. So
instead of being cleaned from the hash table, it will be cleaned from
the ring directly. This should all still be fine since the DESC_UNUSED
and BUFS_UNUSED will reflect the state of the ring. If we ever fall
below the thresholds, the TxQ will still be stopped, giving the
completion queue time to catch up. This may lead to stopping the queue
more frequently, but it guarantees the Tx ring will always be in a good
state.

Also, always use the idpf_tx_splitq_clean function to clean descriptors,
i.e. use it from clean_buf_ring as well. This way we avoid duplicating
the logic and make sure we're using the same reserve buffers guard rail.

This does require a switch from the s16 next_to_clean overflow
descriptor ring wrap calculation to u16 and the normal ring size check.

	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
	Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 24eb35b)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>

Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 4c69c77

Commit d9028db ("idpf: convert to libeth Tx buffer completion")
inadvertently removed code that was necessary for the tx buffer cleaning
routine to iterate over all buffers associated with a packet.

When a frag is too large for a single data descriptor, it will be split
across multiple data descriptors. This means the frag will span multiple
buffers in the buffer ring in order to keep the descriptor and buffer
ring indexes aligned. The buffer entries in the ring are technically
empty and no cleaning actions need to be performed. These empty buffers
can precede other frags associated with the same packet. I.e. a single
packet on the buffer ring can look like:

	buf[0]=skb0.frag0
	buf[1]=skb0.frag1
	buf[2]=empty
	buf[3]=skb0.frag2

The cleaning routine iterates through these buffers based on a matching
completion tag. If the completion tag is not set for buf2, the loop will
end prematurely. Frag2 will be left uncleaned and next_to_clean will be
left pointing to the end of packet, which will break the cleaning logic
for subsequent cleans. This consequently leads to tx timeouts.

Assign the empty bufs the same completion tag for the packet to ensure
the cleaning routine iterates over all of the buffers associated with
the packet.

Fixes: d9028db ("idpf: convert to libeth Tx buffer completion")
	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Acked-by: Alexander Lobakin <aleksander.lobakin@intel.com>
	Reviewed-by: Madhu chittim <madhu.chittim@intel.com>
	Reviewed-by: Simon Horman <horms@kernel.org>
	Tested-by: Krishneil Singh <krishneil.k.singh@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 4c69c77)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit cb83b55
upstream-diff |
	1. adjusted context around idpf_rx_splitq_clean function due to missing
	- 74d1412 ("idpf: use libeth Rx buffer management for payload buffer")
	- 6ad5ff6 ("libeth: convert to netmem")
	2. adjusted context around struct idpf_tx_queue members and docstring
	and did not include the libeth_cacheline_set_assert changes due to missing:
	- 5a816aa ("idpf: strictly assert cachelines of queue and queue vector structures")
	3. fix compilation issue (std=89) in idpf_tx_desc_alloc due to for loop var
	declaration

In certain production environments, it is possible for completion tags
to collide, meaning N packets with the same completion tag are in flight
at the same time. In this environment, any given Tx queue is effectively
used to send both slower traffic and higher throughput traffic
simultaneously. This is the result of a customer's specific
configuration in the device pipeline, the details of which Intel cannot
provide. This configuration results in a small number of out-of-order
completions, i.e., a small number of packets in flight. The existing
guardrails in the driver only protect against a large number of packets
in flight. The slower flow completions are delayed which causes the
out-of-order completions. The fast flow will continue sending traffic
and generating tags. Because tags are generated on the fly, the fast
flow eventually uses the same tag for a packet that is still in flight
from the slower flow. The driver has no idea which packet it should
clean when it processes the completion with that tag, but it will look
for the packet on the buffer ring before the hash table.  If the slower
flow packet completion is processed first, it will end up cleaning the
fast flow packet on the ring prematurely. This leaves the descriptor
ring in a bad state resulting in a crash or Tx timeout.

In summary, generating a tag when a packet is sent can lead to the same
tag being associated with multiple packets. This can lead to resource
leaks, crashes, and/or Tx timeouts.

Before we can replace the tag generation, we need a new mechanism for
the send path to know what tag to use next. The driver will allocate and
initialize a refillq for each TxQ with all of the possible free tag
values. During send, the driver grabs the next free tag from the refillq
from next_to_clean. While cleaning the packet, the clean routine posts
the tag back to the refillq's next_to_use to indicate that it is now
free to use.

This mechanism works exactly the same way as the existing Rx refill
queues, which post the cleaned buffer IDs back to the buffer queue to be
reposted to HW. Since we're using the refillqs for both Rx and Tx now,
genericize some of the existing refillq support.

Note: the refillqs will not be used yet. This is only demonstrating how
they will be used to pass free tags back to the send path.

	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
	Tested-by: Samuel Salin <Samuel.salin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit cb83b55)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit f2d18e1
upstream-diff |
	adjusted context in struct idpf_tx_queue because the order
	of the fields is different due to missing
	- 5a816aa ("idpf: strictly assert cachelines of queue and queue vector structures")

Track the gap between next_to_use and the last RE index. Set RE again
if the gap is large enough to ensure RE bit is set frequently. This is
critical before removing the stashing mechanisms because the
opportunistic descriptor ring cleaning from the out-of-order completions
will go away. Previously the descriptors would be "cleaned" by both the
descriptor (RE) completion and the out-of-order completions. Without the
latter, we must ensure the RE bit is set more frequently. Otherwise,
it's theoretically possible for the descriptor ring next_to_clean to
never advance.  The previous implementation was dependent on the start
of a packet falling on a 64th index in the descriptor ring, which is not
guaranteed with large packets.

	Signed-off-by: Luigi Rizzo <lrizzo@google.com>
	Signed-off-by: Brian Vazquez <brianvv@google.com>
	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
	Tested-by: Samuel Salin <Samuel.salin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit f2d18e1)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit b61dfa9
upstream-diff |
	adjusted context in 2 places:
	- when removing func idpf_tx_dma_map_error due to different memset
	call that uses the hardcoded struct type;
	- in func idpf_tx_splitq_frame due to missing expected
	union idpf_flex_tx_ctx_desc *ctx_desc;
	both differences were introduced in commit
	1a49cf8 ("idpf: add Tx timestamp flows").

Move (and rename) the existing rollback logic to singleq.c since that
will be the only consumer. Create a simplified splitq specific rollback
function to loop through and unmap tx_bufs based on the completion tag.
This is critical before replacing the Tx buffer ring with the buffer
pool since the previous rollback indexing will not work to unmap the
chained buffers from the pool.

Cache the next_to_use index before any portion of the packet is put on
the descriptor ring. In case of an error, the rollback will bump tail to
the correct next_to_use value. Because the splitq path now supports
different types of context descriptors (and potentially multiple in the
future), this will take care of rolling back any and all context
descriptors encoded on the ring for the erroneous packet. The previous
rollback logic was broken for PTP packets since it would not account for
the PTP context descriptor.

Fixes: 1a49cf8 ("idpf: add Tx timestamp flows")
	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
	Tested-by: Samuel Salin <Samuel.salin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit b61dfa9)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 5f417d5
upstream-diff |
	adjusted context in:
	- ifpf_tx_splitq_frame and idpf_tx_clean_bufs;
	- struct idpf_tx_queue due to missing of some elements in the struct;
	both due to missing commit
	- 1a49cf8 ("idpf: add Tx timestamp flows").
	and did not include the cacheline assert changes due to missing
	- 5a816aa ("idpf: strictly assert cachelines of queue and queue vector structures")

Replace the TxQ buffer ring with one large pool/array of buffers (only
for flow scheduling). This eliminates the tag generation and makes it
impossible for a tag to be associated with more than one packet.

The completion tag passed to HW through the descriptor is the index into
the array. That same completion tag is posted back to the driver in the
completion descriptor, and used to index into the array to quickly
retrieve the buffer during cleaning.  In this way, the tags are treated
as a fix sized resource. If all tags are in use, no more packets can be
sent on that particular queue (until some are freed up). The tag pool
size is 64K since the completion tag width is 16 bits.

For each packet, the driver pulls a free tag from the refillq to get the
next free buffer index. When cleaning is complete, the tag is posted
back to the refillq. A multi-frag packet spans multiple buffers in the
driver, therefore it uses multiple buffer indexes/tags from the pool.
Each frag pulls from the refillq to get the next free buffer index.
These are tracked in a next_buf field that replaces the completion tag
field in the buffer struct. This chains the buffers together so that the
packet can be cleaned from the starting completion tag taken from the
completion descriptor, then from the next_buf field for each subsequent
buffer.

In case of a dma_mapping_error occurs or the refillq runs out of free
buf_ids, the packet will execute the rollback error path. This unmaps
any buffers previously mapped for the packet. Since several free
buf_ids could have already been pulled from the refillq, we need to
restore its original state as well. Otherwise, the buf_ids/tags
will be leaked and not used again until the queue is reallocated.

Descriptor completions only advance the descriptor ring index to "clean"
the descriptors. The packet completions only clean the buffers
associated with the given packet completion tag and do not update the
descriptor ring index.

When operating in queue based scheduling mode, the array still acts as a
ring and will only have TxQ descriptor count entries. The tx_bufs are
still associated 1:1 with the descriptor ring entries and we can use the
conventional indexing mechanisms.

Fixes: c2d548c ("idpf: add TX splitq napi poll support")
	Signed-off-by: Luigi Rizzo <lrizzo@google.com>
	Signed-off-by: Brian Vazquez <brianvv@google.com>
	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
	Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
	Tested-by: Samuel Salin <Samuel.salin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 5f417d5)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 0c3f135
upstream-diff |
	adjusted conflict in idpf_tx_splitq_frame func due to missing
	1a49cf8 ("idpf: add Tx timestamp flows").

The Tx refillq logic will cause packets to be silently dropped if there
are not enough buffer resources available to send a packet in flow
scheduling mode. Instead, determine how many buffers are needed along
with number of descriptors. Make sure there are enough of both resources
to send the packet, and stop the queue if not.

Fixes: 7292af0 ("idpf: fix a race in txq wakeup")
	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
	Tested-by: Samuel Salin <Samuel.salin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 0c3f135)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
jira KERNEL-168
commit-author Joshua Hay <joshua.a.hay@intel.com>
commit 6c4e684
upstream-diff |
	- adjusted context in .h due to different order in the struct idpf_tx_queue
	- adjusted context due to missing idpf_tx_read_tstamp func;
	both are due to missing
	1a49cf8 ("idpf: add Tx timestamp flows").
	- did not include libeth_cacheline_set_assert for struct idpf_tx_queue
	due to missing 5a816aa
	("idpf: strictly assert cachelines of queue and queue vector structures")

With the new Tx buffer management scheme, there is no need for all of
the stashing mechanisms, the hash table, the reserve buffer stack, etc.
Remove all of that.

	Signed-off-by: Joshua Hay <joshua.a.hay@intel.com>
	Reviewed-by: Madhu Chittim <madhu.chittim@intel.com>
	Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
	Tested-by: Samuel Salin <Samuel.salin@intel.com>
	Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
(cherry picked from commit 6c4e684)
	Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
@roxanan1996 roxanan1996 marked this pull request as draft February 25, 2026 16:11
@roxanan1996 roxanan1996 self-assigned this Feb 25, 2026
@github-actions
Copy link

🤖 Validation Checks In Progress Workflow run: https://github.com/ctrliq/kernel-src-tree/actions/runs/22405737478

@github-actions
Copy link

🔍 Interdiff Analysis

  • ⚠️ PR commit 78d98f864d04 (idpf: convert to libeth Tx buffer completion) → upstream d9028db618a6
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -1,8 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2023 Intel Corporation */
 
-#include <net/libeth/tx.h>
-
 #include "idpf.h"
 
 /**
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1,8 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (C) 2023 Intel Corporation */
 
-#include <net/libeth/tx.h>
-
 #include "idpf.h"
 #include "idpf_virtchnl.h"
 

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -2,6 +2,7 @@
 /* Copyright (C) 2023 Intel Corporation */
 
 #include <net/libeth/rx.h>
+#include <net/libeth/tx.h>
 
 #include "idpf.h"
 
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2,6 +2,7 @@
 /* Copyright (C) 2023 Intel Corporation */
 
 #include <net/libeth/rx.h>
+#include <net/libeth/tx.h>
 
 #include "idpf.h"
 #include "idpf_virtchnl.h"

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -2,4 +1,8 @@
 /* Copyright (C) 2023 Intel Corporation */
 
+#include <net/libeth/rx.h>
+
+#include <net/libeth/tx.h>
+
 #include "idpf.h"
 
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2,5 +1,9 @@
 /* Copyright (C) 2023 Intel Corporation */
 
+#include <net/libeth/rx.h>
+
+#include <net/libeth/tx.h>
+
 #include "idpf.h"
 #include "idpf_virtchnl.h"
  • ⚠️ PR commit 4a623ccb132f (idpf: refactor Tx completion routines) → upstream 24eb35b15152
    Differences found:
################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -785,7 +785,7 @@
 	u32 next_to_use;
 	u32 next_to_clean;
 
-	u32 num_completions;
+	aligned_u64 num_completions;
 	__cacheline_group_end_aligned(read_write);
 
 	__cacheline_group_begin_aligned(cold);

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -971,4 +920,4 @@
 	u32 num_completions_pending;
 };
 
-/**
+static inline int idpf_q_vector_to_mem(const struct idpf_q_vector *q_vector)
  • ⚠️ PR commit 3d7487afc656 (idpf: add support for Tx refillqs in flow scheduling mode) → upstream cb83b559bea3
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -247,7 +247,6 @@
 	struct device *dev = tx_q->dev;
 	struct idpf_sw_queue *refillq;
 	int err;
-	unsigned int i = 0;
 
 	err = idpf_tx_buf_alloc_all(tx_q);
 	if (err)
@@ -282,7 +281,7 @@
 		goto err_alloc;
 	}
 
-	for (i = 0; i < refillq->desc_count; i++)
+	for (unsigned int i = 0; i < refillq->desc_count; i++)
 		refillq->ring[i] =
 			FIELD_PREP(IDPF_RFL_BI_BUFID_M, i) |
 			FIELD_PREP(IDPF_RFL_BI_GEN_M,

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3551,7 +3630,7 @@
 skip_data:
 		rx_buf->netmem = 0;
 
-		idpf_rx_post_buf_refill(refillq, buf_id);
+		idpf_post_buf_refill(refillq, buf_id);
 		IDPF_RX_BUMP_NTC(rxq, ntc);
 
 		/* skip if it is non EOP desc */
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -622,6 +622,7 @@
  * @cleaned_pkts: Number of packets cleaned for the above said case
  * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
  * @stash: Tx buffer stash for Flow-based scheduling mode
+ * @refillq: Pointer to refill queue
  * @compl_tag_bufid_m: Completion tag buffer id mask
  * @compl_tag_cur_gen: Used to keep track of current completion tag generation
  * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
@@ -671,6 +672,7 @@
 
 	u16 tx_max_bufs;
 	struct idpf_txq_stash *stash;
+	struct idpf_sw_queue *refillq;
 
 	u16 compl_tag_bufid_m;
 	u16 compl_tag_cur_gen;
@@ -692,7 +694,7 @@
 	__cacheline_group_end_aligned(cold);
 };
 libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
-			    112 + sizeof(struct u64_stats_sync),
+			    120 + sizeof(struct u64_stats_sync),
 			    24);
 
 /**

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -244,4 +246,5 @@
 	struct device *dev = tx_q->dev;
 	int err;
+	unsigned int i = 0;
 
 	err = idpf_tx_buf_alloc_all(tx_q);
@@ -3358,4 +3417,4 @@
 		idpf_rx_post_buf_refill(refillq, buf_id);
-
 		IDPF_RX_BUMP_NTC(rxq, ntc);
+
 		/* skip if it is non EOP desc */
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -624,6 +619,6 @@
  * @cleaned_pkts: Number of packets cleaned for the above said case
  * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
- * @tx_min_pkt_len: Min supported packet length
+ * @stash: Tx buffer stash for Flow-based scheduling mode
  * @compl_tag_bufid_m: Completion tag buffer id mask
- * @compl_tag_gen_s: Completion tag generation bit
- *	The format of the completion tag will change based on the TXQ
+ * @compl_tag_cur_gen: Used to keep track of current completion tag generation
+ * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
@@ -743,6 +692,2 @@
 
-	u16 tx_max_bufs;
-	u16 tx_min_pkt_len;
-
-	u16 compl_tag_bufid_m;
-	u16 compl_tag_gen_s;
+/**
  • ⚠️ PR commit 2c34100e4637 (idpf: improve when to set RE bit logic) → upstream f2d18e16479c
    Differences found:
################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -610,6 +610,8 @@
  * @netdev: &net_device corresponding to this queue
  * @next_to_use: Next descriptor to use
  * @next_to_clean: Next descriptor to clean
+ * @last_re: last descriptor index that RE bit was set
+ * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
  * @cleaned_bytes: Splitq only, TXQ only: When a TX completion is received on
  *		   the TX completion queue, it can be for any TXQ associated
  *		   with that completion queue. This means we can clean up to
@@ -620,7 +622,6 @@
  *		   only once at the end of the cleaning routine.
  * @clean_budget: singleq only, queue cleaning budget
  * @cleaned_pkts: Number of packets cleaned for the above said case
- * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
  * @stash: Tx buffer stash for Flow-based scheduling mode
  * @refillq: Pointer to refill queue
  * @compl_tag_bufid_m: Completion tag buffer id mask
@@ -672,7 +675,6 @@
 	};
 	u16 cleaned_pkts;
 
-	u16 tx_max_bufs;
 	struct idpf_txq_stash *stash;
 	struct idpf_sw_queue *refillq;
 

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -607,6 +607,5 @@
- * @desc_count: Number of descriptors
+ * @netdev: &net_device corresponding to this queue
  * @next_to_use: Next descriptor to use
  * @next_to_clean: Next descriptor to clean
- * @netdev: &net_device corresponding to this queue
  * @cleaned_bytes: Splitq only, TXQ only: When a TX completion is received on
  *		   the TX completion queue, it can be for any TXQ associated
@@ -685,5 +622,5 @@
  * @cleaned_pkts: Number of packets cleaned for the above said case
  * @tx_max_bufs: Max buffers that can be transmitted with scatter-gather
- * @tx_min_pkt_len: Min supported packet length
+ * @stash: Tx buffer stash for Flow-based scheduling mode
  * @refillq: Pointer to refill queue
  * @compl_tag_bufid_m: Completion tag buffer id mask
@@ -723,4 +660,4 @@
-	u16 desc_count;
+	__cacheline_group_begin_aligned(read_write);
 	u16 next_to_use;
 	u16 next_to_clean;
 
@@ -731,5 +668,5 @@
 
 	u16 tx_max_bufs;
-	u16 tx_min_pkt_len;
+	struct idpf_txq_stash *stash;
 	struct idpf_sw_queue *refillq;
  • ⚠️ PR commit 916485ec68a4 (idpf: simplify and fix splitq Tx packet rollback error path) → upstream b61dfa9bc443
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2287,4 +2287,55 @@
 
 /**
+ * idpf_tx_dma_map_error - handle TX DMA map errors
+ * @txq: queue to send buffer on
+ * @skb: send buffer
+ * @first: original first buffer info buffer for packet
+ * @idx: starting point on ring to unwind
+ */
+void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb,
+			   struct idpf_tx_buf *first, u16 idx)
+{
+	struct libeth_sq_napi_stats ss = { };
+	struct libeth_cq_pp cp = {
+		.dev	= txq->dev,
+		.ss	= &ss,
+	};
+
+	u64_stats_update_begin(&txq->stats_sync);
+	u64_stats_inc(&txq->q_stats.dma_map_errs);
+	u64_stats_update_end(&txq->stats_sync);
+
+	/* clear dma mappings for failed tx_buf map */
+	for (;;) {
+		struct idpf_tx_buf *tx_buf;
+
+		tx_buf = &txq->tx_buf[idx];
+		libeth_tx_complete(tx_buf, &cp);
+		if (tx_buf == first)
+			break;
+		if (idx == 0)
+			idx = txq->desc_count;
+		idx--;
+	}
+
+	if (skb_is_gso(skb)) {
+		union idpf_tx_flex_desc *tx_desc;
+
+		/* If we failed a DMA mapping for a TSO packet, we will have
+		 * used one additional descriptor for a context
+		 * descriptor. Reset that here.
+		 */
+		tx_desc = &txq->flex_tx[idx];
+		memset(tx_desc, 0, sizeof(struct idpf_flex_tx_ctx_desc));
+		if (idx == 0)
+			idx = txq->desc_count;
+		idx--;
+	}
+
+	/* Update tail in case netdev_xmit_more was previously true */
+	idpf_tx_buf_hw_update(txq, idx, false);
+}
+
+/**
  * idpf_tx_splitq_bump_ntu - adjust NTU and generation
  * @txq: the tx ring to wrap
@@ -2335,35 +2386,4 @@
 
 /**
- * idpf_tx_splitq_pkt_err_unmap - Unmap buffers and bump tail in case of error
- * @txq: Tx queue to unwind
- * @params: pointer to splitq params struct
- * @first: starting buffer for packet to unmap
- */
-static void idpf_tx_splitq_pkt_err_unmap(struct idpf_tx_queue *txq,
-					 struct idpf_tx_splitq_params *params,
-					 struct idpf_tx_buf *first)
-{
-	struct libeth_sq_napi_stats ss = { };
-	struct idpf_tx_buf *tx_buf = first;
-	struct libeth_cq_pp cp = {
-		.dev    = txq->dev,
-		.ss     = &ss,
-	};
-	u32 idx = 0;
-
-	u64_stats_update_begin(&txq->stats_sync);
-	u64_stats_inc(&txq->q_stats.dma_map_errs);
-	u64_stats_update_end(&txq->stats_sync);
-
-	do {
-		libeth_tx_complete(tx_buf, &cp);
-		idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
-	} while (idpf_tx_buf_compl_tag(tx_buf) == params->compl_tag);
-
-	/* Update tail in case netdev_xmit_more was previously true. */
-	idpf_tx_buf_hw_update(txq, params->prev_ntu, false);
-}
-
-/**
  * idpf_tx_splitq_map - Build the Tx flex descriptor
  * @tx_q: queue to send buffer on

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2339,57 +2339,6 @@
 	return count;
 }
 
-/**
- * idpf_tx_dma_map_error - handle TX DMA map errors
- * @txq: queue to send buffer on
- * @skb: send buffer
- * @first: original first buffer info buffer for packet
- * @idx: starting point on ring to unwind
- */
-void idpf_tx_dma_map_error(struct idpf_tx_queue *txq, struct sk_buff *skb,
-			   struct idpf_tx_buf *first, u16 idx)
-{
-	struct libeth_sq_napi_stats ss = { };
-	struct libeth_cq_pp cp = {
-		.dev	= txq->dev,
-		.ss	= &ss,
-	};
-
-	u64_stats_update_begin(&txq->stats_sync);
-	u64_stats_inc(&txq->q_stats.dma_map_errs);
-	u64_stats_update_end(&txq->stats_sync);
-
-	/* clear dma mappings for failed tx_buf map */
-	for (;;) {
-		struct idpf_tx_buf *tx_buf;
-
-		tx_buf = &txq->tx_buf[idx];
-		libeth_tx_complete(tx_buf, &cp);
-		if (tx_buf == first)
-			break;
-		if (idx == 0)
-			idx = txq->desc_count;
-		idx--;
-	}
-
-	if (skb_is_gso(skb)) {
-		union idpf_tx_flex_desc *tx_desc;
-
-		/* If we failed a DMA mapping for a TSO packet, we will have
-		 * used one additional descriptor for a context
-		 * descriptor. Reset that here.
-		 */
-		tx_desc = &txq->flex_tx[idx];
-		memset(tx_desc, 0, sizeof(*tx_desc));
-		if (idx == 0)
-			idx = txq->desc_count;
-		idx--;
-	}
-
-	/* Update tail in case netdev_xmit_more was previously true */
-	idpf_tx_buf_hw_update(txq, idx, false);
-}
-
 /**
  * idpf_tx_splitq_bump_ntu - adjust NTU and generation
  * @txq: the tx ring to wrap
@@ -2438,6 +2387,37 @@
 	return true;
 }
 
+/**
+ * idpf_tx_splitq_pkt_err_unmap - Unmap buffers and bump tail in case of error
+ * @txq: Tx queue to unwind
+ * @params: pointer to splitq params struct
+ * @first: starting buffer for packet to unmap
+ */
+static void idpf_tx_splitq_pkt_err_unmap(struct idpf_tx_queue *txq,
+					 struct idpf_tx_splitq_params *params,
+					 struct idpf_tx_buf *first)
+{
+	struct libeth_sq_napi_stats ss = { };
+	struct idpf_tx_buf *tx_buf = first;
+	struct libeth_cq_pp cp = {
+		.dev    = txq->dev,
+		.ss     = &ss,
+	};
+	u32 idx = 0;
+
+	u64_stats_update_begin(&txq->stats_sync);
+	u64_stats_inc(&txq->q_stats.dma_map_errs);
+	u64_stats_update_end(&txq->stats_sync);
+
+	do {
+		libeth_tx_complete(tx_buf, &cp);
+		idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
+	} while (idpf_tx_buf_compl_tag(tx_buf) == params->compl_tag);
+
+	/* Update tail in case netdev_xmit_more was previously true. */
+	idpf_tx_buf_hw_update(txq, params->prev_ntu, false);
+}
+
 /**
  * idpf_tx_splitq_map - Build the Tx flex descriptor
  * @tx_q: queue to send buffer on
@@ -2482,8 +2462,9 @@
 	for (frag = &skb_shinfo(skb)->frags[0];; frag++) {
 		unsigned int max_data = IDPF_TX_MAX_DESC_DATA_ALIGNED;
 
-		if (dma_mapping_error(tx_q->dev, dma))
-			return idpf_tx_dma_map_error(tx_q, skb, first, i);
+		if (unlikely(dma_mapping_error(tx_q->dev, dma)))
+			return idpf_tx_splitq_pkt_err_unmap(tx_q, params,
+							    first);
 
 		first->nr_frags++;
 		idpf_tx_buf_compl_tag(tx_buf) = params->compl_tag;
@@ -2939,7 +2920,9 @@
 static netdev_tx_t idpf_tx_splitq_frame(struct sk_buff *skb,
 					struct idpf_tx_queue *tx_q)
 {
-	struct idpf_tx_splitq_params tx_params = { };
+	struct idpf_tx_splitq_params tx_params = {
+		.prev_ntu = tx_q->next_to_use,
+	};
 	union idpf_flex_tx_ctx_desc *ctx_desc;
 	struct idpf_tx_buf *first;
 	unsigned int count;

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2326,7 +2380,7 @@
 		 * descriptor. Reset that here.
 		 */
 		tx_desc = &txq->flex_tx[idx];
-		memset(tx_desc, 0, sizeof(struct idpf_flex_tx_ctx_desc));
+		memset(tx_desc, 0, sizeof(*tx_desc));
 		if (idx == 0)
 			idx = txq->desc_count;
 		idx--;
@@ -2817,4 +2871,5 @@
 {
 	struct idpf_tx_splitq_params tx_params = { };
+	union idpf_flex_tx_ctx_desc *ctx_desc;
 	struct idpf_tx_buf *first;
 	unsigned int count;
  • ⚠️ PR commit 1bf91468a70d (idpf: replace flow scheduling buffer ring with buffer pool) → upstream 5f417d551324
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1915,11 +1915,8 @@
 		.napi	= budget,
 	};
 
-	tx_buf = &txq->tx_buf[buf_id];
-	if (tx_buf->type == LIBETH_SQE_SKB) {
+	if (tx_buf->type == LIBETH_SQE_SKB)
 		libeth_tx_complete(tx_buf, &cp);
-		idpf_post_buf_refill(txq->refillq, buf_id);
-	}
 
 	while (idpf_tx_buf_next(tx_buf) != IDPF_TXBUF_NULL) {
 		buf_id = idpf_tx_buf_next(tx_buf);

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1962,6 +1962,7 @@
 		     idpf_tx_buf_compl_tag(tx_buf) != compl_tag))
 		return false;
 
+	tx_buf = &txq->tx_buf[buf_id];
 	if (tx_buf->type == LIBETH_SQE_SKB) {
 		if (skb_shinfo(tx_buf->skb)->tx_flags & SKBTX_IN_PROGRESS)
 			idpf_tx_read_tstamp(txq, tx_buf->skb);
@@ -1965,6 +1966,7 @@
 			idpf_tx_read_tstamp(txq, tx_buf->skb);
 
 		libeth_tx_complete(tx_buf, &cp);
+		idpf_post_buf_refill(txq->refillq, buf_id);
 	}
 
 	idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
@@ -2892,6 +2859,7 @@
 	struct idpf_tx_buf *first;
 	unsigned int count;
 	int tso, idx;
+	u32 buf_id;
 
 	count = idpf_tx_desc_count_required(tx_q, skb);
 	if (unlikely(!count))
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -703,6 +710,7 @@
 	dma_addr_t dma;
 
 	struct idpf_q_vector *q_vector;
+	u32 buf_pool_size;
 	__cacheline_group_end_aligned(cold);
 };
 libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
@@ -706,7 +714,7 @@
 };
 libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
 			    120 + sizeof(struct u64_stats_sync),
-			    24);
+			    32);
 
 /**
  * struct idpf_buf_queue - software structure representing a buffer queue

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1915,8 +1965,12 @@
 		     idpf_tx_buf_compl_tag(tx_buf) != compl_tag))
 		return false;
 
-	if (tx_buf->type == LIBETH_SQE_SKB)
+	if (tx_buf->type == LIBETH_SQE_SKB) {
+		if (skb_shinfo(tx_buf->skb)->tx_flags & SKBTX_IN_PROGRESS)
+			idpf_tx_read_tstamp(txq, tx_buf->skb);
+
 		libeth_tx_complete(tx_buf, &cp);
+	}
 
 	idpf_tx_clean_buf_ring_bump_ntc(txq, idx, tx_buf);
 
@@ -2744,4 +2798,4 @@
-	struct idpf_flex_tx_ctx_desc *desc;
+	union idpf_flex_tx_ctx_desc *desc;
 	int i = txq->next_to_use;
 
 	txq->tx_buf[i].type = LIBETH_SQE_CTX;
@@ -2802,6 +2856,6 @@
 	struct idpf_tx_buf *first;
 	unsigned int count;
-	int tso;
+	int tso, idx;
 
 	count = idpf_tx_desc_count_required(tx_q, skb);
 	if (unlikely(!count))
@@ -2840,4 +2962,4 @@
-		u64_stats_update_end(&tx_q->stats_sync);
+		idpf_tx_set_tstamp_desc(ctx_desc, idx);
 	}
 
 	/* record the location of the first descriptor for this packet */
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -692,5 +694,9 @@
 
 	struct idpf_q_vector *q_vector;
-} ____cacheline_aligned;
+	__cacheline_group_end_aligned(cold);
+};
+libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
+			    120 + sizeof(struct u64_stats_sync),
+			    24);
 
 /**
  • ⚠️ PR commit 6ed9b40baa8e (idpf: stop Tx if there are insufficient buffer resources) → upstream 0c3f135e840d
    Differences found:
################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2909,7 +2926,7 @@
 	};
 	union idpf_flex_tx_ctx_desc *ctx_desc;
 	struct idpf_tx_buf *first;
-	unsigned int count;
+	u32 count, buf_count = 1;
 	int tso, idx;
 	u32 buf_id;
 

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -2768,7 +2821,8 @@
 	};
+	union idpf_flex_tx_ctx_desc *ctx_desc;
 	struct idpf_tx_buf *first;
 	unsigned int count;
-	int tso;
+	int tso, idx;
 	u32 buf_id;
 
 	count = idpf_tx_desc_count_required(tx_q, skb);
  • ⚠️ PR commit fe33d5dfce01 (idpf: remove obsolete stashing code) → upstream 6c4e68480238
    Differences found:
================================================================================
*    DELTA DIFFERENCES - code changes that differ between the patches          *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1557,6 +1557,82 @@
 	wake_up(&vport->sw_marker_wq);
 }
 
+/**
+ * idpf_tx_clean_stashed_bufs - clean bufs that were stored for
+ * out of order completions
+ * @txq: queue to clean
+ * @compl_tag: completion tag of packet to clean (from completion descriptor)
+ * @cleaned: pointer to stats struct to track cleaned packets/bytes
+ * @budget: Used to determine if we are in netpoll
+ */
+static void idpf_tx_clean_stashed_bufs(struct idpf_tx_queue *txq,
+				       u16 compl_tag,
+				       struct libeth_sq_napi_stats *cleaned,
+				       int budget)
+{
+	struct idpf_tx_stash *stash;
+	struct hlist_node *tmp_buf;
+	struct libeth_cq_pp cp = {
+		.dev	= txq->dev,
+		.ss	= cleaned,
+		.napi	= budget,
+	};
+
+	/* Buffer completion */
+	hash_for_each_possible_safe(txq->stash->sched_buf_hash, stash, tmp_buf,
+				    hlist, compl_tag) {
+		if (unlikely(idpf_tx_buf_compl_tag(&stash->buf) != compl_tag))
+			continue;
+
+		hash_del(&stash->hlist);
+		libeth_tx_complete(&stash->buf, &cp);
+
+		/* Push shadow buf back onto stack */
+		idpf_buf_lifo_push(&txq->stash->buf_stack, stash);
+	}
+}
+
+/**
+ * idpf_stash_flow_sch_buffers - store buffer parameters info to be freed at a
+ * later time (only relevant for flow scheduling mode)
+ * @txq: Tx queue to clean
+ * @tx_buf: buffer to store
+ */
+static int idpf_stash_flow_sch_buffers(struct idpf_tx_queue *txq,
+				       struct idpf_tx_buf *tx_buf)
+{
+	struct idpf_tx_stash *stash;
+
+	if (unlikely(tx_buf->type <= LIBETH_SQE_CTX))
+		return 0;
+
+	stash = idpf_buf_lifo_pop(&txq->stash->buf_stack);
+	if (unlikely(!stash)) {
+		net_err_ratelimited("%s: No out-of-order TX buffers left!\n",
+				    netdev_name(txq->netdev));
+
+		return -ENOMEM;
+	}
+
+	/* Store buffer params in shadow buffer */
+	stash->buf.skb = tx_buf->skb;
+	stash->buf.bytes = tx_buf->bytes;
+	stash->buf.packets = tx_buf->packets;
+	stash->buf.type = tx_buf->type;
+	stash->buf.nr_frags = tx_buf->nr_frags;
+	dma_unmap_addr_set(&stash->buf, dma, dma_unmap_addr(tx_buf, dma));
+	dma_unmap_len_set(&stash->buf, len, dma_unmap_len(tx_buf, len));
+	idpf_tx_buf_compl_tag(&stash->buf) = idpf_tx_buf_compl_tag(tx_buf);
+
+	/* Add buffer to buf_hash table to be freed later */
+	hash_add(txq->stash->sched_buf_hash, &stash->hlist,
+		 idpf_tx_buf_compl_tag(&stash->buf));
+
+	tx_buf->type = LIBETH_SQE_EMPTY;
+
+	return 0;
+}
+
 #define idpf_tx_splitq_clean_bump_ntc(txq, ntc, desc, buf)	\
 do {								\
 	if (unlikely(++(ntc) == (txq)->desc_count)) {		\
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -663,6 +663,7 @@
  * @cleaned_pkts: Number of packets cleaned for the above said case
  * @tx_min_pkt_len: Min supported packet length
  * @refillq: Pointer to refill queue
+ * @compl_tag_bufid_m: Completion tag buffer id mask
  * @compl_tag_gen_s: Completion tag generation bit
  *	The format of the completion tag will change based on the TXQ
  *	descriptor ring size so that we can maintain roughly the same level
@@ -683,6 +684,9 @@
  *	--------------------------------
  *
  *	This gives us 8*8160 = 65280 possible unique values.
+ * @compl_tag_cur_gen: Used to keep track of current completion tag generation
+ * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
+ * @stash: Tx buffer stash for Flow-based scheduling mode
  * @stats_sync: See struct u64_stats_sync
  * @q_stats: See union idpf_tx_queue_stats
  * @q_id: Queue id
@@ -724,8 +728,13 @@
 	u16 tx_min_pkt_len;
 	struct idpf_sw_queue *refillq;
 
+	u16 compl_tag_bufid_m;
 	u16 compl_tag_gen_s;
 
+	u16 compl_tag_cur_gen;
+	u16 compl_tag_gen_max;
+
+	struct idpf_txq_stash *stash;
 
 	struct u64_stats_sync stats_sync;
 	struct idpf_tx_queue_stats q_stats;

################################################################################
!    REJECTED PATCH2 HUNKS - could not be compared; manual review needed       !
################################################################################

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1602,87 +1462,6 @@
 	spin_unlock_bh(&tx_tstamp_caps->status_lock);
 }
 
-/**
- * idpf_tx_clean_stashed_bufs - clean bufs that were stored for
- * out of order completions
- * @txq: queue to clean
- * @compl_tag: completion tag of packet to clean (from completion descriptor)
- * @cleaned: pointer to stats struct to track cleaned packets/bytes
- * @budget: Used to determine if we are in netpoll
- */
-static void idpf_tx_clean_stashed_bufs(struct idpf_tx_queue *txq,
-				       u16 compl_tag,
-				       struct libeth_sq_napi_stats *cleaned,
-				       int budget)
-{
-	struct idpf_tx_stash *stash;
-	struct hlist_node *tmp_buf;
-	struct libeth_cq_pp cp = {
-		.dev	= txq->dev,
-		.ss	= cleaned,
-		.napi	= budget,
-	};
-
-	/* Buffer completion */
-	hash_for_each_possible_safe(txq->stash->sched_buf_hash, stash, tmp_buf,
-				    hlist, compl_tag) {
-		if (unlikely(idpf_tx_buf_compl_tag(&stash->buf) != compl_tag))
-			continue;
-
-		hash_del(&stash->hlist);
-
-		if (stash->buf.type == LIBETH_SQE_SKB &&
-		    (skb_shinfo(stash->buf.skb)->tx_flags & SKBTX_IN_PROGRESS))
-			idpf_tx_read_tstamp(txq, stash->buf.skb);
-
-		libeth_tx_complete(&stash->buf, &cp);
-
-		/* Push shadow buf back onto stack */
-		idpf_buf_lifo_push(&txq->stash->buf_stack, stash);
-	}
-}
-
-/**
- * idpf_stash_flow_sch_buffers - store buffer parameters info to be freed at a
- * later time (only relevant for flow scheduling mode)
- * @txq: Tx queue to clean
- * @tx_buf: buffer to store
- */
-static int idpf_stash_flow_sch_buffers(struct idpf_tx_queue *txq,
-				       struct idpf_tx_buf *tx_buf)
-{
-	struct idpf_tx_stash *stash;
-
-	if (unlikely(tx_buf->type <= LIBETH_SQE_CTX))
-		return 0;
-
-	stash = idpf_buf_lifo_pop(&txq->stash->buf_stack);
-	if (unlikely(!stash)) {
-		net_err_ratelimited("%s: No out-of-order TX buffers left!\n",
-				    netdev_name(txq->netdev));
-
-		return -ENOMEM;
-	}
-
-	/* Store buffer params in shadow buffer */
-	stash->buf.skb = tx_buf->skb;
-	stash->buf.bytes = tx_buf->bytes;
-	stash->buf.packets = tx_buf->packets;
-	stash->buf.type = tx_buf->type;
-	stash->buf.nr_frags = tx_buf->nr_frags;
-	dma_unmap_addr_set(&stash->buf, dma, dma_unmap_addr(tx_buf, dma));
-	dma_unmap_len_set(&stash->buf, len, dma_unmap_len(tx_buf, len));
-	idpf_tx_buf_compl_tag(&stash->buf) = idpf_tx_buf_compl_tag(tx_buf);
-
-	/* Add buffer to buf_hash table to be freed later */
-	hash_add(txq->stash->sched_buf_hash, &stash->hlist,
-		 idpf_tx_buf_compl_tag(&stash->buf));
-
-	tx_buf->type = LIBETH_SQE_EMPTY;
-
-	return 0;
-}
-
 #define idpf_tx_splitq_clean_bump_ntc(txq, ntc, desc, buf)	\
 do {								\
 	if (unlikely(++(ntc) == (txq)->desc_count)) {		\
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -598,7 +565,6 @@
  *		   only once at the end of the cleaning routine.
  * @clean_budget: singleq only, queue cleaning budget
  * @cleaned_pkts: Number of packets cleaned for the above said case
- * @stash: Tx buffer stash for Flow-based scheduling mode
  * @refillq: Pointer to refill queue
  * @compl_tag_bufid_m: Completion tag buffer id mask
  * @compl_tag_cur_gen: Used to keep track of current completion tag generation
@@ -600,9 +566,6 @@
  * @cleaned_pkts: Number of packets cleaned for the above said case
  * @stash: Tx buffer stash for Flow-based scheduling mode
  * @refillq: Pointer to refill queue
- * @compl_tag_bufid_m: Completion tag buffer id mask
- * @compl_tag_cur_gen: Used to keep track of current completion tag generation
- * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
  * @cached_tstamp_caps: Tx timestamp capabilities negotiated with the CP
  * @tstamp_task: Work that handles Tx timestamp read
  * @stats_sync: See struct u64_stats_sync
@@ -633,7 +596,6 @@
 	u16 desc_count;
 
 	u16 tx_min_pkt_len;
-	u16 compl_tag_gen_s;
 
 	struct net_device *netdev;
 	__cacheline_group_end_aligned(read_mostly);
@@ -650,7 +612,6 @@
 	};
 	u16 cleaned_pkts;
 
-	struct idpf_txq_stash *stash;
 	struct idpf_sw_queue *refillq;
 
 	u16 compl_tag_bufid_m;
@@ -653,10 +614,6 @@
 	struct idpf_txq_stash *stash;
 	struct idpf_sw_queue *refillq;
 
-	u16 compl_tag_bufid_m;
-	u16 compl_tag_cur_gen;
-	u16 compl_tag_gen_max;
-
 	struct idpf_ptp_vport_tx_tstamp_caps *cached_tstamp_caps;
 	struct work_struct *tstamp_task;
 
@@ -674,7 +631,7 @@
 	__cacheline_group_end_aligned(cold);
 };
 libeth_cacheline_set_assert(struct idpf_tx_queue, 64,
-			    120 + sizeof(struct u64_stats_sync),
+			    104 + sizeof(struct u64_stats_sync),
 			    32);
 
 /**

================================================================================
*    CONTEXT DIFFERENCES - surrounding code differences between the patches    *
================================================================================

--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -3,4 +3,4 @@
-#include "idpf.h"
+#include "idpf_ptp.h"
 #include "idpf_virtchnl.h"
 
 struct idpf_tx_stash {
@@ -1725,6 +1770,11 @@
 			continue;
 
 		hash_del(&stash->hlist);
+
+		if (stash->buf.type == LIBETH_SQE_SKB &&
+		    (skb_shinfo(stash->buf.skb)->tx_flags & SKBTX_IN_PROGRESS))
+			idpf_tx_read_tstamp(txq, stash->buf.skb);
+
 		libeth_tx_complete(&stash->buf, &cp);
 
 		/* Push shadow buf back onto stack */
--- b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -714,9 +663,7 @@
- *	--------------------------------
- *
- *	This gives us 8*8160 = 65280 possible unique values.
- * @compl_tag_cur_gen: Used to keep track of current completion tag generation
- * @compl_tag_gen_max: To determine when compl_tag_cur_gen should be reset
- * @stash: Tx buffer stash for Flow-based scheduling mode
- * @stats_sync: See struct u64_stats_sync
- * @q_stats: See union idpf_tx_queue_stats
- * @q_id: Queue id
+	u16 desc_count;
+
+	u16 tx_min_pkt_len;
+	u16 compl_tag_gen_s;
+
+	struct net_device *netdev;
+	__cacheline_group_end_aligned(read_mostly);

This is an automated interdiff check for backported commits.

@github-actions
Copy link

Validation checks completed successfully View full results: https://github.com/ctrliq/kernel-src-tree/actions/runs/22405737478

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants