diff mbox series

[v1] igc: Qbv scheduling enchancement using frst flag bit

Message ID 20221020145316.1543-1-muhammad.husaini.zulkifli@intel.com
State Changes Requested
Headers show
Series [v1] igc: Qbv scheduling enchancement using frst flag bit | expand

Commit Message

Zulkifli, Muhammad Husaini Oct. 20, 2022, 2:53 p.m. UTC
From: Vinicius Costa Gomes <vinicius.gomes@intel.com>

The I225 hardware has a limitation that packets can only be scheduled
in the [0, cycle-time] interval. So, scheduling a packet to the start
of the next cycle doesn't usually work.

To overcome this, we use the Transmit Descriptor frst flag to indicates
that a packet should be the first packet (from a queue) in a cycle
according to the section 7.5.2.9.3.4 The First Packet on Each QBV Cycle
in Intel Discrete I225/6 User Manual.

But this only works if there was any packet from that queue during the
current cycle, to avoid this issue, we issue an empty packet if that's
not the case. Also require one more descriptor to be available, to take
into account the empty packet that might be issued.

Test Setup:

Talker: Use l2_tai to generate the launchtime into packet load.

Listener: Use timedump.c to compute the delta between packet arrival
and LaunchTime packet payload.

Test Result:

Before:

1666000610127300000,1666000610127300096,96,621273
1666000610127400000,1666000610127400192,192,621274
1666000610127500000,1666000610127500032,32,621275
1666000610127600000,1666000610127600128,128,621276
1666000610127700000,1666000610127700224,224,621277
1666000610127800000,1666000610127800064,64,621278
1666000610127900000,1666000610127900160,160,621279
1666000610128000000,1666000610128000000,0,621280
1666000610128100000,1666000610128100096,96,621281
1666000610128200000,1666000610128200192,192,621282
1666000610128300000,1666000610128300032,32,621283
1666000610128400000,1666000610128301056,-98944,621284
1666000610128500000,1666000610128302080,-197920,621285
1666000610128600000,1666000610128302848,-297152,621286
1666000610128700000,1666000610128303872,-396128,621287
1666000610128800000,1666000610128304896,-495104,621288
1666000610128900000,1666000610128305664,-594336,621289
1666000610129000000,1666000610128306688,-693312,621290
1666000610129100000,1666000610128307712,-792288,621291
1666000610129200000,1666000610128308480,-891520,621292
1666000610129300000,1666000610128309504,-990496,621293
1666000610129400000,1666000610128310528,-1089472,621294
1666000610129500000,1666000610128311296,-1188704,621295
1666000610129600000,1666000610128312320,-1287680,621296
1666000610129700000,1666000610128313344,-1386656,621297
1666000610129800000,1666000610128314112,-1485888,621298
1666000610129900000,1666000610128315136,-1584864,621299
1666000610130000000,1666000610128316160,-1683840,621300
1666000610130100000,1666000610128316928,-1783072,621301
1666000610130200000,1666000610128317952,-1882048,621302
1666000610130300000,1666000610128318976,-1981024,621303
1666000610130400000,1666000610128319744,-2080256,621304
1666000610130500000,1666000610128320768,-2179232,621305
1666000610130600000,1666000610128321792,-2278208,621306
1666000610130700000,1666000610128322816,-2377184,621307
1666000610130800000,1666000610128323584,-2476416,621308
1666000610130900000,1666000610128324608,-2575392,621309
1666000610131000000,1666000610128325632,-2674368,621310
1666000610131100000,1666000610128326400,-2773600,621311
1666000610131200000,1666000610128327424,-2872576,621312
1666000610131300000,1666000610128328448,-2971552,621313
1666000610131400000,1666000610128329216,-3070784,621314
1666000610131500000,1666000610131500032,32,621315
1666000610131600000,1666000610131600128,128,621316
1666000610131700000,1666000610131700224,224,621317

After:

1666073510646200000,1666073510646200064,64,2676462
1666073510646300000,1666073510646300160,160,2676463
1666073510646400000,1666073510646400256,256,2676464
1666073510646500000,1666073510646500096,96,2676465
1666073510646600000,1666073510646600192,192,2676466
1666073510646700000,1666073510646700032,32,2676467
1666073510646800000,1666073510646800128,128,2676468
1666073510646900000,1666073510646900224,224,2676469
1666073510647000000,1666073510647000064,64,2676470
1666073510647100000,1666073510647100160,160,2676471
1666073510647200000,1666073510647200256,256,2676472
1666073510647300000,1666073510647300096,96,2676473
1666073510647400000,1666073510647400192,192,2676474
1666073510647500000,1666073510647500032,32,2676475
1666073510647600000,1666073510647600128,128,2676476
1666073510647700000,1666073510647700224,224,2676477
1666073510647800000,1666073510647800064,64,2676478
1666073510647900000,1666073510647900160,160,2676479
1666073510648000000,1666073510648000000,0,2676480
1666073510648100000,1666073510648100096,96,2676481
1666073510648200000,1666073510648200192,192,2676482
1666073510648300000,1666073510648300032,32,2676483
1666073510648400000,1666073510648400128,128,2676484
1666073510648500000,1666073510648500224,224,2676485
1666073510648600000,1666073510648600064,64,2676486
1666073510648700000,1666073510648700160,160,2676487
1666073510648800000,1666073510648800000,0,2676488
1666073510648900000,1666073510648900096,96,2676489
1666073510649000000,1666073510649000192,192,2676490
1666073510649100000,1666073510649100032,32,2676491
1666073510649200000,1666073510649200128,128,2676492
1666073510649300000,1666073510649300224,224,2676493
1666073510649400000,1666073510649400064,64,2676494
1666073510649500000,1666073510649500160,160,2676495
1666073510649600000,1666073510649600000,0,2676496
1666073510649700000,1666073510649700096,96,2676497
1666073510649800000,1666073510649800192,192,2676498
1666073510649900000,1666073510649900032,32,2676499
1666073510650000000,1666073510650000128,128,2676500

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Co-developed-by: Aravindhan Gunasekaran <aravindhan.gunasekaran@intel.com>
Signed-off-by: Aravindhan Gunasekaran <aravindhan.gunasekaran@intel.com>
Co-developed-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
Signed-off-by: Malli C <mallikarjuna.chilakala@intel.com>
Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
---
 drivers/net/ethernet/intel/igc/igc.h         |   2 +
 drivers/net/ethernet/intel/igc/igc_defines.h |   2 +
 drivers/net/ethernet/intel/igc/igc_main.c    | 185 ++++++++++++++++---
 3 files changed, 159 insertions(+), 30 deletions(-)

