Show a patch.

GET /api/patches/74467/
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 74467,
    "url": "https://patches.dpdk.org/api/patches/74467/",
    "web_url": "https://patches.dpdk.org/patch/74467/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk"
    },
    "msgid": "<1595226378-81144-8-git-send-email-orika@mellanox.com>",
    "date": "2020-07-20T06:26:11",
    "name": "[v6,07/13] regex/mlx5: add program rules support",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "a368a52e0a53d28611f514153eca486d8207f980",
    "submitter": {
        "id": 795,
        "url": "https://patches.dpdk.org/api/people/795/",
        "name": "Ori Kam",
        "email": "orika@mellanox.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/patch/74467/mbox/",
    "series": [
        {
            "id": 11159,
            "url": "https://patches.dpdk.org/api/series/11159/",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=11159",
            "date": "2020-07-20T06:26:04",
            "name": "add Mellanox RegEx PMD",
            "version": 6,
            "mbox": "https://patches.dpdk.org/series/11159/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/74467/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/74467/checks/",
    "tags": {},
    "headers": {
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "List-Post": "<mailto:dev@dpdk.org>",
        "References": "<1593941027-86651-1-git-send-email-orika@mellanox.com>\n <1595226378-81144-1-git-send-email-orika@mellanox.com>",
        "X-BeenThere": "dev@dpdk.org",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "Subject": "[dpdk-dev] [PATCH v6 07/13] regex/mlx5: add program rules support",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "From": "Ori Kam <orika@mellanox.com>",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 2F1C2A0540;\n\tMon, 20 Jul 2020 08:27:53 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 780631BF0B;\n\tMon, 20 Jul 2020 08:26:55 +0200 (CEST)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n by dpdk.org (Postfix) with ESMTP id 6ACA31BEE3\n for <dev@dpdk.org>; Mon, 20 Jul 2020 08:26:48 +0200 (CEST)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n orika@mellanox.com) with SMTP; 20 Jul 2020 09:26:46 +0300",
            "from pegasus04.mtr.labs.mlnx. (pegasus04.mtr.labs.mlnx\n [10.210.16.126])\n by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 06K6QKuj008177;\n Mon, 20 Jul 2020 09:26:46 +0300"
        ],
        "To": "jerinj@marvell.com, xiang.w.wang@intel.com, matan@mellanox.com,\n viacheslavo@mellanox.com",
        "X-Mailer": "git-send-email 1.8.3.1",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Date": "Mon, 20 Jul 2020 06:26:11 +0000",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "In-Reply-To": "<1595226378-81144-1-git-send-email-orika@mellanox.com>",
        "Cc": "guyk@marvell.com, dev@dpdk.org, pbhagavatula@marvell.com,\n shahafs@mellanox.com, hemant.agrawal@nxp.com, opher@mellanox.com,\n alexr@mellanox.com, dovrat@marvell.com, pkapoor@marvell.com,\n nipun.gupta@nxp.com, bruce.richardson@intel.com, yang.a.hong@intel.com,\n harry.chang@intel.com, gu.jian1@zte.com.cn, shanjiangh@chinatelecom.cn,\n zhangy.yun@chinatelecom.cn, lixingfu@huachentel.com,\n wushuai@inspur.com, yuyingxia@yxlink.com, fanchenggang@sunyainfo.com,\n davidfgao@tencent.com, liuzhong1@chinaunicom.cn, zhaoyong11@huawei.com,\n oc@yunify.com, jim@netgate.com, hongjun.ni@intel.com, deri@ntop.org,\n fc@napatech.com, arthur.su@lionic.com, thomas@monjalon.net,\n orika@mellanox.com, rasland@mellanox.com,\n Francis Kelly <fkelly@mellanox.com>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Message-Id": "<1595226378-81144-8-git-send-email-orika@mellanox.com>",
        "Return-Path": "<dev-bounces@dpdk.org>"
    },
    "content": "From: Francis Kelly <fkelly@mellanox.com>\n\nThis commit introduce the ability to program rules to the\nRegEx engine.\n\nSigned-off-by: Francis Kelly <fkelly@mellanox.com>\nAcked-by: Ori Kam <orika@mellanox.com>\n\n---\n drivers/regex/mlx5/mlx5_regex.c      |  34 ++\n drivers/regex/mlx5/mlx5_regex.h      |  52 ++-\n drivers/regex/mlx5/mlx5_regex_devx.c |  67 +++\n drivers/regex/mlx5/mlx5_rxp.c        | 842 +++++++++++++++++++++++++++++++++--\n drivers/regex/mlx5/mlx5_rxp.h        | 138 ++++++\n 5 files changed, 1084 insertions(+), 49 deletions(-)\n create mode 100644 drivers/regex/mlx5/mlx5_rxp.h",
    "diff": "diff --git a/drivers/regex/mlx5/mlx5_regex.c b/drivers/regex/mlx5/mlx5_regex.c\nindex f834ac0..72da3e2 100644\n--- a/drivers/regex/mlx5/mlx5_regex.c\n+++ b/drivers/regex/mlx5/mlx5_regex.c\n@@ -26,6 +26,7 @@\n const struct rte_regexdev_ops mlx5_regexdev_ops = {\n \t.dev_info_get = mlx5_regex_info_get,\n \t.dev_configure = mlx5_regex_configure,\n+\t.dev_db_import = mlx5_regex_rules_db_import,\n };\n \n static struct ibv_device *\n@@ -136,6 +137,9 @@\n \t\tgoto error;\n \t}\n \tpriv->ctx = ctx;\n+\tpriv->nb_engines = 2; /* attr.regexp_num_of_engines */\n+\t/* Default RXP programming mode to Shared. */\n+\tpriv->prog_mode = MLX5_RXP_SHARED_PROG_MODE;\n \tmlx5_regex_get_name(name, pci_dev);\n \tpriv->regexdev = rte_regexdev_register(name);\n \tif (priv->regexdev == NULL) {\n@@ -143,6 +147,24 @@\n \t\trte_errno = rte_errno ? rte_errno : EINVAL;\n \t\tgoto error;\n \t}\n+\tret = mlx5_glue->devx_query_eqn(ctx, 0, &priv->eqn);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"can't query event queue number.\");\n+\t\trte_errno = ENOMEM;\n+\t\tgoto error;\n+\t}\n+\tpriv->uar = mlx5_glue->devx_alloc_uar(ctx, 0);\n+\tif (!priv->uar) {\n+\t\tDRV_LOG(ERR, \"can't allocate uar.\");\n+\t\trte_errno = ENOMEM;\n+\t\tgoto error;\n+\t}\n+\tpriv->pd = mlx5_glue->alloc_pd(ctx);\n+\tif (!priv->pd) {\n+\t\tDRV_LOG(ERR, \"can't allocate pd.\");\n+\t\trte_errno = ENOMEM;\n+\t\tgoto error;\n+\t}\n \tpriv->regexdev->dev_ops = &mlx5_regexdev_ops;\n \tpriv->regexdev->device = (struct rte_device *)pci_dev;\n \tpriv->regexdev->data->dev_private = priv;\n@@ -150,6 +172,12 @@\n \treturn 0;\n \n error:\n+\tif (priv->pd)\n+\t\tmlx5_glue->dealloc_pd(priv->pd);\n+\tif (priv->uar)\n+\t\tmlx5_glue->devx_free_uar(priv->uar);\n+\tif (priv->regexdev)\n+\t\trte_regexdev_unregister(priv->regexdev);\n \tif (ctx)\n \t\tmlx5_glue->close_device(ctx);\n \tif (priv)\n@@ -170,6 +198,12 @@\n \t\treturn 0;\n \tpriv = dev->data->dev_private;\n \tif (priv) {\n+\t\tif (priv->pd)\n+\t\t\tmlx5_glue->dealloc_pd(priv->pd);\n+\t\tif (priv->uar)\n+\t\t\tmlx5_glue->devx_free_uar(priv->uar);\n+\t\tif (priv->regexdev)\n+\t\t\trte_regexdev_unregister(priv->regexdev);\n \t\tif (priv->ctx)\n \t\t\tmlx5_glue->close_device(priv->ctx);\n \t\tif (priv->regexdev)\ndiff --git a/drivers/regex/mlx5/mlx5_regex.h b/drivers/regex/mlx5/mlx5_regex.h\nindex f17b4f8..a2d2c9e 100644\n--- a/drivers/regex/mlx5/mlx5_regex.h\n+++ b/drivers/regex/mlx5/mlx5_regex.h\n@@ -7,14 +7,47 @@\n \n #include <rte_regexdev.h>\n \n+#include <infiniband/verbs.h>\n+#include <infiniband/mlx5dv.h>\n+\n+#include <mlx5_common.h>\n+\n+#include \"mlx5_rxp.h\"\n+\n struct mlx5_regex_sq {\n-\tuint32_t nb_desc; /* Number of desc for this object. */\n+\tuint16_t log_nb_desc; /* Log 2 number of desc for this object. */\n+\tstruct mlx5_devx_obj *obj; /* The SQ DevX object. */\n+\tint64_t dbr_offset; /* Door bell record offset. */\n+\tuint32_t dbr_umem; /* Door bell record umem id. */\n+\tvolatile struct mlx5_cqe *wqe; /* The SQ ring buffer. */\n+\tstruct mlx5dv_devx_umem *wqe_umem; /* SQ buffer umem. */\n+};\n+\n+struct mlx5_regex_cq {\n+\tuint32_t log_nb_desc; /* Log 2 number of desc for this object. */\n+\tstruct mlx5_devx_obj *obj; /* The CQ DevX object. */\n+\tint64_t dbr_offset; /* Door bell record offset. */\n+\tuint32_t dbr_umem; /* Door bell record umem id. */\n+\tvolatile struct mlx5_cqe *cqe; /* The CQ ring buffer. */\n+\tstruct mlx5dv_devx_umem *cqe_umem; /* CQ buffer umem. */\n };\n \n struct mlx5_regex_qp {\n \tuint32_t flags; /* QP user flags. */\n \tuint32_t nb_desc; /* Total number of desc for this qp. */\n \tstruct mlx5_regex_sq *sqs; /* Pointer to sq array. */\n+\tuint16_t nb_obj; /* Number of sq objects. */\n+\tstruct mlx5_regex_cq cq; /* CQ struct. */\n+};\n+\n+struct mlx5_regex_db {\n+\tvoid *ptr; /* Pointer to the db memory. */\n+\tuint32_t len; /* The memory len. */\n+\tbool active; /* Active flag. */\n+\tuint8_t db_assigned_to_eng_num;\n+\t/**< To which engine the db is connected. */\n+\tstruct mlx5_regex_umem umem;\n+\t/**< The umem struct. */\n };\n \n struct mlx5_regex_priv {\n@@ -25,6 +58,14 @@ struct mlx5_regex_priv {\n \tuint16_t nb_queues; /* Number of queues. */\n \tstruct mlx5_regex_qp *qps; /* Pointer to the qp array. */\n \tuint16_t nb_max_matches; /* Max number of matches. */\n+\tenum mlx5_rxp_program_mode prog_mode;\n+\tstruct mlx5_regex_db db[MLX5_RXP_MAX_ENGINES +\n+\t\t\t\tMLX5_RXP_EM_COUNT];\n+\tuint32_t nb_engines; /* Number of RegEx engines. */\n+\tstruct mlx5_dbr_page_list dbrpgs; /* Door-bell pages. */\n+\tuint32_t eqn; /* EQ number. */\n+\tstruct mlx5dv_devx_uar *uar; /* UAR object. */\n+\tstruct ibv_pd *pd;\n };\n \n /* mlx5_rxp.c */\n@@ -32,11 +73,20 @@ int mlx5_regex_info_get(struct rte_regexdev *dev,\n \t\t\tstruct rte_regexdev_info *info);\n int mlx5_regex_configure(struct rte_regexdev *dev,\n \t\t\t const struct rte_regexdev_config *cfg);\n+int mlx5_regex_rules_db_import(struct rte_regexdev *dev,\n+\t\t\t       const char *rule_db, uint32_t rule_db_len);\n \n /* mlx5_regex_devx.c */\n int mlx5_devx_regex_register_write(struct ibv_context *ctx, int engine_id,\n \t\t\t\t   uint32_t addr, uint32_t data);\n int mlx5_devx_regex_register_read(struct ibv_context *ctx, int engine_id,\n \t\t\t\t  uint32_t addr, uint32_t *data);\n+int mlx5_devx_regex_database_stop(void *ctx, uint8_t engine);\n+int mlx5_devx_regex_database_resume(void *ctx, uint8_t engine);\n+int mlx5_devx_regex_database_program(void *ctx, uint8_t engine,\n+\t\t\t\t     uint32_t umem_id, uint64_t umem_offset);\n \n+/* mlx5_regex_control.c */\n+int mlx5_regex_qp_setup(struct rte_regexdev *dev, uint16_t qp_ind,\n+\t\t\tconst struct rte_regexdev_qp_conf *cfg);\n #endif /* MLX5_REGEX_H */\ndiff --git a/drivers/regex/mlx5/mlx5_regex_devx.c b/drivers/regex/mlx5/mlx5_regex_devx.c\nindex 1ffc008..2199687 100644\n--- a/drivers/regex/mlx5/mlx5_regex_devx.c\n+++ b/drivers/regex/mlx5/mlx5_regex_devx.c\n@@ -59,3 +59,70 @@\n \t*data = MLX5_GET(query_regexp_register_out, out, register_data);\n \treturn 0;\n }\n+\n+int\n+mlx5_devx_regex_database_stop(void *ctx, uint8_t engine)\n+{\n+\tuint32_t out[MLX5_ST_SZ_DW(set_regexp_params_out)] = {0};\n+\tuint32_t in[MLX5_ST_SZ_DW(set_regexp_params_in)] = {0};\n+\tint ret;\n+\n+\tMLX5_SET(set_regexp_params_in, in, opcode, MLX5_CMD_SET_REGEX_PARAMS);\n+\tMLX5_SET(set_regexp_params_in, in, engine_id, engine);\n+\tMLX5_SET(set_regexp_params_in, in, regexp_params.stop_engine, 1);\n+\tMLX5_SET(set_regexp_params_in, in, field_select.stop_engine, 1);\n+\tret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out,\n+\t\t\t\t\t  sizeof(out));\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Database stop failed %d\", ret);\n+\t\trte_errno = errno;\n+\t\treturn -errno;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+mlx5_devx_regex_database_resume(void *ctx, uint8_t engine)\n+{\n+\tuint32_t out[MLX5_ST_SZ_DW(set_regexp_params_out)] = {0};\n+\tuint32_t in[MLX5_ST_SZ_DW(set_regexp_params_in)] = {0};\n+\tint ret;\n+\n+\tMLX5_SET(set_regexp_params_in, in, opcode, MLX5_CMD_SET_REGEX_PARAMS);\n+\tMLX5_SET(set_regexp_params_in, in, engine_id, engine);\n+\tMLX5_SET(set_regexp_params_in, in, regexp_params.stop_engine, 0);\n+\tMLX5_SET(set_regexp_params_in, in, field_select.stop_engine, 1);\n+\tret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out,\n+\t\t\t\t\t  sizeof(out));\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Database start failed %d\", ret);\n+\t\trte_errno = errno;\n+\t\treturn -errno;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+mlx5_devx_regex_database_program(void *ctx, uint8_t engine, uint32_t umem_id,\n+\t\t\t\t uint64_t umem_offset)\n+{\n+\tuint32_t out[MLX5_ST_SZ_DW(set_regexp_params_out)] = {0};\n+\tuint32_t in[MLX5_ST_SZ_DW(set_regexp_params_in)] = {0};\n+\tint ret;\n+\n+\tMLX5_SET(set_regexp_params_in, in, opcode, MLX5_CMD_SET_REGEX_PARAMS);\n+\tMLX5_SET(set_regexp_params_in, in, engine_id, engine);\n+\tMLX5_SET(set_regexp_params_in, in, regexp_params.db_umem_id, umem_id);\n+\tMLX5_SET64(set_regexp_params_in, in, regexp_params.db_umem_offset,\n+\t\t   umem_offset);\n+\tMLX5_SET(set_regexp_params_in, in, field_select.db_umem_id, 1);\n+\tret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out,\n+\t\t\t\t\t  sizeof(out));\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Database program failed %d\", ret);\n+\t\trte_errno = errno;\n+\t\treturn -errno;\n+\t}\n+\treturn 0;\n+}\n+\ndiff --git a/drivers/regex/mlx5/mlx5_rxp.c b/drivers/regex/mlx5/mlx5_rxp.c\nindex 18e2338..5dfba26 100644\n--- a/drivers/regex/mlx5/mlx5_rxp.c\n+++ b/drivers/regex/mlx5/mlx5_rxp.c\n@@ -2,8 +2,6 @@\n  * Copyright 2020 Mellanox Technologies, Ltd\n  */\n \n-#include <errno.h>\n-\n #include <rte_log.h>\n #include <rte_errno.h>\n #include <rte_malloc.h>\n@@ -14,15 +12,100 @@\n #include <mlx5_glue.h>\n #include <mlx5_devx_cmds.h>\n #include <mlx5_prm.h>\n+#include <mlx5_common_os.h>\n \n #include \"mlx5_regex.h\"\n #include \"mlx5_regex_utils.h\"\n #include \"mlx5_rxp_csrs.h\"\n+#include \"mlx5_rxp.h\"\n+\n+#define MLX5_REGEX_MAX_MATCHES MLX5_RXP_MAX_MATCHES\n+#define MLX5_REGEX_MAX_PAYLOAD_SIZE MLX5_RXP_MAX_JOB_LENGTH\n+#define MLX5_REGEX_MAX_RULES_PER_GROUP UINT32_MAX\n+#define MLX5_REGEX_MAX_GROUPS MLX5_RXP_MAX_SUBSETS\n+\n+/* Private Declarations */\n+static int\n+rxp_poll_csr_for_value(struct ibv_context *ctx, uint32_t *value,\n+\t\t       uint32_t address, uint32_t expected_value,\n+\t\t       uint32_t expected_mask, uint32_t timeout_ms, uint8_t id);\n+static int\n+mlnx_set_database(struct mlx5_regex_priv *priv, uint8_t id, uint8_t db_to_use);\n+static int\n+mlnx_resume_database(struct mlx5_regex_priv *priv, uint8_t id);\n+static int\n+mlnx_update_database(struct mlx5_regex_priv *priv, uint8_t id);\n+static int\n+program_rxp_rules(struct mlx5_regex_priv *priv,\n+\t\t  struct mlx5_rxp_ctl_rules_pgm *rules, uint8_t id);\n+static int\n+rxp_init_eng(struct mlx5_regex_priv *priv, uint8_t id);\n+static int\n+write_private_rules(struct mlx5_regex_priv *priv,\n+\t\t    struct mlx5_rxp_ctl_rules_pgm *rules,\n+\t\t    uint8_t id);\n+static int\n+write_shared_rules(struct mlx5_regex_priv *priv,\n+\t\t   struct mlx5_rxp_ctl_rules_pgm *rules, uint32_t count,\n+\t\t   uint8_t db_to_program);\n+static int\n+rxp_db_setup(struct mlx5_regex_priv *priv);\n+static void\n+rxp_dump_csrs(struct ibv_context *ctx, uint8_t id);\n+static int\n+rxp_write_rules_via_cp(struct ibv_context *ctx,\n+\t\t       struct mlx5_rxp_rof_entry *rules,\n+\t\t       int count, uint8_t id);\n+static int\n+rxp_flush_rules(struct ibv_context *ctx, struct mlx5_rxp_rof_entry *rules,\n+\t\tint count, uint8_t id);\n+static int\n+rxp_start_engine(struct ibv_context *ctx, uint8_t id);\n+static int\n+rxp_stop_engine(struct ibv_context *ctx, uint8_t id);\n+\n+static void __rte_unused\n+rxp_dump_csrs(struct ibv_context *ctx __rte_unused, uint8_t id __rte_unused)\n+{\n+\tuint32_t reg, i;\n \n-#define MLX5_REGEX_MAX_MATCHES 255\n-#define MLX5_REGEX_MAX_PAYLOAD_SIZE UINT16_MAX\n-#define MLX5_REGEX_MAX_RULES_PER_GROUP UINT16_MAX\n-#define MLX5_REGEX_MAX_GROUPS UINT16_MAX\n+\t/* Main CSRs*/\n+\tfor (i = 0; i < MLX5_RXP_CSR_NUM_ENTRIES; i++) {\n+\t\tif (mlx5_devx_regex_register_read(ctx, id,\n+\t\t\t\t\t\t  (MLX5_RXP_CSR_WIDTH * i) +\n+\t\t\t\t\t\t  MLX5_RXP_CSR_BASE_ADDRESS,\n+\t\t\t\t\t\t  &reg)) {\n+\t\t\tDRV_LOG(ERR, \"Failed to read Main CSRs Engine %d!\", id);\n+\t\t\treturn;\n+\t\t}\n+\t\tDRV_LOG(DEBUG, \"RXP Main CSRs (Eng%d) register (%d): %08x\",\n+\t\t\tid, i, reg);\n+\t}\n+\t/* RTRU CSRs*/\n+\tfor (i = 0; i < MLX5_RXP_CSR_NUM_ENTRIES; i++) {\n+\t\tif (mlx5_devx_regex_register_read(ctx, id,\n+\t\t\t\t\t\t  (MLX5_RXP_CSR_WIDTH * i) +\n+\t\t\t\t\t\t MLX5_RXP_RTRU_CSR_BASE_ADDRESS,\n+\t\t\t\t\t\t  &reg)) {\n+\t\t\tDRV_LOG(ERR, \"Failed to read RTRU CSRs Engine %d!\", id);\n+\t\t\treturn;\n+\t\t}\n+\t\tDRV_LOG(DEBUG, \"RXP RTRU CSRs (Eng%d) register (%d): %08x\",\n+\t\t\tid, i, reg);\n+\t}\n+\t/* STAT CSRs */\n+\tfor (i = 0; i < MLX5_RXP_CSR_NUM_ENTRIES; i++) {\n+\t\tif (mlx5_devx_regex_register_read(ctx, id,\n+\t\t\t\t\t\t  (MLX5_RXP_CSR_WIDTH * i) +\n+\t\t\t\t\t\tMLX5_RXP_STATS_CSR_BASE_ADDRESS,\n+\t\t\t\t\t\t  &reg)) {\n+\t\t\tDRV_LOG(ERR, \"Failed to read STAT CSRs Engine %d!\", id);\n+\t\t\treturn;\n+\t\t}\n+\t\tDRV_LOG(DEBUG, \"RXP STAT CSRs (Eng%d) register (%d): %08x\",\n+\t\t\tid, i, reg);\n+\t}\n+}\n \n int\n mlx5_regex_info_get(struct rte_regexdev *dev __rte_unused,\n@@ -32,24 +115,120 @@\n \tinfo->max_payload_size = MLX5_REGEX_MAX_PAYLOAD_SIZE;\n \tinfo->max_rules_per_group = MLX5_REGEX_MAX_RULES_PER_GROUP;\n \tinfo->max_groups = MLX5_REGEX_MAX_GROUPS;\n+\tinfo->max_queue_pairs = 1;\n \tinfo->regexdev_capa = RTE_REGEXDEV_SUPP_PCRE_GREEDY_F;\n \tinfo->rule_flags = 0;\n \treturn 0;\n }\n \n+/**\n+ * Actual writing of RXP instructions to RXP via CSRs.\n+ */\n+static int\n+rxp_write_rules_via_cp(struct ibv_context *ctx,\n+\t\t       struct mlx5_rxp_rof_entry *rules,\n+\t\t       int count, uint8_t id)\n+{\n+\tint i, ret = 0;\n+\tuint32_t tmp;\n+\n+\tfor (i = 0; i < count; i++) {\n+\t\ttmp = (uint32_t)rules[i].value;\n+\t\tret |= mlx5_devx_regex_register_write(ctx, id,\n+\t\t\t\t\t\t      MLX5_RXP_RTRU_CSR_DATA_0,\n+\t\t\t\t\t\t      tmp);\n+\t\ttmp = (uint32_t)(rules[i].value >> 32);\n+\t\tret |= mlx5_devx_regex_register_write(ctx, id,\n+\t\t\t\t\t\t      MLX5_RXP_RTRU_CSR_DATA_0 +\n+\t\t\t\t\t\t      MLX5_RXP_CSR_WIDTH, tmp);\n+\t\ttmp = rules[i].addr;\n+\t\tret |= mlx5_devx_regex_register_write(ctx, id,\n+\t\t\t\t\t\t      MLX5_RXP_RTRU_CSR_ADDR,\n+\t\t\t\t\t\t      tmp);\n+\t\tif (ret) {\n+\t\t\tDRV_LOG(ERR, \"Failed to copy instructions to RXP.\");\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tDRV_LOG(DEBUG, \"Written %d instructions\", count);\n+\treturn 0;\n+}\n+\n+static int\n+rxp_flush_rules(struct ibv_context *ctx, struct mlx5_rxp_rof_entry *rules,\n+\t\tint count, uint8_t id)\n+{\n+\tuint32_t val, fifo_depth;\n+\tint ret;\n+\n+\tret = rxp_write_rules_via_cp(ctx, rules, count, id);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"Failed to write rules via CSRs.\");\n+\t\treturn -1;\n+\t}\n+\tret = mlx5_devx_regex_register_read(ctx, id,\n+\t\t\t\t\t    MLX5_RXP_RTRU_CSR_CAPABILITY,\n+\t\t\t\t\t    &fifo_depth);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"CSR read failed!\");\n+\t\treturn -1;\n+\t}\n+\tret = rxp_poll_csr_for_value(ctx, &val, MLX5_RXP_RTRU_CSR_FIFO_STAT,\n+\t\t\t\t     count, ~0,\n+\t\t\t\t     MLX5_RXP_POLL_CSR_FOR_VALUE_TIMEOUT, id);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"Rules not rx by RXP: credit: %d, depth: %d\", val,\n+\t\t\tfifo_depth);\n+\t\treturn ret;\n+\t}\n+\tDRV_LOG(DEBUG, \"RTRU FIFO depth: 0x%x\", fifo_depth);\n+\tDRV_LOG(DEBUG, \"Rules flush took %d cycles.\", ret);\n+\tret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n+\t\t\t\t\t    &val);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"CSR read failed!\");\n+\t\treturn -1;\n+\t}\n+\tval |= MLX5_RXP_RTRU_CSR_CTRL_GO;\n+\tret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n+\t\t\t\t\t     val);\n+\tret = rxp_poll_csr_for_value(ctx, &val, MLX5_RXP_RTRU_CSR_STATUS,\n+\t\t\t\t     MLX5_RXP_RTRU_CSR_STATUS_UPDATE_DONE,\n+\t\t\t\t     MLX5_RXP_RTRU_CSR_STATUS_UPDATE_DONE,\n+\t\t\t\t     MLX5_RXP_POLL_CSR_FOR_VALUE_TIMEOUT, id);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"Rules update timeout: 0x%08X\", val);\n+\t\treturn ret;\n+\t}\n+\tDRV_LOG(DEBUG, \"Rules update took %d cycles\", ret);\n+\tif (mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n+\t\t\t\t\t  &val)) {\n+\t\tDRV_LOG(ERR, \"CSR read failed!\");\n+\t\treturn -1;\n+\t}\n+\tval &= ~(MLX5_RXP_RTRU_CSR_CTRL_GO);\n+\tif (mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n+\t\t\t\t\t   val)) {\n+\t\tDRV_LOG(ERR, \"CSR write write failed!\");\n+\t\treturn -1;\n+\t}\n+\n+\tDRV_LOG(DEBUG, \"RXP Flush rules finished.\");\n+\treturn 0;\n+}\n+\n static int\n rxp_poll_csr_for_value(struct ibv_context *ctx, uint32_t *value,\n \t\t       uint32_t address, uint32_t expected_value,\n \t\t       uint32_t expected_mask, uint32_t timeout_ms, uint8_t id)\n {\n \tunsigned int i;\n-\tint ret;\n+\tint ret = 0;\n \n \tret = -EBUSY;\n \tfor (i = 0; i < timeout_ms; i++) {\n \t\tif (mlx5_devx_regex_register_read(ctx, id, address, value))\n \t\t\treturn -1;\n-\n \t\tif ((*value & expected_mask) == expected_value) {\n \t\t\tret = 0;\n \t\t\tbreak;\n@@ -69,6 +248,7 @@\n \tif (ret)\n \t\treturn ret;\n \tctrl |= MLX5_RXP_CSR_CTRL_GO;\n+\tctrl |= MLX5_RXP_CSR_CTRL_DISABLE_L2C;\n \tret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);\n \treturn ret;\n }\n@@ -96,23 +276,23 @@\n \tuint32_t expected_mask;\n \tint ret = 0;\n \n-\t/* Read the rtru ctrl CSR */\n+\t/* Read the rtru ctrl CSR. */\n \tret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n \t\t\t\t\t    &ctrl_value);\n \tif (ret)\n \t\treturn -1;\n-\t/* Clear any previous init modes */\n+\t/* Clear any previous init modes. */\n \tctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_MASK);\n \tif (ctrl_value & MLX5_RXP_RTRU_CSR_CTRL_INIT) {\n \t\tctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT);\n \t\tmlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n \t\t\t\t\t       ctrl_value);\n \t}\n-\t/* Set the init_mode bits in the rtru ctrl CSR */\n+\t/* Set the init_mode bits in the rtru ctrl CSR. */\n \tctrl_value |= init_bits;\n \tmlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n \t\t\t\t       ctrl_value);\n-\t/* Need to sleep for a short period after pulsing the rtru init bit.  */\n+\t/* Need to sleep for a short period after pulsing the rtru init bit. */\n \trte_delay_us(20000);\n \t/* Poll the rtru status CSR until all the init done bits are set. */\n \tDRV_LOG(DEBUG, \"waiting for RXP rule memory to complete init\");\n@@ -128,11 +308,11 @@\n \tif (init_bits == MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_L1_L2) {\n \t\t/* Must be incremental mode */\n \t\texpected_value = MLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |\n-\t\t\t\t MLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;\n+\t\t\tMLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;\n \t} else {\n \t\texpected_value = MLX5_RXP_RTRU_CSR_STATUS_IM_INIT_DONE |\n-\t\t\t\t MLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |\n-\t\t\t\t MLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;\n+\t\t\tMLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |\n+\t\t\tMLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;\n \t}\n \texpected_mask = expected_value;\n \tret = rxp_poll_csr_for_value(ctx, &poll_value,\n@@ -141,7 +321,7 @@\n \t\t\t\t     MLX5_RXP_CSR_STATUS_TRIAL_TIMEOUT, id);\n \tif (ret)\n \t\treturn ret;\n-\tDRV_LOG(DEBUG, \"rule Memory initialise: 0x%08X\", poll_value);\n+\tDRV_LOG(DEBUG, \"rule memory initialise: 0x%08X\", poll_value);\n \t/* Clear the init bit in the rtru ctrl CSR */\n \tctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT);\n \tmlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,\n@@ -150,7 +330,206 @@\n }\n \n static int\n-rxp_init(struct mlx5_regex_priv *priv, uint8_t id)\n+rxp_parse_rof(const char *buf, uint32_t len,\n+\t      struct mlx5_rxp_ctl_rules_pgm **rules)\n+{\n+\tstatic const char del[] = \"\\n\\r\";\n+\tchar *line;\n+\tchar *tmp;\n+\tchar *cur_pos;\n+\tuint32_t lines = 0;\n+\tuint32_t entries;\n+\tstruct mlx5_rxp_rof_entry *curentry;\n+\n+\ttmp = rte_malloc(\"\", len, 0);\n+\tif (!tmp)\n+\t\treturn -ENOMEM;\n+\tmemcpy(tmp, buf, len);\n+\tline = strtok(tmp, del);\n+\twhile (line) {\n+\t\tif (line[0] != '#' && line[0] != '\\0')\n+\t\t\tlines++;\n+\t\tline = strtok(NULL, del);\n+\t}\n+\t*rules = rte_malloc(\"\", lines * sizeof(*curentry) + sizeof(**rules), 0);\n+\tif (!(*rules)) {\n+\t\trte_free(tmp);\n+\t\treturn -ENOMEM;\n+\t}\n+\tmemset(*rules, 0, lines * sizeof(curentry) + sizeof(**rules));\n+\tcurentry = (*rules)->rules;\n+\t(*rules)->hdr.cmd = MLX5_RXP_CTL_RULES_PGM;\n+\tentries = 0;\n+\tmemcpy(tmp, buf, len);\n+\tline = strtok(tmp, del);\n+\twhile (line) {\n+\t\tif (line[0] == '#' || line[0] == '\\0') {\n+\t\t\tline = strtok(NULL, del);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tcurentry->type = strtoul(line, &cur_pos, 10);\n+\t\tif (cur_pos == line || cur_pos[0] != ',')\n+\t\t\tgoto parse_error;\n+\t\tcur_pos++;\n+\t\tcurentry->addr = strtoul(cur_pos, &cur_pos, 16);\n+\t\tif (cur_pos[0] != ',')\n+\t\t\tgoto parse_error;\n+\t\tcur_pos++;\n+\t\tcurentry->value = strtoull(cur_pos, &cur_pos, 16);\n+\t\tif (cur_pos[0] != '\\0' && cur_pos[0] != '\\n')\n+\t\t\tgoto parse_error;\n+\t\tcurentry++;\n+\t\tentries++;\n+\t\tif (entries > lines)\n+\t\t\tgoto parse_error;\n+\t\tline = strtok(NULL, del);\n+\t}\n+\t(*rules)->count = entries;\n+\t(*rules)->hdr.len = entries * sizeof(*curentry) + sizeof(**rules);\n+\trte_free(tmp);\n+\treturn 0;\n+parse_error:\n+\trte_free(tmp);\n+\tif (*rules)\n+\t\trte_free(*rules);\n+\treturn -EINVAL;\n+}\n+\n+static int\n+mlnx_set_database(struct mlx5_regex_priv *priv, uint8_t id, uint8_t db_to_use)\n+{\n+\tint ret;\n+\tuint32_t umem_id;\n+\n+\tret = mlx5_devx_regex_database_stop(priv->ctx, id);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"stop engine failed!\");\n+\t\treturn ret;\n+\t}\n+\tumem_id = mlx5_os_get_umem_id(priv->db[db_to_use].umem.umem);\n+\tret = mlx5_devx_regex_database_program(priv->ctx, id, umem_id, 0);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"program db failed!\");\n+\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+mlnx_resume_database(struct mlx5_regex_priv *priv, uint8_t id)\n+{\n+\tmlx5_devx_regex_database_resume(priv->ctx, id);\n+\treturn 0;\n+}\n+\n+/*\n+ * Assign db memory for RXP programming.\n+ */\n+static int\n+mlnx_update_database(struct mlx5_regex_priv *priv, uint8_t id)\n+{\n+\tunsigned int i;\n+\tuint8_t db_free = MLX5_RXP_DB_NOT_ASSIGNED;\n+\tuint8_t eng_assigned = MLX5_RXP_DB_NOT_ASSIGNED;\n+\n+\t/* Check which database rxp_eng is currently located if any? */\n+\tfor (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT);\n+\t     i++) {\n+\t\tif (priv->db[i].db_assigned_to_eng_num == id) {\n+\t\t\teng_assigned = i;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\t/*\n+\t * If private mode then, we can keep the same db ptr as RXP will be\n+\t * programming EM itself if necessary, however need to see if\n+\t * programmed yet.\n+\t */\n+\tif ((priv->prog_mode == MLX5_RXP_PRIVATE_PROG_MODE) &&\n+\t    (eng_assigned != MLX5_RXP_DB_NOT_ASSIGNED))\n+\t\treturn eng_assigned;\n+\t/* Check for inactive db memory to use. */\n+\tfor (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT);\n+\t     i++) {\n+\t\tif (priv->db[i].active == true)\n+\t\t\tcontinue; /* Already in use, so skip db. */\n+\t\t/* Set this db to active now as free to use. */\n+\t\tpriv->db[i].active = true;\n+\t\t/* Now unassign last db index in use by RXP Eng. */\n+\t\tif (eng_assigned != MLX5_RXP_DB_NOT_ASSIGNED) {\n+\t\t\tpriv->db[eng_assigned].active = false;\n+\t\t\tpriv->db[eng_assigned].db_assigned_to_eng_num =\n+\t\t\t\tMLX5_RXP_DB_NOT_ASSIGNED;\n+\n+\t\t\t/* Set all DB memory to 0's before setting up DB. */\n+\t\t\tmemset(priv->db[i].ptr, 0x00, MLX5_MAX_DB_SIZE);\n+\t\t}\n+\t\t/* Now reassign new db index with RXP Engine. */\n+\t\tpriv->db[i].db_assigned_to_eng_num = id;\n+\t\tdb_free = i;\n+\t\tbreak;\n+\t}\n+\tif (db_free == MLX5_RXP_DB_NOT_ASSIGNED)\n+\t\treturn -1;\n+\treturn db_free;\n+}\n+\n+/*\n+ * Program RXP instruction db to RXP engine/s.\n+ */\n+static int\n+program_rxp_rules(struct mlx5_regex_priv *priv,\n+\t\t  struct mlx5_rxp_ctl_rules_pgm *rules, uint8_t id)\n+{\n+\tint ret, db_free;\n+\tuint32_t rule_cnt;\n+\n+\trule_cnt = rules->count;\n+\tdb_free = mlnx_update_database(priv, id);\n+\tif (db_free < 0) {\n+\t\tDRV_LOG(ERR, \"Failed to setup db memory!\");\n+\t\treturn db_free;\n+\t}\n+\tif (priv->prog_mode == MLX5_RXP_PRIVATE_PROG_MODE) {\n+\t\t/* Register early to ensure RXP writes to EM use valid addr. */\n+\t\tret = mlnx_set_database(priv, id, db_free);\n+\t\tif (ret < 0) {\n+\t\t\tDRV_LOG(ERR, \"Failed to register db memory!\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\tret = write_private_rules(priv, rules, id);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"Failed to write rules!\");\n+\t\treturn ret;\n+\t}\n+\tif (priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE) {\n+\t\t/* Write external rules directly to EM. */\n+\t\trules->count = rule_cnt;\n+\t       /* Now write external instructions to EM. */\n+\t\tret = write_shared_rules(priv, rules, rules->hdr.len, db_free);\n+\t\tif (ret < 0) {\n+\t\t\tDRV_LOG(ERR, \"Failed to write EM rules!\");\n+\t\t\treturn ret;\n+\t\t}\n+\t\tret = mlnx_set_database(priv, id, db_free);\n+\t\tif (ret < 0) {\n+\t\t\tDRV_LOG(ERR, \"Failed to register db memory!\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\tret = mlnx_resume_database(priv, id);\n+\tif (ret < 0) {\n+\t\tDRV_LOG(ERR, \"Failed to resume engine!\");\n+\t\treturn ret;\n+\t}\n+\tDRV_LOG(DEBUG, \"Programmed RXP Engine %d\\n\", id);\n+\trules->count = rule_cnt;\n+\treturn 0;\n+}\n+\n+static int\n+rxp_init_eng(struct mlx5_regex_priv *priv, uint8_t id)\n {\n \tuint32_t ctrl;\n \tuint32_t reg;\n@@ -174,7 +553,6 @@\n \tctrl &= ~MLX5_RXP_CSR_CTRL_INIT;\n \tret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);\n \trte_delay_us(20000);\n-\n \tret = rxp_poll_csr_for_value(ctx, &ctrl, MLX5_RXP_CSR_STATUS,\n \t\t\t\t     MLX5_RXP_CSR_STATUS_INIT_DONE,\n \t\t\t\t     MLX5_RXP_CSR_STATUS_INIT_DONE,\n@@ -189,7 +567,6 @@\n \t\t\t\t\t     ctrl);\n \tif (ret)\n \t\treturn ret;\n-\trxp_init_rtru(ctx, id, MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_IM_L1_L2);\n \tret = rxp_init_rtru(ctx, id, MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_IM_L1_L2);\n \tif (ret)\n \t\treturn ret;\n@@ -199,8 +576,16 @@\n \t\treturn ret;\n \tDRV_LOG(DEBUG, \"max matches: %d, DDOS threshold: %d\", reg >> 16,\n \t\treg & 0xffff);\n-\tret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_MAX_MATCH,\n-\t\t\t\t\t     priv->nb_max_matches);\n+\tif ((reg >> 16) >= priv->nb_max_matches)\n+\t\tret = mlx5_devx_regex_register_write(ctx, id,\n+\t\t\t\t\t\t     MLX5_RXP_CSR_MAX_MATCH,\n+\t\t\t\t\t\t     priv->nb_max_matches);\n+\telse\n+\t\tret = mlx5_devx_regex_register_write(ctx, id,\n+\t\t\t\t\t\t     MLX5_RXP_CSR_MAX_MATCH,\n+\t\t\t\t\t\t     (reg >> 16));\n+\tret |= mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_MAX_PREFIX,\n+\t\t\t\t\t (reg & 0xFFFF));\n \tret |= mlx5_devx_regex_register_write(ctx, id,\n \t\t\t\t\t      MLX5_RXP_CSR_MAX_LATENCY, 0);\n \tret |= mlx5_devx_regex_register_write(ctx, id,\n@@ -208,15 +593,389 @@\n \treturn ret;\n }\n \n+static int\n+write_private_rules(struct mlx5_regex_priv *priv,\n+\t\t    struct mlx5_rxp_ctl_rules_pgm *rules,\n+\t\t    uint8_t id)\n+{\n+\tunsigned int pending;\n+\tuint32_t block, reg, val, rule_cnt, rule_offset, rtru_max_num_entries;\n+\tint ret = 1;\n+\n+\tif (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED)\n+\t\treturn -EINVAL;\n+\tif (rules->hdr.len == 0 || rules->hdr.cmd < MLX5_RXP_CTL_RULES_PGM ||\n+\t\t\t\t   rules->hdr.cmd > MLX5_RXP_CTL_RULES_PGM_INCR)\n+\t\treturn -EINVAL;\n+\t/* For a non-incremental rules program, re-init the RXP. */\n+\tif (rules->hdr.cmd == MLX5_RXP_CTL_RULES_PGM) {\n+\t\tret = rxp_init_eng(priv, id);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t} else if (rules->hdr.cmd == MLX5_RXP_CTL_RULES_PGM_INCR) {\n+\t\t/* Flush RXP L1 and L2 cache by using MODE_L1_L2. */\n+\t\tret = rxp_init_rtru(priv->ctx, id,\n+\t\t\t\t    MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_L1_L2);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t}\n+\tif (rules->count == 0)\n+\t\treturn -EINVAL;\n+\t/* Confirm the RXP is initialised. */\n+\tif (mlx5_devx_regex_register_read(priv->ctx, id,\n+\t\t\t\t\t    MLX5_RXP_CSR_STATUS, &val)) {\n+\t\tDRV_LOG(ERR, \"Failed to read from RXP!\");\n+\t\treturn -ENODEV;\n+\t}\n+\tif (!(val & MLX5_RXP_CSR_STATUS_INIT_DONE)) {\n+\t\tDRV_LOG(ERR, \"RXP not initialised...\");\n+\t\treturn -EBUSY;\n+\t}\n+\t/* Get the RTRU maximum number of entries allowed. */\n+\tif (mlx5_devx_regex_register_read(priv->ctx, id,\n+\t\t\tMLX5_RXP_RTRU_CSR_CAPABILITY, &rtru_max_num_entries)) {\n+\t\tDRV_LOG(ERR, \"Failed to read RTRU capability!\");\n+\t\treturn -ENODEV;\n+\t}\n+\trtru_max_num_entries = (rtru_max_num_entries & 0x00FF);\n+\trule_cnt = 0;\n+\tpending = 0;\n+\twhile (rules->count > 0) {\n+\t\tif ((rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_INST) ||\n+\t\t    (rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_IM) ||\n+\t\t    (rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_EM)) {\n+\t\t\tif ((rules->rules[rule_cnt].type ==\n+\t\t\t     MLX5_RXP_ROF_ENTRY_EM) &&\n+\t\t\t    (priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE)) {\n+\t\t\t\t/* Skip EM rules programming. */\n+\t\t\t\tif (pending > 0) {\n+\t\t\t\t\t/* Flush any rules that are pending. */\n+\t\t\t\t\trule_offset = (rule_cnt - pending);\n+\t\t\t\t\tret = rxp_flush_rules(priv->ctx,\n+\t\t\t\t\t\t&rules->rules[rule_offset],\n+\t\t\t\t\t\tpending, id);\n+\t\t\t\t\tif (ret < 0) {\n+\t\t\t\t\t\tDRV_LOG(ERR, \"Flushing rules.\");\n+\t\t\t\t\t\treturn -ENODEV;\n+\t\t\t\t\t}\n+\t\t\t\t\tpending = 0;\n+\t\t\t\t}\n+\t\t\t\trule_cnt++;\n+\t\t\t} else {\n+\t\t\t\tpending++;\n+\t\t\t\trule_cnt++;\n+\t\t\t\t/*\n+\t\t\t\t * If parsing the last rule, or if reached the\n+\t\t\t\t * maximum number of rules for this batch, then\n+\t\t\t\t * flush the rules batch to the RXP.\n+\t\t\t\t */\n+\t\t\t\tif ((rules->count == 1) ||\n+\t\t\t\t    (pending == rtru_max_num_entries)) {\n+\t\t\t\t\trule_offset = (rule_cnt - pending);\n+\t\t\t\t\tret = rxp_flush_rules(priv->ctx,\n+\t\t\t\t\t\t&rules->rules[rule_offset],\n+\t\t\t\t\t\tpending, id);\n+\t\t\t\t\tif (ret < 0) {\n+\t\t\t\t\t\tDRV_LOG(ERR, \"Flushing rules.\");\n+\t\t\t\t\t\treturn -ENODEV;\n+\t\t\t\t\t}\n+\t\t\t\t\tpending = 0;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else if ((rules->rules[rule_cnt].type ==\n+\t\t\t\tMLX5_RXP_ROF_ENTRY_EQ) ||\n+\t\t\t (rules->rules[rule_cnt].type ==\n+\t\t\t\tMLX5_RXP_ROF_ENTRY_GTE) ||\n+\t\t\t (rules->rules[rule_cnt].type ==\n+\t\t\t\tMLX5_RXP_ROF_ENTRY_LTE) ||\n+\t\t\t (rules->rules[rule_cnt].type ==\n+\t\t\t\tMLX5_RXP_ROF_ENTRY_CHECKSUM) ||\n+\t\t\t (rules->rules[rule_cnt].type ==\n+\t\t\t\tMLX5_RXP_ROF_ENTRY_CHECKSUM_EX_EM)) {\n+\t\t\tif (pending) {\n+\t\t\t\t/* Flush rules before checking reg values. */\n+\t\t\t\trule_offset = (rule_cnt - pending);\n+\t\t\t\tret = rxp_flush_rules(priv->ctx,\n+\t\t\t\t\t&rules->rules[rule_offset],\n+\t\t\t\t\tpending, id);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\tDRV_LOG(ERR, \"Failed to flush rules.\");\n+\t\t\t\t\treturn -ENODEV;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tblock = (rules->rules[rule_cnt].addr >> 16) & 0xFFFF;\n+\t\t\tif (block == 0)\n+\t\t\t\treg = MLX5_RXP_CSR_BASE_ADDRESS;\n+\t\t\telse if (block == 1)\n+\t\t\t\treg = MLX5_RXP_RTRU_CSR_BASE_ADDRESS;\n+\t\t\telse {\n+\t\t\t\tDRV_LOG(ERR, \"Invalid ROF register 0x%08X!\",\n+\t\t\t\t\trules->rules[rule_cnt].addr);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\treg += (rules->rules[rule_cnt].addr & 0xFFFF) *\n+\t\t\t\tMLX5_RXP_CSR_WIDTH;\n+\t\t\tret = mlx5_devx_regex_register_read(priv->ctx, id,\n+\t\t\t\t\t\t\t    reg, &val);\n+\t\t\tif (ret) {\n+\t\t\t\tDRV_LOG(ERR, \"RXP CSR read failed!\");\n+\t\t\t\treturn ret;\n+\t\t\t}\n+\t\t\tif ((priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE) &&\n+\t\t\t    ((rules->rules[rule_cnt].type ==\n+\t\t\t    MLX5_RXP_ROF_ENTRY_CHECKSUM_EX_EM) &&\n+\t\t\t    (val != rules->rules[rule_cnt].value))) {\n+\t\t\t\tDRV_LOG(ERR, \"Unexpected value for register:\");\n+\t\t\t\tDRV_LOG(ERR, \"reg %x\" PRIu32 \" got %x\" PRIu32,\n+\t\t\t\t\trules->rules[rule_cnt].addr, val);\n+\t\t\t\tDRV_LOG(ERR, \"expected %\" PRIx64 \".\",\n+\t\t\t\t\trules->rules[rule_cnt].value);\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t} else if ((priv->prog_mode ==\n+\t\t\t\t MLX5_RXP_PRIVATE_PROG_MODE) &&\n+\t\t\t\t (rules->rules[rule_cnt].type ==\n+\t\t\t\t MLX5_RXP_ROF_ENTRY_CHECKSUM) &&\n+\t\t\t\t (val != rules->rules[rule_cnt].value)) {\n+\t\t\t\tDRV_LOG(ERR, \"Unexpected value for register:\");\n+\t\t\t\tDRV_LOG(ERR, \"reg %x\" PRIu32 \" got %x\" PRIu32,\n+\t\t\t\t\trules->rules[rule_cnt].addr, val);\n+\t\t\t\tDRV_LOG(ERR, \"expected %\" PRIx64 \".\",\n+\t\t\t\t\trules->rules[rule_cnt].value);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t} else if ((rules->rules[rule_cnt].type ==\n+\t\t\t\t\tMLX5_RXP_ROF_ENTRY_EQ) &&\n+\t\t\t\t  (val != rules->rules[rule_cnt].value)) {\n+\t\t\t\tDRV_LOG(ERR, \"Unexpected value for register:\");\n+\t\t\t\tDRV_LOG(ERR, \"reg %x\" PRIu32 \" got %x\" PRIu32,\n+\t\t\t\t\trules->rules[rule_cnt].addr, val);\n+\t\t\t\tDRV_LOG(ERR, \"expected %\" PRIx64 \".\",\n+\t\t\t\t\trules->rules[rule_cnt].value);\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t} else if ((rules->rules[rule_cnt].type ==\n+\t\t\t\t\tMLX5_RXP_ROF_ENTRY_GTE) &&\n+\t\t\t\t (val < rules->rules[rule_cnt].value)) {\n+\t\t\t\tDRV_LOG(ERR, \"Unexpected value reg 0x%08X,\",\n+\t\t\t\t\trules->rules[rule_cnt].addr);\n+\t\t\t\tDRV_LOG(ERR, \"got %X, expected >= %\" PRIx64 \".\",\n+\t\t\t\t\tval, rules->rules[rule_cnt].value);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t} else if ((rules->rules[rule_cnt].type ==\n+\t\t\t\t\tMLX5_RXP_ROF_ENTRY_LTE) &&\n+\t\t\t\t (val > rules->rules[rule_cnt].value)) {\n+\t\t\t\tDRV_LOG(ERR, \"Unexpected value reg 0x%08X,\",\n+\t\t\t\t\trules->rules[rule_cnt].addr);\n+\t\t\t\tDRV_LOG(ERR, \"got %08X expected <= %\" PRIx64,\n+\t\t\t\t\tval, rules->rules[rule_cnt].value);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\trule_cnt++;\n+\t\t\tpending = 0;\n+\t\t} else {\n+\t\t\tDRV_LOG(ERR, \"Error: Invalid rule type %d!\",\n+\t\t\t\trules->rules[rule_cnt].type);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\trules->count--;\n+\t}\n+\treturn ret;\n+}\n+\n+/*\n+ * Shared memory programming mode, here all external db instructions are written\n+ * to EM via the host.\n+ */\n+static int\n+write_shared_rules(struct mlx5_regex_priv *priv,\n+\t\t   struct mlx5_rxp_ctl_rules_pgm *rules, uint32_t count,\n+\t\t   uint8_t db_to_program)\n+{\n+\tuint32_t rule_cnt, rof_rule_addr;\n+\tuint64_t tmp_write_swap[4];\n+\n+\tif (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED)\n+\t\treturn -EINVAL;\n+\tif ((rules->count == 0) || (count == 0))\n+\t\treturn -EINVAL;\n+\trule_cnt = 0;\n+\t/*\n+\t * Note the following section of code carries out a 32byte swap of\n+\t * instruction to coincide with HW 32byte swap. This may need removed\n+\t * in new variants of this programming function!\n+\t */\n+\twhile (rule_cnt < rules->count) {\n+\t\tif ((rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_EM) &&\n+\t\t    (priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE)) {\n+\t\t\t/*\n+\t\t\t * Note there are always blocks of 8 instructions for\n+\t\t\t * 7's written sequentially. However there is no\n+\t\t\t * guarantee that all blocks are sequential!\n+\t\t\t */\n+\t\t\tif (count >= (rule_cnt + MLX5_RXP_INST_BLOCK_SIZE)) {\n+\t\t\t\t/*\n+\t\t\t\t * Ensure memory write not exceeding boundary\n+\t\t\t\t * Check essential to ensure 0x10000 offset\n+\t\t\t\t * accounted for!\n+\t\t\t\t */\n+\t\t\t\tif ((uint8_t *)((uint8_t *)\n+\t\t\t\t    priv->db[db_to_program].ptr +\n+\t\t\t\t    ((rules->rules[rule_cnt + 7].addr <<\n+\t\t\t\t    MLX5_RXP_INST_OFFSET))) >=\n+\t\t\t\t    ((uint8_t *)((uint8_t *)\n+\t\t\t\t    priv->db[db_to_program].ptr +\n+\t\t\t\t    MLX5_MAX_DB_SIZE))) {\n+\t\t\t\t\tDRV_LOG(ERR, \"DB exceeded memory!\");\n+\t\t\t\t\treturn -ENODEV;\n+\t\t\t\t}\n+\t\t\t\t/*\n+\t\t\t\t * Rule address Offset to align with RXP\n+\t\t\t\t * external instruction offset.\n+\t\t\t\t */\n+\t\t\t\trof_rule_addr = (rules->rules[rule_cnt].addr <<\n+\t\t\t\t\t\t MLX5_RXP_INST_OFFSET);\n+\t\t\t\t/* 32 byte instruction swap (sw work around)! */\n+\t\t\t\ttmp_write_swap[0] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 4)].value);\n+\t\t\t\ttmp_write_swap[1] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 5)].value);\n+\t\t\t\ttmp_write_swap[2] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 6)].value);\n+\t\t\t\ttmp_write_swap[3] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 7)].value);\n+\t\t\t\t/* Write only 4 of the 8 instructions. */\n+\t\t\t\tmemcpy((uint8_t *)((uint8_t *)\n+\t\t\t\t       priv->db[db_to_program].ptr +\n+\t\t\t\t       rof_rule_addr), &tmp_write_swap,\n+\t\t\t\t       (sizeof(uint64_t) * 4));\n+\t\t\t\t/* Write 1st 4 rules of block after last 4. */\n+\t\t\t\trof_rule_addr = (rules->rules[\n+\t\t\t\t\t\t (rule_cnt + 4)].addr <<\n+\t\t\t\t\t\t MLX5_RXP_INST_OFFSET);\n+\t\t\t\ttmp_write_swap[0] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 0)].value);\n+\t\t\t\ttmp_write_swap[1] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 1)].value);\n+\t\t\t\ttmp_write_swap[2] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 2)].value);\n+\t\t\t\ttmp_write_swap[3] = le64toh(\n+\t\t\t\t\trules->rules[(rule_cnt + 3)].value);\n+\t\t\t\tmemcpy((uint8_t *)((uint8_t *)\n+\t\t\t\t       priv->db[db_to_program].ptr +\n+\t\t\t\t       rof_rule_addr), &tmp_write_swap,\n+\t\t\t\t       (sizeof(uint64_t) * 4));\n+\t\t\t} else\n+\t\t\t\treturn -1;\n+\t\t\t/* Fast forward as already handled block of 8. */\n+\t\t\trule_cnt += MLX5_RXP_INST_BLOCK_SIZE;\n+\t\t} else\n+\t\t\trule_cnt++; /* Must be something other than EM rule. */\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+rxp_db_setup(struct mlx5_regex_priv *priv)\n+{\n+\tint ret;\n+\tuint8_t i;\n+\n+\t/* Setup database memories for both RXP engines + reprogram memory. */\n+\tfor (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT); i++) {\n+\t\tpriv->db[i].ptr = rte_malloc(\"\", MLX5_MAX_DB_SIZE, 0);\n+\t\tif (!priv->db[i].ptr) {\n+\t\t\tDRV_LOG(ERR, \"Failed to alloc db memory!\");\n+\t\t\tret = ENODEV;\n+\t\t\tgoto tidyup_error;\n+\t\t}\n+\t\t/* Register the memory. */\n+\t\tpriv->db[i].umem.umem = mlx5_glue->devx_umem_reg(priv->ctx,\n+\t\t\t\t\t\t\tpriv->db[i].ptr,\n+\t\t\t\t\t\t\tMLX5_MAX_DB_SIZE, 7);\n+\t\tif (!priv->db[i].umem.umem) {\n+\t\t\tDRV_LOG(ERR, \"Failed to register memory!\");\n+\t\t\tret = ENODEV;\n+\t\t\tgoto tidyup_error;\n+\t\t}\n+\t\t/* Ensure set all DB memory to 0's before setting up DB. */\n+\t\tmemset(priv->db[i].ptr, 0x00, MLX5_MAX_DB_SIZE);\n+\t\t/* No data currently in database. */\n+\t\tpriv->db[i].len = 0;\n+\t\tpriv->db[i].active = false;\n+\t\tpriv->db[i].db_assigned_to_eng_num = MLX5_RXP_DB_NOT_ASSIGNED;\n+\t}\n+\treturn 0;\n+tidyup_error:\n+\tfor (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT); i++) {\n+\t\tif (priv->db[i].ptr)\n+\t\t\trte_free(priv->db[i].ptr);\n+\t\tif (priv->db[i].umem.umem)\n+\t\t\tmlx5_glue->devx_umem_dereg(priv->db[i].umem.umem);\n+\t}\n+\treturn -ret;\n+}\n+\n+int\n+mlx5_regex_rules_db_import(struct rte_regexdev *dev,\n+\t\t     const char *rule_db, uint32_t rule_db_len)\n+{\n+\tstruct mlx5_regex_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_rxp_ctl_rules_pgm *rules = NULL;\n+\tuint8_t id;\n+\tint ret;\n+\n+\tif (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED) {\n+\t\tDRV_LOG(ERR, \"RXP programming mode not set!\");\n+\t\treturn -1;\n+\t}\n+\tif (rule_db == NULL) {\n+\t\tDRV_LOG(ERR, \"Database empty!\");\n+\t\treturn -ENODEV;\n+\t}\n+\tif (rule_db_len == 0)\n+\t\treturn -EINVAL;\n+\tret = rxp_parse_rof(rule_db, rule_db_len, &rules);\n+\tif (ret) {\n+\t\tDRV_LOG(ERR, \"Can't parse ROF file.\");\n+\t\treturn ret;\n+\t}\n+\t/* Need to ensure RXP not busy before stop! */\n+\tfor (id = 0; id < priv->nb_engines; id++) {\n+\t\tret = rxp_stop_engine(priv->ctx, id);\n+\t\tif (ret) {\n+\t\t\tDRV_LOG(ERR, \"Can't stop engine.\");\n+\t\t\tret = -ENODEV;\n+\t\t\tgoto tidyup_error;\n+\t\t}\n+\t\tret = program_rxp_rules(priv, rules, id);\n+\t\tif (ret < 0) {\n+\t\t\tDRV_LOG(ERR, \"Failed to program rxp rules.\");\n+\t\t\tret = -ENODEV;\n+\t\t\tgoto tidyup_error;\n+\t\t}\n+\t\tret = rxp_start_engine(priv->ctx, id);\n+\t\tif (ret) {\n+\t\t\tDRV_LOG(ERR, \"Can't start engine.\");\n+\t\t\tret = -ENODEV;\n+\t\t\tgoto tidyup_error;\n+\t\t}\n+\t}\n+\trte_free(rules);\n+\treturn 0;\n+tidyup_error:\n+\trte_free(rules);\n+\treturn ret;\n+}\n+\n int\n mlx5_regex_configure(struct rte_regexdev *dev,\n \t\t     const struct rte_regexdev_config *cfg)\n {\n \tstruct mlx5_regex_priv *priv = dev->data->dev_private;\n \tint ret;\n-\tuint8_t id;\n \n+\tif (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED)\n+\t\treturn -1;\n \tpriv->nb_queues = cfg->nb_queue_pairs;\n+\tdev->data->dev_conf.nb_queue_pairs = priv->nb_queues;\n \tpriv->qps = rte_zmalloc(NULL, sizeof(struct mlx5_regex_qp) *\n \t\t\t\tpriv->nb_queues, 0);\n \tif (!priv->nb_queues) {\n@@ -225,35 +984,22 @@\n \t\treturn -rte_errno;\n \t}\n \tpriv->nb_max_matches = cfg->nb_max_matches;\n-\tfor (id = 0; id < 2; id++) {\n-\t\tret = rxp_stop_engine(priv->ctx, id);\n-\t\tif (ret) {\n-\t\t\tDRV_LOG(ERR, \"can't stop engine.\");\n-\t\t\trte_errno = ENODEV;\n-\t\t\treturn -rte_errno;\n-\t\t}\n-\t\tret = rxp_init(priv, id);\n-\t\tif (ret) {\n-\t\t\tDRV_LOG(ERR, \"can't init engine.\");\n-\t\t\trte_errno = ENODEV;\n-\t\t\treturn -rte_errno;\n-\t\t}\n-\t\tret = mlx5_devx_regex_register_write(priv->ctx, id,\n-\t\t\t\t\t\t     MLX5_RXP_CSR_MAX_MATCH,\n-\t\t\t\t\t\t     priv->nb_max_matches);\n-\t\tif (ret) {\n-\t\t\tDRV_LOG(ERR, \"can't update number of matches.\");\n-\t\t\trte_errno = ENODEV;\n-\t\t\tgoto configure_error;\n-\t\t}\n-\t\tret = rxp_start_engine(priv->ctx, id);\n-\t\tif (ret) {\n-\t\t\tDRV_LOG(ERR, \"can't start engine.\");\n+\t/* Setup rxp db memories. */\n+\tif (rxp_db_setup(priv)) {\n+\t\tDRV_LOG(ERR, \"Failed to setup RXP db memory\");\n+\t\trte_errno = ENOMEM;\n+\t\treturn -rte_errno;\n+\t}\n+\tif (cfg->rule_db != NULL) {\n+\t\tret = mlx5_regex_rules_db_import(dev, cfg->rule_db,\n+\t\t\t\t\t\t cfg->rule_db_len);\n+\t\tif (ret < 0) {\n+\t\t\tDRV_LOG(ERR, \"Failed to program rxp rules.\");\n \t\t\trte_errno = ENODEV;\n \t\t\tgoto configure_error;\n \t\t}\n-\n-\t}\n+\t} else\n+\t\tDRV_LOG(DEBUG, \"Regex config without rules programming!\");\n \treturn 0;\n configure_error:\n \tif (priv->qps)\ndiff --git a/drivers/regex/mlx5/mlx5_rxp.h b/drivers/regex/mlx5/mlx5_rxp.h\nnew file mode 100644\nindex 0000000..9686e24\n--- /dev/null\n+++ b/drivers/regex/mlx5/mlx5_rxp.h\n@@ -0,0 +1,138 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2020 Mellanox Technologies, Ltd\n+ */\n+\n+#ifndef RTE_PMD_MLX5_REGEX_RXP_H_\n+#define RTE_PMD_MLX5_REGEX_RXP_H_\n+\n+#define MLX5_RXP_MAX_JOB_LENGTH\t16384\n+#define MLX5_RXP_MAX_SUBSETS 4095\n+#define MLX5_RXP_CSR_NUM_ENTRIES 31\n+\n+#define MLX5_RXP_CTRL_TYPE_MASK\t7\n+#define MLX5_RXP_CTRL_TYPE_JOB_DESCRIPTOR 0\n+#define MLX5_RXP_CTRL_TYPE_RESPONSE_DESCRIPTOR 1\n+#define MLX5_RXP_CTRL_TYPE_MEMORY_WRITE\t4\n+#define MLX5_RXP_CSR_CTRL_DISABLE_L2C (1 << 7)\n+\n+#define MLX5_RXP_CTRL_JOB_DESC_SOF 0x0010\n+#define MLX5_RXP_CTRL_JOB_DESC_EOF 0x0020\n+#define MLX5_RXP_CTRL_JOB_DESC_HPM_ENABLE 0x0100\n+#define MLX5_RXP_CTRL_JOB_DESC_ANYMATCH_ENABLE 0x0200\n+#define MLX5_RXP_CTRL_JOB_DESC_FLAGS (MLX5_RXP_CTRL_JOB_DESC_SOF | \\\n+\t\t\t\t      MLX5_RXP_CTRL_JOB_DESC_EOF | \\\n+\t\t\t\t      MLX5_RXP_CTRL_JOB_DESC_HPM_ENABLE | \\\n+\t\t\t\t      MLX5_RXP_CTRL_JOB_DESC_ANYMATCH_ENABLE)\n+\n+#define MLX5_RXP_CTRL_VALID 0x8000\n+\n+#define MLX5_RXP_RESP_STATUS_MAX_PRI_THREADS (1 << 3)\n+#define MLX5_RXP_RESP_STATUS_MAX_SEC_THREADS (1 << 4)\n+#define MLX5_RXP_RESP_STATUS_MAX_LATENCY (1 << 5)\n+#define MLX5_RXP_RESP_STATUS_MAX_MATCH (1 << 6)\n+#define MLX5_RXP_RESP_STATUS_MAX_PREFIX\t(1 << 7)\n+#define MLX5_RXP_RESP_STATUS_HPM (1 << 8)\n+#define MLX5_RXP_RESP_STATUS_ANYMATCH (1 << 9)\n+#define MLX5_RXP_RESP_STATUS_PMI_SOJ (1 << 13)\n+#define MLX5_RXP_RESP_STATUS_PMI_EOJ (1 << 14)\n+\n+/* This describes the header the RXP expects for any search data. */\n+struct mlx5_rxp_job_desc {\n+\tuint32_t job_id;\n+\tuint16_t ctrl;\n+\tuint16_t len;\n+\tuint16_t subset[4];\n+} __rte_packed;\n+\n+struct mlx5_rxp_response_desc {\n+\tuint32_t job_id;\n+\tuint16_t status;\n+\tuint8_t\tdetected_match_count;\n+\tuint8_t\tmatch_count;\n+\tuint16_t primary_thread_count;\n+\tuint16_t instruction_count;\n+\tuint16_t latency_count;\n+\tuint16_t pmi_min_byte_ptr;\n+} __rte_packed;\n+\n+struct mlx5_rxp_match_tuple {\n+\tuint32_t rule_id;\n+\tuint16_t start_ptr;\n+\tuint16_t length;\n+} __rte_packed;\n+\n+struct mlx5_rxp_response {\n+\tstruct mlx5_rxp_response_desc header;\n+\tstruct mlx5_rxp_match_tuple matches[0];\n+};\n+\n+#define MLX5_RXP_MAX_MATCHES 254\n+\n+#define MLX5_RXP_CTL_RULES_PGM 1\n+#define MLX5_RXP_CTL_RULES_PGM_INCR 2\n+\n+#define MLX5_RXP_ROF_ENTRY_INST 0\n+#define MLX5_RXP_ROF_ENTRY_EQ 1\n+#define MLX5_RXP_ROF_ENTRY_GTE 2\n+#define MLX5_RXP_ROF_ENTRY_LTE 3\n+#define MLX5_RXP_ROF_ENTRY_CHECKSUM 4\n+#define MLX5_RXP_ROF_ENTRY_CHECKSUM_EX_EM 5\n+#define MLX5_RXP_ROF_ENTRY_IM 6\n+#define MLX5_RXP_ROF_ENTRY_EM 7\n+#define MLX5_RXP_ROF_ENTRY_TYPE_MAX 7\n+\n+#define MLX5_RXP_INST_OFFSET 3\n+#define\tMLX5_RXP_INST_BLOCK_SIZE 8\n+#define MLX5_MAX_SIZE_RES_DES (sizeof(struct mlx5_rxp_response_desc))\n+#define MLX5_MAX_DB_SIZE (1u << 27u)\n+#define MLX5_MAX_SIZE_MATCH_RESP (254 * sizeof(struct mlx5_rxp_match_tuple))\n+#define MLX5_RXP_SQ_NOT_BUSY false\n+#define MLX5_RXP_SQ_BUSY true\n+\n+\n+struct mlx5_rxp_ctl_hdr {\n+\tuint16_t cmd;\n+\tuint32_t len;\n+};\n+\n+struct mlx5_rxp_rof_entry {\n+\tuint8_t\ttype;\n+\tuint32_t addr;\n+\tuint64_t value;\n+};\n+\n+struct mlx5_rxp_rof {\n+\tuint32_t rof_version;\n+\tchar *timestamp;\n+\tchar *rxp_compiler_version;\n+\tuint32_t rof_revision;\n+\tuint32_t number_of_entries;\n+\tstruct mlx5_rxp_rof_entry *rof_entries;\n+};\n+\n+struct mlx5_rxp_ctl_rules_pgm {\n+\tstruct mlx5_rxp_ctl_hdr hdr;\n+\tuint32_t count;\n+\tstruct mlx5_rxp_rof_entry rules[0];\n+} __rte_packed;\n+\n+/* RXP programming mode setting. */\n+enum mlx5_rxp_program_mode {\n+\tMLX5_RXP_MODE_NOT_DEFINED = 0,\n+\tMLX5_RXP_SHARED_PROG_MODE,\n+\tMLX5_RXP_PRIVATE_PROG_MODE,\n+};\n+\n+#define MLX5_RXP_POLL_CSR_FOR_VALUE_TIMEOUT 3000 /* Poll timeout in ms. */\n+#define MLX5_RXP_INITIALIZATION_TIMEOUT 60000 /* Initialize timeout in ms. */\n+#define MLX5_RXP_MAX_ENGINES 2u /* Number of RXP engines. */\n+#define MLX5_RXP_EM_COUNT 1u /* Extra External Memories to use. */\n+#define MLX5_RXP_DB_NOT_ASSIGNED 0xFF\n+\n+struct mlx5_regex_umem {\n+\tstruct mlx5dv_devx_umem *umem;\n+\tuint32_t id;\n+\tuint64_t offset;\n+};\n+\n+#endif /* RTE_PMD_MLX5_REGEX_RXP_H_ */\n",
    "prefixes": [
        "v6",
        "07/13"
    ]
}