diff mbox series

[bpf-next,v8,4/5] igc: Refactor empty packet insertion into a reusable function

Message ID 20250205024116.798862-5-yoong.siang.song@intel.com (mailing list archive)
State New
Delegated to: BPF
Headers show
Series xsk: TX metadata Launch Time support | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat-kernel
bpf/vmtest-bpf-next-VM_Test-18 success Logs for s390x-gcc / veristat-meta
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-11 success Logs for aarch64-gcc / veristat-meta
bpf/vmtest-bpf-next-VM_Test-19 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-17 success Logs for s390x-gcc / veristat-kernel
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-gcc / veristat-kernel / x86_64-gcc veristat_kernel
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-gcc / veristat-meta / x86_64-gcc veristat_meta
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-17 / veristat-kernel
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-17 / veristat-meta
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-42 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-43 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-44 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-45 success Logs for x86_64-llvm-18 / veristat-kernel
bpf/vmtest-bpf-next-VM_Test-46 success Logs for x86_64-llvm-18 / veristat-meta
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next
netdev/ynl fail Tree is dirty after regen; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 13 of 13 maintainers
netdev/build_clang success Errors and warnings before: 2 this patch: 2
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 54 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 29 this patch: 29
netdev/source_inline success Was 0 now: 0

Commit Message

Song, Yoong Siang Feb. 5, 2025, 2:41 a.m. UTC
Refactor the code for inserting an empty packet into a new function
igc_insert_empty_packet(). This change extracts the logic for inserting
an empty packet from igc_xmit_frame_ring() into a separate function,
allowing it to be reused in future implementations, such as the XDP
zero copy transmit function.

This patch introduces no functional changes.

Signed-off-by: Song Yoong Siang <yoong.siang.song@intel.com>
Reviewed-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>
---
 drivers/net/ethernet/intel/igc/igc_main.c | 42 ++++++++++++-----------
 1 file changed, 22 insertions(+), 20 deletions(-)

Comments

Maciej Fijalkowski Feb. 5, 2025, 12:31 p.m. UTC | #1
On Wed, Feb 05, 2025 at 10:41:15AM +0800, Song Yoong Siang wrote:
> Refactor the code for inserting an empty packet into a new function
> igc_insert_empty_packet(). This change extracts the logic for inserting
> an empty packet from igc_xmit_frame_ring() into a separate function,
> allowing it to be reused in future implementations, such as the XDP
> zero copy transmit function.
> 
> This patch introduces no functional changes.
> 
> Signed-off-by: Song Yoong Siang <yoong.siang.song@intel.com>

Your SoB should be last in the set of tags.

