On Thu, Feb 06, 2025 at 02:04:08PM +0800, Song Yoong Siang wrote: > Enable Launch Time Control (LTC) support for XDP zero copy via XDP Tx > metadata framework. > > This patch has been tested with tools/testing/selftests/bpf/xdp_hw_metadata > on Intel I225-LM Ethernet controller. Below are the test steps and result. > > Test 1: Send a single packet with the launch time set to 1 s in the future. > > Test steps: > 1. On the DUT, start the xdp_hw_metadata selftest application: > $ sudo ./xdp_hw_metadata enp2s0 -l 1000000000 -L 1 > > 2. On the Link Partner, send a UDP packet with VLAN priority 1 to port 9091 > of the DUT. > > Result: > When the launch time is set to 1 s in the future, the delta between the > launch time and the transmit hardware timestamp is 0.016 us, as shown in > printout of the xdp_hw_metadata application below. > 0x562ff5dc8880: rx_desc[4]->addr=84110 addr=84110 comp_addr=84110 EoP > rx_hash: 0xE343384 with RSS type:0x1 > HW RX-time: 1734578015467548904 (sec:1734578015.4675) > delta to User RX-time sec:0.0002 (183.103 usec) > XDP RX-time: 1734578015467651698 (sec:1734578015.4677) > delta to User RX-time sec:0.0001 (80.309 usec) > No rx_vlan_tci or rx_vlan_proto, err=-95 > 0x562ff5dc8880: ping-pong with csum=561c (want c7dd) > csum_start=34 csum_offset=6 > HW RX-time: 1734578015467548904 (sec:1734578015.4675) > delta to HW Launch-time sec:1.0000 (1000000.000 usec) > 0x562ff5dc8880: complete tx idx=4 addr=4018 > HW Launch-time: 1734578016467548904 (sec:1734578016.4675) > delta to HW TX-complete-time sec:0.0000 (0.016 usec) > HW TX-complete-time: 1734578016467548920 (sec:1734578016.4675) > delta to User TX-complete-time sec:0.0000 > (32.546 usec) > XDP RX-time: 1734578015467651698 (sec:1734578015.4677) > delta to User TX-complete-time sec:0.9999 > (999929.768 usec) > HW RX-time: 1734578015467548904 (sec:1734578015.4675) > delta to HW TX-complete-time sec:1.0000 (1000000.016 usec) > 0x562ff5dc8880: complete rx idx=132 addr=84110 > > Test 2: Send 1000 packets with a 10 ms interval and the launch time set to > 500 us in the future. > > Test steps: > 1. On the DUT, start the xdp_hw_metadata selftest application: > $ sudo chrt -f 99 ./xdp_hw_metadata enp2s0 -l 500000 -L 1 > \ > /dev/shm/result.log > > 2. On the Link Partner, send 1000 UDP packets with a 10 ms interval and > VLAN priority 1 to port 9091 of the DUT. > > Result: > When the launch time is set to 500 us in the future, the average delta > between the launch time and the transmit hardware timestamp is 0.016 us, > as shown in the analysis of /dev/shm/result.log below. The XDP launch time > works correctly in sending 1000 packets continuously. > Min delta: 0.005 us > Avr delta: 0.016 us > Max delta: 0.031 us > Total packets forwarded: 1000 > > Signed-off-by: Song Yoong Siang <yoong.siang.song@xxxxxxxxx> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@xxxxxxxxx> also with one nit. Thanks! > --- > drivers/net/ethernet/intel/igc/igc.h | 1 + > drivers/net/ethernet/intel/igc/igc_main.c | 57 ++++++++++++++++++++++- > 2 files changed, 56 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h > index b8111ad9a9a8..cd1d7b6c1782 100644 > --- a/drivers/net/ethernet/intel/igc/igc.h > +++ b/drivers/net/ethernet/intel/igc/igc.h > @@ -579,6 +579,7 @@ struct igc_metadata_request { > struct xsk_tx_metadata *meta; > struct igc_ring *tx_ring; > u32 cmd_type; > + u16 used_desc; > }; > > struct igc_q_vector { > diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c > index 3df608601a4b..f239f744247d 100644 > --- a/drivers/net/ethernet/intel/igc/igc_main.c > +++ b/drivers/net/ethernet/intel/igc/igc_main.c > @@ -2973,9 +2973,44 @@ static u64 igc_xsk_fill_timestamp(void *_priv) > return *(u64 *)_priv; > } > > +static void igc_xsk_request_launch_time(u64 launch_time, void *_priv) > +{ > + struct igc_metadata_request *meta_req = _priv; > + struct igc_ring *tx_ring = meta_req->tx_ring; > + __le32 launch_time_offset; > + bool insert_empty = false; > + bool first_flag = false; > + > + if (!tx_ring->launchtime_enable) > + return; > + > + launch_time_offset = igc_tx_launchtime(tx_ring, > + ns_to_ktime(launch_time), > + &first_flag, &insert_empty); > + if (insert_empty) { > + /* Disregard the launch time request if the required empty frame > + * fails to be inserted. > + */ > + if (igc_insert_empty_frame(tx_ring)) > + return; > + > + meta_req->tx_buffer = > + &tx_ring->tx_buffer_info[tx_ring->next_to_use]; > + /* Inserting an empty packet requires two descriptors: > + * one data descriptor and one context descriptor. > + */ > + meta_req->used_desc += 2; tiny nit: you could accumulate the amount of used descs in local variable and update the igc_metadata_request::used_desc once. > + } > + > + /* Use one context descriptor to specify launch time and first flag. */ > + igc_tx_ctxtdesc(tx_ring, launch_time_offset, first_flag, 0, 0, 0); > + meta_req->used_desc += 1; > +} > + > const struct xsk_tx_metadata_ops igc_xsk_tx_metadata_ops = { > .tmo_request_timestamp = igc_xsk_request_timestamp, > .tmo_fill_timestamp = igc_xsk_fill_timestamp, > + .tmo_request_launch_time = igc_xsk_request_launch_time, > }; > > static void igc_xdp_xmit_zc(struct igc_ring *ring) > @@ -2998,7 +3033,13 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring) > ntu = ring->next_to_use; > budget = igc_desc_unused(ring); > > - while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) { > + /* Packets with launch time require one data descriptor and one context > + * descriptor. When the launch time falls into the next Qbv cycle, we > + * may need to insert an empty packet, which requires two more > + * descriptors. Therefore, to be safe, we always ensure we have at least > + * 4 descriptors available. > + */ > + while (xsk_tx_peek_desc(pool, &xdp_desc) && budget >= 4) { > struct igc_metadata_request meta_req; > struct xsk_tx_metadata *meta = NULL; > struct igc_tx_buffer *bi; > @@ -3019,9 +3060,19 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring) > meta_req.tx_ring = ring; > meta_req.tx_buffer = bi; > meta_req.meta = meta; > + meta_req.used_desc = 0; > xsk_tx_metadata_request(meta, &igc_xsk_tx_metadata_ops, > &meta_req); > > + /* xsk_tx_metadata_request() may have updated next_to_use */ > + ntu = ring->next_to_use; > + > + /* xsk_tx_metadata_request() may have updated Tx buffer info */ > + bi = meta_req.tx_buffer; > + > + /* xsk_tx_metadata_request() may use a few descriptors */ > + budget -= meta_req.used_desc; > + > tx_desc = IGC_TX_DESC(ring, ntu); > tx_desc->read.cmd_type_len = cpu_to_le32(meta_req.cmd_type); > tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); > @@ -3039,9 +3090,11 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring) > ntu++; > if (ntu == ring->count) > ntu = 0; > + > + ring->next_to_use = ntu; > + budget--; > } > > - ring->next_to_use = ntu; > if (tx_desc) { > igc_flush_tx_descriptors(ring); > xsk_tx_release(pool); > -- > 2.34.1 >