@@ -31,8 +31,8 @@ avf_tx_desc_get_dtyp (avf_tx_desc_t * d)
3131}
3232
3333static_always_inline u16
34- avf_tx_enqueue (vlib_main_t * vm , avf_txq_t * txq , u32 * buffers ,
35- u32 n_packets , int use_va_dma )
34+ avf_tx_enqueue (vlib_main_t * vm , vlib_node_runtime_t * node , avf_txq_t * txq ,
35+ u32 * buffers , u32 n_packets , int use_va_dma )
3636{
3737 u16 next = txq -> next ;
3838 u64 bits = AVF_TXD_CMD_EOP | AVF_TXD_CMD_RSV ;
@@ -41,13 +41,16 @@ avf_tx_enqueue (vlib_main_t * vm, avf_txq_t * txq, u32 * buffers,
4141 u16 mask = txq -> size - 1 ;
4242 vlib_buffer_t * b [4 ];
4343 avf_tx_desc_t * d = txq -> descs + next ;
44+ u16 n_desc_needed ;
45+ vlib_buffer_t * b0 ;
4446
4547 /* avoid ring wrap */
4648 n_desc_left = txq -> size - clib_max (txq -> next , txq -> n_enqueued + 8 );
4749
4850 if (n_desc_left == 0 )
4951 return 0 ;
5052
53+ /* Fast path, no ring wrap */
5154 while (n_packets_left && n_desc_left )
5255 {
5356 u32 or_flags ;
@@ -103,6 +106,57 @@ avf_tx_enqueue (vlib_main_t * vm, avf_txq_t * txq, u32 * buffers,
103106 txq -> bufs [next ] = buffers [0 ];
104107 b [0 ] = vlib_get_buffer (vm , buffers [0 ]);
105108
109+ /* Deal with chain buffer if present */
110+ if (b [0 ]-> flags & VLIB_BUFFER_NEXT_PRESENT )
111+ {
112+ n_desc_needed = 1 ;
113+ b0 = b [0 ];
114+
115+ /* Wish there were a buffer count for chain buffer */
116+ while (b0 -> flags & VLIB_BUFFER_NEXT_PRESENT )
117+ {
118+ b0 = vlib_get_buffer (vm , b0 -> next_buffer );
119+ n_desc_needed ++ ;
120+ }
121+
122+ /* spec says data descriptor is limited to 8 segments */
123+ if (PREDICT_FALSE (n_desc_needed > 8 ))
124+ {
125+ vlib_buffer_free_one (vm , buffers [0 ]);
126+ vlib_error_count (vm , node -> node_index ,
127+ AVF_TX_ERROR_SEGMENT_SIZE_EXCEEDED , 1 );
128+ n_packets_left -= 1 ;
129+ buffers += 1 ;
130+ continue ;
131+ }
132+
133+ if (PREDICT_FALSE (n_desc_left < n_desc_needed ))
134+ /*
135+ * Slow path may be able to to deal with this since it can handle
136+ * ring wrap
137+ */
138+ break ;
139+
140+ while (b [0 ]-> flags & VLIB_BUFFER_NEXT_PRESENT )
141+ {
142+ if (use_va_dma )
143+ d [0 ].qword [0 ] = vlib_buffer_get_current_va (b [0 ]);
144+ else
145+ d [0 ].qword [0 ] = vlib_buffer_get_current_pa (vm , b [0 ]);
146+
147+ d [0 ].qword [1 ] = (((u64 ) b [0 ]-> current_length ) << 34 ) |
148+ AVF_TXD_CMD_RSV ;
149+
150+ next += 1 ;
151+ n_desc += 1 ;
152+ n_desc_left -= 1 ;
153+ d += 1 ;
154+
155+ txq -> bufs [next ] = b [0 ]-> next_buffer ;
156+ b [0 ] = vlib_get_buffer (vm , b [0 ]-> next_buffer );
157+ }
158+ }
159+
106160 if (use_va_dma )
107161 d [0 ].qword [0 ] = vlib_buffer_get_current_va (b [0 ]);
108162 else
@@ -118,6 +172,84 @@ avf_tx_enqueue (vlib_main_t * vm, avf_txq_t * txq, u32 * buffers,
118172 d += 1 ;
119173 }
120174
175+ /* Slow path to support ring wrap */
176+ if (PREDICT_FALSE (n_packets_left ))
177+ {
178+ txq -> n_enqueued += n_desc ;
179+
180+ n_desc = 0 ;
181+ d = txq -> descs + (next & mask );
182+
183+ /* +8 to be consistent with fast path */
184+ n_desc_left = txq -> size - (txq -> n_enqueued + 8 );
185+
186+ while (n_packets_left && n_desc_left )
187+ {
188+ txq -> bufs [next & mask ] = buffers [0 ];
189+ b [0 ] = vlib_get_buffer (vm , buffers [0 ]);
190+
191+ /* Deal with chain buffer if present */
192+ if (b [0 ]-> flags & VLIB_BUFFER_NEXT_PRESENT )
193+ {
194+ n_desc_needed = 1 ;
195+ b0 = b [0 ];
196+
197+ while (b0 -> flags & VLIB_BUFFER_NEXT_PRESENT )
198+ {
199+ b0 = vlib_get_buffer (vm , b0 -> next_buffer );
200+ n_desc_needed ++ ;
201+ }
202+
203+ /* Spec says data descriptor is limited to 8 segments */
204+ if (PREDICT_FALSE (n_desc_needed > 8 ))
205+ {
206+ vlib_buffer_free_one (vm , buffers [0 ]);
207+ vlib_error_count (vm , node -> node_index ,
208+ AVF_TX_ERROR_SEGMENT_SIZE_EXCEEDED , 1 );
209+ n_packets_left -= 1 ;
210+ buffers += 1 ;
211+ continue ;
212+ }
213+
214+ if (PREDICT_FALSE (n_desc_left < n_desc_needed ))
215+ break ;
216+
217+ while (b [0 ]-> flags & VLIB_BUFFER_NEXT_PRESENT )
218+ {
219+ if (use_va_dma )
220+ d [0 ].qword [0 ] = vlib_buffer_get_current_va (b [0 ]);
221+ else
222+ d [0 ].qword [0 ] = vlib_buffer_get_current_pa (vm , b [0 ]);
223+
224+ d [0 ].qword [1 ] = (((u64 ) b [0 ]-> current_length ) << 34 ) |
225+ AVF_TXD_CMD_RSV ;
226+
227+ next += 1 ;
228+ n_desc += 1 ;
229+ n_desc_left -= 1 ;
230+ d = txq -> descs + (next & mask );
231+
232+ txq -> bufs [next & mask ] = b [0 ]-> next_buffer ;
233+ b [0 ] = vlib_get_buffer (vm , b [0 ]-> next_buffer );
234+ }
235+ }
236+
237+ if (use_va_dma )
238+ d [0 ].qword [0 ] = vlib_buffer_get_current_va (b [0 ]);
239+ else
240+ d [0 ].qword [0 ] = vlib_buffer_get_current_pa (vm , b [0 ]);
241+
242+ d [0 ].qword [1 ] = (((u64 ) b [0 ]-> current_length ) << 34 ) | bits ;
243+
244+ next += 1 ;
245+ n_desc += 1 ;
246+ buffers += 1 ;
247+ n_packets_left -= 1 ;
248+ n_desc_left -= 1 ;
249+ d = txq -> descs + (next & mask );
250+ }
251+ }
252+
121253 if ((slot = clib_ring_enq (txq -> rs_slots )))
122254 {
123255 u16 rs_slot = slot [0 ] = (next - 1 ) & mask ;
@@ -177,15 +309,15 @@ VNET_DEVICE_CLASS_TX_FN (avf_device_class) (vlib_main_t * vm,
177309 n_free = (complete_slot + 1 - first ) & mask ;
178310
179311 txq -> n_enqueued -= n_free ;
180- vlib_buffer_free_from_ring (vm , txq -> bufs , first , txq -> size ,
181- n_free );
312+ vlib_buffer_free_from_ring_no_next (vm , txq -> bufs , first , txq -> size ,
313+ n_free );
182314 }
183315 }
184316
185317 if (ad -> flags & AVF_DEVICE_F_VA_DMA )
186- n_enq = avf_tx_enqueue (vm , txq , buffers , n_left , 1 );
318+ n_enq = avf_tx_enqueue (vm , node , txq , buffers , n_left , 1 );
187319 else
188- n_enq = avf_tx_enqueue (vm , txq , buffers , n_left , 0 );
320+ n_enq = avf_tx_enqueue (vm , node , txq , buffers , n_left , 0 );
189321
190322 n_left -= n_enq ;
191323
0 commit comments