armada: introduce dev_armada plugin

Also retires old marvell plugin.

Change-Id: Icedec11f5661909058fdfe8d5fc455306adafacd
Type: feature
Signed-off-by: Damjan Marion <damarion@cisco.com>
This commit is contained in:
Damjan Marion 2024-08-27 18:12:33 +02:00 committed by Mohammed HAWARI
parent 1f7d14c810
commit 4e51841896
27 changed files with 1364 additions and 1813 deletions

View File

@ -500,10 +500,10 @@ I: memif
M: Damjan Marion <damarion@cisco.com>
F: src/plugins/memif/
Plugin - Marvell MUSDK device driver
I: marvell
Plugin - Marvell Armada device driver
I: armada
M: Damjan Marion <damarion@cisco.com>
F: src/plugins/marvell/
F: src/plugins/dev_armada/
Plugin - performance counter
I: perfmon

View File

@ -0,0 +1 @@
../../../src/plugins/dev_armada/README.rst

View File

@ -19,9 +19,9 @@ For more on plugins please refer to :ref:`add_plugin`.
quic
cnat
dev_armada
lcp
srv6/index
marvell
lldp
nat64
nat44_ei_ha

View File

@ -1 +0,0 @@
../../../src/plugins/marvell/README.rst

View File

@ -0,0 +1,30 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright(c) 2022 Cisco Systems, Inc.
find_path(MUSDK_INCLUDE_DIR NAMES mv_std.h)
find_library(MUSDK_LIB NAMES libmusdk.a)
if(NOT MUSDK_INCLUDE_DIR OR NOT MUSDK_LIB)
message(WARNING "Marvell MUSDK not found - dev_armada plugin disabled")
return()
endif()
get_filename_component(MUSDK_LIB_DIR ${MUSDK_LIB} DIRECTORY)
set(MUSDK_LINK_FLAGS "-Wl,--whole-archive,${MUSDK_LIB_DIR}/libmusdk.a,--no-whole-archive")
add_vpp_plugin(dev_armada
SOURCES
plugin.c
pp2/init.c
pp2/format.c
pp2/port.c
pp2/queue.c
pp2/rx.c
pp2/tx.c
LINK_FLAGS
${MUSDK_LINK_FLAGS}
)
include_directories(${MUSDK_INCLUDE_DIR})

View File

@ -0,0 +1,61 @@
Armada device plugin
=====================
Overview
--------
This plugins provides native device support for Marvell PP2 network
device, found in Marvel Armada family of SOCs.
It uses Marvell Usermode SDK
(`MUSDK <https://github.com/MarvellEmbeddedProcessors/musdk-marvell>`__).
Prerequisites
-------------
Plugins depends on installed MUSDK and Marvell provided linux in Marvell SDK.
Following kernel modules from MUSDK must be loaded for plugin to work:
``musdk_cma.ko``
``mv_pp_uio.ko``
Musdk 18.09.3 compilation steps
-------------------------------
::
./bootstrap
./configure --prefix=/opt/vpp/external/aarch64/ CFLAGS="-Wno-error=unused-result -g -fPIC" --enable-shared=no
sed -i -e 's/marvell,mv-pp-uio/generic-uio/' modules/pp2/mv_pp_uio.c
sed -i -e 's/O_CREAT/O_CREAT, S_IRUSR | S_IWUSR/' src/lib/file_utils.c
make
sudo make install
Usage
-----
Interface Creation and Deletion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Interfaces are using new vnet dev APIs, CLIs or startup.conf to create and
delete interfaces.
Sample startup.conf:
::
devices {
dev platform/f2000000.ethernet {
port 1 { name ppio1 }
}
Device identifier in this example is 'platform/f2000000.ethernet' where
'platform' is bus name and 'f2000000.ethernet' is linux platform bus
identifier for specific PP2.
Platform identifier can be found in sysfs:
::
$ ls /sys/bus/platform/devices | grep ethernet
f2000000.ethernet

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2023 Cisco Systems, Inc.
*/
#ifndef _MUSDK_H_
#define _MUSDK_H_
#define MVCONF_DBG_LEVEL 0
#define MVCONF_PP2_BPOOL_COOKIE_SIZE 32
#define MVCONF_PP2_BPOOL_DMA_ADDR_SIZE 64
#define MVCONF_DMA_PHYS_ADDR_T_SIZE 64
#define MVCONF_SYS_DMA_UIO
#define MVCONF_TYPES_PUBLIC
#define MVCONF_DMA_PHYS_ADDR_T_PUBLIC
#include <mv_std.h>
#include <env/mv_sys_dma.h>
#include <drivers/mv_pp2.h>
#include <drivers/mv_pp2_bpool.h>
#include <drivers/mv_pp2_ppio.h>
#endif /* _MUSDK_H_ */

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2023 Cisco Systems, Inc.
*/
#include <vlib/vlib.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "Marvell Armada Drivers",
};

View File