Comments

Paul Menzel Oct. 20, 2022, 3:08 p.m. UTC | #1
Dear Muhammad,


Thank you for the patch.

There is a small typo in the summary/title: f*i*rst. Also it’d be nice 
if you made it a statement. Maybe:

> igc: Enhance Qbv scheduling by using first flag bit


Kind regards,

Paul
kernel test robot Oct. 20, 2022, 10:28 p.m. UTC | #2
Hi Muhammad,

I love your patch! Yet something to improve:

[auto build test ERROR on tnguy-next-queue/dev-queue]
[also build test ERROR on linus/master v6.1-rc1 next-20221020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Muhammad-Husaini-Zulkifli/igc-Qbv-scheduling-enchancement-using-frst-flag-bit/20221020-230538
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git dev-queue
patch link:    https://lore.kernel.org/r/20221020145316.1543-1-muhammad.husaini.zulkifli%40intel.com
patch subject: [Intel-wired-lan] [PATCH v1] igc: Qbv scheduling enchancement using frst flag bit
config: i386-randconfig-a012-20221017
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/892f41356aa172194b2b1f6a1f288508fc2282d0
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Muhammad-Husaini-Zulkifli/igc-Qbv-scheduling-enchancement-using-frst-flag-bit/20221020-230538
        git checkout 892f41356aa172194b2b1f6a1f288508fc2282d0
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "__moddi3" [drivers/net/ethernet/intel/igc/igc.ko] undefined!
kernel test robot Oct. 20, 2022, 10:28 p.m. UTC | #3
Hi Muhammad,

I love your patch! Yet something to improve:

[auto build test ERROR on tnguy-next-queue/dev-queue]
[also build test ERROR on linus/master v6.1-rc1 next-20221020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Muhammad-Husaini-Zulkifli/igc-Qbv-scheduling-enchancement-using-frst-flag-bit/20221020-230538
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git dev-queue
patch link:    https://lore.kernel.org/r/20221020145316.1543-1-muhammad.husaini.zulkifli%40intel.com
patch subject: [Intel-wired-lan] [PATCH v1] igc: Qbv scheduling enchancement using frst flag bit
config: i386-randconfig-a013-20221017
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/892f41356aa172194b2b1f6a1f288508fc2282d0
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Muhammad-Husaini-Zulkifli/igc-Qbv-scheduling-enchancement-using-frst-flag-bit/20221020-230538
        git checkout 892f41356aa172194b2b1f6a1f288508fc2282d0
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: __moddi3
   >>> referenced by igc_main.c
   >>>               drivers/net/ethernet/intel/igc/igc_main.o:(igc_xmit_frame) in archive vmlinux.a
Zulkifli, Muhammad Husaini Oct. 20, 2022, 10:44 p.m. UTC | #4
Hi Paul,

Thanks for the review.

> -----Original Message-----
> From: Paul Menzel <pmenzel@molgen.mpg.de>
> Sent: Thursday, 20 October, 2022 11:08 PM
> To: Zulkifli, Muhammad Husaini <muhammad.husaini.zulkifli@intel.com>
> Cc: Chilakala, Mallikarjuna <mallikarjuna.chilakala@intel.com>; intel-wired-
> lan@osuosl.org
> Subject: Re: [Intel-wired-lan] [PATCH v1] igc: Qbv scheduling enchancement
> using frst flag bit
> 
> Dear Muhammad,
> 
> 
> Thank you for the patch.
> 
> There is a small typo in the summary/title: f*i*rst. Also it’d be nice if you
> made it a statement. Maybe:
> 
> > igc: Enhance Qbv scheduling by using first flag bit

The bit was mentioned as "frst flag" bit in the software user manual.

> 
> 
> Kind regards,
> 
> Paul
Tony Nguyen Nov. 2, 2022, 9:27 p.m. UTC | #5
On 10/20/2022 7:53 AM, Muhammad Husaini Zulkifli wrote:
> From: Vinicius Costa Gomes <vinicius.gomes@intel.com>
> 
> The I225 hardware has a limitation that packets can only be scheduled
> in the [0, cycle-time] interval. So, scheduling a packet to the start
> of the next cycle doesn't usually work.
> 
> To overcome this, we use the Transmit Descriptor frst flag to indicates
> that a packet should be the first packet (from a queue) in a cycle
> according to the section 7.5.2.9.3.4 The First Packet on Each QBV Cycle
> in Intel Discrete I225/6 User Manual.
> 
> But this only works if there was any packet from that queue during the
> current cycle, to avoid this issue, we issue an empty packet if that's
> not the case. Also require one more descriptor to be available, to take
> into account the empty packet that might be issued.
> 
> Test Setup:
> 
> Talker: Use l2_tai to generate the launchtime into packet load.
> 
> Listener: Use timedump.c to compute the delta between packet arrival
> and LaunchTime packet payload.
> 
> Test Result:
> 
> Before:
> 
> 1666000610127300000,1666000610127300096,96,621273
> 1666000610127400000,1666000610127400192,192,621274
> 1666000610127500000,1666000610127500032,32,621275
> 1666000610127600000,1666000610127600128,128,621276
> 1666000610127700000,1666000610127700224,224,621277
> 1666000610127800000,1666000610127800064,64,621278
> 1666000610127900000,1666000610127900160,160,621279
> 1666000610128000000,1666000610128000000,0,621280
> 1666000610128100000,1666000610128100096,96,621281
> 1666000610128200000,1666000610128200192,192,621282
> 1666000610128300000,1666000610128300032,32,621283
> 1666000610128400000,1666000610128301056,-98944,621284
> 1666000610128500000,1666000610128302080,-197920,621285
> 1666000610128600000,1666000610128302848,-297152,621286
> 1666000610128700000,1666000610128303872,-396128,621287
> 1666000610128800000,1666000610128304896,-495104,621288
> 1666000610128900000,1666000610128305664,-594336,621289
> 1666000610129000000,1666000610128306688,-693312,621290
> 1666000610129100000,1666000610128307712,-792288,621291
> 1666000610129200000,1666000610128308480,-891520,621292
> 1666000610129300000,1666000610128309504,-990496,621293
> 1666000610129400000,1666000610128310528,-1089472,621294
> 1666000610129500000,1666000610128311296,-1188704,621295
> 1666000610129600000,1666000610128312320,-1287680,621296
> 1666000610129700000,1666000610128313344,-1386656,621297
> 1666000610129800000,1666000610128314112,-1485888,621298
> 1666000610129900000,1666000610128315136,-1584864,621299
> 1666000610130000000,1666000610128316160,-1683840,621300
> 1666000610130100000,1666000610128316928,-1783072,621301
> 1666000610130200000,1666000610128317952,-1882048,621302
> 1666000610130300000,1666000610128318976,-1981024,621303
> 1666000610130400000,1666000610128319744,-2080256,621304
> 1666000610130500000,1666000610128320768,-2179232,621305
> 1666000610130600000,1666000610128321792,-2278208,621306
> 1666000610130700000,1666000610128322816,-2377184,621307
> 1666000610130800000,1666000610128323584,-2476416,621308
> 1666000610130900000,1666000610128324608,-2575392,621309
> 1666000610131000000,1666000610128325632,-2674368,621310
> 1666000610131100000,1666000610128326400,-2773600,621311
> 1666000610131200000,1666000610128327424,-2872576,621312
> 1666000610131300000,1666000610128328448,-2971552,621313
> 1666000610131400000,1666000610128329216,-3070784,621314
> 1666000610131500000,1666000610131500032,32,621315
> 1666000610131600000,1666000610131600128,128,621316
> 1666000610131700000,1666000610131700224,224,621317
> 
> After:
> 
> 1666073510646200000,1666073510646200064,64,2676462
> 1666073510646300000,1666073510646300160,160,2676463
> 1666073510646400000,1666073510646400256,256,2676464
> 1666073510646500000,1666073510646500096,96,2676465
> 1666073510646600000,1666073510646600192,192,2676466
> 1666073510646700000,1666073510646700032,32,2676467
> 1666073510646800000,1666073510646800128,128,2676468
> 1666073510646900000,1666073510646900224,224,2676469
> 1666073510647000000,1666073510647000064,64,2676470
> 1666073510647100000,1666073510647100160,160,2676471
> 1666073510647200000,1666073510647200256,256,2676472
> 1666073510647300000,1666073510647300096,96,2676473
> 1666073510647400000,1666073510647400192,192,2676474
> 1666073510647500000,1666073510647500032,32,2676475
> 1666073510647600000,1666073510647600128,128,2676476
> 1666073510647700000,1666073510647700224,224,2676477
> 1666073510647800000,1666073510647800064,64,2676478
> 1666073510647900000,1666073510647900160,160,2676479
> 1666073510648000000,1666073510648000000,0,2676480
> 1666073510648100000,1666073510648100096,96,2676481
> 1666073510648200000,1666073510648200192,192,2676482
> 1666073510648300000,1666073510648300032,32,2676483
> 1666073510648400000,1666073510648400128,128,2676484
> 1666073510648500000,1666073510648500224,224,2676485
> 1666073510648600000,1666073510648600064,64,2676486
> 1666073510648700000,1666073510648700160,160,2676487
> 1666073510648800000,1666073510648800000,0,2676488
> 1666073510648900000,1666073510648900096,96,2676489
> 1666073510649000000,1666073510649000192,192,2676490
> 1666073510649100000,1666073510649100032,32,2676491
> 1666073510649200000,1666073510649200128,128,2676492
> 1666073510649300000,1666073510649300224,224,2676493
> 1666073510649400000,1666073510649400064,64,2676494
> 1666073510649500000,1666073510649500160,160,2676495
> 1666073510649600000,1666073510649600000,0,2676496
> 1666073510649700000,1666073510649700096,96,2676497
> 1666073510649800000,1666073510649800192,192,2676498
> 1666073510649900000,1666073510649900032,32,2676499
> 1666073510650000000,1666073510650000128,128,2676500
> 
> Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
> Co-developed-by: Aravindhan Gunasekaran <aravindhan.gunasekaran@intel.com>
> Signed-off-by: Aravindhan Gunasekaran <aravindhan.gunasekaran@intel.com>
> Co-developed-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
> Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>
> Signed-off-by: Malli C <mallikarjuna.chilakala@intel.com>
> Signed-off-by: Muhammad Husaini Zulkifli <muhammad.husaini.zulkifli@intel.com>

Your sign off is on here twice

> ---
>   drivers/net/ethernet/intel/igc/igc.h         |   2 +
>   drivers/net/ethernet/intel/igc/igc_defines.h |   2 +
>   drivers/net/ethernet/intel/igc/igc_main.c    | 185 ++++++++++++++++---
>   3 files changed, 159 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
> index 1e7e7071f64d..66a57636d329 100644
> --- a/drivers/net/ethernet/intel/igc/igc.h
> +++ b/drivers/net/ethernet/intel/igc/igc.h
> @@ -94,6 +94,8 @@ struct igc_ring {
>   	u8 queue_index;                 /* logical index of the ring*/
>   	u8 reg_idx;                     /* physical index of the ring */
>   	bool launchtime_enable;         /* true if LaunchTime is enabled */
> +	ktime_t last_tx_cycle;          /* end of the cycle with a launchtime transmission */
> +	ktime_t last_ff_cycle;          /* Last cycle with an active first flag */
>   
>   	u32 start_time;
>   	u32 end_time;
> diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
> index f7311aeb293b..a7b22639cfcd 100644
> --- a/drivers/net/ethernet/intel/igc/igc_defines.h
> +++ b/drivers/net/ethernet/intel/igc/igc_defines.h
> @@ -321,6 +321,8 @@
>   #define IGC_ADVTXD_L4LEN_SHIFT	8  /* Adv ctxt L4LEN shift */
>   #define IGC_ADVTXD_MSS_SHIFT	16 /* Adv ctxt MSS shift */
>   
> +#define IGC_ADVTXD_TSN_CNTX_FIRST	0x00000080
> +
>   /* Transmit Control */
>   #define IGC_TCTL_EN		0x00000002 /* enable Tx */
>   #define IGC_TCTL_PSP		0x00000008 /* pad short packets */
> diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
> index 671255edf3c2..28cc395c6fff 100644
> --- a/drivers/net/ethernet/intel/igc/igc_main.c
> +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> @@ -1000,31 +1000,122 @@ static int igc_write_mc_addr_list(struct net_device *netdev)
>   	return netdev_mc_count(netdev);
>   }
>   
> -static __le32 igc_tx_launchtime(struct igc_adapter *adapter, ktime_t txtime)
> +static __le32 igc_tx_launchtime(struct igc_ring *ring, ktime_t txtime,
> +				bool *first_flag, bool *insert_empty)
>   {
> +	struct igc_adapter *adapter = netdev_priv(ring->netdev);
>   	ktime_t cycle_time = adapter->cycle_time;
>   	ktime_t base_time = adapter->base_time;
> -	u32 launchtime;
> +	ktime_t now = ktime_get_clocktai();
> +	ktime_t baset_est, end_of_cycle;
> +	s64 n;
>   
> -	/* FIXME: when using ETF together with taprio, we may have a
> -	 * case where 'delta' is larger than the cycle_time, this may
> -	 * cause problems if we don't read the current value of
> -	 * IGC_BASET, as the value writen into the launchtime
> -	 * descriptor field may be misinterpreted.
> +	n = div64_s64(ktime_sub_ns(now, base_time), cycle_time);
> +
> +	baset_est = ktime_add_ns(base_time, cycle_time * (n));
> +	end_of_cycle = ktime_add_ns(baset_est, cycle_time);
> +
> +	if (ktime_compare(txtime, end_of_cycle) >= 0) {
> +		if (baset_est != ring->last_ff_cycle) {
> +			*first_flag = true;
> +			ring->last_ff_cycle = baset_est;
> +
> +			if (ktime_compare(txtime, ring->last_tx_cycle) > 0)
> +				*insert_empty = true;
> +		}
> +	}
> +
> +	/* Introducing a window at end of cycle on which packets
> +	 * potentially not honor launchtime. Window of 5us chosen
> +	 * considering software update the tail pointer and packets
> +	 * are dma'ed to packet buffer.
>   	 */
> -	div_s64_rem(ktime_sub_ns(txtime, base_time), cycle_time, &launchtime);
> +	if ((ktime_sub_ns(end_of_cycle, now) < 5 * NSEC_PER_USEC)) {
> +		netdev_warn(ring->netdev, "Packet with txtime=%llu may not be honoured\n",
> +			    txtime);
> +	}

nit: These braces aren't needed

> +
> +	ring->last_tx_cycle = end_of_cycle;
> +
> +	txtime = ktime_sub_ns(txtime, baset_est);
> +	txtime = (txtime > 0 ? txtime % cycle_time : 0);

The parentheses as well I believe

> +
> +	return cpu_to_le32(txtime);
> +}
> +
> +static int igc_init_empty_frame(struct igc_ring *ring,
> +				struct igc_tx_buffer *buffer,
> +				struct sk_buff *skb)
> +{
> +	dma_addr_t dma;
> +	unsigned int size;

Please reorder to be RCT

> +
> +	size = skb_headlen(skb);
> +
> +	dma = dma_map_single(ring->dev, skb->data, size, DMA_TO_DEVICE);
> +	if (dma_mapping_error(ring->dev, dma)) {
> +		netdev_err_once(ring->netdev, "Failed to map DMA for TX\n");
> +		return -ENOMEM;
> +	}
> +
> +	buffer->skb = skb;
> +	buffer->protocol = 0;
> +	buffer->bytecount = skb->len;
> +	buffer->gso_segs = 1;
> +	buffer->time_stamp = jiffies;
> +	dma_unmap_len_set(buffer, len, skb->len);
> +	dma_unmap_addr_set(buffer, dma, dma);
> +
> +	return 0;
> +}
> +
> +static int 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;
>   
> -	return cpu_to_le32(launchtime);
> +	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 |
> +		   first->bytecount;
> +	olinfo_status = first->bytecount << IGC_ADVTXD_PAYLEN_SHIFT;
> +
> +	desc = IGC_TX_DESC(ring, ring->next_to_use);
> +	desc->read.cmd_type_len = cpu_to_le32(cmd_type);
> +	desc->read.olinfo_status = cpu_to_le32(olinfo_status);
> +	desc->read.buffer_addr = cpu_to_le64(dma_unmap_addr(first, dma));
> +
> +	netdev_tx_sent_queue(txring_txq(ring), skb->len);
> +
> +	first->next_to_watch = desc;
> +
> +	ring->next_to_use++;
> +	if (ring->next_to_use == ring->count)
> +		ring->next_to_use = 0;
> +
> +	return 0;
>   }
>   
> +#define IGC_EMPTY_FRAME_SIZE 60
> +
>   static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
> -			    struct igc_tx_buffer *first,
> +			    __le32 launch_time, bool first_flag,
>   			    u32 vlan_macip_lens, u32 type_tucmd,
>   			    u32 mss_l4len_idx)
>   {
>   	struct igc_adv_tx_context_desc *context_desc;
> -	u16 i = tx_ring->next_to_use;
> +	u16 i;
>   
> +	i = tx_ring->next_to_use;

What's the reason for this change?

>   	context_desc = IGC_TX_CTXTDESC(tx_ring, i);
>   
>   	i++;

>
Zulkifli, Muhammad Husaini Nov. 3, 2022, 12:52 a.m. UTC | #6
Hello,

Thanks for your review.

> -----Original Message-----
> From: Nguyen, Anthony L <anthony.l.nguyen@intel.com>
> Sent: Thursday, 3 November, 2022 5:28 AM
> To: Zulkifli, Muhammad Husaini <muhammad.husaini.zulkifli@intel.com>;
> intel-wired-lan@osuosl.org
> Cc: Chilakala, Mallikarjuna <mallikarjuna.chilakala@intel.com>
> Subject: Re: [Intel-wired-lan] [PATCH v1] igc: Qbv scheduling enchancement
> using frst flag bit
> 
> 
> 
> On 10/20/2022 7:53 AM, Muhammad Husaini Zulkifli wrote:
> > From: Vinicius Costa Gomes <vinicius.gomes@intel.com>
> >
> > The I225 hardware has a limitation that packets can only be scheduled
> > in the [0, cycle-time] interval. So, scheduling a packet to the start
> > of the next cycle doesn't usually work.
> >
> > To overcome this, we use the Transmit Descriptor frst flag to
> > indicates that a packet should be the first packet (from a queue) in a
> > cycle according to the section 7.5.2.9.3.4 The First Packet on Each
> > QBV Cycle in Intel Discrete I225/6 User Manual.
> >
> > But this only works if there was any packet from that queue during the
> > current cycle, to avoid this issue, we issue an empty packet if that's
> > not the case. Also require one more descriptor to be available, to
> > take into account the empty packet that might be issued.
> >
> > Test Setup:
> >
> > Talker: Use l2_tai to generate the launchtime into packet load.
> >
> > Listener: Use timedump.c to compute the delta between packet arrival
> > and LaunchTime packet payload.
> >
> > Test Result:
> >
> > Before:
> >
> > 1666000610127300000,1666000610127300096,96,621273
> > 1666000610127400000,1666000610127400192,192,621274
> > 1666000610127500000,1666000610127500032,32,621275
> > 1666000610127600000,1666000610127600128,128,621276
> > 1666000610127700000,1666000610127700224,224,621277
> > 1666000610127800000,1666000610127800064,64,621278
> > 1666000610127900000,1666000610127900160,160,621279
> > 1666000610128000000,1666000610128000000,0,621280
> > 1666000610128100000,1666000610128100096,96,621281
> > 1666000610128200000,1666000610128200192,192,621282
> > 1666000610128300000,1666000610128300032,32,621283
> > 1666000610128400000,1666000610128301056,-98944,621284
> > 1666000610128500000,1666000610128302080,-197920,621285
> > 1666000610128600000,1666000610128302848,-297152,621286
> > 1666000610128700000,1666000610128303872,-396128,621287
> > 1666000610128800000,1666000610128304896,-495104,621288
> > 1666000610128900000,1666000610128305664,-594336,621289
> > 1666000610129000000,1666000610128306688,-693312,621290
> > 1666000610129100000,1666000610128307712,-792288,621291
> > 1666000610129200000,1666000610128308480,-891520,621292
> > 1666000610129300000,1666000610128309504,-990496,621293
> > 1666000610129400000,1666000610128310528,-1089472,621294
> > 1666000610129500000,1666000610128311296,-1188704,621295
> > 1666000610129600000,1666000610128312320,-1287680,621296
> > 1666000610129700000,1666000610128313344,-1386656,621297
> > 1666000610129800000,1666000610128314112,-1485888,621298
> > 1666000610129900000,1666000610128315136,-1584864,621299
> > 1666000610130000000,1666000610128316160,-1683840,621300
> > 1666000610130100000,1666000610128316928,-1783072,621301
> > 1666000610130200000,1666000610128317952,-1882048,621302
> > 1666000610130300000,1666000610128318976,-1981024,621303
> > 1666000610130400000,1666000610128319744,-2080256,621304
> > 1666000610130500000,1666000610128320768,-2179232,621305
> > 1666000610130600000,1666000610128321792,-2278208,621306
> > 1666000610130700000,1666000610128322816,-2377184,621307
> > 1666000610130800000,1666000610128323584,-2476416,621308
> > 1666000610130900000,1666000610128324608,-2575392,621309
> > 1666000610131000000,1666000610128325632,-2674368,621310
> > 1666000610131100000,1666000610128326400,-2773600,621311
> > 1666000610131200000,1666000610128327424,-2872576,621312
> > 1666000610131300000,1666000610128328448,-2971552,621313
> > 1666000610131400000,1666000610128329216,-3070784,621314
> > 1666000610131500000,1666000610131500032,32,621315
> > 1666000610131600000,1666000610131600128,128,621316
> > 1666000610131700000,1666000610131700224,224,621317
> >
> > After:
> >
> > 1666073510646200000,1666073510646200064,64,2676462
> > 1666073510646300000,1666073510646300160,160,2676463
> > 1666073510646400000,1666073510646400256,256,2676464
> > 1666073510646500000,1666073510646500096,96,2676465
> > 1666073510646600000,1666073510646600192,192,2676466
> > 1666073510646700000,1666073510646700032,32,2676467
> > 1666073510646800000,1666073510646800128,128,2676468
> > 1666073510646900000,1666073510646900224,224,2676469
> > 1666073510647000000,1666073510647000064,64,2676470
> > 1666073510647100000,1666073510647100160,160,2676471
> > 1666073510647200000,1666073510647200256,256,2676472
> > 1666073510647300000,1666073510647300096,96,2676473
> > 1666073510647400000,1666073510647400192,192,2676474
> > 1666073510647500000,1666073510647500032,32,2676475
> > 1666073510647600000,1666073510647600128,128,2676476
> > 1666073510647700000,1666073510647700224,224,2676477
> > 1666073510647800000,1666073510647800064,64,2676478
> > 1666073510647900000,1666073510647900160,160,2676479
> > 1666073510648000000,1666073510648000000,0,2676480
> > 1666073510648100000,1666073510648100096,96,2676481
> > 1666073510648200000,1666073510648200192,192,2676482
> > 1666073510648300000,1666073510648300032,32,2676483
> > 1666073510648400000,1666073510648400128,128,2676484
> > 1666073510648500000,1666073510648500224,224,2676485
> > 1666073510648600000,1666073510648600064,64,2676486
> > 1666073510648700000,1666073510648700160,160,2676487
> > 1666073510648800000,1666073510648800000,0,2676488
> > 1666073510648900000,1666073510648900096,96,2676489
> > 1666073510649000000,1666073510649000192,192,2676490
> > 1666073510649100000,1666073510649100032,32,2676491
> > 1666073510649200000,1666073510649200128,128,2676492
> > 1666073510649300000,1666073510649300224,224,2676493
> > 1666073510649400000,1666073510649400064,64,2676494
> > 1666073510649500000,1666073510649500160,160,2676495
> > 1666073510649600000,1666073510649600000,0,2676496
> > 1666073510649700000,1666073510649700096,96,2676497
> > 1666073510649800000,1666073510649800192,192,2676498
> > 1666073510649900000,1666073510649900032,32,2676499
> > 1666073510650000000,1666073510650000128,128,2676500
> >
> > Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
> > Co-developed-by: Aravindhan Gunasekaran
> > <aravindhan.gunasekaran@intel.com>
> > Signed-off-by: Aravindhan Gunasekaran
> > <aravindhan.gunasekaran@intel.com>
> > Co-developed-by: Muhammad Husaini Zulkifli
> > <muhammad.husaini.zulkifli@intel.com>
> > Signed-off-by: Muhammad Husaini Zulkifli
> > <muhammad.husaini.zulkifli@intel.com>
> > Signed-off-by: Malli C <mallikarjuna.chilakala@intel.com>
> > Signed-off-by: Muhammad Husaini Zulkifli
> > <muhammad.husaini.zulkifli@intel.com>
> 
> Your sign off is on here twice

Yes you are right. I already fixed this in v2. 

> 
> > ---
> >   drivers/net/ethernet/intel/igc/igc.h         |   2 +
> >   drivers/net/ethernet/intel/igc/igc_defines.h |   2 +
> >   drivers/net/ethernet/intel/igc/igc_main.c    | 185 ++++++++++++++++---
> >   3 files changed, 159 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/intel/igc/igc.h
> > b/drivers/net/ethernet/intel/igc/igc.h
> > index 1e7e7071f64d..66a57636d329 100644
> > --- a/drivers/net/ethernet/intel/igc/igc.h
> > +++ b/drivers/net/ethernet/intel/igc/igc.h
> > @@ -94,6 +94,8 @@ struct igc_ring {
> >   	u8 queue_index;                 /* logical index of the ring*/
> >   	u8 reg_idx;                     /* physical index of the ring */
> >   	bool launchtime_enable;         /* true if LaunchTime is enabled */
> > +	ktime_t last_tx_cycle;          /* end of the cycle with a launchtime
> transmission */
> > +	ktime_t last_ff_cycle;          /* Last cycle with an active first flag */
> >
> >   	u32 start_time;
> >   	u32 end_time;
> > diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h
> > b/drivers/net/ethernet/intel/igc/igc_defines.h
> > index f7311aeb293b..a7b22639cfcd 100644
> > --- a/drivers/net/ethernet/intel/igc/igc_defines.h
> > +++ b/drivers/net/ethernet/intel/igc/igc_defines.h
> > @@ -321,6 +321,8 @@
> >   #define IGC_ADVTXD_L4LEN_SHIFT	8  /* Adv ctxt L4LEN shift */
> >   #define IGC_ADVTXD_MSS_SHIFT	16 /* Adv ctxt MSS shift */
> >
> > +#define IGC_ADVTXD_TSN_CNTX_FIRST	0x00000080
> > +
> >   /* Transmit Control */
> >   #define IGC_TCTL_EN		0x00000002 /* enable Tx */
> >   #define IGC_TCTL_PSP		0x00000008 /* pad short packets */
> > diff --git a/drivers/net/ethernet/intel/igc/igc_main.c
> > b/drivers/net/ethernet/intel/igc/igc_main.c
> > index 671255edf3c2..28cc395c6fff 100644
> > --- a/drivers/net/ethernet/intel/igc/igc_main.c
> > +++ b/drivers/net/ethernet/intel/igc/igc_main.c
> > @@ -1000,31 +1000,122 @@ static int igc_write_mc_addr_list(struct
> net_device *netdev)
> >   	return netdev_mc_count(netdev);
> >   }
> >
> > -static __le32 igc_tx_launchtime(struct igc_adapter *adapter, ktime_t
> > txtime)
> > +static __le32 igc_tx_launchtime(struct igc_ring *ring, ktime_t txtime,
> > +				bool *first_flag, bool *insert_empty)
> >   {
> > +	struct igc_adapter *adapter = netdev_priv(ring->netdev);
> >   	ktime_t cycle_time = adapter->cycle_time;
> >   	ktime_t base_time = adapter->base_time;
> > -	u32 launchtime;
> > +	ktime_t now = ktime_get_clocktai();
> > +	ktime_t baset_est, end_of_cycle;
> > +	s64 n;
> >
> > -	/* FIXME: when using ETF together with taprio, we may have a
> > -	 * case where 'delta' is larger than the cycle_time, this may
> > -	 * cause problems if we don't read the current value of
> > -	 * IGC_BASET, as the value writen into the launchtime
> > -	 * descriptor field may be misinterpreted.
> > +	n = div64_s64(ktime_sub_ns(now, base_time), cycle_time);
> > +
> > +	baset_est = ktime_add_ns(base_time, cycle_time * (n));
> > +	end_of_cycle = ktime_add_ns(baset_est, cycle_time);
> > +
> > +	if (ktime_compare(txtime, end_of_cycle) >= 0) {
> > +		if (baset_est != ring->last_ff_cycle) {
> > +			*first_flag = true;
> > +			ring->last_ff_cycle = baset_est;
> > +
> > +			if (ktime_compare(txtime, ring->last_tx_cycle) > 0)
> > +				*insert_empty = true;
> > +		}
> > +	}
> > +
> > +	/* Introducing a window at end of cycle on which packets
> > +	 * potentially not honor launchtime. Window of 5us chosen
> > +	 * considering software update the tail pointer and packets
> > +	 * are dma'ed to packet buffer.
> >   	 */
> > -	div_s64_rem(ktime_sub_ns(txtime, base_time), cycle_time,
> &launchtime);
> > +	if ((ktime_sub_ns(end_of_cycle, now) < 5 * NSEC_PER_USEC)) {
> > +		netdev_warn(ring->netdev, "Packet with txtime=%llu may not
> be honoured\n",
> > +			    txtime);
> > +	}
> 
> nit: These braces aren't needed

Sure. Will remove in v3.

> 
> > +
> > +	ring->last_tx_cycle = end_of_cycle;
> > +
> > +	txtime = ktime_sub_ns(txtime, baset_est);
> > +	txtime = (txtime > 0 ? txtime % cycle_time : 0);
> 
> The parentheses as well I believe

In v2, this code has been changed due to kernel robot report.

> 
> > +
> > +	return cpu_to_le32(txtime);
> > +}
> > +
> > +static int igc_init_empty_frame(struct igc_ring *ring,
> > +				struct igc_tx_buffer *buffer,
> > +				struct sk_buff *skb)
> > +{
> > +	dma_addr_t dma;
> > +	unsigned int size;
> 
> Please reorder to be RCT

Will do. Thanks

> 
> > +
> > +	size = skb_headlen(skb);
> > +
> > +	dma = dma_map_single(ring->dev, skb->data, size,
> DMA_TO_DEVICE);
> > +	if (dma_mapping_error(ring->dev, dma)) {
> > +		netdev_err_once(ring->netdev, "Failed to map DMA for
> TX\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	buffer->skb = skb;
> > +	buffer->protocol = 0;
> > +	buffer->bytecount = skb->len;
> > +	buffer->gso_segs = 1;
> > +	buffer->time_stamp = jiffies;
> > +	dma_unmap_len_set(buffer, len, skb->len);
> > +	dma_unmap_addr_set(buffer, dma, dma);
> > +
> > +	return 0;
> > +}
> > +
> > +static int 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;
> >
> > -	return cpu_to_le32(launchtime);
> > +	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 |
> > +		   first->bytecount;
> > +	olinfo_status = first->bytecount << IGC_ADVTXD_PAYLEN_SHIFT;
> > +
> > +	desc = IGC_TX_DESC(ring, ring->next_to_use);
> > +	desc->read.cmd_type_len = cpu_to_le32(cmd_type);
> > +	desc->read.olinfo_status = cpu_to_le32(olinfo_status);
> > +	desc->read.buffer_addr = cpu_to_le64(dma_unmap_addr(first,
> dma));
> > +
> > +	netdev_tx_sent_queue(txring_txq(ring), skb->len);
> > +
> > +	first->next_to_watch = desc;
> > +
> > +	ring->next_to_use++;
> > +	if (ring->next_to_use == ring->count)
> > +		ring->next_to_use = 0;
> > +
> > +	return 0;
> >   }
> >
> > +#define IGC_EMPTY_FRAME_SIZE 60
> > +
> >   static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
> > -			    struct igc_tx_buffer *first,
> > +			    __le32 launch_time, bool first_flag,
> >   			    u32 vlan_macip_lens, u32 type_tucmd,
> >   			    u32 mss_l4len_idx)
> >   {
> >   	struct igc_adv_tx_context_desc *context_desc;
> > -	u16 i = tx_ring->next_to_use;
> > +	u16 i;
> >
> > +	i = tx_ring->next_to_use;
> 
> What's the reason for this change?

Will revert back to previous in v3.

> 
> >   	context_desc = IGC_TX_CTXTDESC(tx_ring, i);
> >
> >   	i++;
> 
> >
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 1e7e7071f64d..66a57636d329 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -94,6 +94,8 @@  struct igc_ring {
 	u8 queue_index;                 /* logical index of the ring*/
 	u8 reg_idx;                     /* physical index of the ring */
 	bool launchtime_enable;         /* true if LaunchTime is enabled */
+	ktime_t last_tx_cycle;          /* end of the cycle with a launchtime transmission */
+	ktime_t last_ff_cycle;          /* Last cycle with an active first flag */
 
 	u32 start_time;
 	u32 end_time;
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index f7311aeb293b..a7b22639cfcd 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -321,6 +321,8 @@ 
 #define IGC_ADVTXD_L4LEN_SHIFT	8  /* Adv ctxt L4LEN shift */
 #define IGC_ADVTXD_MSS_SHIFT	16 /* Adv ctxt MSS shift */
 
+#define IGC_ADVTXD_TSN_CNTX_FIRST	0x00000080
+
 /* Transmit Control */
 #define IGC_TCTL_EN		0x00000002 /* enable Tx */
 #define IGC_TCTL_PSP		0x00000008 /* pad short packets */
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 671255edf3c2..28cc395c6fff 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1000,31 +1000,122 @@  static int igc_write_mc_addr_list(struct net_device *netdev)
 	return netdev_mc_count(netdev);
 }
 
-static __le32 igc_tx_launchtime(struct igc_adapter *adapter, ktime_t txtime)
+static __le32 igc_tx_launchtime(struct igc_ring *ring, ktime_t txtime,
+				bool *first_flag, bool *insert_empty)
 {
+	struct igc_adapter *adapter = netdev_priv(ring->netdev);
 	ktime_t cycle_time = adapter->cycle_time;
 	ktime_t base_time = adapter->base_time;
-	u32 launchtime;
+	ktime_t now = ktime_get_clocktai();
+	ktime_t baset_est, end_of_cycle;
+	s64 n;
 
-	/* FIXME: when using ETF together with taprio, we may have a
-	 * case where 'delta' is larger than the cycle_time, this may
-	 * cause problems if we don't read the current value of
-	 * IGC_BASET, as the value writen into the launchtime
-	 * descriptor field may be misinterpreted.
+	n = div64_s64(ktime_sub_ns(now, base_time), cycle_time);
+
+	baset_est = ktime_add_ns(base_time, cycle_time * (n));
+	end_of_cycle = ktime_add_ns(baset_est, cycle_time);
+
+	if (ktime_compare(txtime, end_of_cycle) >= 0) {
+		if (baset_est != ring->last_ff_cycle) {
+			*first_flag = true;
+			ring->last_ff_cycle = baset_est;
+
+			if (ktime_compare(txtime, ring->last_tx_cycle) > 0)
+				*insert_empty = true;
+		}
+	}
+
+	/* Introducing a window at end of cycle on which packets
+	 * potentially not honor launchtime. Window of 5us chosen
+	 * considering software update the tail pointer and packets
+	 * are dma'ed to packet buffer.
 	 */
-	div_s64_rem(ktime_sub_ns(txtime, base_time), cycle_time, &launchtime);
+	if ((ktime_sub_ns(end_of_cycle, now) < 5 * NSEC_PER_USEC)) {
+		netdev_warn(ring->netdev, "Packet with txtime=%llu may not be honoured\n",
+			    txtime);
+	}
+
+	ring->last_tx_cycle = end_of_cycle;
+
+	txtime = ktime_sub_ns(txtime, baset_est);
+	txtime = (txtime > 0 ? txtime % cycle_time : 0);
+
+	return cpu_to_le32(txtime);
+}
+
+static int igc_init_empty_frame(struct igc_ring *ring,
+				struct igc_tx_buffer *buffer,
+				struct sk_buff *skb)
+{
+	dma_addr_t dma;
+	unsigned int size;
+
+	size = skb_headlen(skb);
+
+	dma = dma_map_single(ring->dev, skb->data, size, DMA_TO_DEVICE);
+	if (dma_mapping_error(ring->dev, dma)) {
+		netdev_err_once(ring->netdev, "Failed to map DMA for TX\n");
+		return -ENOMEM;
+	}
+
+	buffer->skb = skb;
+	buffer->protocol = 0;
+	buffer->bytecount = skb->len;
+	buffer->gso_segs = 1;
+	buffer->time_stamp = jiffies;
+	dma_unmap_len_set(buffer, len, skb->len);
+	dma_unmap_addr_set(buffer, dma, dma);
+
+	return 0;
+}
+
+static int 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;
 
-	return cpu_to_le32(launchtime);
+	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 |
+		   first->bytecount;
+	olinfo_status = first->bytecount << IGC_ADVTXD_PAYLEN_SHIFT;
+
+	desc = IGC_TX_DESC(ring, ring->next_to_use);
+	desc->read.cmd_type_len = cpu_to_le32(cmd_type);
+	desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+	desc->read.buffer_addr = cpu_to_le64(dma_unmap_addr(first, dma));
+
+	netdev_tx_sent_queue(txring_txq(ring), skb->len);
+
+	first->next_to_watch = desc;
+
+	ring->next_to_use++;
+	if (ring->next_to_use == ring->count)
+		ring->next_to_use = 0;
+
+	return 0;
 }
 
+#define IGC_EMPTY_FRAME_SIZE 60
+
 static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
-			    struct igc_tx_buffer *first,
+			    __le32 launch_time, bool first_flag,
 			    u32 vlan_macip_lens, u32 type_tucmd,
 			    u32 mss_l4len_idx)
 {
 	struct igc_adv_tx_context_desc *context_desc;
-	u16 i = tx_ring->next_to_use;
+	u16 i;
 
+	i = tx_ring->next_to_use;
 	context_desc = IGC_TX_CTXTDESC(tx_ring, i);
 
 	i++;
@@ -1037,26 +1128,26 @@  static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,
 	if (test_bit(IGC_RING_FLAG_TX_CTX_IDX, &tx_ring->flags))
 		mss_l4len_idx |= tx_ring->reg_idx << 4;
 
+	if (first_flag)
+		mss_l4len_idx |= IGC_ADVTXD_TSN_CNTX_FIRST;
+
 	context_desc->vlan_macip_lens	= cpu_to_le32(vlan_macip_lens);
 	context_desc->type_tucmd_mlhl	= cpu_to_le32(type_tucmd);
 	context_desc->mss_l4len_idx	= cpu_to_le32(mss_l4len_idx);
+	context_desc->launch_time	= launch_time;
+}
 
