numam-dpdk/drivers/regex/mlx5/mlx5_regex.c
Suanming Mou 330a70b773 regex/mlx5: add data path scattered mbuf process
UMR (User-Mode Memory Registration) WQE can present data buffers
scattered within multiple mbufs with single indirect mkey. Take
advantage of the UMR WQE, scattered mbuf in one operation can be
presented to an indirect mkey. The RegEx which only accepts one
mkey can now process the whole scattered mbuf in one operation.

The maximum scattered mbuf can be supported in one UMR WQE is now
defined as 64. The mbufs from multiple operations can be combined
into one UMR WQE as well if there is enough space in the KLM array,
since the operations can address their own mbuf's content by the
mkey's address and length. However, one operation's scattered mbuf's
can't be placed in two different UMR WQE's KLM array, if the UMR
WQE's KLM does not has enough free space for one operation, the
extra UMR WQE will be engaged.

In case the UMR WQE's indirect mkey will be over wrapped by the SQ's
WQE move, the mkey's index used by the UMR WQE should be the index
of last the RegEX WQE in the operations. As one operation consumes
one WQE set, build the RegEx WQE by reverse helps address the mkey
more efficiently. Once the operations in one burst consumes multiple
mkeys, when the mkey KLM array is full, the reverse WQE set index
will always be the last of the new mkey's for the new UMR WQE.

In GGA mode, the SQ WQE's memory layout becomes UMR/NOP and RegEx
WQE by interleave. The UMR and RegEx WQE can be called as WQE set.
The SQ's pi and ci will also be increased as WQE set not as WQE.

For operations don't have scattered mbuf, uses the mbuf's mkey directly,
the WQE set combination is NOP + RegEx.
For operations have scattered mbuf but share the UMR WQE with others,
the WQE set combination is NOP + RegEx.
For operations complete the UMR WQE, the WQE set combination is UMR +
RegEx.

Signed-off-by: John Hurley <jhurley@nvidia.com>
Signed-off-by: Suanming Mou <suanmingm@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
2021-04-08 22:52:55 +02:00

