Skip to content

Commit f7ab7b2

Browse files
sluong99Dave Barach
authored andcommitted
avf: Handle chain buffer in TX properly
For chain buffer, need to traverse b->next_buffer to transmit all buffers in the chain. Only set EOP at the last descriptor in the chain to signal this is a chain descriptor. Introduce slow path to handle ring wrap. This is needed because chain buffer may consist of multiple pieces and it may span from near the end of the ring to the beginning of the ring. Type: fix Signed-off-by: Steven Luong <[email protected]> Change-Id: Id7c872f3e39e09f3566aa63f3cdba8f40736d508
1 parent 2da3971 commit f7ab7b2

File tree

2 files changed

+140
-7
lines changed

2 files changed

+140
-7
lines changed

src/plugins/avf/avf.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ typedef struct
333333
} avf_input_trace_t;
334334

335335
#define foreach_avf_tx_func_error \
336-
_(NO_FREE_SLOTS, "no free tx slots")
336+
_(SEGMENT_SIZE_EXCEEDED, "segment size exceeded") \
337+
_(NO_FREE_SLOTS, "no free tx slots")
337338

338339
typedef enum
339340
{

src/plugins/avf/output.c

Lines changed: 138 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ avf_tx_desc_get_dtyp (avf_tx_desc_t * d)
3131
}
3232

3333
static_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

Comments
 (0)