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:
parent
1f7d14c810
commit
4e51841896
@ -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
|
||||
|
1
docs/developer/plugins/dev_armada.rst
Symbolic link
1
docs/developer/plugins/dev_armada.rst
Symbolic link
@ -0,0 +1 @@
|
||||
../../../src/plugins/dev_armada/README.rst
|
@ -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
|
||||
|
@ -1 +0,0 @@
|
||||
../../../src/plugins/marvell/README.rst
|
30
src/plugins/dev_armada/CMakeLists.txt
Normal file
30
src/plugins/dev_armada/CMakeLists.txt
Normal 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})
|
||||
|
61
src/plugins/dev_armada/README.rst
Normal file
61
src/plugins/dev_armada/README.rst
Normal 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
|
||||
|
||||
|
22
src/plugins/dev_armada/musdk.h
Normal file
22
src/plugins/dev_armada/musdk.h
Normal 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_ */
|
12
src/plugins/dev_armada/plugin.c
Normal file
12
src/plugins/dev_armada/plugin.c
Normal 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",
|
||||
};
|
176
src/plugins/dev_armada/pp2/format.c
Normal file
176
src/plugins/dev_armada/pp2/format.c
Normal 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;
|
||||
}
|
343
src/plugins/dev_armada/pp2/init.c
Normal file
343
src/plugins/dev_armada/pp2/init.c
Normal file
File diff suppressed because it is too large
Load Diff
280
src/plugins/dev_armada/pp2/port.c
Normal file
280
src/plugins/dev_armada/pp2/port.c
Normal 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;
|
||||
}
|
144
src/plugins/dev_armada/pp2/pp2.h
Normal file
144
src/plugins/dev_armada/pp2/pp2.h
Normal 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_ */
|
48
src/plugins/dev_armada/pp2/queue.c
Normal file
48
src/plugins/dev_armada/pp2/queue.c
Normal 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;
|
||||
}
|
||||
}
|
158
src/plugins/dev_armada/pp2/rx.c
Normal file
158
src/plugins/dev_armada/pp2/rx.c
Normal 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;
|
||||
}
|
83
src/plugins/dev_armada/pp2/tx.c
Normal file
83
src/plugins/dev_armada/pp2/tx.c
Normal 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;
|
||||
}
|
@ -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()
|
@ -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 doesn’t 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 }
|
||||
}
|
@ -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:
|
||||
*/
|
@ -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:
|
||||
*/
|
@ -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
@ -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
@ -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:
|
||||
*/
|
@ -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:
|
||||
*/
|
@ -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:
|
||||
*/
|
@ -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_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user