308 lines
7.7 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2020 Mellanox Technologies, Ltd
*/
#include <rte_malloc.h>
#include <rte_log.h>
#include <rte_errno.h>
#include <rte_pci.h>
#include <rte_regexdev.h>
#include <rte_regexdev_core.h>
#include <rte_regexdev_driver.h>
#include <mlx5_common_pci.h>
#include <mlx5_glue.h>
#include <mlx5_devx_cmds.h>
#include <mlx5_prm.h>
#include "mlx5_regex.h"
#include "mlx5_regex_utils.h"
#include "mlx5_rxp_csrs.h"
#define MLX5_REGEX_DRIVER_NAME regex_mlx5
#define MLX5_REGEX_LOG_NAME pmd.regex.mlx5
int mlx5_regex_logtype;
const struct rte_regexdev_ops mlx5_regexdev_ops = {
.dev_info_get = mlx5_regex_info_get,
.dev_configure = mlx5_regex_configure,
.dev_db_import = mlx5_regex_rules_db_import,
.dev_qp_setup = mlx5_regex_qp_setup,
.dev_start = mlx5_regex_start,
.dev_stop = mlx5_regex_stop,
.dev_close = mlx5_regex_close,
};
int
mlx5_regex_start(struct rte_regexdev *dev __rte_unused)
{
return 0;
}
int
mlx5_regex_stop(struct rte_regexdev *dev __rte_unused)
{
return 0;
}
int
mlx5_regex_close(struct rte_regexdev *dev __rte_unused)
{
return 0;
}
static struct ibv_device *
mlx5_regex_get_ib_device_match(struct rte_pci_addr *addr)
{
int n;
struct ibv_device **ibv_list = mlx5_glue->get_device_list(&n);
struct ibv_device *ibv_match = NULL;
if (!ibv_list) {
rte_errno = ENOSYS;
return NULL;
}
while (n-- > 0) {
struct rte_pci_addr pci_addr;
DRV_LOG(DEBUG, "Checking device \"%s\"..", ibv_list[n]->name);
if (mlx5_dev_to_pci_addr(ibv_list[n]->ibdev_path, &pci_addr))
continue;
if (rte_pci_addr_cmp(addr, &pci_addr))
continue;
ibv_match = ibv_list[n];
break;
}
if (!ibv_match)
rte_errno = ENOENT;
mlx5_glue->free_device_list(ibv_list);
return ibv_match;
}
static int
mlx5_regex_engines_status(struct ibv_context *ctx, int num_engines)
{
uint32_t fpga_ident = 0;
int err;
int i;
for (i = 0; i < num_engines; i++) {
err = mlx5_devx_regex_register_read(ctx, i,
MLX5_RXP_CSR_IDENTIFIER,
&fpga_ident);
fpga_ident = (fpga_ident & (0x0000FFFF));
if (err || fpga_ident != MLX5_RXP_IDENTIFIER) {
DRV_LOG(ERR, "Failed setup RXP %d err %d database "
"memory 0x%x", i, err, fpga_ident);
if (!err)
err = EINVAL;
return err;
}
}
return 0;
}
static void
mlx5_regex_get_name(char *name, struct rte_pci_device *pci_dev __rte_unused)
{
sprintf(name, "mlx5_regex_%02x:%02x.%02x", pci_dev->addr.bus,
pci_dev->addr.devid, pci_dev->addr.function);
}
static int
mlx5_regex_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
{
struct ibv_device *ibv;
struct mlx5_regex_priv *priv = NULL;
struct ibv_context *ctx = NULL;
struct mlx5_hca_attr attr;
char name[RTE_REGEXDEV_NAME_MAX_LEN];
int ret;
uint32_t val;
ibv = mlx5_regex_get_ib_device_match(&pci_dev->addr);
if (!ibv) {
DRV_LOG(ERR, "No matching IB device for PCI slot "
PCI_PRI_FMT ".", pci_dev->addr.domain,
pci_dev->addr.bus, pci_dev->addr.devid,
pci_dev->addr.function);
return -rte_errno;
}
DRV_LOG(INFO, "PCI information matches for device \"%s\".",
ibv->name);
ctx = mlx5_glue->dv_open_device(ibv);
if (!ctx) {
DRV_LOG(ERR, "Failed to open IB device \"%s\".", ibv->name);
rte_errno = ENODEV;
return -rte_errno;
}
ret = mlx5_devx_cmd_query_hca_attr(ctx, &attr);
if (ret) {
DRV_LOG(ERR, "Unable to read HCA capabilities.");
rte_errno = ENOTSUP;
goto dev_error;
} else if (!attr.regex || attr.regexp_num_of_engines == 0) {
DRV_LOG(ERR, "Not enough capabilities to support RegEx, maybe "
"old FW/OFED version?");
rte_errno = ENOTSUP;
goto dev_error;
}
if (mlx5_regex_engines_status(ctx, 2)) {
DRV_LOG(ERR, "RegEx engine error.");
rte_errno = ENOMEM;
goto dev_error;
}
priv = rte_zmalloc("mlx5 regex device private", sizeof(*priv),
RTE_CACHE_LINE_SIZE);
if (!priv) {
DRV_LOG(ERR, "Failed to allocate private memory.");
rte_errno = ENOMEM;
goto dev_error;
}
priv->sq_ts_format = attr.sq_ts_format;
priv->ctx = ctx;
priv->nb_engines = 2; /* attr.regexp_num_of_engines */
ret = mlx5_devx_regex_register_read(priv->ctx, 0,
MLX5_RXP_CSR_IDENTIFIER, &val);
if (ret) {
DRV_LOG(ERR, "CSR read failed!");
return -1;
}
if (val == MLX5_RXP_BF2_IDENTIFIER)
priv->is_bf2 = 1;
/* Default RXP programming mode to Shared. */
priv->prog_mode = MLX5_RXP_SHARED_PROG_MODE;
mlx5_regex_get_name(name, pci_dev);
priv->regexdev = rte_regexdev_register(name);
if (priv->regexdev == NULL) {
DRV_LOG(ERR, "Failed to register RegEx device.");
rte_errno = rte_errno ? rte_errno : EINVAL;
goto error;
}
/*
* This PMD always claims the write memory barrier on UAR
* registers writings, it is safe to allocate UAR with any
* memory mapping type.
*/
priv->uar = mlx5_devx_alloc_uar(ctx, -1);
if (!priv->uar) {
DRV_LOG(ERR, "can't allocate uar.");
rte_errno = ENOMEM;
goto error;
}
priv->pd = mlx5_glue->alloc_pd(ctx);
if (!priv->pd) {
DRV_LOG(ERR, "can't allocate pd.");
rte_errno = ENOMEM;
goto error;
}
priv->regexdev->dev_ops = &mlx5_regexdev_ops;
priv->regexdev->enqueue = mlx5_regexdev_enqueue;
#ifdef HAVE_MLX5_UMR_IMKEY
if (!attr.umr_indirect_mkey_disabled &&
!attr.umr_modify_entity_size_disabled)
priv->has_umr = 1;
if (priv->has_umr)
priv->regexdev->enqueue = mlx5_regexdev_enqueue_gga;
#endif
priv->regexdev->dequeue = mlx5_regexdev_dequeue;
priv->regexdev->device = (struct rte_device *)pci_dev;
priv->regexdev->data->dev_private = priv;
priv->regexdev->state = RTE_REGEXDEV_READY;
priv->mr_scache.reg_mr_cb = mlx5_common_verbs_reg_mr;
priv->mr_scache.dereg_mr_cb = mlx5_common_verbs_dereg_mr;
ret = mlx5_mr_btree_init(&priv->mr_scache.cache,
MLX5_MR_BTREE_CACHE_N * 2,
rte_socket_id());
if (ret) {
DRV_LOG(ERR, "MR init tree failed.");
rte_errno = ENOMEM;
goto error;
}
DRV_LOG(INFO, "RegEx GGA is %s.",
priv->has_umr ? "supported" : "unsupported");
return 0;
error:
if (priv->pd)
mlx5_glue->dealloc_pd(priv->pd);
if (priv->uar)
mlx5_glue->devx_free_uar(priv->uar);
if (priv->regexdev)
rte_regexdev_unregister(priv->regexdev);
dev_error:
if (ctx)
mlx5_glue->close_device(ctx);
if (priv)
rte_free(priv);
return -rte_errno;
}
static int
mlx5_regex_pci_remove(struct rte_pci_device *pci_dev)
{
char name[RTE_REGEXDEV_NAME_MAX_LEN];
struct rte_regexdev *dev;
struct mlx5_regex_priv *priv = NULL;
mlx5_regex_get_name(name, pci_dev);
dev = rte_regexdev_get_device_by_name(name);
if (!dev)
return 0;
priv = dev->data->dev_private;
if (priv) {
if (priv->pd)
mlx5_glue->dealloc_pd(priv->pd);
if (priv->uar)
mlx5_glue->devx_free_uar(priv->uar);
if (priv->regexdev)
rte_regexdev_unregister(priv->regexdev);
if (priv->ctx)
mlx5_glue->close_device(priv->ctx);
if (priv->regexdev)
rte_regexdev_unregister(priv->regexdev);
rte_free(priv);
}
return 0;
}
static const struct rte_pci_id mlx5_regex_pci_id_map[] = {
{
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
PCI_DEVICE_ID_MELLANOX_CONNECTX6DXBF)
},
{
RTE_PCI_DEVICE(PCI_VENDOR_ID_MELLANOX,
PCI_DEVICE_ID_MELLANOX_CONNECTX7BF)
},
{
.vendor_id = 0
}
};
static struct mlx5_pci_driver mlx5_regex_driver = {
.driver_class = MLX5_CLASS_REGEX,
.pci_driver = {
.driver = {
.name = RTE_STR(MLX5_REGEX_DRIVER_NAME),
},
.id_table = mlx5_regex_pci_id_map,
.probe = mlx5_regex_pci_probe,
.remove = mlx5_regex_pci_remove,
.drv_flags = 0,
},
};
RTE_INIT(rte_mlx5_regex_init)
{
mlx5_common_init();
if (mlx5_glue)
mlx5_pci_driver_register(&mlx5_regex_driver);
}
RTE_LOG_REGISTER(mlx5_regex_logtype, MLX5_REGEX_LOG_NAME, NOTICE)
RTE_PMD_EXPORT_NAME(MLX5_REGEX_DRIVER_NAME, __COUNTER__);
RTE_PMD_REGISTER_PCI_TABLE(MLX5_REGEX_DRIVER_NAME, mlx5_regex_pci_id_map);
RTE_PMD_REGISTER_KMOD_DEP(MLX5_REGEX_DRIVER_NAME, "* ib_uverbs & mlx5_core & mlx5_ib");