diff options
Diffstat (limited to 'src/plugins/dev_octeon/init.c')
-rw-r--r-- | src/plugins/dev_octeon/init.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/plugins/dev_octeon/init.c b/src/plugins/dev_octeon/init.c new file mode 100644 index 00000000000..bee449f2123 --- /dev/null +++ b/src/plugins/dev_octeon/init.c @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2023 Cisco Systems, Inc. + */ + +#include <vnet/vnet.h> +#include <vnet/dev/dev.h> +#include <vnet/dev/pci.h> +#include <vnet/dev/counters.h> +#include <vnet/ethernet/ethernet.h> +#include <vnet/plugin/plugin.h> +#include <vpp/app/version.h> +#include <dev_octeon/octeon.h> + +#include <base/roc_api.h> +#include <common.h> + +struct roc_model oct_model; + +VLIB_REGISTER_LOG_CLASS (oct_log, static) = { + .class_name = "octeon", + .subclass_name = "init", +}; + +#define _(f, n, s, d) \ + { .name = #n, .desc = d, .severity = VL_COUNTER_SEVERITY_##s }, + +vlib_error_desc_t oct_tx_node_counters[] = { foreach_oct_tx_node_counter }; +#undef _ + +vnet_dev_node_t oct_rx_node = { + .format_trace = format_oct_rx_trace, +}; + +vnet_dev_node_t oct_tx_node = { + .format_trace = format_oct_tx_trace, + .error_counters = oct_tx_node_counters, + .n_error_counters = ARRAY_LEN (oct_tx_node_counters), +}; + +static struct +{ + u16 device_id; + oct_device_type_t type; + char *description; +} oct_dev_types[] = { + +#define _(id, device_type, desc) \ + { \ + .device_id = (id), .type = OCT_DEVICE_TYPE_##device_type, \ + .description = (desc) \ + } + + _ (0xa063, RVU_PF, "Marvell Octeon Resource Virtualization Unit PF"), + _ (0xa0f3, CPT_VF, "Marvell Octeon Cryptographic Accelerator Unit VF"), +#undef _ +}; + +static u8 * +oct_probe (vlib_main_t *vm, vnet_dev_bus_index_t bus_index, void *dev_info) +{ + vnet_dev_bus_pci_device_info_t *di = dev_info; + + if (di->vendor_id != 0x177d) /* Cavium */ + return 0; + + FOREACH_ARRAY_ELT (dt, oct_dev_types) + { + if (dt->device_id == di->device_id) + return format (0, "%s", dt->description); + } + + return 0; +} + +vnet_dev_rv_t +cnx_return_roc_err (vnet_dev_t *dev, int rrv, char *fmt, ...) +{ + va_list va; + va_start (va, fmt); + u8 *s = va_format (0, fmt, &va); + va_end (va); + + log_err (dev, "%v: %s [%d]", s, roc_error_msg_get (rrv), rrv); + vec_free (s); + + return VNET_DEV_ERR_UNSUPPORTED_DEVICE; +} + +static vnet_dev_rv_t +oct_alloc (vlib_main_t *vm, vnet_dev_t *dev) +{ + oct_device_t *cd = vnet_dev_get_data (dev); + cd->nix = + clib_mem_alloc_aligned (sizeof (struct roc_nix), CLIB_CACHE_LINE_BYTES); + return VNET_DEV_OK; +} + +static vnet_dev_rv_t +oct_init_nix (vlib_main_t *vm, vnet_dev_t *dev) +{ + oct_device_t *cd = vnet_dev_get_data (dev); + u8 mac_addr[6]; + int rrv; + oct_port_t oct_port = {}; + + *cd->nix = (struct roc_nix){ + .reta_sz = ROC_NIX_RSS_RETA_SZ_256, + .max_sqb_count = 512, + .pci_dev = &cd->plt_pci_dev, + }; + + if ((rrv = roc_nix_dev_init (cd->nix))) + return cnx_return_roc_err (dev, rrv, "roc_nix_dev_init"); + + if (roc_nix_npc_mac_addr_get (cd->nix, mac_addr)) + return cnx_return_roc_err (dev, rrv, "roc_nix_npc_mac_addr_get"); + + vnet_dev_port_add_args_t port_add_args = { + .port = { + .attr = { + .type = VNET_DEV_PORT_TYPE_ETHERNET, + .max_rx_queues = 64, + .max_tx_queues = 64, + .max_supported_rx_frame_size = roc_nix_max_pkt_len (cd->nix), + .caps = { + .rss = 1, + }, + .rx_offloads = { + .ip4_cksum = 1, + }, + }, + .ops = { + .init = oct_port_init, + .deinit = oct_port_deinit, + .start = oct_port_start, + .stop = oct_port_stop, + .config_change = oct_port_cfg_change, + .format_status = format_oct_port_status, + }, + .data_size = sizeof (oct_port_t), + .initial_data = &oct_port, + }, + .rx_node = &oct_rx_node, + .tx_node = &oct_tx_node, + .rx_queue = { + .config = { + .data_size = sizeof (oct_rxq_t), + .default_size = 1024, + .multiplier = 32, + .min_size = 256, + .max_size = 16384, + }, + .ops = { + .alloc = oct_rx_queue_alloc, + .free = oct_rx_queue_free, + .format_info = format_oct_rxq_info, + }, + }, + .tx_queue = { + .config = { + .data_size = sizeof (oct_txq_t), + .default_size = 1024, + .multiplier = 32, + .min_size = 256, + .max_size = 16384, + }, + .ops = { + .alloc = oct_tx_queue_alloc, + .free = oct_tx_queue_free, + .format_info = format_oct_txq_info, + }, + }, + }; + + vnet_dev_set_hw_addr_eth_mac (&port_add_args.port.attr.hw_addr, mac_addr); + + log_info (dev, "MAC address is %U", format_ethernet_address, mac_addr); + + return vnet_dev_port_add (vm, dev, 0, &port_add_args); +} + +static vnet_dev_rv_t +oct_init_cpt (vlib_main_t *vm, vnet_dev_t *dev) +{ + oct_device_t *cd = vnet_dev_get_data (dev); + int rrv; + struct roc_cpt cpt = { + .pci_dev = &cd->plt_pci_dev, + }; + + if ((rrv = roc_cpt_dev_init (&cpt))) + return cnx_return_roc_err (dev, rrv, "roc_cpt_dev_init"); + return VNET_DEV_OK; +} + +static vnet_dev_rv_t +oct_init (vlib_main_t *vm, vnet_dev_t *dev) +{ + oct_device_t *cd = vnet_dev_get_data (dev); + vlib_pci_config_hdr_t pci_hdr; + vnet_dev_rv_t rv; + + rv = vnet_dev_pci_read_config_header (vm, dev, &pci_hdr); + if (rv != VNET_DEV_OK) + return rv; + + if (pci_hdr.vendor_id != 0x177d) + return VNET_DEV_ERR_UNSUPPORTED_DEVICE; + + FOREACH_ARRAY_ELT (dt, oct_dev_types) + { + if (dt->device_id == pci_hdr.device_id) + cd->type = dt->type; + } + + if (cd->type == OCT_DEVICE_TYPE_UNKNOWN) + return rv; + + rv = VNET_DEV_ERR_UNSUPPORTED_DEVICE; + + cd->plt_pci_dev = (struct plt_pci_device){ + .id.vendor_id = pci_hdr.vendor_id, + .id.device_id = pci_hdr.device_id, + .id.class_id = pci_hdr.class << 16 | pci_hdr.subclass, + .pci_handle = vnet_dev_get_pci_handle (dev), + }; + + foreach_int (i, 2, 4) + { + rv = vnet_dev_pci_map_region (vm, dev, i, + &cd->plt_pci_dev.mem_resource[i].addr); + if (rv != VNET_DEV_OK) + return rv; + } + + strncpy ((char *) cd->plt_pci_dev.name, dev->device_id, + sizeof (cd->plt_pci_dev.name) - 1); + + if (cd->type == OCT_DEVICE_TYPE_RVU_PF) + return oct_init_nix (vm, dev); + else if (cd->type == OCT_DEVICE_TYPE_CPT_VF) + return oct_init_cpt (vm, dev); + else + return VNET_DEV_ERR_UNSUPPORTED_DEVICE; + + return 0; +} + +static void +oct_deinit (vlib_main_t *vm, vnet_dev_t *dev) +{ + oct_device_t *cd = vnet_dev_get_data (dev); + + if (cd->nix_initialized) + roc_nix_dev_fini (cd->nix); +} + +static void +oct_free (vlib_main_t *vm, vnet_dev_t *dev) +{ + oct_device_t *cd = vnet_dev_get_data (dev); + + if (cd->nix_initialized) + roc_nix_dev_fini (cd->nix); +} + +VNET_DEV_REGISTER_DRIVER (octeon) = { + .name = "octeon", + .bus = "pci", + .device_data_sz = sizeof (oct_device_t), + .ops = { + .alloc = oct_alloc, + .init = oct_init, + .deinit = oct_deinit, + .free = oct_free, + .probe = oct_probe, + }, +}; + +static clib_error_t * +oct_plugin_init (vlib_main_t *vm) +{ + int rv; + extern oct_plt_init_param_t oct_plt_init_param; + + rv = oct_plt_init (&oct_plt_init_param); + if (rv) + return clib_error_return (0, "oct_plt_init failed"); + + rv = roc_model_init (&oct_model); + if (rv) + return clib_error_return (0, "roc_model_init failed"); + return 0; +} + +VLIB_INIT_FUNCTION (oct_plugin_init); + +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "dev_octeon", +}; |