@ -0,0 +1,176 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2023 Cisco Systems, Inc.
*/
#include <vnet/vnet.h>
#include <vnet/dev/dev.h>
#include <vnet/dev/counters.h>
#include <vnet/dev/bus/platform.h>
#include <dev_armada/musdk.h>
#include <dev_armada/pp2/pp2.h>
static inline u32
mrvl_get_u32_bits (void *start, int offset, int first, int last)
{
u32 value = *(u32 *) (((u8 *) start) + offset);
if ((last == 0) && (first == 31))
return value;
value >>= last;
value &= (1 << (first - last + 1)) - 1;
return value;
}
u8 *
format_pp2_ppio_link_info (u8 *s, va_list *args)
{
struct pp2_ppio_link_info *li = va_arg (*args, struct pp2_ppio_link_info *);
char *port_duplex[] = {
[MV_NET_LINK_DUPLEX_HALF] = "half",
[MV_NET_LINK_DUPLEX_FULL] = "full",
};
u32 port_speeds[] = {
[MV_NET_LINK_SPEED_10] = 10, [MV_NET_LINK_SPEED_100] = 100,
[MV_NET_LINK_SPEED_1000] = 1000, [MV_NET_LINK_SPEED_2500] = 2500,
[MV_NET_LINK_SPEED_10000] = 10000,
};
char *port_phy_modes[] = {
[MV_NET_PHY_MODE_NONE] = "NONE",
[MV_NET_PHY_MODE_MII] = "MII",
[MV_NET_PHY_MODE_GMII] = "GMII",
[MV_NET_PHY_MODE_SGMII] = "SGMII",
[MV_NET_PHY_MODE_TBI] = "TBI",
[MV_NET_PHY_MODE_REVMII] = "REVMII",
[MV_NET_PHY_MODE_RMII] = "RMII",
[MV_NET_PHY_MODE_RGMII] = "RGMII",
[MV_NET_PHY_MODE_RGMII_ID] = "RGMII_ID",
[MV_NET_PHY_MODE_RGMII_RXID] = "RGMII_RXID",
[MV_NET_PHY_MODE_RGMII_TXID] = "RGMII_TXID",
[MV_NET_PHY_MODE_RTBI] = "RTBI",
[MV_NET_PHY_MODE_SMII] = "SMII",
[MV_NET_PHY_MODE_XGMII] = "XGMII",
[MV_NET_PHY_MODE_MOCA] = "MOCA",
[MV_NET_PHY_MODE_QSGMII] = "QSGMII",
[MV_NET_PHY_MODE_XAUI] = "XAUI",
[MV_NET_PHY_MODE_RXAUI] = "RXAUI",
[MV_NET_PHY_MODE_KR] = "KR",
};
s =
format (s, "duplex %s speed %d up %d phy_mode %s", port_duplex[li->duplex],
port_speeds[li->speed], li->up, port_phy_modes[li->phy_mode]);
return s;
}
u8 *
format_mvpp2_port_status (u8 *s, va_list *args)
{
vnet_dev_format_args_t __clib_unused *a =
va_arg (*args, vnet_dev_format_args_t *);
vnet_dev_port_t *port = va_arg (*args, vnet_dev_port_t *);
mvpp2_port_t *mp = vnet_dev_get_port_data (port);
struct pp2_ppio_link_info li = {};
if (mp->ppio == 0 || pp2_ppio_get_link_info (mp->ppio, &li))
return format (s, "link info not available");
return format (s, "%U", format_pp2_ppio_link_info, &li);
}
u8 *
format_mvpp2_dev_info (u8 *s, va_list *args)
{
vnet_dev_format_args_t __clib_unused *a =
va_arg (*args, vnet_dev_format_args_t *);
vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
mvpp2_device_t *md = vnet_dev_get_data (dev);
format (s, "pp_id is %u", md->pp_id);
return s;
}
#define foreach_pp2_rx_desc_field \
_ (0x00, 6, 0, l3_offset) \
_ (0x00, 12, 8, ip_hdlen) \
_ (0x00, 14, 13, ec) \
_ (0x00, 15, 15, es) \
_ (0x00, 19, 16, pool_id) \
_ (0x00, 21, 21, hwf_sync) \
_ (0x00, 22, 22, l4_chk_ok) \
_ (0x00, 23, 23, ip_frg) \
_ (0x00, 24, 24, ipv4_hdr_err) \
_ (0x00, 27, 25, l4_info) \
_ (0x00, 30, 28, l3_info) \
_ (0x00, 31, 31, buf_header) \
_ (0x04, 5, 0, lookup_id) \
_ (0x04, 8, 6, cpu_code) \
_ (0x04, 9, 9, pppoe) \
_ (0x04, 11, 10, l3_cast_info) \
_ (0x04, 13, 12, l2_cast_info) \
_ (0x04, 15, 14, vlan_info) \
_ (0x04, 31, 16, byte_count) \
_ (0x08, 11, 0, gem_port_id) \
_ (0x08, 13, 12, color) \
_ (0x08, 14, 14, gop_sop_u) \
_ (0x08, 15, 15, key_hash_enable) \
_ (0x08, 31, 16, l4chk) \
_ (0x0c, 31, 0, timestamp) \
_ (0x10, 31, 0, buf_phys_ptr_lo) \
_ (0x14, 7, 0, buf_phys_ptr_hi) \
_ (0x14, 31, 8, key_hash) \
_ (0x18, 31, 0, buf_virt_ptr_lo) \
_ (0x1c, 7, 0, buf_virt_ptr_hi) \
_ (0x1c, 14, 8, buf_qset_no) \
_ (0x1c, 15, 15, buf_type) \
_ (0x1c, 21, 16, mod_dscp) \
_ (0x1c, 24, 22, mod_pri) \
_ (0x1c, 25, 25, mdscp) \
_ (0x1c, 26, 26, mpri) \
_ (0x1c, 27, 27, mgpid) \
_ (0x1c, 31, 29, port_num)
u8 *
format_mvpp2_rx_desc (u8 *s, va_list *args)
{
struct pp2_ppio_desc *d = va_arg (*args, struct pp2_ppio_desc *);
u32 indent = format_get_indent (s);
u32 r32;
#define _(a, b, c, n) \
r32 = mrvl_get_u32_bits (d, a, b, c); \
if (r32 > 9) \
s = format (s, "%s %u (0x%x)", #n, r32, r32); \
else \
s = format (s, "%s %u", #n, r32); \
if (format_get_indent (s) > 72) \
s = format (s, "\n%U", format_white_space, indent + 2); \
else \
s = format (s, " ");
foreach_pp2_rx_desc_field;
return s;
}
u8 *
format_mvpp2_rx_trace (u8 *s, va_list *args)
{
vlib_main_t *vm = va_arg (*args, vlib_main_t *);
vlib_node_t *node = va_arg (*args, vlib_node_t *);
mvpp2_rx_trace_t *t = va_arg (*args, mvpp2_rx_trace_t *);
vnet_main_t *vnm = vnet_get_main ();
u32 hw_if_index = t->rxq->port->intf.hw_if_index;
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
u32 indent = format_get_indent (s);
struct pp2_ppio_desc *d = &t->desc;
s = format (s, "pp2: %v (%d) next-node %U", hi->name, hw_if_index,
format_vlib_next_node_name, vm, node->index, t->rxq->next_index);
s = format (s, "\n%U%U", format_white_space, indent + 2,
format_mvpp2_rx_desc, d);
return s;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -0,0 +1,144 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2023 Cisco Systems, Inc.
*/
#ifndef _PP2_H_
#define _PP2_H_
#include <vppinfra/clib.h>
#include <vppinfra/error_bootstrap.h>
#include <vppinfra/format.h>
#include <vnet/vnet.h>
#include <vnet/dev/dev.h>
#define MVCONF_DBG_LEVEL 0
#define MVCONF_PP2_BPOOL_COOKIE_SIZE 32
#define MVCONF_PP2_BPOOL_DMA_ADDR_SIZE 64
#define MVCONF_DMA_PHYS_ADDR_T_SIZE 64
#define MVCONF_SYS_DMA_UIO
#define MVCONF_TYPES_PUBLIC
#define MVCONF_DMA_PHYS_ADDR_T_PUBLIC
#include "mv_std.h"
#include "env/mv_sys_dma.h"
#include "drivers/mv_pp2.h"
#include <drivers/mv_pp2_bpool.h>
#include <drivers/mv_pp2_ppio.h>
#define MVPP2_NUM_HIFS 9
#define MVPP2_NUM_BPOOLS 16
#define MVPP2_MAX_THREADS 4
#define MRVL_PP2_BUFF_BATCH_SZ 32
typedef struct
{
u8 pp_id;
struct pp2_hif *hif[MVPP2_NUM_HIFS];
struct
{
struct pp2_bpool *bpool;
struct buff_release_entry bre[MRVL_PP2_BUFF_BATCH_SZ];
} thread[MVPP2_NUM_BPOOLS];
} mvpp2_device_t;
typedef struct
{
u8 is_enabled : 1;
u8 is_dsa : 1;
struct pp2_ppio *ppio;
u8 ppio_id;
struct pp2_ppio_link_info last_link_info;
} mvpp2_port_t;
typedef struct
{
u16 next;
u16 n_enq;
u32 *buffers;
} mvpp2_txq_t;
typedef struct
{
} mvpp2_rxq_t;
typedef struct
{
struct pp2_ppio_desc desc;
vnet_dev_rx_queue_t *rxq;
} mvpp2_rx_trace_t;
/* format.c */
format_function_t format_pp2_ppio_link_info;
format_function_t format_mvpp2_port_status;
format_function_t format_mvpp2_dev_info;
format_function_t format_mvpp2_rx_trace;
format_function_t format_mvpp2_rx_desc;
/* port.c */
vnet_dev_port_op_t mvpp2_port_init;
vnet_dev_port_op_no_rv_t mvpp2_port_deinit;
vnet_dev_port_op_t mvpp2_port_start;
vnet_dev_port_op_no_rv_t mvpp2_port_stop;
vnet_dev_rv_t mvpp2_port_cfg_change (vlib_main_t *, vnet_dev_port_t *,
vnet_dev_port_cfg_change_req_t *);
vnet_dev_rv_t
mvpp2_port_cfg_change_validate (vlib_main_t *, vnet_dev_port_t *,
vnet_dev_port_cfg_change_req_t *);
/* queue.c */
vnet_dev_tx_queue_op_t mvpp2_txq_alloc;
vnet_dev_tx_queue_op_no_rv_t mvpp2_txq_free;
/* inline funcs */
#define log_debug(dev, f, ...) \
vlib_log (VLIB_LOG_LEVEL_DEBUG, mvpp2_log.class, "%U" f, \
format_vnet_dev_log, (dev), \
clib_string_skip_prefix (__func__, "mvpp2_"), ##__VA_ARGS__)
#define log_info(dev, f, ...) \
vlib_log (VLIB_LOG_LEVEL_INFO, mvpp2_log.class, "%U" f, \
format_vnet_dev_log, (dev), 0, ##__VA_ARGS__)
#define log_notice(dev, f, ...) \
vlib_log (VLIB_LOG_LEVEL_NOTICE, mvpp2_log.class, "%U" f, \
format_vnet_dev_log, (dev), 0, ##__VA_ARGS__)
#define log_warn(dev, f, ...) \
vlib_log (VLIB_LOG_LEVEL_WARNING, mvpp2_log.class, "%U" f, \
format_vnet_dev_log, (dev), 0, ##__VA_ARGS__)
#define log_err(dev, f, ...) \
vlib_log (VLIB_LOG_LEVEL_ERR, mvpp2_log.class, "%U" f, format_vnet_dev_log, \
(dev), 0, ##__VA_ARGS__)
#define foreach_mvpp2_tx_node_counter \
_ (NO_FREE_SLOTS, no_free_slots, ERROR, "no free tx slots") \
_ (PPIO_SEND, ppio_semd, ERROR, "pp2_ppio_send errors") \
_ (PPIO_GET_NUM_OUTQ_DONE, ppio_get_num_outq_done, ERROR, \
"pp2_ppio_get_num_outq_done errors")
typedef enum
{
#define _(f, n, s, d) MVPP2_TX_NODE_CTR_##f,
foreach_mvpp2_tx_node_counter
#undef _
} mvpp2_tx_node_counter_t;
#define foreach_mvpp2_rx_node_counter \
_ (PPIO_RECV, ppio_recv, ERROR, "pp2_ppio_recv error") \
_ (BPOOL_GET_NUM_BUFFS, bpool_get_num_bufs, ERROR, \
"pp2_bpool_get_num_buffs error") \
_ (BPOOL_PUT_BUFFS, bpool_put_buffs, ERROR, "pp2_bpool_put_buffs error") \
_ (BUFFER_ALLOC, buffer_alloc, ERROR, "buffer alloc error") \
_ (MAC_CE, mac_ce, ERROR, "MAC error (CRC error)") \
_ (MAC_OR, mac_or, ERROR, "overrun error") \
_ (MAC_RSVD, mac_rsvd, ERROR, "unknown MAC error") \
_ (MAC_RE, mac_re, ERROR, "resource error") \
_ (IP_HDR, ip_hdr, ERROR, "ip4 header error")
typedef enum
{
#define _(f, n, s, d) MVPP2_RX_NODE_CTR_##f,
foreach_mvpp2_rx_node_counter
#undef _
} mvpp2_rx_node_counter_t;
#endif /* _PP2_H_ */

View File

@ -0,0 +1,48 @@
/* 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-queue",
};
vnet_dev_rv_t
mvpp2_txq_alloc (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
{
vnet_dev_rv_t rv = VNET_DEV_OK;
mvpp2_txq_t *mtq = vnet_dev_get_tx_queue_data (txq);
log_debug (txq->port->dev, "");
ASSERT (mtq->buffers == 0);
if (mtq->buffers == 0)
{
u32 sz = sizeof (u32) * txq->size;
mtq->buffers = clib_mem_alloc_aligned (sz, CLIB_CACHE_LINE_BYTES);
clib_memset (mtq->buffers, 0, sz);
}
return rv;
}
void
mvpp2_txq_free (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
{
mvpp2_txq_t *mtq = vnet_dev_get_tx_queue_data (txq);
log_debug (txq->port->dev, "");
if (mtq->buffers)
{
clib_mem_free (mtq->buffers);
mtq->buffers = 0;
}
}

View File

@ -0,0 +1,158 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2024 Cisco Systems, Inc.
*/
#include <vlib/vlib.h>
#include <vnet/dev/dev.h>
#include <vnet/ethernet/ethernet.h>
#include <dev_armada/pp2/pp2.h>
static_always_inline void
mvpp2_rx_trace (vlib_main_t *vm, vlib_node_runtime_t *node,
vnet_dev_rx_queue_t *rxq, vlib_buffer_t *b0, uword *n_trace,
struct pp2_ppio_desc *d)
{
if (PREDICT_TRUE (vlib_trace_buffer (vm, node, rxq->next_index, b0,
/* follow_chain */ 0)))
{
mvpp2_rx_trace_t *tr;
vlib_set_trace_count (vm, node, --(*n_trace));
tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
tr->desc = *d;
tr->rxq = rxq;
}
}
static_always_inline uword
mrvl_pp2_rx_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_frame_t *frame, vnet_dev_rx_queue_t *rxq)
{
vnet_main_t *vnm = vnet_get_main ();
vnet_dev_port_t *port = rxq->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);
vlib_buffer_template_t bt = rxq->buffer_template;
u32 thread_index = vm->thread_index;
uword n_trace = vlib_get_trace_count (vm, node);
u32 next_index = rxq->next_index;
u32 n_rx_packets = 0, n_rx_bytes = 0;
struct pp2_hif *hif = md->hif[thread_index];
struct pp2_ppio_desc descs[VLIB_FRAME_SIZE], *d;
struct pp2_bpool *bpool = md->thread[thread_index].bpool;
struct buff_release_entry *bre = md->thread[thread_index].bre;
u16 n_desc = VLIB_FRAME_SIZE;
u32 buffers[VLIB_FRAME_SIZE];
u32 n_bufs, *bi, i;
vlib_buffer_t *b0, *b1;
if (PREDICT_FALSE (
pp2_ppio_recv (mp->ppio, 0, rxq->queue_id, descs, &n_desc)))
{
vlib_error_count (vm, node->node_index, MVPP2_RX_NODE_CTR_PPIO_RECV, 1);
n_desc = 0;
}
n_rx_packets = n_desc;
for (i = 0; i < n_desc; i++)
buffers[i] = pp2_ppio_inq_desc_get_cookie (descs + i);
bt.current_data = 2;
for (d = descs, bi = buffers; n_desc >= 4; d += 2, bi += 2, n_desc -= 2)
{
/* prefetch */
b0 = vlib_get_buffer (vm, bi[0]);
b1 = vlib_get_buffer (vm, bi[1]);
b0->template = bt;
b1->template = bt;
n_rx_bytes += b0->current_length = pp2_ppio_inq_desc_get_pkt_len (d);
n_rx_bytes += b1->current_length = pp2_ppio_inq_desc_get_pkt_len (d + 1);
if (PREDICT_FALSE (n_trace > 0))
{
mvpp2_rx_trace (vm, node, rxq, b0, &n_trace, d);
if (n_trace > 0)
mvpp2_rx_trace (vm, node, rxq, b1, &n_trace, d + 1);
}
}
for (; n_desc; d++, bi++, n_desc--)
{
b0 = vlib_get_buffer (vm, bi[0]);
b0->template = bt;
n_rx_bytes += b0->current_length = pp2_ppio_inq_desc_get_pkt_len (d);
if (PREDICT_FALSE (n_trace > 0))
mvpp2_rx_trace (vm, node, rxq, b0, &n_trace, d);
}
vlib_buffer_enqueue_to_single_next (vm, node, buffers, next_index,
n_rx_packets);
vlib_increment_combined_counter (
vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
thread_index, port->intf.sw_if_index, n_rx_packets, n_rx_bytes);
if (PREDICT_FALSE (pp2_bpool_get_num_buffs (bpool, &n_bufs)))
{
vlib_error_count (vm, node->node_index,
MVPP2_RX_NODE_CTR_BPOOL_GET_NUM_BUFFS, 1);
goto done;
}
n_bufs = rxq->size - n_bufs;
while (n_bufs >= MRVL_PP2_BUFF_BATCH_SZ)
{
u16 n_alloc, i;
struct buff_release_entry *e = bre;
n_alloc = vlib_buffer_alloc (vm, buffers, MRVL_PP2_BUFF_BATCH_SZ);
i = n_alloc;
if (PREDICT_FALSE (n_alloc == 0))
{
vlib_error_count (vm, node->node_index,
MVPP2_RX_NODE_CTR_BUFFER_ALLOC, 1);
goto done;
}
for (bi = buffers; i--; e++, bi++)
{
vlib_buffer_t *b = vlib_get_buffer (vm, bi[0]);
e->buff.addr = vlib_buffer_get_pa (vm, b) - 64;
e->buff.cookie = bi[0];
}
i = n_alloc;
if (PREDICT_FALSE (pp2_bpool_put_buffs (hif, bre, &i)))
{
vlib_error_count (vm, node->node_index,
MVPP2_RX_NODE_CTR_BPOOL_PUT_BUFFS, 1);
vlib_buffer_free (vm, buffers, n_alloc);
goto done;
}
if (PREDICT_FALSE (i != n_alloc))
vlib_buffer_free (vm, buffers + i, n_alloc - i);
n_bufs -= i;
}
done:
return n_rx_packets;
}
VNET_DEV_NODE_FN (mvpp2_rx_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
u32 n_rx = 0;
foreach_vnet_dev_rx_queue_runtime (rxq, node)
n_rx += mrvl_pp2_rx_inline (vm, node, frame, rxq);
return n_rx;
}

View File

@ -0,0 +1,83 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2024 Cisco Systems, Inc.
*/
#include <vlib/vlib.h>
#include <vnet/dev/dev.h>
#include <vnet/ethernet/ethernet.h>
#include <dev_armada/pp2/pp2.h>
VNET_DEV_NODE_FN (mvpp2_tx_node)
(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
vnet_dev_tx_node_runtime_t *rt = vnet_dev_get_tx_node_runtime (node);
vnet_dev_tx_queue_t *txq = rt->tx_queue;
vnet_dev_port_t *port = txq->port;
vnet_dev_t *dev = port->dev;
mvpp2_txq_t *mtq = vnet_dev_get_tx_queue_data (txq);
mvpp2_port_t *mp = vnet_dev_get_port_data (port);
mvpp2_device_t *md = vnet_dev_get_data (dev);
u8 qid = txq->queue_id;
u32 *buffers = vlib_frame_vector_args (frame);
u32 n_vectors = frame->n_vectors, n_left;
u16 n_sent;
struct pp2_ppio *ppio = mp->ppio;
struct pp2_hif *hif = md->hif[vm->thread_index];
struct pp2_ppio_desc descs[VLIB_FRAME_SIZE], *d = descs;
u16 sz = txq->size;
u16 mask = sz - 1;
if (mtq->n_enq)
{
u16 n_done = 0;
if (PREDICT_FALSE (pp2_ppio_get_num_outq_done (ppio, hif, qid, &n_done)))
vlib_error_count (vm, node->node_index,
MVPP2_TX_NODE_CTR_PPIO_GET_NUM_OUTQ_DONE, 1);
if (n_done)
{
vlib_buffer_free_from_ring (
vm, mtq->buffers, (mtq->next - mtq->n_enq) & mask, sz, n_done);
mtq->n_enq -= n_done;
}
}
n_sent = clib_min (n_vectors, sz - mtq->n_enq);
for (d = descs, n_left = n_sent; n_left; d++, buffers++, n_left--)
{
vlib_buffer_t *b0 = vlib_get_buffer (vm, buffers[0]);
u64 paddr = vlib_buffer_get_pa (vm, b0);
pp2_ppio_outq_desc_reset (d);
pp2_ppio_outq_desc_set_phys_addr (d, paddr + b0->current_data);
pp2_ppio_outq_desc_set_pkt_offset (d, 0);
pp2_ppio_outq_desc_set_pkt_len (d, b0->current_length);
}
buffers = vlib_frame_vector_args (frame);
if (pp2_ppio_send (ppio, hif, qid, descs, &n_sent))
{
n_sent = 0;
vlib_error_count (vm, node->node_index, MVPP2_TX_NODE_CTR_PPIO_SEND, 1);
}
else if (n_sent)
{
vlib_buffer_copy_indices_to_ring (mtq->buffers, buffers,
mtq->next & mask, sz, n_sent);
mtq->next += n_sent;
mtq->n_enq += n_sent;
}
/* free unsent buffers */
if (PREDICT_FALSE (n_sent != n_vectors))
{
vlib_buffer_free (vm, buffers + n_sent, n_vectors - n_sent);
vlib_error_count (vm, node->node_index, MVPP2_TX_NODE_CTR_NO_FREE_SLOTS,
n_vectors - n_sent);
}
return n_sent;
}

View File

@ -1,47 +0,0 @@
# Copyright (c) 2018 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
return()
endif()
find_path(MUSDK_INCLUDE_DIR NAMES mv_std.h)
find_library(MUSDK_LIB NAMES libmusdk.a)
if(MUSDK_INCLUDE_DIR AND MUSDK_LIB)
get_filename_component(MUSDK_LIB_DIR ${MUSDK_LIB} DIRECTORY)
set(MUSDK_LINK_FLAGS "-Wl,--whole-archive,${MUSDK_LIB_DIR}/libmusdk.a,--no-whole-archive")
add_vpp_plugin(marvell
SOURCES
plugin.c
pp2/cli.c
pp2/format.c
pp2/input.c
pp2/output.c
pp2/pp2.c
pp2/pp2_api.c
API_FILES
pp2/pp2.api
API_TEST_SOURCES
pp2/pp2_test.c
LINK_FLAGS
${MUSDK_LINK_FLAGS}
)
include_directories(${MUSDK_INCLUDE_DIR})
message(STATUS "Found Marvell MUSDK in ${MUSDK_INCLUDE_DIR}")
else()
message(WARNING "Marvell MUSDK not found - marvell_plugin disabled")
endif()

View File

@ -1,85 +0,0 @@
Marvell device plugin
=====================
Overview
--------
This plugins provides native device support for Marvell PP2 network
device, by use of Marvell Usermode SDK
(`MUSDK <https://github.com/MarvellEmbeddedProcessors/musdk-marvell>`__).
Code is developed and tested on
`MACCHIATObin <http://macchiatobin.net>`__ board.
Prerequisites
-------------
Plugins depends on installed MUSDK and Marvell provided linux
`kernel <https://github.com/MarvellEmbeddedProcessors/linux-marvell>`__
with MUSDK provided kernel patches (see ``patches/linux`` in musdk repo
and relevant documentation. Kernel version used: **4.14.22
armada-18.09.3** MUSDK version used: **armada-18.09.3** Following kernel
modules from MUSDK must be loaded for plugin to work: \*
``musdk_cma.ko`` \* ``mv_pp_uio.ko``
Musdk 18.09.3 compilation steps
-------------------------------
::
./bootstrap
./configure --prefix=/opt/vpp/external/aarch64/ CFLAGS="-Wno-error=unused-result -g -fPIC" --enable-shared=no
sed -i -e 's/marvell,mv-pp-uio/generic-uio/' modules/pp2/mv_pp_uio.c
sed -i -e 's/O_CREAT/O_CREAT, S_IRUSR | S_IWUSR/' src/lib/file_utils.c
make
sudo make install
Usage
-----
Interface Creation
~~~~~~~~~~~~~~~~~~
Interfaces are dynamically created with following CLI:
::
create interface marvell pp2 name eth0
set interface state mv-ppio-0/0 up
Where ``eth0`` is linux interface name and ``mv-ppio-X/Y`` is VPP
interface name where X is PP2 device ID and Y is PPIO ID Interface needs
to be assigned to MUSDK in FDT configuration and linux interface state
must be up.
Interface Deletion
~~~~~~~~~~~~~~~~~~
Interface can be deleted with following CLI:
::
delete interface marvell pp2 <interface name>
Interface Statistics
~~~~~~~~~~~~~~~~~~~~
Interface statistics can be displayed with
``sh hardware-interface mv-ppio0/0`` command.
Interaction with DPDK plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This plugin doesnt have any dependency on DPDK or DPDK plugin but it
can work with DPDK plugin enabled or disabled. It is observed that
performance is better around 30% when DPDK plugin is disabled, as DPDK
plugin registers own buffer manager, which needs to deal with additional
metadata in each packet.
DPKD plugin can be disabled by adding following config to the
startup.conf.
::
plugins {
dpdk_plugin.so { disable }
}

View File

@ -1,33 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <vlib/vlib.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "Marvell PP2 Device Driver",
};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -1,135 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <stdint.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/ethernet/ethernet.h>
#include <marvell/pp2/pp2.h>
static clib_error_t *
mrvl_pp2_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
mrvl_pp2_create_if_args_t args = { 0 };
unsigned int val;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "name %s", &args.name))
;
else if (unformat (line_input, "rx-queue-size %u", &val))
args.rx_q_sz = val;
else if (unformat (line_input, "tx-queue-size %u", &val))
args.tx_q_sz = val;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
unformat_free (line_input);
mrvl_pp2_create_if (&args);
vec_free (args.name);
return args.error;
}
VLIB_CLI_COMMAND (mrvl_pp2_create_command, static) = {
.path = "create interface marvell pp2",
.short_help = "create interface marvell pp2 [name <ifname>] [rx-queue-size slots] [tx-queue-size slots]",
.function = mrvl_pp2_create_command_fn,
};
static clib_error_t *
mrvl_pp2_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
u32 sw_if_index = ~0;
vnet_hw_interface_t *hw;
mrvl_pp2_main_t *mm = &mrvl_pp2_main;
mrvl_pp2_if_t *dif;
vnet_main_t *vnm = vnet_get_main ();
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "sw_if_index %d", &sw_if_index))
;
else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
vnm, &sw_if_index))
;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
unformat_free (line_input);
if (sw_if_index == ~0)
return clib_error_return (0,
"please specify interface name or sw_if_index");
hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
if (hw == NULL || mrvl_pp2_device_class.index != hw->dev_class_index)
return clib_error_return (0, "not a Marvell PP2 interface");
dif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
mrvl_pp2_delete_if (dif);
return 0;
}
VLIB_CLI_COMMAND (mrvl_pp2_delete_command, static) = {
.path = "delete interface marvell pp2",
.short_help = "delete interface marvell pp2 "
"{<interface> | sw_if_index <sw_idx>}",
.function = mrvl_pp2_delete_command_fn,
};
clib_error_t *
mrvl_pp2_cli_init (vlib_main_t * vm)
{
/* initialize binary API */
mrvl_pp2_plugin_api_hookup (vm);
return 0;
}
VLIB_INIT_FUNCTION (mrvl_pp2_cli_init);
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -1,200 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/plugin/plugin.h>
#include <marvell/pp2/pp2.h>
static inline u32
mrvl_get_u32_bits (void *start, int offset, int first, int last)
{
u32 value = *(u32 *) (((u8 *) start) + offset);
if ((last == 0) && (first == 31))
return value;
value >>= last;
value &= (1 << (first - last + 1)) - 1;
return value;
}
u8 *
format_mrvl_pp2_interface_name (u8 * s, va_list * args)
{
mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
u32 dev_instance = va_arg (*args, u32);
mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, dev_instance);
return format (s, "mv-ppio-%d/%d", ppif->ppio->pp2_id, ppif->ppio->port_id);
}
#define foreach_ppio_statistics_entry \
_(rx_packets) \
_(rx_fullq_dropped) \
_(rx_bm_dropped) \
_(rx_early_dropped) \
_(rx_fifo_dropped) \
_(rx_cls_dropped) \
_(tx_packets)
#define foreach_ppio_inq_statistics_entry \
_(enq_desc) \
_(drop_early) \
_(drop_fullq) \
_(drop_bm)
#define foreach_ppio_outq_statistics_entry \
_(enq_desc) \
_(enq_dec_to_ddr) \
_(enq_buf_to_ddr) \
_(deq_desc)
u8 *
format_mrvl_pp2_interface (u8 * s, va_list * args)
{
mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
u32 dev_instance = va_arg (*args, u32);
u32 indent = format_get_indent (s);
mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, dev_instance);
struct pp2_ppio_statistics stat;
int i;
u8 *s2 = 0;
pp2_ppio_get_statistics (ppif->ppio, &stat, 0);
#define _(c) if (stat.c) \
s2 = format (s2, "\n%U%-25U%16Ld", \
format_white_space, indent + 2, \
format_c_identifier, #c, stat.c);
foreach_ppio_statistics_entry;
if (vec_len (s2))
s = format (s, "Interface statistics:%v", s2);
vec_reset_length (s2);
vec_foreach_index (i, ppif->inqs)
{
struct pp2_ppio_inq_statistics stat = { 0 };
pp2_ppio_inq_get_statistics (ppif->ppio, 0, i, &stat, 0);
foreach_ppio_inq_statistics_entry;
if (vec_len (s2))
s = format (s, "\n%UInput queue %u statistics:%v",
format_white_space, indent, i, s2);
vec_reset_length (s2);
}
vec_foreach_index (i, ppif->outqs)
{
struct pp2_ppio_outq_statistics stat = { 0 };
pp2_ppio_outq_get_statistics (ppif->ppio, i, &stat, 0);
foreach_ppio_outq_statistics_entry;
if (vec_len (s2))
s = format (s, "\n%UOutput queue %u statistics:%v",
format_white_space, indent, i, s2);
vec_reset_length (s2);
}
#undef _
vec_free (s2);
return s;
}
#define foreach_pp2_rx_desc_field \
_(0x00, 6, 0, l3_offset) \
_(0x00, 12, 8, ip_hdlen) \
_(0x00, 14, 13, ec) \
_(0x00, 15, 15, es) \
_(0x00, 19, 16, pool_id) \
_(0x00, 21, 21, hwf_sync) \
_(0x00, 22, 22, l4_chk_ok) \
_(0x00, 23, 23, ip_frg) \
_(0x00, 24, 24, ipv4_hdr_err) \
_(0x00, 27, 25, l4_info) \
_(0x00, 30, 28, l3_info) \
_(0x00, 31, 31, buf_header) \
_(0x04, 5, 0, lookup_id) \
_(0x04, 8, 6, cpu_code) \
_(0x04, 9, 9, pppoe) \
_(0x04, 11, 10, l3_cast_info) \
_(0x04, 13, 12, l2_cast_info) \
_(0x04, 15, 14, vlan_info) \
_(0x04, 31, 16, byte_count) \
_(0x08, 11, 0, gem_port_id) \
_(0x08, 13, 12, color) \
_(0x08, 14, 14, gop_sop_u) \
_(0x08, 15, 15, key_hash_enable) \
_(0x08, 31, 16, l4chk) \
_(0x0c, 31, 0, timestamp) \
_(0x10, 31, 0, buf_phys_ptr_lo) \
_(0x14, 7, 0, buf_phys_ptr_hi) \
_(0x14, 31, 8, key_hash) \
_(0x18, 31, 0, buf_virt_ptr_lo) \
_(0x1c, 7, 0, buf_virt_ptr_hi) \
_(0x1c, 14, 8, buf_qset_no) \
_(0x1c, 15, 15, buf_type) \
_(0x1c, 21, 16, mod_dscp) \
_(0x1c, 24, 22, mod_pri) \
_(0x1c, 25, 25, mdscp) \
_(0x1c, 26, 26, mpri) \
_(0x1c, 27, 27, mgpid) \
_(0x1c, 31, 29, port_num)
u8 *
format_mrvl_pp2_input_trace (u8 * s, va_list * args)
{
vlib_main_t *vm = va_arg (*args, vlib_main_t *);
vlib_node_t *node = va_arg (*args, vlib_node_t *);
mrvl_pp2_input_trace_t *t = va_arg (*args, mrvl_pp2_input_trace_t *);
vnet_main_t *vnm = vnet_get_main ();
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, t->hw_if_index);
u32 indent = format_get_indent (s);
struct pp2_ppio_desc *d = &t->desc;
u32 r32;
s = format (s, "pp2: %v (%d) next-node %U",
hi->name, t->hw_if_index, format_vlib_next_node_name, vm,
node->index, t->next_index);
s = format (s, "\n%U", format_white_space, indent + 2);
#define _(a, b, c, n) \
r32 = mrvl_get_u32_bits (d, a, b, c); \
if (r32 > 9) \
s = format (s, "%s %u (0x%x)", #n, r32, r32); \
else \
s = format (s, "%s %u", #n,r32); \
if (format_get_indent (s) > 72) \
s = format (s, "\n%U", format_white_space, indent + 2); \
else s = format (s, " ");
foreach_pp2_rx_desc_field;
#undef _
return s;
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,121 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <stdint.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/ethernet/ethernet.h>
#include <vnet/devices/devices.h>
#include <marvell/pp2/pp2.h>
uword
mrvl_pp2_interface_tx (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, rd->dev_instance);
u32 thread_index = vm->thread_index;
mrvl_pp2_per_thread_data_t *ptd =
vec_elt_at_index (ppm->per_thread_data, thread_index);
u8 qid = thread_index;
mrvl_pp2_outq_t *outq = vec_elt_at_index (ppif->outqs, qid);
u32 *buffers = vlib_frame_vector_args (frame);
u16 n_desc = frame->n_vectors, n_left = n_desc, n_sent = n_desc, n_done;
struct pp2_ppio_desc *d;
u16 mask = outq->size - 1;
if (PREDICT_FALSE (pp2_ppio_get_num_outq_done (ppif->ppio, ptd->hif, qid,
&n_done)))
{
n_done = 0;
vlib_error_count (vm, node->node_index,
MRVL_PP2_TX_ERROR_PPIO_GET_NUM_OUTQ_DONE, 1);
}
if (n_done)
{
u16 n_free = clib_min (n_done, outq->size - (outq->tail & mask));
vlib_buffer_free (vm, outq->buffers + (outq->tail & mask), n_free);
if (PREDICT_FALSE (n_free < n_done))
vlib_buffer_free (vm, outq->buffers, n_done - n_free);
outq->tail += n_done;
}
vec_validate_aligned (ptd->descs, n_left, CLIB_CACHE_LINE_BYTES);
d = ptd->descs;
while (n_left)
{
u32 bi0 = buffers[0];
vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
u64 paddr = vlib_buffer_get_pa (vm, b0);
pp2_ppio_outq_desc_reset (d);
pp2_ppio_outq_desc_set_phys_addr (d, paddr + b0->current_data);
pp2_ppio_outq_desc_set_pkt_offset (d, 0);
pp2_ppio_outq_desc_set_pkt_len (d, b0->current_length);
d++;
buffers++;
n_left--;
}
if (pp2_ppio_send (ppif->ppio, ptd->hif, qid, ptd->descs, &n_sent))
{
n_sent = 0;
vlib_error_count (vm, node->node_index, MRVL_PP2_TX_ERROR_PPIO_SEND, 1);
}
/* free unsent buffers */
if (PREDICT_FALSE (n_sent != n_desc))
{
vlib_buffer_free (vm, vlib_frame_vector_args (frame) + n_sent,
frame->n_vectors - n_sent);
vlib_error_count (vm, node->node_index, MRVL_PP2_TX_ERROR_NO_FREE_SLOTS,
frame->n_vectors - n_sent);
}
/* store buffer index for each enqueued packet into the ring
so we can know what to free after packet is sent */
if (n_sent)
{
u16 slot = outq->head & mask;
buffers = vlib_frame_vector_args (frame);
u16 n_copy = clib_min (outq->size - slot, n_sent);
vlib_buffer_copy_indices (outq->buffers + slot, buffers, n_copy);
if (PREDICT_FALSE (n_copy < n_sent))
clib_memcpy_fast (outq->buffers, buffers + n_copy,
(n_sent - n_copy) * sizeof (u32));
outq->head += n_sent;
}
return n_sent;
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#define MVCONF_DBG_LEVEL 0
#define MVCONF_PP2_BPOOL_COOKIE_SIZE 32
#define MVCONF_PP2_BPOOL_DMA_ADDR_SIZE 64
#define MVCONF_DMA_PHYS_ADDR_T_SIZE 64
#define MVCONF_SYS_DMA_UIO
#define MVCONF_TYPES_PUBLIC
#define MVCONF_DMA_PHYS_ADDR_T_PUBLIC
#include <vlib/vlib.h>
#include "mv_std.h"
#include "env/mv_sys_dma.h"
#include "drivers/mv_pp2.h"
#include <drivers/mv_pp2_bpool.h>
#include <drivers/mv_pp2_ppio.h>
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
u16 size;
u32 queue_index;
struct pp2_bpool *bpool;
} mrvl_pp2_inq_t;
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
u16 size;
u32 *buffers;
u16 head;
u16 tail;
} mrvl_pp2_outq_t;
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
u32 flags;
#define MRVL_PP2_IF_F_ADMIN_UP (1 << 0)
struct pp2_ppio *ppio;
u32 per_interface_next_index;
mrvl_pp2_inq_t *inqs;
mrvl_pp2_outq_t *outqs;
u32 dev_instance;
u32 sw_if_index;
u32 hw_if_index;
} mrvl_pp2_if_t;
#define MRVL_PP2_BUFF_BATCH_SZ VLIB_FRAME_SIZE
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
struct pp2_hif *hif;
struct pp2_ppio_desc *descs;
struct buff_release_entry bre[MRVL_PP2_BUFF_BATCH_SZ];
u32 buffers[VLIB_FRAME_SIZE];
} mrvl_pp2_per_thread_data_t;
typedef struct
{
mrvl_pp2_if_t *interfaces;
mrvl_pp2_per_thread_data_t *per_thread_data;
/* API message ID base */
u16 msg_id_base;
} mrvl_pp2_main_t;
extern vnet_device_class_t mrvl_pp2_device_class;
extern mrvl_pp2_main_t mrvl_pp2_main;
typedef struct
{
u8 *name;
u16 rx_q_sz;
u16 tx_q_sz;
/* return */
i32 rv;
u32 sw_if_index;
clib_error_t *error;
} mrvl_pp2_create_if_args_t;
void mrvl_pp2_create_if (mrvl_pp2_create_if_args_t * args);
void mrvl_pp2_delete_if (mrvl_pp2_if_t * dfif);
clib_error_t *mrvl_pp2_plugin_api_hookup (vlib_main_t * vm);
/* output.c */
#define foreach_mrvl_pp2_tx_func_error \
_(NO_FREE_SLOTS, "no free tx slots") \
_(PPIO_SEND, "pp2_ppio_send errors") \
_(PPIO_GET_NUM_OUTQ_DONE, "pp2_ppio_get_num_outq_done errors")
typedef enum
{
#define _(f,s) MRVL_PP2_TX_ERROR_##f,
foreach_mrvl_pp2_tx_func_error
#undef _
MRVL_PP2_TX_N_ERROR,
} mrvl_pp2_tx_func_error_t;
uword mrvl_pp2_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame);
/* input.c */
typedef struct
{
u32 next_index;
u32 hw_if_index;
struct pp2_ppio_desc desc;
} mrvl_pp2_input_trace_t;
extern vlib_node_registration_t mrvl_pp2_input_node;
/* format.c */
format_function_t format_mrvl_pp2_input_trace;
format_function_t format_mrvl_pp2_interface;
format_function_t format_mrvl_pp2_interface_name;
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -1,100 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2019 Arm Limited.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/ethernet/ethernet.h>
#include <marvell/pp2/pp2.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
/* define message IDs */
#include <marvell/pp2/pp2.api_enum.h>
#include <marvell/pp2/pp2.api_types.h>
#define REPLY_MSG_ID_BASE (pp2->msg_id_base)
#include <vlibapi/api_helper_macros.h>
static void
vl_api_mrvl_pp2_create_t_handler (vl_api_mrvl_pp2_create_t * mp)
{
mrvl_pp2_main_t *pp2 = &mrvl_pp2_main;
mrvl_pp2_create_if_args_t args = { 0 };
vl_api_mrvl_pp2_create_reply_t *rmp;
int rv;
args.name = format (0, "%s", mp->if_name);
args.rx_q_sz = ntohs (mp->rx_q_sz);
args.tx_q_sz = ntohs (mp->tx_q_sz);
mrvl_pp2_create_if (&args);
rv = args.rv;
vec_free (args.name);
if (args.error)
{
clib_error_free (args.error);
}
REPLY_MACRO2 (VL_API_MRVL_PP2_CREATE_REPLY,
({ rmp->sw_if_index = ntohl (args.sw_if_index); }));
}
static void
vl_api_mrvl_pp2_delete_t_handler (vl_api_mrvl_pp2_delete_t * mp)
{
vnet_main_t *vnm = vnet_get_main ();
vnet_hw_interface_t *hw;
mrvl_pp2_main_t *pp2 = &mrvl_pp2_main;
vl_api_mrvl_pp2_delete_reply_t *rmp;
mrvl_pp2_if_t *dif;
int rv = 0;
mp->sw_if_index = ntohl (mp->sw_if_index);
hw = vnet_get_sup_hw_interface (vnm, mp->sw_if_index);
if (hw == NULL || mrvl_pp2_device_class.index != hw->dev_class_index)
{
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
goto reply;
}
dif = pool_elt_at_index (pp2->interfaces, hw->dev_instance);
mrvl_pp2_delete_if (dif);
reply:
REPLY_MACRO (VL_API_MRVL_PP2_DELETE_REPLY);
}
#include <marvell/pp2/pp2.api.c>
/* set up the API message handling tables */
clib_error_t *
mrvl_pp2_plugin_api_hookup (vlib_main_t * vm)
{
mrvl_pp2_main_t *pp2 = &mrvl_pp2_main;
/* ask for a correctly-sized block of API message decode slots */
pp2->msg_id_base = setup_message_id_table ();
return 0;
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -1,144 +0,0 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2019 Arm Limited.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <vnet/ethernet/ethernet.h>
#include <vat/vat.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vppinfra/error.h>
#include <marvell/pp2/pp2.h>
#define __plugin_msg_base pp2_test_main.msg_id_base
#include <vlibapi/vat_helper_macros.h>
/* declare message IDs */
#include <marvell/pp2/pp2.api_enum.h>
#include <marvell/pp2/pp2.api_types.h>
typedef struct
{
/* API message ID base */
u16 msg_id_base;
vat_main_t *vat_main;
} pp2_test_main_t;
pp2_test_main_t pp2_test_main;
/* mrvl_pp2 create API */
static int
api_mrvl_pp2_create (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
vl_api_mrvl_pp2_create_t *mp;
mrvl_pp2_create_if_args_t args;
int ret;
u16 size;
clib_memset (&args, 0, sizeof (mrvl_pp2_create_if_args_t));
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "name %s", &args.name))
;
else if (unformat (i, "rx-queue-size %u", &size))
args.rx_q_sz = size;
else if (unformat (i, "tx-queue-size %u", &size))
args.tx_q_sz = size;
else
{
clib_warning ("unknown input '%U'", format_unformat_error, i);
return -99;
}
}
M (MRVL_PP2_CREATE, mp);
strncpy_s ((char *) mp->if_name, ARRAY_LEN (mp->if_name),
(char *) (args.name), strlen ((char *) args.name));
mp->rx_q_sz = clib_host_to_net_u16 (args.rx_q_sz);
mp->tx_q_sz = clib_host_to_net_u16 (args.tx_q_sz);
S (mp);
W (ret);
vec_free (args.name);
return ret;
}
/* mrvl_pp2 create reply handler */
static void
vl_api_mrvl_pp2_create_reply_t_handler (vl_api_mrvl_pp2_create_reply_t * mp)
{
vat_main_t *vam = pp2_test_main.vat_main;
i32 retval = ntohl (mp->retval);
if (retval == 0)
{
fformat (vam->ofp, "created mrvl_pp2 with sw_if_index %d\n",
ntohl (mp->sw_if_index));
}
vam->retval = retval;
vam->result_ready = 1;
vam->regenerate_interface_table = 1;
}
/* mrvl_pp2 delete API */
static int
api_mrvl_pp2_delete (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
//vnet_main_t *vnm = vnet_get_main ();
vl_api_mrvl_pp2_delete_t *mp;
u32 sw_if_index = 0;
int ret;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "sw_if_index %d", &sw_if_index))
;
else
{
clib_warning ("unknown input '%U'", format_unformat_error, i);
return -99;
}
}
M (MRVL_PP2_DELETE, mp);
mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
S (mp);
W (ret);
return ret;
}
#include <marvell/pp2/pp2.api_test.c>
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

View File

@ -41,6 +41,7 @@
_ (UNSUPPORTED_DEVICE, "unsupported device") \
_ (UNSUPPORTED_DEVICE_VER, "unsupported device version") \
_ (ALREADY_DONE, "already done") \
_ (NO_SUCH_INTERFACE, "no such interface")
_ (NO_SUCH_INTERFACE, "no such interface") \
_ (INIT_FAILED, "init failed")
#endif /* _VNET_DEV_ERRORS_H_ */