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