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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
18 #include <sys/types.h>
21 #include <sys/ioctl.h>
23 #include <vlib/vlib.h>
24 #include <vlib/unix/unix.h>
25 #include <vnet/plugin/plugin.h>
26 #include <marvell/pp2/pp2.h>
27 #include <vnet/interface/rx_queue_funcs.h>
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
36 mrvl_pp2_main_t mrvl_pp2_main;
37 extern vnet_device_class_t ppa2_device_class;
40 mrvl_pp2_main_deinit ()
42 mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
44 vec_foreach_index (i, ppm->per_thread_data)
46 mrvl_pp2_per_thread_data_t *ptd = vec_elt_at_index (ppm->per_thread_data,
49 pp2_hif_deinit (ptd->hif);
50 vec_free (ptd->descs);
52 vec_free (ppm->per_thread_data);
54 mv_sys_dma_mem_destroy ();
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 };
67 rv = mv_sys_dma_mem_init (MV_SYS_DMA_MEM_SZ);
69 return clib_error_return (0, "mv_sys_dma_mem_init failed, rv = %u", rv);
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);
76 err = clib_error_return (0, "mrvl_pp2_init failed, rv = %u", rv);
80 vec_validate_aligned (ppm->per_thread_data, tm->n_vlib_mains - 1,
81 CLIB_CACHE_LINE_BYTES);
83 vec_foreach_index (i, ppm->per_thread_data)
85 mrvl_pp2_per_thread_data_t *ptd = vec_elt_at_index (ppm->per_thread_data,
87 struct pp2_hif_params hif_params = { 0 };
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))
94 err = clib_error_return (0, "hif '%s' init failed", s);
101 mrvl_pp2_main_deinit ();
107 mrvl_pp2_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
110 /* nothing for now */
115 mrvl_pp2_delete_if (mrvl_pp2_if_t * ppif)
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;
123 if (ppif->hw_if_index != ~0)
124 ethernet_delete_interface (vnm, ppif->hw_if_index);
128 pp2_ppio_disable (ppif->ppio);
129 pp2_ppio_deinit (ppif->ppio);
133 /* free buffers hanging in the tx ring */
134 vec_foreach (outq, ppif->outqs)
136 while (outq->tail < outq->head)
138 u16 slot = outq->tail & (outq->size - 1);
139 vlib_buffer_free (vm, outq->buffers + slot, 1);
142 vec_free (outq->buffers);
144 vec_free (ppif->outqs);
146 /* free buffers hangin in the rx buffer pool */
147 vec_foreach (inq, ppif->inqs)
151 pp2_bpool_get_num_buffs (inq->bpool, &n_bufs);
154 struct pp2_buff_inf binf;
155 if (pp2_bpool_get_buff (ppm->per_thread_data[0].hif, inq->bpool,
158 u32 bi = binf.cookie;
159 vlib_buffer_free (vm, &bi, 1);
162 pp2_bpool_deinit (inq->bpool);
164 vec_free (ppif->inqs);
168 pool_put (ppm->interfaces, ppif);
170 if (pool_elts (ppm->interfaces) == 0)
171 mrvl_pp2_main_deinit ();
175 mrvl_pp2_create_if (mrvl_pp2_create_if_args_t * args)
177 vlib_main_t *vm = vlib_get_main ();
178 vnet_main_t *vnm = vnet_get_main ();
179 vlib_thread_main_t *tm = vlib_get_thread_main ();
180 vnet_eth_interface_registration_t eir = {};
181 mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
182 struct pp2_bpool_params bpool_params = { 0 };
183 struct pp2_ppio_params ppio_params = { 0 };
184 struct pp2_ppio_inq_params inq_params = { 0 };
185 vnet_sw_interface_t *sw;
186 mrvl_pp2_if_t *ppif = 0;
187 u8 pp2_id, port_id, *s = 0;
189 u8 n_outqs, n_inqs = 1;
192 if (tm->n_vlib_mains > PP2_PPIO_MAX_NUM_OUTQS)
194 args->rv = VNET_API_ERROR_INIT_FAILED;
195 args->error = clib_error_return (0, "number of threads (main + workers)"
196 " is bigger than number of output "
197 "queues (%u)", PP2_PPIO_MAX_NUM_OUTQS);
200 n_outqs = tm->n_vlib_mains;
203 args->tx_q_sz = args->tx_q_sz ? args->tx_q_sz : 2 * VLIB_FRAME_SIZE;
204 args->rx_q_sz = args->rx_q_sz ? args->rx_q_sz : 2 * VLIB_FRAME_SIZE;
206 if (vec_len (ppm->per_thread_data) == 0)
208 if ((args->error = mrvl_pp2_main_init ()) != 0)
210 args->rv = VNET_API_ERROR_INIT_FAILED;
215 pool_get_zero (ppm->interfaces, ppif);
216 ppif->dev_instance = ppif - ppm->interfaces;
217 ppif->hw_if_index = ~0;
218 vec_validate_aligned (ppif->inqs, n_inqs - 1, CLIB_CACHE_LINE_BYTES);
219 vec_validate_aligned (ppif->outqs, n_outqs - 1, CLIB_CACHE_LINE_BYTES);
221 for (i = 0; i < n_inqs; i++)
223 mrvl_pp2_inq_t *inq = vec_elt_at_index (ppif->inqs, i);
224 inq->size = args->rx_q_sz;
226 for (i = 0; i < n_outqs; i++)
228 mrvl_pp2_outq_t *outq = vec_elt_at_index (ppif->outqs, i);
229 outq->size = args->tx_q_sz;
230 vec_validate_aligned (outq->buffers, outq->size, CLIB_CACHE_LINE_BYTES);
233 if (pp2_netdev_get_ppio_info ((char *) args->name, &pp2_id, &port_id))
235 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
236 args->error = clib_error_return (0, "Invalid interface '%s'",
241 /* FIXME bpool bit select per pp */
242 s = format (s, "pool-%d:%d%c", pp2_id, pp2_id + 8, 0);
243 bpool_params.match = (char *) s;
244 bpool_params.buff_len = vlib_buffer_get_default_data_size (vm);
246 if (pp2_bpool_init (&bpool_params, &ppif->inqs[0].bpool))
248 args->rv = VNET_API_ERROR_INIT_FAILED;
249 args->error = clib_error_return (0, "bpool '%s' init failed", s);
252 vec_reset_length (s);
254 s = format (s, "ppio-%d:%d%c", pp2_id, port_id, 0);
255 ppio_params.match = (char *) s;
256 ppio_params.type = PP2_PPIO_T_NIC;
257 inq_params.size = args->rx_q_sz;
258 ppio_params.inqs_params.num_tcs = 1;
259 ppio_params.inqs_params.tcs_params[0].pkt_offset = 0;
260 ppio_params.inqs_params.tcs_params[0].num_in_qs = n_inqs;
261 ppio_params.inqs_params.tcs_params[0].inqs_params = &inq_params;
262 ppio_params.inqs_params.tcs_params[0].pools[0][0] = ppif->inqs[0].bpool;
263 ppio_params.outqs_params.num_outqs = n_outqs;
264 for (i = 0; i < n_outqs; i++)
266 ppio_params.outqs_params.outqs_params[i].weight = 1;
267 ppio_params.outqs_params.outqs_params[i].size = args->tx_q_sz;
269 if (pp2_ppio_init (&ppio_params, &ppif->ppio))
271 args->rv = VNET_API_ERROR_INIT_FAILED;
272 args->error = clib_error_return (0, "ppio '%s' init failed", s);
275 vec_reset_length (s);
277 if (pp2_ppio_get_mac_addr (ppif->ppio, mac_addr))
279 args->rv = VNET_API_ERROR_INIT_FAILED;
281 clib_error_return (0, "%s: pp2_ppio_get_mac_addr failed", s);
285 eir.dev_class_index = mrvl_pp2_device_class.index;
286 eir.dev_instance = ppif->dev_instance;
287 eir.address = mac_addr;
288 eir.cb.flag_change = mrvl_pp2_eth_flag_change;
289 ppif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
291 sw = vnet_get_hw_sw_interface (vnm, ppif->hw_if_index);
292 ppif->sw_if_index = sw->sw_if_index;
293 ppif->per_interface_next_index = ~0;
294 args->sw_if_index = sw->sw_if_index;
295 vnet_hw_if_set_input_node (vnm, ppif->hw_if_index,
296 mrvl_pp2_input_node.index);
297 /* FIXME: only one RX queue ? */
298 ppif->inqs[0].queue_index = vnet_hw_if_register_rx_queue (
299 vnm, ppif->hw_if_index, 0, VNET_HW_IF_RXQ_THREAD_ANY);
301 vnet_hw_if_set_rx_queue_mode (vnm, ppif->inqs[0].queue_index,
302 VNET_HW_IF_RX_MODE_POLLING);
303 vnet_hw_if_update_runtime_data (vnm, ppif->hw_if_index);
304 vnet_hw_interface_set_flags (vnm, ppif->hw_if_index,
305 VNET_HW_INTERFACE_FLAG_LINK_UP);
309 mrvl_pp2_delete_if (ppif);
314 static clib_error_t *
315 mrvl_pp2_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
318 mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
319 vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
320 mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, hw->dev_instance);
321 static clib_error_t *error = 0;
322 int is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
326 rv = pp2_ppio_enable (ppif->ppio);
328 rv = pp2_ppio_disable (ppif->ppio);
331 return clib_error_return (0, "failed to %s interface",
332 is_up ? "enable" : "disable");
335 ppif->flags |= MRVL_PP2_IF_F_ADMIN_UP;
337 ppif->flags &= ~MRVL_PP2_IF_F_ADMIN_UP;
343 mrvl_pp2_clear_interface_counters (u32 instance)
345 mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
346 mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, instance);
347 struct pp2_ppio_statistics stats;
349 pp2_ppio_get_statistics (ppif->ppio, &stats, 1);
353 mrvl_pp2_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
356 mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
357 vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
358 mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, hw->dev_instance);
360 /* Shut off redirection */
361 if (node_index == ~0)
363 ppif->per_interface_next_index = node_index;
367 ppif->per_interface_next_index =
368 vlib_node_add_next (vlib_get_main (), mrvl_pp2_input_node.index,
372 static char *mrvl_pp2_tx_func_error_strings[] = {
374 foreach_mrvl_pp2_tx_func_error
379 VNET_DEVICE_CLASS (mrvl_pp2_device_class,) =
381 .name = "Marvell PPv2 interface",
382 .format_device_name = format_mrvl_pp2_interface_name,
383 .format_device = format_mrvl_pp2_interface,
384 .tx_function = mrvl_pp2_interface_tx,
385 .tx_function_n_errors = MRVL_PP2_TX_N_ERROR,
386 .tx_function_error_strings = mrvl_pp2_tx_func_error_strings,
387 .admin_up_down_function = mrvl_pp2_interface_admin_up_down,
388 .clear_counters = mrvl_pp2_clear_interface_counters,
389 .rx_redirect_to_node = mrvl_pp2_set_interface_next_node,
393 static clib_error_t *
394 mrvl_pp2_init (vlib_main_t * vm)
399 VLIB_INIT_FUNCTION (mrvl_pp2_init);
402 * fd.io coding-style-patch-verification: ON
405 * eval: (c-set-style "gnu")