summaryrefslogtreecommitdiffstats
path: root/src/plugins/dev_armada/pp2/port.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/dev_armada/pp2/port.c')
-rw-r--r--src/plugins/dev_armada/pp2/port.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/plugins/dev_armada/pp2/port.c b/src/plugins/dev_armada/pp2/port.c
new file mode 100644
index 00000000000..8e785e5e0e4
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/port.c
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/counters.h>
+#include <vnet/dev/bus/platform.h>
+#include <vppinfra/ring.h>
+#include <dev_armada/musdk.h>
+#include <dev_armada/pp2/pp2.h>
+
+VLIB_REGISTER_LOG_CLASS (mvpp2_log, static) = {
+ .class_name = "armada",
+ .subclass_name = "pp2-port",
+};
+
+vnet_dev_rv_t
+mvpp2_port_init (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ vnet_dev_t *dev = port->dev;
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ struct pp2_ppio_link_info li;
+ char match[16];
+ int mrv;
+
+ log_debug (port->dev, "");
+
+ snprintf (match, sizeof (match), "ppio-%d:%d", md->pp_id, port->port_id);
+
+ struct pp2_ppio_params ppio_params = {
+ .match = match,
+ .type = PP2_PPIO_T_NIC,
+ .eth_start_hdr = mp->is_dsa ? PP2_PPIO_HDR_ETH_DSA : PP2_PPIO_HDR_ETH,
+ .inqs_params = {
+ .num_tcs = 1,
+ .tcs_params[0] = {
+ .pkt_offset = 0,
+ .num_in_qs = 1,
+ .inqs_params = &(struct pp2_ppio_inq_params) { .size = 512 },
+ .pools[0][0] = md->thread[0].bpool,
+ },
+ },
+ };
+
+ foreach_vnet_dev_port_rx_queue (q, port)
+ {
+ struct pp2_ppio_outqs_params *oqs = &ppio_params.outqs_params;
+ oqs->outqs_params[0].weight = 1;
+ oqs->outqs_params[0].size = q->size;
+ oqs->num_outqs++;
+ }
+
+ mrv = pp2_ppio_init (&ppio_params, &mp->ppio);
+ if (mrv)
+ {
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ log_err (dev, "port %u ppio '%s' init failed, rv %d", port->port_id,
+ match, mrv);
+ goto done;
+ }
+ log_debug (dev, "port %u ppio '%s' init ok", port->port_id, match);
+
+ mrv = pp2_ppio_get_link_info (mp->ppio, &li);
+ if (mrv)
+ {
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ log_err (dev, "failed to get link info for port %u, rv %d",
+ port->port_id, mrv);
+ goto done;
+ }
+
+ log_debug (dev, "port %u %U", port->port_id, format_pp2_ppio_link_info, &li);
+
+done:
+ if (rv != VNET_DEV_OK)
+ mvpp2_port_stop (vm, port);
+ return rv;
+}
+
+void
+mvpp2_port_deinit (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+
+ log_debug (port->dev, "");
+
+ if (mp->ppio)
+ {
+ pp2_ppio_deinit (mp->ppio);
+ mp->ppio = 0;
+ }
+}
+
+void
+mvpp2_port_poll (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vnet_dev_t *dev = port->dev;
+ vnet_dev_port_state_changes_t changes = {};
+ struct pp2_ppio_link_info li;
+ int mrv;
+
+ mrv = pp2_ppio_get_link_info (mp->ppio, &li);
+
+ if (mrv)
+ {
+ log_debug (dev, "pp2_ppio_get_link_info: failed, rv %d", mrv);
+ return;
+ }
+
+ if (mp->last_link_info.up != li.up)
+ {
+ changes.change.link_state = 1;
+ changes.link_state = li.up != 0;
+ log_debug (dev, "link state changed to %u", changes.link_state);
+ }
+
+ if (mp->last_link_info.duplex != li.duplex)
+ {
+ changes.change.link_duplex = 1;
+ changes.full_duplex = li.duplex != 0;
+ log_debug (dev, "link full duplex changed to %u", changes.full_duplex);
+ }
+
+ if (mp->last_link_info.speed != li.speed)
+ {
+ u32 speeds[] = {
+ [MV_NET_LINK_SPEED_AN] = 0,
+ [MV_NET_LINK_SPEED_10] = 10000,
+ [MV_NET_LINK_SPEED_100] = 100000,
+ [MV_NET_LINK_SPEED_1000] = 1000000,
+ [MV_NET_LINK_SPEED_2500] = 2500000,
+ [MV_NET_LINK_SPEED_10000] = 10000000,
+ };
+
+ if (li.speed < ARRAY_LEN (speeds))
+ {
+ changes.change.link_speed = 1;
+ changes.link_speed = speeds[li.speed];
+ log_debug (dev, "link speed changed to %u", changes.link_speed);
+ }
+ }
+
+ if (changes.change.any == 0)
+ return;
+
+ mp->last_link_info = li;
+
+ vnet_dev_port_state_change (vm, port, changes);
+}
+
+vnet_dev_rv_t
+mvpp2_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ int mrv;
+
+ log_debug (port->dev, "");
+
+ mrv = pp2_ppio_enable (mp->ppio);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_enable() failed, rv %d", mrv);
+ return VNET_DEV_ERR_NOT_READY;
+ }
+
+ mp->is_enabled = 1;
+
+ vnet_dev_poll_port_add (vm, port, 0.5, mvpp2_port_poll);
+
+ return VNET_DEV_OK;
+}
+
+void
+mvpp2_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ int rv;
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+
+ log_debug (port->dev, "");
+
+ if (mp->is_enabled)
+ {
+ vnet_dev_poll_port_remove (vm, port, mvpp2_port_poll);
+
+ rv = pp2_ppio_disable (mp->ppio);
+ if (rv)
+ log_err (port->dev, "pp2_ppio_disable() failed, rv %d", rv);
+
+ vnet_dev_port_state_change (vm, port,
+ (vnet_dev_port_state_changes_t){
+ .change.link_state = 1,
+ .change.link_speed = 1,
+ .link_speed = 0,
+ .link_state = 0,
+ });
+ mp->is_enabled = 0;
+ }
+}
+
+vnet_dev_rv_t
+mvpp2_port_cfg_change_validate (vlib_main_t *vm, vnet_dev_port_t *port,
+ vnet_dev_port_cfg_change_req_t *req)
+{
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+
+ switch (req->type)
+ {
+ case VNET_DEV_PORT_CFG_PROMISC_MODE:
+ case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
+ case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
+ break;
+
+ default:
+ rv = VNET_DEV_ERR_NOT_SUPPORTED;
+ };
+
+ return rv;
+}
+
+vnet_dev_rv_t
+mvpp2_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
+ vnet_dev_port_cfg_change_req_t *req)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ eth_addr_t addr;
+ int mrv;
+
+ switch (req->type)
+ {
+
+ case VNET_DEV_PORT_CFG_PROMISC_MODE:
+ mrv = pp2_ppio_set_promisc (mp->ppio, req->promisc);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_set_promisc: failed, rv %d", mrv);
+ rv = VNET_DEV_ERR_INTERNAL;
+ }
+ else
+ log_debug (port->dev, "pp2_ppio_set_promisc: promisc %u",
+ req->promisc);
+ break;
+
+ case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
+ clib_memcpy (&addr, req->addr.eth_mac, sizeof (addr));
+ mrv = pp2_ppio_add_mac_addr (mp->ppio, addr);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_add_mac_addr: failed, rv %d", mrv);
+ rv = VNET_DEV_ERR_INTERNAL;
+ }
+ else
+ log_debug (port->dev, "pp2_ppio_add_mac_addr: %U added",
+ format_ethernet_address, &addr);
+ break;
+
+ case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
+ clib_memcpy (&addr, req->addr.eth_mac, sizeof (addr));
+ mrv = pp2_ppio_remove_mac_addr (mp->ppio, addr);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_remove_mac_addr: failed, rv %d", mrv);
+ rv = VNET_DEV_ERR_INTERNAL;
+ }
+ else
+ log_debug (port->dev, "pp2_ppio_remove_mac_addr: %U added",
+ format_ethernet_address, &addr);
+ break;
+
+ default:
+ return VNET_DEV_ERR_NOT_SUPPORTED;
+ };
+
+ return rv;
+}