> Reviewed-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>
> ---
>  drivers/net/ethernet/intel/igc/igc_main.c | 42 ++++++++++++-----------
>  1 file changed, 22 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
> index 21f318f12a8d..553d6d82af0d 100644
> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> @@ -1566,6 +1566,26 @@ static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *s
>  	return false;
>  }
>  
> +static void igc_insert_empty_packet(struct igc_ring *tx_ring)
> +{
> +	struct igc_tx_buffer *empty_info;
> +	struct sk_buff *empty;
> +	void *data;
> +
> +	empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
> +	empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
> +	if (!empty)
> +		return;
> +
> +	data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
> +	memset(data, 0, IGC_EMPTY_FRAME_SIZE);
> +
> +	igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
> +
> +	if (igc_init_tx_empty_descriptor(tx_ring, empty, empty_info) < 0)
> +		dev_kfree_skb_any(empty);

I still don't like the fact igc_insert_empty_packet() doesn't communicate
to caller whether it successfully produced descriptors or not.

Look at this from igc_xmit_frame_ring() POV:
- at the beginning you peek at Tx ring whether there is required amount of
  descriptors free to be used
- but then here's your additional routine which might consume two more
  descs and you are not aware of the status
- then you continue to further produce descriptors assuming there is
  enough space in Tx ring

Right now igc_init_tx_empty_descriptor() returns -EBUSY when ring is full.
How can that happen in the first place + what if it would *really* happen
though? You just continue with your Tx flow.

What I'm trying to say here is, at least from correctness POV, you should
take into the account two potential descriptors for launchtime feature
when calling igc_maybe_stop_tx(). And igc_init_tx_empty_descriptor()
should not really care about space in ring, it should be a caller's job to
call it only when it will be sure it's safe to do so.

> +}
> +
>  static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
>  				       struct igc_ring *tx_ring)
>  {
> @@ -1603,26 +1623,8 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
>  	skb->tstamp = ktime_set(0, 0);
>  	launch_time = igc_tx_launchtime(tx_ring, txtime, &first_flag, &insert_empty);
>  
> -	if (insert_empty) {
> -		struct igc_tx_buffer *empty_info;
> -		struct sk_buff *empty;
> -		void *data;
> -
> -		empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
> -		empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
> -		if (!empty)
> -			goto done;
> -
> -		data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
> -		memset(data, 0, IGC_EMPTY_FRAME_SIZE);
> -
> -		igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
> -
> -		if (igc_init_tx_empty_descriptor(tx_ring,
> -						 empty,
> -						 empty_info) < 0)
> -			dev_kfree_skb_any(empty);
> -	}
> +	if (insert_empty)
> +		igc_insert_empty_packet(tx_ring);
>  
>  done:
>  	/* record the location of the first descriptor for this packet */
> -- 
> 2.34.1
>
Song, Yoong Siang Feb. 5, 2025, 2:43 p.m. UTC | #2
On Wednesday, February 5, 2025 8:31 PM, Fijalkowski, Maciej <maciej.fijalkowski@intel.com> wrote:
>On Wed, Feb 05, 2025 at 10:41:15AM +0800, Song Yoong Siang wrote:
>> Refactor the code for inserting an empty packet into a new function
>> igc_insert_empty_packet(). This change extracts the logic for inserting
>> an empty packet from igc_xmit_frame_ring() into a separate function,
>> allowing it to be reused in future implementations, such as the XDP
>> zero copy transmit function.
>>
>> This patch introduces no functional changes.
>>
>> Signed-off-by: Song Yoong Siang <yoong.siang.song@intel.com>
>
>Your SoB should be last in the set of tags.
>

Noted. Thanks for the tips.

>> Reviewed-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>
>> ---
>>  drivers/net/ethernet/intel/igc/igc_main.c | 42 ++++++++++++-----------
>>  1 file changed, 22 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
>b/drivers/net/ethernet/intel/igc/igc_main.c
>> index 21f318f12a8d..553d6d82af0d 100644
>> --- a/drivers/net/ethernet/intel/igc/igc_main.c
>> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
>> @@ -1566,6 +1566,26 @@ static bool igc_request_tx_tstamp(struct igc_adapter
>*adapter, struct sk_buff *s
>>  	return false;
>>  }
>>
>> +static void igc_insert_empty_packet(struct igc_ring *tx_ring)
>> +{
>> +	struct igc_tx_buffer *empty_info;
>> +	struct sk_buff *empty;
>> +	void *data;
>> +
>> +	empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
>> +	empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
>> +	if (!empty)
>> +		return;
>> +
>> +	data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
>> +	memset(data, 0, IGC_EMPTY_FRAME_SIZE);
>> +
>> +	igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
>> +
>> +	if (igc_init_tx_empty_descriptor(tx_ring, empty, empty_info) < 0)
>> +		dev_kfree_skb_any(empty);
>
>I still don't like the fact igc_insert_empty_packet() doesn't communicate
>to caller whether it successfully produced descriptors or not.
>
>Look at this from igc_xmit_frame_ring() POV:
>- at the beginning you peek at Tx ring whether there is required amount of
>  descriptors free to be used
>- but then here's your additional routine which might consume two more
>  descs and you are not aware of the status
>- then you continue to further produce descriptors assuming there is
>  enough space in Tx ring
>
>Right now igc_init_tx_empty_descriptor() returns -EBUSY when ring is full.
>How can that happen in the first place + what if it would *really* happen
>though? You just continue with your Tx flow.
>
>What I'm trying to say here is, at least from correctness POV, you should
>take into the account two potential descriptors for launchtime feature
>when calling igc_maybe_stop_tx(). And igc_init_tx_empty_descriptor()
>should not really care about space in ring, it should be a caller's job to
>call it only when it will be sure it's safe to do so.
>

Agree with you.

In db0b124f02ba ("igc: Enhance Qbv scheduling by using first flag bit"),
the 2 descriptors needed by empty packet is already taken into
consideration by changing igc_maybe_stop_tx(tx_ring, count + 3) to
igc_maybe_stop_tx(tx_ring, count + 5), so not enough ring space issue will not
happened. However, the comment session is not updated, maybe i can update
it in next version of this patch as below:

@@ -1586,6 +1608,7 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
         *      + 1 desc for skb_headlen/IGC_MAX_DATA_PER_TXD,
         *      + 2 desc gap to keep tail from touching head,
         *      + 1 desc for context descriptor,
+        *      + 2 desc for inserting an empty packet for launch time,
         * otherwise try next time
         */
        for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)

Since number of descriptor needed is guaranteed. I will take out the
igc_desc_unused() checking in igc_init_tx_empty_descriptor().
However, empty packet insertion might fail due to skb allocation failure
and DMA mapping error. How about i make sure skb allocation and DMA
mapping working, before proceed to fill in igc_tx_buffer, context desc,
and data desc?
IMHO, because these two errors are unlikely to happen, print a kernel
warning msg should be enough.

@@ -1108,20 +1108,12 @@ static int igc_init_empty_frame(struct igc_ring *ring,
        return 0;
 }

-static int igc_init_tx_empty_descriptor(struct igc_ring *ring,
+static void igc_init_tx_empty_descriptor(struct igc_ring *ring,
                                        struct sk_buff *skb,
                                        struct igc_tx_buffer *first)
 {
        union igc_adv_tx_desc *desc;
        u32 cmd_type, olinfo_status;
-       int err;
-
-       if (!igc_desc_unused(ring))
-               return -EBUSY;
-
-       err = igc_init_empty_frame(ring, first, skb);
-       if (err)
-               return err;

        cmd_type = IGC_ADVTXD_DTYP_DATA | IGC_ADVTXD_DCMD_DEXT |
                   IGC_ADVTXD_DCMD_IFCS | IGC_TXD_DCMD |
@@ -1140,8 +1132,6 @@ static int igc_init_tx_empty_descriptor(struct igc_ring *ring,
        ring->next_to_use++;
        if (ring->next_to_use == ring->count)
                ring->next_to_use = 0;
-
-       return 0;
 }

 #define IGC_EMPTY_FRAME_SIZE 60
@@ -1567,6 +1557,38 @@ static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *s
        return false;
 }

+static void igc_insert_empty_packet(struct igc_ring *tx_ring)
+{
+       struct igc_tx_buffer *empty_info;
+       struct sk_buff *empty;
+       void *data;
+
+       empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+       empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
+       if (unlikely(!empty)) {
+               netdev_warn(tx_ring->netdev,
+                           "Fail to alloc skb for empty packet\n");
+               return;
+       }
+
+       data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
+       memset(data, 0, IGC_EMPTY_FRAME_SIZE);
+
+       /* Prepare DMA mapping and Tx buffer information */
+       if (unlikely(igc_init_empty_frame(tx_ring, empty_info, empty))) {
+               dev_kfree_skb_any(empty);
+               netdev_warn(tx_ring->netdev,
+                           "Fail to map DMA for empty packet\n");
+               return;
+       }
+
+       /* Prepare context descriptor for empty packet */
+       igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
+
+       /* Prepare data descriptor for empty packet */
+       igc_init_tx_empty_descriptor(tx_ring, empty, empty_info);
+}
+
 static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
                                       struct igc_ring *tx_ring)
 {

Are above codes resolve your concern? If yes, i can test and add
them into this patch in next version submission.

Thanks & Regards
Siang
Maciej Fijalkowski Feb. 5, 2025, 4:07 p.m. UTC | #3
On Wed, Feb 05, 2025 at 03:43:19PM +0100, Song, Yoong Siang wrote:
> On Wednesday, February 5, 2025 8:31 PM, Fijalkowski, Maciej <maciej.fijalkowski@intel.com> wrote:
> >On Wed, Feb 05, 2025 at 10:41:15AM +0800, Song Yoong Siang wrote:
> >> Refactor the code for inserting an empty packet into a new function
> >> igc_insert_empty_packet(). This change extracts the logic for inserting
> >> an empty packet from igc_xmit_frame_ring() into a separate function,
> >> allowing it to be reused in future implementations, such as the XDP
> >> zero copy transmit function.
> >>
> >> This patch introduces no functional changes.
> >>
> >> Signed-off-by: Song Yoong Siang <yoong.siang.song@intel.com>
> >
> >Your SoB should be last in the set of tags.
> >
> 
> Noted. Thanks for the tips.
> 
> >> Reviewed-by: Faizal Rahim <faizal.abdul.rahim@linux.intel.com>
> >> ---
> >>  drivers/net/ethernet/intel/igc/igc_main.c | 42 ++++++++++++-----------
> >>  1 file changed, 22 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
> >b/drivers/net/ethernet/intel/igc/igc_main.c
> >> index 21f318f12a8d..553d6d82af0d 100644
> >> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> >> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> >> @@ -1566,6 +1566,26 @@ static bool igc_request_tx_tstamp(struct igc_adapter
> >*adapter, struct sk_buff *s
> >>  	return false;
> >>  }
> >>
> >> +static void igc_insert_empty_packet(struct igc_ring *tx_ring)
> >> +{
> >> +	struct igc_tx_buffer *empty_info;
> >> +	struct sk_buff *empty;
> >> +	void *data;
> >> +
> >> +	empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
> >> +	empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
> >> +	if (!empty)
> >> +		return;
> >> +
> >> +	data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
> >> +	memset(data, 0, IGC_EMPTY_FRAME_SIZE);
> >> +
> >> +	igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
> >> +
> >> +	if (igc_init_tx_empty_descriptor(tx_ring, empty, empty_info) < 0)
> >> +		dev_kfree_skb_any(empty);
> >
> >I still don't like the fact igc_insert_empty_packet() doesn't communicate
> >to caller whether it successfully produced descriptors or not.
> >
> >Look at this from igc_xmit_frame_ring() POV:
> >- at the beginning you peek at Tx ring whether there is required amount of
> >  descriptors free to be used
> >- but then here's your additional routine which might consume two more
> >  descs and you are not aware of the status
> >- then you continue to further produce descriptors assuming there is
> >  enough space in Tx ring
> >
> >Right now igc_init_tx_empty_descriptor() returns -EBUSY when ring is full.
> >How can that happen in the first place + what if it would *really* happen
> >though? You just continue with your Tx flow.
> >
> >What I'm trying to say here is, at least from correctness POV, you should
> >take into the account two potential descriptors for launchtime feature
> >when calling igc_maybe_stop_tx(). And igc_init_tx_empty_descriptor()
> >should not really care about space in ring, it should be a caller's job to
> >call it only when it will be sure it's safe to do so.
> >
> 
> Agree with you.
> 
> In db0b124f02ba ("igc: Enhance Qbv scheduling by using first flag bit"),
> the 2 descriptors needed by empty packet is already taken into
> consideration by changing igc_maybe_stop_tx(tx_ring, count + 3) to
> igc_maybe_stop_tx(tx_ring, count + 5), so not enough ring space issue will not
> happened. However, the comment session is not updated, maybe i can update
> it in next version of this patch as below:
> 
> @@ -1586,6 +1608,7 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
>          *      + 1 desc for skb_headlen/IGC_MAX_DATA_PER_TXD,
>          *      + 2 desc gap to keep tail from touching head,
>          *      + 1 desc for context descriptor,
> +        *      + 2 desc for inserting an empty packet for launch time,
>          * otherwise try next time
>          */
>         for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)

Ahh good then, I didn't pay enough attention to comment. So it meant that
first two entries from comment were covered by @count and 2 desc gap + 1
ctxt desc were behind '3', previously.

> 
> Since number of descriptor needed is guaranteed. I will take out the
> igc_desc_unused() checking in igc_init_tx_empty_descriptor().

Yes

> However, empty packet insertion might fail due to skb allocation failure
> and DMA mapping error. How about i make sure skb allocation and DMA
> mapping working, before proceed to fill in igc_tx_buffer, context desc,
> and data desc?
> IMHO, because these two errors are unlikely to happen, print a kernel
> warning msg should be enough.
> 
> @@ -1108,20 +1108,12 @@ static int igc_init_empty_frame(struct igc_ring *ring,
>         return 0;
>  }
> 
> -static int igc_init_tx_empty_descriptor(struct igc_ring *ring,
> +static void igc_init_tx_empty_descriptor(struct igc_ring *ring,
>                                         struct sk_buff *skb,
>                                         struct igc_tx_buffer *first)
>  {
>         union igc_adv_tx_desc *desc;
>         u32 cmd_type, olinfo_status;
> -       int err;
> -
> -       if (!igc_desc_unused(ring))
> -               return -EBUSY;
> -
> -       err = igc_init_empty_frame(ring, first, skb);
> -       if (err)
> -               return err;
> 
>         cmd_type = IGC_ADVTXD_DTYP_DATA | IGC_ADVTXD_DCMD_DEXT |
>                    IGC_ADVTXD_DCMD_IFCS | IGC_TXD_DCMD |
> @@ -1140,8 +1132,6 @@ static int igc_init_tx_empty_descriptor(struct igc_ring *ring,
>         ring->next_to_use++;
>         if (ring->next_to_use == ring->count)
>                 ring->next_to_use = 0;
> -
> -       return 0;
>  }
> 
>  #define IGC_EMPTY_FRAME_SIZE 60
> @@ -1567,6 +1557,38 @@ static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *s
>         return false;
>  }
> 
> +static void igc_insert_empty_packet(struct igc_ring *tx_ring)
> +{
> +       struct igc_tx_buffer *empty_info;
> +       struct sk_buff *empty;
> +       void *data;
> +
> +       empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
> +       empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
> +       if (unlikely(!empty)) {
> +               netdev_warn(tx_ring->netdev,
> +                           "Fail to alloc skb for empty packet\n");

That should be at least ratelimited I think, but what really is the
problem to make these routines return status and check them on caller
side?

> +               return;
> +       }
> +
> +       data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
> +       memset(data, 0, IGC_EMPTY_FRAME_SIZE);
> +
> +       /* Prepare DMA mapping and Tx buffer information */
> +       if (unlikely(igc_init_empty_frame(tx_ring, empty_info, empty))) {
> +               dev_kfree_skb_any(empty);
> +               netdev_warn(tx_ring->netdev,
> +                           "Fail to map DMA for empty packet\n");
> +               return;
> +       }
> +
> +       /* Prepare context descriptor for empty packet */
> +       igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
> +
> +       /* Prepare data descriptor for empty packet */
> +       igc_init_tx_empty_descriptor(tx_ring, empty, empty_info);
> +}
> +
>  static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
>                                        struct igc_ring *tx_ring)
>  {
> 
> Are above codes resolve your concern? If yes, i can test and add
> them into this patch in next version submission.
> 
> Thanks & Regards
> Siang
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 21f318f12a8d..553d6d82af0d 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1566,6 +1566,26 @@  static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *s
 	return false;
 }
 
+static void igc_insert_empty_packet(struct igc_ring *tx_ring)
+{
+	struct igc_tx_buffer *empty_info;
+	struct sk_buff *empty;
+	void *data;
+
+	empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
+	empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
+	if (!empty)
+		return;
+
+	data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
+	memset(data, 0, IGC_EMPTY_FRAME_SIZE);
+
+	igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
+
+	if (igc_init_tx_empty_descriptor(tx_ring, empty, empty_info) < 0)
+		dev_kfree_skb_any(empty);
+}
+
 static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
 				       struct igc_ring *tx_ring)
 {
@@ -1603,26 +1623,8 @@  static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
 	skb->tstamp = ktime_set(0, 0);
 	launch_time = igc_tx_launchtime(tx_ring, txtime, &first_flag, &insert_empty);
 
-	if (insert_empty) {
-		struct igc_tx_buffer *empty_info;
-		struct sk_buff *empty;
-		void *data;
-
-		empty_info = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
-		empty = alloc_skb(IGC_EMPTY_FRAME_SIZE, GFP_ATOMIC);
-		if (!empty)
-			goto done;
-
-		data = skb_put(empty, IGC_EMPTY_FRAME_SIZE);
-		memset(data, 0, IGC_EMPTY_FRAME_SIZE);
-
-		igc_tx_ctxtdesc(tx_ring, 0, false, 0, 0, 0);
-
-		if (igc_init_tx_empty_descriptor(tx_ring,
-						 empty,
-						 empty_info) < 0)
-			dev_kfree_skb_any(empty);
-	}
+	if (insert_empty)
+		igc_insert_empty_packet(tx_ring);
 
 done:
 	/* record the location of the first descriptor for this packet */