marvell: bump musdk version to 18.09.3
[vpp.git] / src / plugins / marvell / pp2 / pp2.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22
23 #include <vlib/vlib.h>
24 #include <vlib/unix/unix.h>
25 #include <vppinfra/linux/syscall.h>
26 #include <vnet/plugin/plugin.h>
27 #include <marvell/pp2/pp2.h>
28
29 /* size of DMA memory used by musdk (not used for buffers) */
30 #define MV_SYS_DMA_MEM_SZ               (2 << 20)
31 /* number of HIFs reserved (first X) */
32 #define NUM_HIFS_RSVD                   4
33 /* number of buffer pools reserved (first X) */
34 #define NUM_BPOOLS_RSVD                 7
35
36 mrvl_pp2_main_t mrvl_pp2_main;
37 extern vnet_device_class_t ppa2_device_class;
38
39 static void
40 mrvl_pp2_main_deinit ()
41 {
42   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
43   int i;
44   vec_foreach_index (i, ppm->per_thread_data)
45   {
46     mrvl_pp2_per_thread_data_t *ptd = vec_elt_at_index (ppm->per_thread_data,
47                                                         i);
48     if (ptd->hif)
49       pp2_hif_deinit (ptd->hif);
50     vec_free (ptd->descs);
51   }
52   vec_free (ppm->per_thread_data);
53   pp2_deinit ();
54   mv_sys_dma_mem_destroy ();
55 }
56
57 static clib_error_t *
58 mrvl_pp2_main_init ()
59 {
60   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
61   vlib_thread_main_t *tm = vlib_get_thread_main ();
62   clib_error_t *err = 0;
63   struct pp2_init_params init_params = { 0 };
64   int i, rv;
65   u8 *s = 0;
66
67   rv = mv_sys_dma_mem_init (MV_SYS_DMA_MEM_SZ);
68   if (rv)
69     return clib_error_return (0, "mv_sys_dma_mem_init failed, rv = %u", rv);
70
71   init_params.hif_reserved_map = ((1 << NUM_HIFS_RSVD) - 1);
72   init_params.bm_pool_reserved_map = ((1 << NUM_BPOOLS_RSVD) - 1);
73   rv = pp2_init (&init_params);
74   if (rv)
75     {
76       err = clib_error_return (0, "mrvl_pp2_init failed, rv = %u", rv);
77       goto done;
78     }
79
80   vec_validate_aligned (ppm->per_thread_data, tm->n_vlib_mains - 1,
81                         CLIB_CACHE_LINE_BYTES);
82
83   vec_foreach_index (i, ppm->per_thread_data)
84   {
85     mrvl_pp2_per_thread_data_t *ptd = vec_elt_at_index (ppm->per_thread_data,
86                                                         i);
87     struct pp2_hif_params hif_params = { 0 };
88     vec_reset_length (s);
89     s = format (s, "hif-%d%c", NUM_HIFS_RSVD + i, 0);
90     hif_params.match = (char *) s;
91     hif_params.out_size = 2048; /* FIXME */
92     if (pp2_hif_init (&hif_params, &ptd->hif))
93       {
94         err = clib_error_return (0, "hif '%s' init failed", s);
95         goto done;
96       }
97   }
98
99 done:
100   if (err)
101     mrvl_pp2_main_deinit ();
102   vec_free (s);
103   return err;
104 }
105
106 static u32
107 mrvl_pp2_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
108                           u32 flags)
109 {
110   /* nothing for now */
111   return 0;
112 }
113
114 void
115 mrvl_pp2_delete_if (mrvl_pp2_if_t * ppif)
116 {
117   vlib_main_t *vm = vlib_get_main ();
118   vnet_main_t *vnm = vnet_get_main ();
119   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
120   mrvl_pp2_outq_t *outq;
121   mrvl_pp2_inq_t *inq;
122   int i;
123
124   if (ppif->hw_if_index != ~0)
125     {
126       vec_foreach_index (i, ppif->inqs)
127         vnet_hw_interface_unassign_rx_thread (vnm, ppif->hw_if_index, i);
128       ethernet_delete_interface (vnm, ppif->hw_if_index);
129     }
130
131   if (ppif->ppio)
132     {
133       pp2_ppio_disable (ppif->ppio);
134       pp2_ppio_deinit (ppif->ppio);
135     }
136
137   /* *INDENT-OFF* */
138   /* free buffers hanging in the tx ring */
139   vec_foreach (outq, ppif->outqs)
140     {
141       while (outq->tail < outq->head)
142         {
143           u16 slot = outq->tail & (outq->size - 1);
144           vlib_buffer_free (vm, outq->buffers + slot, 1);
145           outq->tail++;
146         }
147       vec_free (outq->buffers);
148     }
149   vec_free (ppif->outqs);
150
151   /* free buffers hangin in the rx buffer pool */
152   vec_foreach (inq, ppif->inqs)
153     if (inq->bpool)
154       {
155         u32 n_bufs = 0;
156         pp2_bpool_get_num_buffs (inq->bpool, &n_bufs);
157         while (n_bufs--)
158           {
159             struct pp2_buff_inf binf;
160             if (pp2_bpool_get_buff (ppm->per_thread_data[0].hif, inq->bpool,
161                                     &binf) == 0)
162               {
163                  u32 bi = binf.cookie;
164                  vlib_buffer_free (vm, &bi, 1);
165               }
166           }
167         pp2_bpool_deinit (inq->bpool);
168       }
169   vec_free (ppif->inqs);
170   /* *INDENT-ON* */
171
172
173   pool_put (ppm->interfaces, ppif);
174
175   if (pool_elts (ppm->interfaces) == 0)
176     mrvl_pp2_main_deinit ();
177 }
178
179 void
180 mrvl_pp2_create_if (mrvl_pp2_create_if_args_t * args)
181 {
182   vnet_main_t *vnm = vnet_get_main ();
183   vlib_thread_main_t *tm = vlib_get_thread_main ();
184   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
185   struct pp2_bpool_params bpool_params = { 0 };
186   struct pp2_ppio_params ppio_params = { 0 };
187   struct pp2_ppio_inq_params inq_params = { 0 };
188   vnet_sw_interface_t *sw;
189   mrvl_pp2_if_t *ppif = 0;
190   u8 pp2_id, port_id, *s = 0;
191   eth_addr_t mac_addr;
192   u8 n_outqs, n_inqs = 1;
193   int i;
194
195   if (tm->n_vlib_mains > PP2_PPIO_MAX_NUM_OUTQS)
196     {
197       args->rv = VNET_API_ERROR_INIT_FAILED;
198       args->error = clib_error_return (0, "number of threads (main + workers)"
199                                        " is bigger than number of output "
200                                        "queues (%u)", PP2_PPIO_MAX_NUM_OUTQS);
201       return;
202     }
203   n_outqs = tm->n_vlib_mains;
204
205   /* defaults */
206   args->tx_q_sz = args->tx_q_sz ? args->tx_q_sz : 2 * VLIB_FRAME_SIZE;
207   args->rx_q_sz = args->rx_q_sz ? args->rx_q_sz : 2 * VLIB_FRAME_SIZE;
208
209   if (vec_len (ppm->per_thread_data) == 0)
210     {
211       if ((args->error = mrvl_pp2_main_init ()) != 0)
212         {
213           args->rv = VNET_API_ERROR_INIT_FAILED;
214           return;
215         }
216     }
217
218   pool_get_zero (ppm->interfaces, ppif);
219   ppif->dev_instance = ppif - ppm->interfaces;
220   ppif->hw_if_index = ~0;
221   vec_validate_aligned (ppif->inqs, n_inqs - 1, CLIB_CACHE_LINE_BYTES);
222   vec_validate_aligned (ppif->outqs, n_outqs - 1, CLIB_CACHE_LINE_BYTES);
223
224   for (i = 0; i < n_inqs; i++)
225     {
226       mrvl_pp2_inq_t *inq = vec_elt_at_index (ppif->inqs, i);
227       inq->size = args->rx_q_sz;
228     }
229   for (i = 0; i < n_outqs; i++)
230     {
231       mrvl_pp2_outq_t *outq = vec_elt_at_index (ppif->outqs, i);
232       outq->size = args->tx_q_sz;
233       vec_validate_aligned (outq->buffers, outq->size, CLIB_CACHE_LINE_BYTES);
234     }
235
236   if (pp2_netdev_get_ppio_info ((char *) args->name, &pp2_id, &port_id))
237     {
238       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
239       args->error = clib_error_return (0, "Invalid interface '%s'",
240                                        args->name);
241       goto error;
242     }
243
244   /* FIXME bpool bit select per pp */
245   s = format (s, "pool-%d:%d%c", pp2_id, pp2_id + 8, 0);
246   bpool_params.match = (char *) s;
247   bpool_params.buff_len = VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES;
248   /* FIXME +64 ? */
249   if (pp2_bpool_init (&bpool_params, &ppif->inqs[0].bpool))
250     {
251       args->rv = VNET_API_ERROR_INIT_FAILED;
252       args->error = clib_error_return (0, "bpool '%s' init failed", s);
253       goto error;
254     }
255   vec_reset_length (s);
256
257   s = format (s, "ppio-%d:%d%c", pp2_id, port_id, 0);
258   ppio_params.match = (char *) s;
259   ppio_params.type = PP2_PPIO_T_NIC;
260   inq_params.size = args->rx_q_sz;
261   ppio_params.inqs_params.num_tcs = 1;
262   ppio_params.inqs_params.tcs_params[0].pkt_offset = 0;
263   ppio_params.inqs_params.tcs_params[0].num_in_qs = n_inqs;
264   ppio_params.inqs_params.tcs_params[0].inqs_params = &inq_params;
265   ppio_params.inqs_params.tcs_params[0].pools[0][0] = ppif->inqs[0].bpool;
266   ppio_params.outqs_params.num_outqs = n_outqs;
267   for (i = 0; i < n_outqs; i++)
268     {
269       ppio_params.outqs_params.outqs_params[i].weight = 1;
270       ppio_params.outqs_params.outqs_params[i].size = args->tx_q_sz;
271     }
272   if (pp2_ppio_init (&ppio_params, &ppif->ppio))
273     {
274       args->rv = VNET_API_ERROR_INIT_FAILED;
275       args->error = clib_error_return (0, "ppio '%s' init failed", s);
276       goto error;
277     }
278   vec_reset_length (s);
279
280   if (pp2_ppio_get_mac_addr (ppif->ppio, mac_addr))
281     {
282       args->rv = VNET_API_ERROR_INIT_FAILED;
283       args->error =
284         clib_error_return (0, "%s: pp2_ppio_get_mac_addr failed", s);
285       goto error;
286     }
287
288   args->error = ethernet_register_interface (vnm, mrvl_pp2_device_class.index,
289                                              ppif->dev_instance,
290                                              mac_addr,
291                                              &ppif->hw_if_index,
292                                              mrvl_pp2_eth_flag_change);
293   if (args->error)
294     {
295       args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
296       goto error;
297     }
298
299   sw = vnet_get_hw_sw_interface (vnm, ppif->hw_if_index);
300   ppif->sw_if_index = sw->sw_if_index;
301   ppif->per_interface_next_index = ~0;
302   vnet_hw_interface_set_input_node (vnm, ppif->hw_if_index,
303                                     mrvl_pp2_input_node.index);
304   vnet_hw_interface_assign_rx_thread (vnm, ppif->hw_if_index, 0, ~0);
305   vnet_hw_interface_set_rx_mode (vnm, ppif->hw_if_index, 0,
306                                  VNET_HW_INTERFACE_RX_MODE_POLLING);
307   vnet_hw_interface_set_flags (vnm, ppif->hw_if_index,
308                                VNET_HW_INTERFACE_FLAG_LINK_UP);
309   goto done;
310
311 error:
312   mrvl_pp2_delete_if (ppif);
313 done:
314   vec_free (s);
315 }
316
317 static clib_error_t *
318 mrvl_pp2_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
319                                   u32 flags)
320 {
321   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
322   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
323   mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, hw->dev_instance);
324   static clib_error_t *error = 0;
325   int is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
326   int rv;
327
328   if (is_up)
329     rv = pp2_ppio_enable (ppif->ppio);
330   else
331     rv = pp2_ppio_disable (ppif->ppio);
332
333   if (rv)
334     return clib_error_return (0, "failed to %s interface",
335                               is_up ? "enable" : "disable");
336
337   if (is_up)
338     ppif->flags |= MRVL_PP2_IF_F_ADMIN_UP;
339   else
340     ppif->flags &= ~MRVL_PP2_IF_F_ADMIN_UP;
341
342   return error;
343 }
344
345 static void
346 mrvl_pp2_clear_interface_counters (u32 instance)
347 {
348   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
349   mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, instance);
350   struct pp2_ppio_statistics stats;
351
352   pp2_ppio_get_statistics (ppif->ppio, &stats, 1);
353 }
354
355 static void
356 mrvl_pp2_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
357                                   u32 node_index)
358 {
359   mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
360   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
361   mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, hw->dev_instance);
362
363   /* Shut off redirection */
364   if (node_index == ~0)
365     {
366       ppif->per_interface_next_index = node_index;
367       return;
368     }
369
370   ppif->per_interface_next_index =
371     vlib_node_add_next (vlib_get_main (), mrvl_pp2_input_node.index,
372                         node_index);
373 }
374
375 static char *mrvl_pp2_tx_func_error_strings[] = {
376 #define _(n,s) s,
377   foreach_mrvl_pp2_tx_func_error
378 #undef _
379 };
380
381 /* *INDENT-OFF* */
382 VNET_DEVICE_CLASS (mrvl_pp2_device_class,) =
383 {
384   .name = "Marvell PPv2 interface",
385   .format_device_name = format_mrvl_pp2_interface_name,
386   .format_device = format_mrvl_pp2_interface,
387   .tx_function = mrvl_pp2_interface_tx,
388   .tx_function_n_errors = MRVL_PP2_TX_N_ERROR,
389   .tx_function_error_strings = mrvl_pp2_tx_func_error_strings,
390   .admin_up_down_function = mrvl_pp2_interface_admin_up_down,
391   .clear_counters = mrvl_pp2_clear_interface_counters,
392   .rx_redirect_to_node = mrvl_pp2_set_interface_next_node,
393 };
394 /* *INDENT-ON* */
395
396 static clib_error_t *
397 mrvl_pp2_init (vlib_main_t * vm)
398 {
399   return 0;
400 }
401
402 VLIB_INIT_FUNCTION (mrvl_pp2_init);
403
404 /*
405  * fd.io coding-style-patch-verification: ON
406  *
407  * Local Variables:
408  * eval: (c-set-style "gnu")
409  * End:
410  */