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