-	/* We assume there is always a valid Tx time available. Invalid times
-	 * should have been handled by the upper layers.
-	 */
-	if (tx_ring->launchtime_enable) {
-		struct igc_adapter *adapter = netdev_priv(tx_ring->netdev);
-		ktime_t txtime = first->skb->tstamp;
+static inline bool igc_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+	unsigned int offset = 0;
 
-		skb_txtime_consumed(first->skb);
-		context_desc->launch_time = igc_tx_launchtime(adapter,
-							      txtime);
-	} else {
-		context_desc->launch_time = 0;
-	}
+	ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+	return offset == skb_checksum_start_offset(skb);
 }
 
-static void igc_tx_csum(struct igc_ring *tx_ring, struct igc_tx_buffer *first)
+static void igc_tx_csum(struct igc_ring *tx_ring, struct igc_tx_buffer *first,
+			__le32 launch_time, bool first_flag)
 {
 	struct sk_buff *skb = first->skb;
 	u32 vlan_macip_lens = 0;
@@ -1096,7 +1187,8 @@  static void igc_tx_csum(struct igc_ring *tx_ring, struct igc_tx_buffer *first)
 	vlan_macip_lens |= skb_network_offset(skb) << IGC_ADVTXD_MACLEN_SHIFT;
 	vlan_macip_lens |= first->tx_flags & IGC_TX_FLAGS_VLAN_MASK;
 
-	igc_tx_ctxtdesc(tx_ring, first, vlan_macip_lens, type_tucmd, 0);
+	igc_tx_ctxtdesc(tx_ring, launch_time, first_flag,
+			vlan_macip_lens, type_tucmd, 0);
 }
 
 static int __igc_maybe_stop_tx(struct igc_ring *tx_ring, const u16 size)
