dev: move bus code to bus/
[vpp.git] / src / plugins / dev_octeon / rx_node.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #include <vlib/vlib.h>
6 #include <vnet/dev/dev.h>
7 #include <vnet/ethernet/ethernet.h>
8 #include <dev_octeon/octeon.h>
9 #include <dev_octeon/hw_defs.h>
10
11 typedef struct
12 {
13   u32 next_index;
14   u32 sw_if_index;
15   u32 hw_if_index;
16   u32 trace_count;
17   u32 n_traced;
18   oct_nix_rx_cqe_desc_t *next_desc;
19   u64 parse_w0_or;
20   u32 n_left_to_next;
21   u32 *to_next;
22   u32 n_rx_pkts;
23   u32 n_rx_bytes;
24   u32 n_segs;
25 } oct_rx_node_ctx_t;
26
27 static_always_inline vlib_buffer_t *
28 oct_seg_to_bp (void *p)
29 {
30   return (vlib_buffer_t *) p - 1;
31 }
32
33 static_always_inline void
34 oct_rx_attach_tail (vlib_main_t *vm, oct_rx_node_ctx_t *ctx, vlib_buffer_t *h,
35                     oct_nix_rx_cqe_desc_t *d)
36 {
37   u32 tail_sz = 0, n_tail_segs = 0;
38   vlib_buffer_t *p, *b;
39   u8 segs0 = d->sg0.segs, segs1 = 0;
40
41   if (segs0 < 2)
42     return;
43
44   b = oct_seg_to_bp (d->segs0[1]);
45   h->next_buffer = vlib_get_buffer_index (vm, b);
46   tail_sz += b->current_length = d->sg0.seg2_size;
47   n_tail_segs++;
48
49   if (segs0 == 2)
50     goto done;
51
52   p = b;
53   p->flags = VLIB_BUFFER_NEXT_PRESENT;
54   b = oct_seg_to_bp (d->segs0[2]);
55   p->next_buffer = vlib_get_buffer_index (vm, b);
56   tail_sz += b->current_length = d->sg0.seg3_size;
57   n_tail_segs++;
58
59   if (d->sg1.subdc != NIX_SUBDC_SG)
60     goto done;
61
62   segs1 = d->sg1.segs;
63   if (segs1 == 0)
64     goto done;
65
66   p = b;
67   p->flags = VLIB_BUFFER_NEXT_PRESENT;
68   b = oct_seg_to_bp (d->segs1[0]);
69   p->next_buffer = vlib_get_buffer_index (vm, b);
70   tail_sz += b->current_length = d->sg1.seg1_size;
71   n_tail_segs++;
72
73   if (segs1 == 1)
74     goto done;
75
76   p = b;
77   p->flags = VLIB_BUFFER_NEXT_PRESENT;
78   b = oct_seg_to_bp (d->segs1[1]);
79   p->next_buffer = vlib_get_buffer_index (vm, b);
80   tail_sz += b->current_length = d->sg1.seg2_size;
81   n_tail_segs++;
82
83   if (segs1 == 2)
84     goto done;
85
86   p = b;
87   p->flags = VLIB_BUFFER_NEXT_PRESENT;
88   b = oct_seg_to_bp (d->segs1[2]);
89   p->next_buffer = vlib_get_buffer_index (vm, b);
90   tail_sz += b->current_length = d->sg1.seg3_size;
91   n_tail_segs++;
92
93 done:
94   b->flags = 0;
95   h->total_length_not_including_first_buffer = tail_sz;
96   h->flags |= VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
97   ctx->n_rx_bytes += tail_sz;
98   ctx->n_segs += n_tail_segs;
99 }
100
101 static_always_inline u32
102 oct_rx_batch (vlib_main_t *vm, oct_rx_node_ctx_t *ctx,
103               vnet_dev_rx_queue_t *rxq, u32 n)
104 {
105   oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq);
106   vlib_buffer_template_t bt = rxq->buffer_template;
107   u32 n_left;
108   oct_nix_rx_cqe_desc_t *d = ctx->next_desc;
109   vlib_buffer_t *b[4];
110
111   for (n_left = n; n_left >= 8; d += 4, n_left -= 4, ctx->to_next += 4)
112     {
113       u32 segs = 0;
114       clib_prefetch_store (oct_seg_to_bp (d[4].segs0[0]));
115       clib_prefetch_store (oct_seg_to_bp (d[5].segs0[0]));
116       b[0] = oct_seg_to_bp (d[0].segs0[0]);
117       clib_prefetch_store (oct_seg_to_bp (d[6].segs0[0]));
118       b[1] = oct_seg_to_bp (d[1].segs0[0]);
119       clib_prefetch_store (oct_seg_to_bp (d[7].segs0[0]));
120       b[2] = oct_seg_to_bp (d[2].segs0[0]);
121       b[3] = oct_seg_to_bp (d[3].segs0[0]);
122       ctx->to_next[0] = vlib_get_buffer_index (vm, b[0]);
123       ctx->to_next[1] = vlib_get_buffer_index (vm, b[1]);
124       ctx->to_next[2] = vlib_get_buffer_index (vm, b[2]);
125       ctx->to_next[3] = vlib_get_buffer_index (vm, b[3]);
126       b[0]->template = bt;
127       b[1]->template = bt;
128       b[2]->template = bt;
129       b[3]->template = bt;
130       ctx->n_rx_bytes += b[0]->current_length = d[0].sg0.seg1_size;
131       ctx->n_rx_bytes += b[1]->current_length = d[1].sg0.seg1_size;
132       ctx->n_rx_bytes += b[2]->current_length = d[2].sg0.seg1_size;
133       ctx->n_rx_bytes += b[3]->current_length = d[3].sg0.seg1_size;
134       b[0]->flow_id = d[0].parse.w[3] >> 48;
135       b[1]->flow_id = d[1].parse.w[3] >> 48;
136       b[2]->flow_id = d[2].parse.w[3] >> 48;
137       b[3]->flow_id = d[3].parse.w[3] >> 48;
138       ctx->n_segs += 4;
139       segs = d[0].sg0.segs + d[1].sg0.segs + d[2].sg0.segs + d[3].sg0.segs;
140
141       if (PREDICT_FALSE (segs > 4))
142         {
143           oct_rx_attach_tail (vm, ctx, b[0], d + 0);
144           oct_rx_attach_tail (vm, ctx, b[1], d + 1);
145           oct_rx_attach_tail (vm, ctx, b[2], d + 2);
146           oct_rx_attach_tail (vm, ctx, b[3], d + 3);
147         }
148     }
149
150   for (; n_left; d += 1, n_left -= 1, ctx->to_next += 1)
151     {
152       b[0] = (vlib_buffer_t *) d->segs0[0] - 1;
153       ctx->to_next[0] = vlib_get_buffer_index (vm, b[0]);
154       b[0]->template = bt;
155       ctx->n_rx_bytes += b[0]->current_length = d[0].sg0.seg1_size;
156       b[0]->flow_id = d[0].parse.w[3] >> 48;
157       ctx->n_segs += 1;
158       if (d[0].sg0.segs > 1)
159         oct_rx_attach_tail (vm, ctx, b[0], d + 0);
160     }
161
162   plt_write64 ((crq->cq.wdata | n), crq->cq.door);
163   ctx->n_rx_pkts += n;
164   ctx->n_left_to_next -= n;
165   return n;
166 }
167
168 #ifdef PLATFORM_OCTEON9
169 static_always_inline u32
170 oct_rxq_refill (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq, u16 n_refill)
171 {
172   u32 n_alloc, n_free;
173   u32 buffer_indices[n_refill];
174   vlib_buffer_t *buffers[n_refill];
175   u8 bpi = vnet_dev_get_rx_queue_buffer_pool_index (rxq);
176   oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq);
177   u64 aura = roc_npa_aura_handle_to_aura (crq->aura_handle);
178   const uint64_t addr =
179     roc_npa_aura_handle_to_base (crq->aura_handle) + NPA_LF_AURA_OP_FREE0;
180
181   if (n_refill < 256)
182     return 0;
183
184   n_alloc = vlib_buffer_alloc (vm, buffer_indices, n_refill);
185   if (PREDICT_FALSE (n_alloc < n_refill))
186     goto alloc_fail;
187
188   vlib_get_buffers (vm, buffer_indices, (vlib_buffer_t **) buffers, n_alloc);
189
190   for (n_free = 0; n_free < n_alloc; n_free++)
191     roc_store_pair ((u64) buffers[n_free], aura, addr);
192
193   return n_alloc;
194
195 alloc_fail:
196   vlib_buffer_unalloc_to_pool (vm, buffer_indices, n_alloc, bpi);
197   return 0;
198 }
199 #else
200 static_always_inline void
201 oct_rxq_refill_batch (vlib_main_t *vm, u64 lmt_id, u64 addr,
202                       oct_npa_lf_aura_batch_free_line_t *lines, u32 *bi,
203                       oct_npa_lf_aura_batch_free0_t w0, u64 n_lines)
204 {
205   u64 data;
206
207   for (u32 i = 0; i < n_lines; i++, bi += 15)
208     {
209       lines[i].w0 = w0;
210       vlib_get_buffers (vm, bi, (vlib_buffer_t **) lines[i].data, 15);
211     }
212
213   data = lmt_id | ((n_lines - 1) << 12) | ((1ULL << (n_lines * 3)) - 1) << 19;
214   roc_lmt_submit_steorl (data, addr);
215
216   /* Data Store Memory Barrier - outer shareable domain */
217   asm volatile("dmb oshst" ::: "memory");
218 }
219
220 static_always_inline u32
221 oct_rxq_refill (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq, u16 n_refill)
222 {
223   const u32 batch_max_lines = 16;
224   const u32 bufs_per_line = 15;
225   const u32 batch_max_bufs = 15 * 16;
226
227   u32 batch_bufs, n_lines, n_alloc;
228   u32 buffer_indices[batch_max_bufs];
229   u64 lmt_addr, lmt_id, addr, n_enq = 0;
230   u8 bpi = vnet_dev_get_rx_queue_buffer_pool_index (rxq);
231   oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq);
232   oct_npa_lf_aura_batch_free_line_t *lines;
233
234   if (n_refill < bufs_per_line)
235     return 0;
236
237   n_lines = n_refill / bufs_per_line;
238
239   addr = crq->aura_batch_free_ioaddr;
240   lmt_addr = crq->lmt_base_addr;
241   lmt_id = vm->thread_index << ROC_LMT_LINES_PER_CORE_LOG2;
242   lmt_addr += lmt_id << ROC_LMT_LINE_SIZE_LOG2;
243   lines = (oct_npa_lf_aura_batch_free_line_t *) lmt_addr;
244
245   oct_npa_lf_aura_batch_free0_t w0 = {
246     .aura = roc_npa_aura_handle_to_aura (crq->aura_handle),
247     .count_eot = 1,
248   };
249
250   while (n_lines >= batch_max_lines)
251     {
252       n_alloc =
253         vlib_buffer_alloc_from_pool (vm, buffer_indices, batch_max_bufs, bpi);
254       if (PREDICT_FALSE (n_alloc < batch_max_bufs))
255         goto alloc_fail;
256       oct_rxq_refill_batch (vm, lmt_id, addr, lines, buffer_indices, w0,
257                             batch_max_lines);
258       n_lines -= batch_max_lines;
259       n_enq += batch_max_bufs;
260     }
261
262   if (n_lines == 0)
263     return n_enq;
264
265   batch_bufs = n_lines * bufs_per_line;
266   n_alloc = vlib_buffer_alloc_from_pool (vm, buffer_indices, batch_bufs, bpi);
267
268   if (PREDICT_FALSE (n_alloc < batch_bufs))
269     {
270     alloc_fail:
271       if (n_alloc >= bufs_per_line)
272         {
273           u32 n_unalloc;
274           n_lines = n_alloc / bufs_per_line;
275           batch_bufs = n_lines * bufs_per_line;
276           n_unalloc = n_alloc - batch_bufs;
277
278           if (n_unalloc)
279             vlib_buffer_unalloc_to_pool (vm, buffer_indices + batch_bufs,
280                                          n_unalloc, bpi);
281         }
282       else
283         {
284           if (n_alloc)
285             vlib_buffer_unalloc_to_pool (vm, buffer_indices, n_alloc, bpi);
286           return n_enq;
287         }
288     }
289
290   oct_rxq_refill_batch (vm, lmt_id, addr, lines, buffer_indices, w0, n_lines);
291   n_enq += batch_bufs;
292
293   return n_enq;
294 }
295 #endif
296
297 static_always_inline void
298 oct_rx_trace (vlib_main_t *vm, vlib_node_runtime_t *node,
299               oct_rx_node_ctx_t *ctx, oct_nix_rx_cqe_desc_t *d, u32 n_desc)
300 {
301   u32 i = 0;
302   if (PREDICT_TRUE (ctx->trace_count == 0))
303     return;
304
305   while (ctx->n_traced < ctx->trace_count && i < n_desc)
306     {
307       vlib_buffer_t *b = (vlib_buffer_t *) d[i].segs0[0] - 1;
308
309       if (PREDICT_TRUE (vlib_trace_buffer (vm, node, ctx->next_index, b,
310                                            /* follow_chain */ 0)))
311         {
312           oct_rx_trace_t *tr = vlib_add_trace (vm, node, b, sizeof (*tr));
313           tr->next_index = ctx->next_index;
314           tr->sw_if_index = ctx->sw_if_index;
315           tr->desc = d[i];
316           ctx->n_traced++;
317         }
318       i++;
319     }
320 }
321
322 static_always_inline uword
323 oct_rx_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
324                     vlib_frame_t *frame, vnet_dev_port_t *port,
325                     vnet_dev_rx_queue_t *rxq, int with_flows)
326 {
327   vnet_main_t *vnm = vnet_get_main ();
328   u32 thr_idx = vlib_get_thread_index ();
329   oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq);
330   u32 n_desc, head, n, n_enq;
331   u32 cq_size = crq->cq.nb_desc;
332   u32 cq_mask = crq->cq.qmask;
333   oct_nix_rx_cqe_desc_t *descs = crq->cq.desc_base;
334   oct_nix_lf_cq_op_status_t status;
335   oct_rx_node_ctx_t _ctx = {
336     .next_index = rxq->next_index,
337     .sw_if_index = port->intf.sw_if_index,
338     .hw_if_index = port->intf.hw_if_index,
339   }, *ctx = &_ctx;
340
341   /* get head and tail from NIX_LF_CQ_OP_STATUS */
342   status.as_u64 = roc_atomic64_add_sync (crq->cq.wdata, crq->cq.status);
343   if (status.cq_err || status.op_err)
344     return 0;
345
346   head = status.head;
347   n_desc = (status.tail - head) & cq_mask;
348
349   if (n_desc == 0)
350     goto refill;
351
352   vlib_get_new_next_frame (vm, node, ctx->next_index, ctx->to_next,
353                            ctx->n_left_to_next);
354
355   ctx->trace_count = vlib_get_trace_count (vm, node);
356
357   while (1)
358     {
359       ctx->next_desc = descs + head;
360       n = clib_min (cq_size - head, clib_min (n_desc, ctx->n_left_to_next));
361       n = oct_rx_batch (vm, ctx, rxq, n);
362       oct_rx_trace (vm, node, ctx, descs + head, n);
363
364       if (ctx->n_left_to_next == 0)
365         break;
366
367       status.as_u64 = roc_atomic64_add_sync (crq->cq.wdata, crq->cq.status);
368       if (status.cq_err || status.op_err)
369         break;
370
371       head = status.head;
372       n_desc = (status.tail - head) & cq_mask;
373       if (n_desc == 0)
374         break;
375     }
376
377   if (ctx->n_traced)
378     vlib_set_trace_count (vm, node, ctx->trace_count - ctx->n_traced);
379
380   if (PREDICT_TRUE (ctx->next_index == VNET_DEV_ETH_RX_PORT_NEXT_ETH_INPUT))
381     {
382       vlib_next_frame_t *nf;
383       vlib_frame_t *f;
384       ethernet_input_frame_t *ef;
385       oct_nix_rx_parse_t p = { .w[0] = ctx->parse_w0_or };
386       nf = vlib_node_runtime_get_next_frame (vm, node, ctx->next_index);
387       f = vlib_get_frame (vm, nf->frame);
388       f->flags = ETH_INPUT_FRAME_F_SINGLE_SW_IF_IDX;
389
390       ef = vlib_frame_scalar_args (f);
391       ef->sw_if_index = ctx->sw_if_index;
392       ef->hw_if_index = ctx->hw_if_index;
393
394       if (p.f.errcode == 0 && p.f.errlev == 0)
395         f->flags |= ETH_INPUT_FRAME_F_IP4_CKSUM_OK;
396
397       vlib_frame_no_append (f);
398     }
399
400   vlib_put_next_frame (vm, node, ctx->next_index, ctx->n_left_to_next);
401
402   vlib_increment_combined_counter (
403     vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
404     thr_idx, ctx->hw_if_index, ctx->n_rx_pkts, ctx->n_rx_bytes);
405
406 refill:
407   n_enq = crq->n_enq - ctx->n_segs;
408   n_enq += oct_rxq_refill (vm, rxq, rxq->size - n_enq);
409   crq->n_enq = n_enq;
410
411   return ctx->n_rx_pkts;
412 }
413
414 VNET_DEV_NODE_FN (oct_rx_node)
415 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
416 {
417   u32 n_rx = 0;
418   foreach_vnet_dev_rx_queue_runtime (rxq, node)
419     {
420       vnet_dev_port_t *port = rxq->port;
421       n_rx += oct_rx_node_inline (vm, node, frame, port, rxq, 0);
422     }
423
424   return n_rx;
425 }