octeon: add flow offload infra
[vpp.git] / src / plugins / dev_octeon / port.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #include <vnet/vnet.h>
6 #include <vnet/dev/dev.h>
7 #include <vnet/dev/pci.h>
8 #include <vnet/dev/counters.h>
9 #include <dev_octeon/octeon.h>
10 #include <dev_octeon/common.h>
11 #include <vnet/ethernet/ethernet.h>
12
13 #define OCT_FLOW_PREALLOC_SIZE 1
14 #define OCT_FLOW_MAX_PRIORITY  7
15
16 VLIB_REGISTER_LOG_CLASS (oct_log, static) = {
17   .class_name = "octeon",
18   .subclass_name = "port",
19 };
20
21 static const u8 default_rss_key[] = {
22   0xfe, 0xed, 0x0b, 0xad, 0xfe, 0xed, 0x0b, 0xad, 0xad, 0x0b, 0xed, 0xfe,
23   0xad, 0x0b, 0xed, 0xfe, 0x13, 0x57, 0x9b, 0xef, 0x24, 0x68, 0xac, 0x0e,
24   0x91, 0x72, 0x53, 0x11, 0x82, 0x64, 0x20, 0x44, 0x12, 0xef, 0x34, 0xcd,
25   0x56, 0xbc, 0x78, 0x9a, 0x9a, 0x78, 0xbc, 0x56, 0xcd, 0x34, 0xef, 0x12
26 };
27
28 static const u32 default_rss_flowkey =
29   (FLOW_KEY_TYPE_IPV4 | FLOW_KEY_TYPE_IPV6 | FLOW_KEY_TYPE_TCP |
30    FLOW_KEY_TYPE_UDP | FLOW_KEY_TYPE_SCTP);
31
32 static const u64 rxq_cfg =
33   ROC_NIX_LF_RX_CFG_DIS_APAD | ROC_NIX_LF_RX_CFG_IP6_UDP_OPT |
34   ROC_NIX_LF_RX_CFG_L2_LEN_ERR | ROC_NIX_LF_RX_CFG_DROP_RE |
35   ROC_NIX_LF_RX_CFG_CSUM_OL4 | ROC_NIX_LF_RX_CFG_CSUM_IL4 |
36   ROC_NIX_LF_RX_CFG_LEN_OL3 | ROC_NIX_LF_RX_CFG_LEN_OL4 |
37   ROC_NIX_LF_RX_CFG_LEN_IL3 | ROC_NIX_LF_RX_CFG_LEN_IL4;
38
39 static vnet_dev_rv_t
40 oct_roc_err (vnet_dev_t *dev, int rv, char *fmt, ...)
41 {
42   u8 *s = 0;
43   va_list va;
44
45   va_start (va, fmt);
46   s = va_format (s, fmt, &va);
47   va_end (va);
48
49   log_err (dev, "%v - ROC error %s (%d)", s, roc_error_msg_get (rv), rv);
50
51   vec_free (s);
52   return VNET_DEV_ERR_INTERNAL;
53 }
54
55 vnet_dev_rv_t
56 oct_port_init (vlib_main_t *vm, vnet_dev_port_t *port)
57 {
58   vnet_dev_t *dev = port->dev;
59   oct_device_t *cd = vnet_dev_get_data (dev);
60   oct_port_t *cp = vnet_dev_get_port_data (port);
61   struct roc_nix *nix = cd->nix;
62   vnet_dev_rv_t rv;
63   int rrv;
64
65   log_debug (dev, "port init: port %u", port->port_id);
66
67   if ((rrv = roc_nix_lf_alloc (nix, port->intf.num_rx_queues,
68                                port->intf.num_tx_queues, rxq_cfg)))
69     {
70       oct_port_deinit (vm, port);
71       return oct_roc_err (
72         dev, rrv,
73         "roc_nix_lf_alloc(nb_rxq = %u, nb_txq = %d, rxq_cfg=0x%lx) failed",
74         port->intf.num_rx_queues, port->intf.num_tx_queues, rxq_cfg);
75     }
76   cp->lf_allocated = 1;
77
78   if ((rrv = roc_nix_tm_init (nix)))
79     {
80       oct_port_deinit (vm, port);
81       return oct_roc_err (dev, rrv, "roc_nix_tm_init() failed");
82     }
83   cp->tm_initialized = 1;
84
85   if ((rrv = roc_nix_tm_hierarchy_enable (nix, ROC_NIX_TM_DEFAULT,
86                                           /* xmit_enable */ 0)))
87     {
88       oct_port_deinit (vm, port);
89       return oct_roc_err (dev, rrv, "roc_nix_tm_hierarchy_enable() failed");
90     }
91
92   if ((rrv = roc_nix_rss_default_setup (nix, default_rss_flowkey)))
93     {
94       oct_port_deinit (vm, port);
95       return oct_roc_err (dev, rrv, "roc_nix_rss_default_setup() failed");
96     }
97
98   roc_nix_rss_key_set (nix, default_rss_key);
99
100   cp->npc.roc_nix = nix;
101   cp->npc.flow_prealloc_size = OCT_FLOW_PREALLOC_SIZE;
102   cp->npc.flow_max_priority = OCT_FLOW_MAX_PRIORITY;
103   if ((rrv = roc_npc_init (&cp->npc)))
104     {
105       oct_port_deinit (vm, port);
106       return oct_roc_err (dev, rrv, "roc_npc_init() failed");
107     }
108   cp->npc_initialized = 1;
109
110   foreach_vnet_dev_port_rx_queue (q, port)
111     if (q->enabled)
112       if ((rv = oct_rxq_init (vm, q)))
113         {
114           oct_port_deinit (vm, port);
115           return rv;
116         }
117
118   foreach_vnet_dev_port_tx_queue (q, port)
119     if (q->enabled)
120       if ((rv = oct_txq_init (vm, q)))
121         {
122           oct_port_deinit (vm, port);
123           return rv;
124         }
125
126   return VNET_DEV_OK;
127 }
128
129 void
130 oct_port_deinit (vlib_main_t *vm, vnet_dev_port_t *port)
131 {
132   vnet_dev_t *dev = port->dev;
133   oct_device_t *cd = vnet_dev_get_data (dev);
134   oct_port_t *cp = vnet_dev_get_port_data (port);
135   struct roc_nix *nix = cd->nix;
136   int rrv;
137
138   foreach_vnet_dev_port_rx_queue (q, port)
139     oct_rxq_deinit (vm, q);
140   foreach_vnet_dev_port_tx_queue (q, port)
141     oct_txq_deinit (vm, q);
142
143   if (cp->npc_initialized)
144     {
145       if ((rrv = roc_npc_fini (&cp->npc)))
146         oct_roc_err (dev, rrv, "roc_npc_fini() failed");
147       cp->npc_initialized = 0;
148     }
149
150   if (cp->tm_initialized)
151     {
152       roc_nix_tm_fini (nix);
153       cp->tm_initialized = 0;
154     }
155
156   if (cp->lf_allocated)
157     {
158       if ((rrv = roc_nix_lf_free (nix)))
159         oct_roc_err (dev, rrv, "roc_nix_lf_free() failed");
160       cp->lf_allocated = 0;
161     }
162 }
163
164 void
165 oct_port_poll (vlib_main_t *vm, vnet_dev_port_t *port)
166 {
167   vnet_dev_t *dev = port->dev;
168   oct_device_t *cd = vnet_dev_get_data (dev);
169   struct roc_nix *nix = cd->nix;
170   struct roc_nix_link_info link_info = {};
171   vnet_dev_port_state_changes_t changes = {};
172   int rrv;
173
174   rrv = roc_nix_mac_link_info_get (nix, &link_info);
175   if (rrv)
176     return;
177
178   if (cd->status != link_info.status)
179     {
180       changes.change.link_state = 1;
181       changes.link_state = link_info.status;
182       cd->status = link_info.status;
183     }
184
185   if (cd->full_duplex != link_info.full_duplex)
186     {
187       changes.change.link_duplex = 1;
188       changes.full_duplex = link_info.full_duplex;
189       cd->full_duplex = link_info.full_duplex;
190     }
191
192   if (cd->speed != link_info.speed)
193     {
194       changes.change.link_speed = 1;
195       changes.link_speed = link_info.speed;
196       cd->speed = link_info.speed;
197     }
198
199   if (changes.change.any == 0)
200     return;
201
202   log_debug (dev,
203              "status %u full_duplex %u speed %u port %u lmac_type_id %u "
204              "fec %u aautoneg %u",
205              link_info.status, link_info.full_duplex, link_info.speed,
206              link_info.port, link_info.lmac_type_id, link_info.fec,
207              link_info.autoneg);
208   vnet_dev_port_state_change (vm, port, changes);
209 }
210
211 vnet_dev_rv_t
212 oct_rxq_start (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
213 {
214   vnet_dev_t *dev = rxq->port->dev;
215   oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq);
216   u32 buffer_indices[rxq->size], n_alloc;
217   u8 bpi = vnet_dev_get_rx_queue_buffer_pool_index (rxq);
218   int rrv;
219
220   n_alloc = vlib_buffer_alloc_from_pool (vm, buffer_indices, rxq->size, bpi);
221
222   for (int i = 0; i < n_alloc; i++)
223     roc_npa_aura_op_free (
224       crq->aura_handle, 0,
225       pointer_to_uword (vlib_get_buffer (vm, buffer_indices[i])) -
226         crq->hdr_off);
227
228   crq->n_enq = n_alloc;
229
230   if (roc_npa_aura_op_available (crq->aura_handle) != rxq->size)
231     log_warn (rxq->port->dev, "rx queue %u aura not filled completelly",
232               rxq->queue_id);
233
234   if ((rrv = roc_nix_rq_ena_dis (&crq->rq, 1)))
235     return oct_roc_err (dev, rrv, "roc_nix_rq_ena_dis() failed");
236
237   return VNET_DEV_OK;
238 }
239 void
240 oct_rxq_stop (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq)
241 {
242   vnet_dev_t *dev = rxq->port->dev;
243   oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq);
244   int rrv;
245   u32 n;
246
247   if ((rrv = roc_nix_rq_ena_dis (&crq->rq, 0)))
248     oct_roc_err (dev, rrv, "roc_nix_rq_ena_dis() failed");
249
250   n = oct_aura_free_all_buffers (vm, crq->aura_handle, crq->hdr_off);
251
252   if (crq->n_enq - n > 0)
253     log_err (dev, "%u buffers leaked on rx queue %u stop", crq->n_enq - n,
254              rxq->queue_id);
255   else
256     log_debug (dev, "%u buffers freed from rx queue %u", n, rxq->queue_id);
257
258   crq->n_enq = 0;
259 }
260
261 void
262 oct_txq_stop (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
263 {
264   vnet_dev_t *dev = txq->port->dev;
265   oct_txq_t *ctq = vnet_dev_get_tx_queue_data (txq);
266   oct_npa_batch_alloc_cl128_t *cl;
267   u32 n, off = ctq->hdr_off;
268
269   n = oct_aura_free_all_buffers (vm, ctq->aura_handle, off);
270   ctq->n_enq -= n;
271
272   if (ctq->n_enq > 0 && ctq->ba_num_cl > 0)
273     for (n = ctq->ba_num_cl, cl = ctq->ba_buffer + ctq->ba_first_cl; n;
274          cl++, n--)
275       {
276         if (cl->status.ccode != 0)
277           for (u32 i = 0; i < cl->status.count; i++)
278             {
279               vlib_buffer_t *b = (vlib_buffer_t *) (cl->iova[i] + off);
280               vlib_buffer_free_one (vm, vlib_get_buffer_index (vm, b));
281               ctq->n_enq--;
282             }
283       }
284
285   if (ctq->n_enq > 0)
286     log_err (dev, "%u buffers leaked on tx queue %u stop", ctq->n_enq,
287              txq->queue_id);
288   else
289     log_debug (dev, "%u buffers freed from tx queue %u", n, txq->queue_id);
290
291   ctq->n_enq = 0;
292 }
293
294 vnet_dev_rv_t
295 oct_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
296 {
297   vnet_dev_t *dev = port->dev;
298   oct_device_t *cd = vnet_dev_get_data (dev);
299   struct roc_nix *nix = cd->nix;
300   struct roc_nix_eeprom_info eeprom_info = {};
301   vnet_dev_rv_t rv;
302   int rrv;
303
304   log_debug (port->dev, "port start: port %u", port->port_id);
305
306   foreach_vnet_dev_port_rx_queue (q, port)
307     if ((rv = oct_rxq_start (vm, q)) != VNET_DEV_OK)
308       goto done;
309
310   foreach_vnet_dev_port_tx_queue (q, port)
311     {
312       oct_txq_t *ctq = vnet_dev_get_tx_queue_data (q);
313       ctq->n_enq = 0;
314     }
315
316   if ((rrv = roc_nix_mac_mtu_set (nix, 9200)))
317     {
318       rv = oct_roc_err (dev, rrv, "roc_nix_mac_mtu_set() failed");
319       goto done;
320     }
321
322   if ((rrv = roc_nix_npc_rx_ena_dis (nix, true)))
323     {
324       rv = oct_roc_err (dev, rrv, "roc_nix_npc_rx_ena_dis() failed");
325       goto done;
326     }
327
328   vnet_dev_poll_port_add (vm, port, 0.5, oct_port_poll);
329
330   if (roc_nix_eeprom_info_get (nix, &eeprom_info) == 0)
331     {
332       log_debug (dev, "sff_id %u data %U", eeprom_info.sff_id, format_hexdump,
333                  eeprom_info.buf, sizeof (eeprom_info.buf));
334     }
335 done:
336   if (rv != VNET_DEV_OK)
337     oct_port_stop (vm, port);
338   return VNET_DEV_OK;
339 }
340
341 void
342 oct_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
343 {
344   vnet_dev_t *dev = port->dev;
345   oct_device_t *cd = vnet_dev_get_data (dev);
346   struct roc_nix *nix = cd->nix;
347   int rrv;
348
349   log_debug (port->dev, "port stop: port %u", port->port_id);
350
351   vnet_dev_poll_port_remove (vm, port, oct_port_poll);
352
353   rrv = roc_nix_npc_rx_ena_dis (nix, false);
354   if (rrv)
355     {
356       oct_roc_err (dev, rrv, "roc_nix_npc_rx_ena_dis() failed");
357       return;
358     }
359
360   foreach_vnet_dev_port_rx_queue (q, port)
361     oct_rxq_stop (vm, q);
362
363   foreach_vnet_dev_port_tx_queue (q, port)
364     oct_txq_stop (vm, q);
365 }
366
367 vnet_dev_rv_t
368 oct_port_cfg_change_validate (vlib_main_t *vm, vnet_dev_port_t *port,
369                               vnet_dev_port_cfg_change_req_t *req)
370 {
371   vnet_dev_rv_t rv = VNET_DEV_OK;
372
373   switch (req->type)
374     {
375     case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
376       if (port->started)
377         rv = VNET_DEV_ERR_PORT_STARTED;
378       break;
379
380     case VNET_DEV_PORT_CFG_PROMISC_MODE:
381     case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
382     case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
383     case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
384       break;
385
386     case VNET_DEV_PORT_CFG_ADD_RX_FLOW:
387     case VNET_DEV_PORT_CFG_DEL_RX_FLOW:
388     case VNET_DEV_PORT_CFG_GET_RX_FLOW_COUNTER:
389     case VNET_DEV_PORT_CFG_RESET_RX_FLOW_COUNTER:
390       rv = oct_flow_validate_params (vm, port, req->type, req->flow_index,
391                                      req->private_data);
392       break;
393
394     default:
395       rv = VNET_DEV_ERR_NOT_SUPPORTED;
396     };
397
398   return rv;
399 }
400
401 vnet_dev_rv_t
402 oct_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
403                      vnet_dev_port_cfg_change_req_t *req)
404 {
405   vnet_dev_rv_t rv = VNET_DEV_OK;
406
407   switch (req->type)
408     {
409     case VNET_DEV_PORT_CFG_PROMISC_MODE:
410       break;
411
412     case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
413       break;
414
415     case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
416       break;
417
418     case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
419       break;
420
421     case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
422       break;
423
424     case VNET_DEV_PORT_CFG_ADD_RX_FLOW:
425     case VNET_DEV_PORT_CFG_DEL_RX_FLOW:
426     case VNET_DEV_PORT_CFG_GET_RX_FLOW_COUNTER:
427     case VNET_DEV_PORT_CFG_RESET_RX_FLOW_COUNTER:
428       rv = oct_flow_ops_fn (vm, port, req->type, req->flow_index,
429                             req->private_data);
430
431       break;
432
433     default:
434       return VNET_DEV_ERR_NOT_SUPPORTED;
435     };
436
437   return rv;
438 }