@@ -1320,6 +1412,7 @@  static int igc_tx_map(struct igc_ring *tx_ring,
 
 static int igc_tso(struct igc_ring *tx_ring,
 		   struct igc_tx_buffer *first,
+		   __le32 launch_time, bool first_flag,
 		   u8 *hdr_len)
 {
 	u32 vlan_macip_lens, type_tucmd, mss_l4len_idx;
@@ -1406,8 +1499,8 @@  static int igc_tso(struct igc_ring *tx_ring,
 	vlan_macip_lens |= (ip.hdr - skb->data) << IGC_ADVTXD_MACLEN_SHIFT;
 	vlan_macip_lens |= first->tx_flags & IGC_TX_FLAGS_VLAN_MASK;
 
-	igc_tx_ctxtdesc(tx_ring, first, vlan_macip_lens,
-			type_tucmd, mss_l4len_idx);
+	igc_tx_ctxtdesc(tx_ring, launch_time, first_flag,
+			vlan_macip_lens, type_tucmd, mss_l4len_idx);
 
 	return 1;
 }
@@ -1415,11 +1508,14 @@  static int igc_tso(struct igc_ring *tx_ring,
 static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
 				       struct igc_ring *tx_ring)
 {
+	bool first_flag = false, insert_empty = false;
 	u16 count = TXD_USE_COUNT(skb_headlen(skb));
 	__be16 protocol = vlan_get_protocol(skb);
 	struct igc_tx_buffer *first;
+	__le32 launch_time = 0;
 	u32 tx_flags = 0;
 	unsigned short f;
+	ktime_t txtime;
 	u8 hdr_len = 0;
 	int tso = 0;
 
@@ -1433,11 +1529,40 @@  static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
 		count += TXD_USE_COUNT(skb_frag_size(
 						&skb_shinfo(skb)->frags[f]));
 
-	if (igc_maybe_stop_tx(tx_ring, count + 3)) {
+	if (igc_maybe_stop_tx(tx_ring, count + 5)) {
 		/* this is a hard error */
 		return NETDEV_TX_BUSY;
 	}
 
+	if (!tx_ring->launchtime_enable)
+		goto done;
+
+	txtime = skb->tstamp;
+	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);
+	}
+
+done:
 	/* record the location of the first descriptor for this packet */
 	first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
 	first->type = IGC_TX_BUFFER_TYPE_SKB;
@@ -1474,11 +1599,11 @@  static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
 	first->tx_flags = tx_flags;
 	first->protocol = protocol;
 
-	tso = igc_tso(tx_ring, first, &hdr_len);
+	tso = igc_tso(tx_ring, first, launch_time, first_flag, &hdr_len);
 	if (tso < 0)
 		goto out_drop;
 	else if (!tso)
-		igc_tx_csum(tx_ring, first);
+		igc_tx_csum(tx_ring, first, launch_time, first_flag);
 
 	igc_tx_map(tx_ring, first, hdr_len);