get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 61236,
    "url": "http://patches.dpdk.org/api/patches/61236/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1571130263-120863-4-git-send-email-orika@mellanox.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "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",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1571130263-120863-4-git-send-email-orika@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1571130263-120863-4-git-send-email-orika@mellanox.com",
    "date": "2019-10-15T09:04:11",
    "name": "[v3,03/14] net/mlx5: support Rx hairpin queues",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "83f1a93088290b45d96ea955455f6aed00aa6f72",
    "submitter": {
        "id": 795,
        "url": "http://patches.dpdk.org/api/people/795/?format=api",
        "name": "Ori Kam",
        "email": "orika@mellanox.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1571130263-120863-4-git-send-email-orika@mellanox.com/mbox/",
    "series": [
        {
            "id": 6855,
            "url": "http://patches.dpdk.org/api/series/6855/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=6855",
            "date": "2019-10-15T09:04:08",
            "name": "add hairpin feature",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/6855/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/61236/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/61236/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 0E4551E4E1;\n\tTue, 15 Oct 2019 11:05:12 +0200 (CEST)",
            "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n\tby dpdk.org (Postfix) with ESMTP id B89C91DFE4\n\tfor <dev@dpdk.org>; Tue, 15 Oct 2019 11:05:10 +0200 (CEST)",
            "from Internal Mail-Server by MTLPINE1 (envelope-from\n\torika@mellanox.com)\n\twith ESMTPS (AES256-SHA encrypted); 15 Oct 2019 11:05:09 +0200",
            "from pegasus04.mtr.labs.mlnx. (pegasus04.mtr.labs.mlnx\n\t[10.210.16.126])\n\tby labmailer.mlnx (8.13.8/8.13.8) with ESMTP id x9F94hce029891;\n\tTue, 15 Oct 2019 12:05:09 +0300"
        ],
        "From": "Ori Kam <orika@mellanox.com>",
        "To": "Matan Azrad <matan@mellanox.com>, Shahaf Shuler <shahafs@mellanox.com>, \n\tViacheslav Ovsiienko <viacheslavo@mellanox.com>",
        "Cc": "dev@dpdk.org, orika@mellanox.com, jingjing.wu@intel.com,\n\tstephen@networkplumber.org",
        "Date": "Tue, 15 Oct 2019 09:04:11 +0000",
        "Message-Id": "<1571130263-120863-4-git-send-email-orika@mellanox.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1571130263-120863-1-git-send-email-orika@mellanox.com>",
        "References": "<1569479349-36962-1-git-send-email-orika@mellanox.com>\n\t<1571130263-120863-1-git-send-email-orika@mellanox.com>",
        "Subject": "[dpdk-dev] [PATCH v3 03/14] net/mlx5: support Rx hairpin queues",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This commit adds the support for creating Rx hairpin queues.\nHairpin queue is a queue that is created using DevX and only used\nby the HW. This results in that all the data part of the RQ is not being\nused.\n\nSigned-off-by: Ori Kam <orika@mellanox.com>\nAcked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>\n\n---\n drivers/net/mlx5/mlx5.c         |   2 +\n drivers/net/mlx5/mlx5_rxq.c     | 270 ++++++++++++++++++++++++++++++++++++----\n drivers/net/mlx5/mlx5_rxtx.h    |  15 +++\n drivers/net/mlx5/mlx5_trigger.c |   7 ++\n 4 files changed, 270 insertions(+), 24 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 34376f6..49edb7e 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -974,6 +974,7 @@ struct mlx5_dev_spawn_data {\n \t.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,\n \t.vlan_filter_set = mlx5_vlan_filter_set,\n \t.rx_queue_setup = mlx5_rx_queue_setup,\n+\t.rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,\n \t.tx_queue_setup = mlx5_tx_queue_setup,\n \t.rx_queue_release = mlx5_rx_queue_release,\n \t.tx_queue_release = mlx5_tx_queue_release,\n@@ -1040,6 +1041,7 @@ struct mlx5_dev_spawn_data {\n \t.dev_supported_ptypes_get = mlx5_dev_supported_ptypes_get,\n \t.vlan_filter_set = mlx5_vlan_filter_set,\n \t.rx_queue_setup = mlx5_rx_queue_setup,\n+\t.rx_hairpin_queue_setup = mlx5_rx_hairpin_queue_setup,\n \t.tx_queue_setup = mlx5_tx_queue_setup,\n \t.rx_queue_release = mlx5_rx_queue_release,\n \t.tx_queue_release = mlx5_tx_queue_release,\ndiff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c\nindex 0db065a..66596df 100644\n--- a/drivers/net/mlx5/mlx5_rxq.c\n+++ b/drivers/net/mlx5/mlx5_rxq.c\n@@ -106,21 +106,25 @@\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n \tuint16_t i;\n \tuint16_t n = 0;\n+\tuint16_t n_ibv = 0;\n \n \tif (mlx5_check_mprq_support(dev) < 0)\n \t\treturn 0;\n \t/* All the configured queues should be enabled. */\n \tfor (i = 0; i < priv->rxqs_n; ++i) {\n \t\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[i];\n+\t\tstruct mlx5_rxq_ctrl *rxq_ctrl = container_of\n+\t\t\t(rxq, struct mlx5_rxq_ctrl, rxq);\n \n-\t\tif (!rxq)\n+\t\tif (rxq == NULL || rxq_ctrl->type != MLX5_RXQ_TYPE_STANDARD)\n \t\t\tcontinue;\n+\t\tn_ibv++;\n \t\tif (mlx5_rxq_mprq_enabled(rxq))\n \t\t\t++n;\n \t}\n \t/* Multi-Packet RQ can't be partially configured. */\n-\tassert(n == 0 || n == priv->rxqs_n);\n-\treturn n == priv->rxqs_n;\n+\tassert(n == 0 || n == n_ibv);\n+\treturn n == n_ibv;\n }\n \n /**\n@@ -427,6 +431,7 @@\n }\n \n /**\n+ * Rx queue presetup checks.\n  *\n  * @param dev\n  *   Pointer to Ethernet device structure.\n@@ -434,25 +439,14 @@\n  *   RX queue index.\n  * @param desc\n  *   Number of descriptors to configure in queue.\n- * @param socket\n- *   NUMA socket on which memory must be allocated.\n- * @param[in] conf\n- *   Thresholds parameters.\n- * @param mp\n- *   Memory pool for buffer allocations.\n  *\n  * @return\n  *   0 on success, a negative errno value otherwise and rte_errno is set.\n  */\n-int\n-mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n-\t\t    unsigned int socket, const struct rte_eth_rxconf *conf,\n-\t\t    struct rte_mempool *mp)\n+static int\n+mlx5_rx_queue_pre_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc)\n {\n \tstruct mlx5_priv *priv = dev->data->dev_private;\n-\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[idx];\n-\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n-\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n \n \tif (!rte_is_power_of_2(desc)) {\n \t\tdesc = 1 << log2above(desc);\n@@ -476,6 +470,41 @@\n \t\treturn -rte_errno;\n \t}\n \tmlx5_rxq_release(dev, idx);\n+\treturn 0;\n+}\n+\n+/**\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ * @param idx\n+ *   RX queue index.\n+ * @param desc\n+ *   Number of descriptors to configure in queue.\n+ * @param socket\n+ *   NUMA socket on which memory must be allocated.\n+ * @param[in] conf\n+ *   Thresholds parameters.\n+ * @param mp\n+ *   Memory pool for buffer allocations.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+int\n+mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n+\t\t    unsigned int socket, const struct rte_eth_rxconf *conf,\n+\t\t    struct rte_mempool *mp)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[idx];\n+\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n+\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\tint res;\n+\n+\tres = mlx5_rx_queue_pre_setup(dev, idx, desc);\n+\tif (res)\n+\t\treturn res;\n \trxq_ctrl = mlx5_rxq_new(dev, idx, desc, socket, conf, mp);\n \tif (!rxq_ctrl) {\n \t\tDRV_LOG(ERR, \"port %u unable to allocate queue index %u\",\n@@ -490,6 +519,56 @@\n }\n \n /**\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device structure.\n+ * @param idx\n+ *   RX queue index.\n+ * @param desc\n+ *   Number of descriptors to configure in queue.\n+ * @param hairpin_conf\n+ *   Hairpin configuration parameters.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+int\n+mlx5_rx_hairpin_queue_setup(struct rte_eth_dev *dev, uint16_t idx,\n+\t\t\t    uint16_t desc,\n+\t\t\t    const struct rte_eth_hairpin_conf *hairpin_conf)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[idx];\n+\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n+\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\tint res;\n+\n+\tres = mlx5_rx_queue_pre_setup(dev, idx, desc);\n+\tif (res)\n+\t\treturn res;\n+\tif (hairpin_conf->peer_n != 1 ||\n+\t    hairpin_conf->peers[0].port != dev->data->port_id ||\n+\t    hairpin_conf->peers[0].queue >= priv->txqs_n) {\n+\t\tDRV_LOG(ERR, \"port %u unable to setup hairpin queue index %u \"\n+\t\t\t\" invalid hairpind configuration\", dev->data->port_id,\n+\t\t\tidx);\n+\t\trte_errno = EINVAL;\n+\t\treturn -rte_errno;\n+\t}\n+\trxq_ctrl = mlx5_rxq_hairpin_new(dev, idx, desc, hairpin_conf);\n+\tif (!rxq_ctrl) {\n+\t\tDRV_LOG(ERR, \"port %u unable to allocate queue index %u\",\n+\t\t\tdev->data->port_id, idx);\n+\t\trte_errno = ENOMEM;\n+\t\treturn -rte_errno;\n+\t}\n+\tDRV_LOG(DEBUG, \"port %u adding Rx queue %u to list\",\n+\t\tdev->data->port_id, idx);\n+\t(*priv->rxqs)[idx] = &rxq_ctrl->rxq;\n+\treturn 0;\n+}\n+\n+/**\n  * DPDK callback to release a RX queue.\n  *\n  * @param dpdk_rxq\n@@ -561,6 +640,24 @@\n }\n \n /**\n+ * Release an Rx hairpin related resources.\n+ *\n+ * @param rxq_obj\n+ *   Hairpin Rx queue object.\n+ */\n+static void\n+rxq_obj_hairpin_release(struct mlx5_rxq_obj *rxq_obj)\n+{\n+\tstruct mlx5_devx_modify_rq_attr rq_attr = { 0 };\n+\n+\tassert(rxq_obj);\n+\trq_attr.state = MLX5_RQC_STATE_RST;\n+\trq_attr.rq_state = MLX5_RQC_STATE_RDY;\n+\tmlx5_devx_cmd_modify_rq(rxq_obj->rq, &rq_attr);\n+\tclaim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));\n+}\n+\n+/**\n  * Release an Rx verbs/DevX queue object.\n  *\n  * @param rxq_obj\n@@ -577,14 +674,22 @@\n \t\tassert(rxq_obj->wq);\n \tassert(rxq_obj->cq);\n \tif (rte_atomic32_dec_and_test(&rxq_obj->refcnt)) {\n-\t\trxq_free_elts(rxq_obj->rxq_ctrl);\n-\t\tif (rxq_obj->type == MLX5_RXQ_OBJ_TYPE_IBV) {\n+\t\tswitch (rxq_obj->type) {\n+\t\tcase MLX5_RXQ_OBJ_TYPE_IBV:\n+\t\t\trxq_free_elts(rxq_obj->rxq_ctrl);\n \t\t\tclaim_zero(mlx5_glue->destroy_wq(rxq_obj->wq));\n-\t\t} else if (rxq_obj->type == MLX5_RXQ_OBJ_TYPE_DEVX_RQ) {\n+\t\t\tclaim_zero(mlx5_glue->destroy_cq(rxq_obj->cq));\n+\t\t\tbreak;\n+\t\tcase MLX5_RXQ_OBJ_TYPE_DEVX_RQ:\n+\t\t\trxq_free_elts(rxq_obj->rxq_ctrl);\n \t\t\tclaim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));\n \t\t\trxq_release_rq_resources(rxq_obj->rxq_ctrl);\n+\t\t\tclaim_zero(mlx5_glue->destroy_cq(rxq_obj->cq));\n+\t\t\tbreak;\n+\t\tcase MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN:\n+\t\t\trxq_obj_hairpin_release(rxq_obj);\n+\t\t\tbreak;\n \t\t}\n-\t\tclaim_zero(mlx5_glue->destroy_cq(rxq_obj->cq));\n \t\tif (rxq_obj->channel)\n \t\t\tclaim_zero(mlx5_glue->destroy_comp_channel\n \t\t\t\t   (rxq_obj->channel));\n@@ -1132,6 +1237,70 @@\n }\n \n /**\n+ * Create the Rx hairpin queue object.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param idx\n+ *   Queue index in DPDK Rx queue array\n+ *\n+ * @return\n+ *   The hairpin DevX object initialised, NULL otherwise and rte_errno is set.\n+ */\n+static struct mlx5_rxq_obj *\n+mlx5_rxq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_rxq_data *rxq_data = (*priv->rxqs)[idx];\n+\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n+\t\tcontainer_of(rxq_data, struct mlx5_rxq_ctrl, rxq);\n+\tstruct mlx5_devx_create_rq_attr attr = { 0 };\n+\tstruct mlx5_rxq_obj *tmpl = NULL;\n+\tint ret = 0;\n+\n+\tassert(rxq_data);\n+\tassert(!rxq_ctrl->obj);\n+\ttmpl = rte_calloc_socket(__func__, 1, sizeof(*tmpl), 0,\n+\t\t\t\t rxq_ctrl->socket);\n+\tif (!tmpl) {\n+\t\tDRV_LOG(ERR,\n+\t\t\t\"port %u Rx queue %u cannot allocate verbs resources\",\n+\t\t\tdev->data->port_id, rxq_data->idx);\n+\t\trte_errno = ENOMEM;\n+\t\tgoto error;\n+\t}\n+\ttmpl->type = MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN;\n+\ttmpl->rxq_ctrl = rxq_ctrl;\n+\tattr.hairpin = 1;\n+\t/* Workaround for hairpin startup */\n+\tattr.wq_attr.log_hairpin_num_packets = log2above(32);\n+\t/* Workaround for packets larger than 1KB */\n+\tattr.wq_attr.log_hairpin_data_sz =\n+\t\t\tpriv->config.hca_attr.log_max_hairpin_wq_data_sz;\n+\ttmpl->rq = mlx5_devx_cmd_create_rq(priv->sh->ctx, &attr,\n+\t\t\t\t\t   rxq_ctrl->socket);\n+\tif (!tmpl->rq) {\n+\t\tDRV_LOG(ERR,\n+\t\t\t\"port %u Rx hairpin queue %u can't create rq object\",\n+\t\t\tdev->data->port_id, idx);\n+\t\trte_errno = errno;\n+\t\tgoto error;\n+\t}\n+\tDRV_LOG(DEBUG, \"port %u rxq %u updated with %p\", dev->data->port_id,\n+\t\tidx, (void *)&tmpl);\n+\trte_atomic32_inc(&tmpl->refcnt);\n+\tLIST_INSERT_HEAD(&priv->rxqsobj, tmpl, next);\n+\tpriv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE;\n+\treturn tmpl;\n+error:\n+\tret = rte_errno; /* Save rte_errno before cleanup. */\n+\tif (tmpl->rq)\n+\t\tmlx5_devx_cmd_destroy(tmpl->rq);\n+\trte_errno = ret; /* Restore rte_errno. */\n+\treturn NULL;\n+}\n+\n+/**\n  * Create the Rx queue Verbs/DevX object.\n  *\n  * @param dev\n@@ -1163,6 +1332,8 @@ struct mlx5_rxq_obj *\n \n \tassert(rxq_data);\n \tassert(!rxq_ctrl->obj);\n+\tif (type == MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN)\n+\t\treturn mlx5_rxq_obj_hairpin_new(dev, idx);\n \tpriv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_RX_QUEUE;\n \tpriv->verbs_alloc_ctx.obj = rxq_ctrl;\n \ttmpl = rte_calloc_socket(__func__, 1, sizeof(*tmpl), 0,\n@@ -1433,15 +1604,19 @@ struct mlx5_rxq_obj *\n \tunsigned int strd_num_n = 0;\n \tunsigned int strd_sz_n = 0;\n \tunsigned int i;\n+\tunsigned int n_ibv = 0;\n \n \tif (!mlx5_mprq_enabled(dev))\n \t\treturn 0;\n \t/* Count the total number of descriptors configured. */\n \tfor (i = 0; i != priv->rxqs_n; ++i) {\n \t\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[i];\n+\t\tstruct mlx5_rxq_ctrl *rxq_ctrl = container_of\n+\t\t\t(rxq, struct mlx5_rxq_ctrl, rxq);\n \n-\t\tif (rxq == NULL)\n+\t\tif (rxq == NULL || rxq_ctrl->type != MLX5_RXQ_TYPE_STANDARD)\n \t\t\tcontinue;\n+\t\tn_ibv++;\n \t\tdesc += 1 << rxq->elts_n;\n \t\t/* Get the max number of strides. */\n \t\tif (strd_num_n < rxq->strd_num_n)\n@@ -1466,7 +1641,7 @@ struct mlx5_rxq_obj *\n \t * this Mempool gets available again.\n \t */\n \tdesc *= 4;\n-\tobj_num = desc + MLX5_MPRQ_MP_CACHE_SZ * priv->rxqs_n;\n+\tobj_num = desc + MLX5_MPRQ_MP_CACHE_SZ * n_ibv;\n \t/*\n \t * rte_mempool_create_empty() has sanity check to refuse large cache\n \t * size compared to the number of elements.\n@@ -1514,8 +1689,10 @@ struct mlx5_rxq_obj *\n \t/* Set mempool for each Rx queue. */\n \tfor (i = 0; i != priv->rxqs_n; ++i) {\n \t\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[i];\n+\t\tstruct mlx5_rxq_ctrl *rxq_ctrl = container_of\n+\t\t\t(rxq, struct mlx5_rxq_ctrl, rxq);\n \n-\t\tif (rxq == NULL)\n+\t\tif (rxq == NULL || rxq_ctrl->type != MLX5_RXQ_TYPE_STANDARD)\n \t\t\tcontinue;\n \t\trxq->mprq_mp = mp;\n \t}\n@@ -1620,6 +1797,7 @@ struct mlx5_rxq_ctrl *\n \t\trte_errno = ENOMEM;\n \t\treturn NULL;\n \t}\n+\ttmpl->type = MLX5_RXQ_TYPE_STANDARD;\n \tif (mlx5_mr_btree_init(&tmpl->rxq.mr_ctrl.cache_bh,\n \t\t\t       MLX5_MR_BTREE_CACHE_N, socket)) {\n \t\t/* rte_errno is already set. */\n@@ -1788,6 +1966,49 @@ struct mlx5_rxq_ctrl *\n }\n \n /**\n+ * Create a DPDK Rx hairpin queue.\n+ *\n+ * @param dev\n+ *   Pointer to Ethernet device.\n+ * @param idx\n+ *   RX queue index.\n+ * @param desc\n+ *   Number of descriptors to configure in queue.\n+ * @param hairpin_conf\n+ *   The hairpin binding configuration.\n+ *\n+ * @return\n+ *   A DPDK queue object on success, NULL otherwise and rte_errno is set.\n+ */\n+struct mlx5_rxq_ctrl *\n+mlx5_rxq_hairpin_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n+\t\t     const struct rte_eth_hairpin_conf *hairpin_conf)\n+{\n+\tstruct mlx5_priv *priv = dev->data->dev_private;\n+\tstruct mlx5_rxq_ctrl *tmpl;\n+\n+\ttmpl = rte_calloc_socket(\"RXQ\", 1, sizeof(*tmpl), 0, SOCKET_ID_ANY);\n+\tif (!tmpl) {\n+\t\trte_errno = ENOMEM;\n+\t\treturn NULL;\n+\t}\n+\ttmpl->type = MLX5_RXQ_TYPE_HAIRPIN;\n+\ttmpl->socket = SOCKET_ID_ANY;\n+\ttmpl->rxq.rss_hash = 0;\n+\ttmpl->rxq.port_id = dev->data->port_id;\n+\ttmpl->priv = priv;\n+\ttmpl->rxq.mp = NULL;\n+\ttmpl->rxq.elts_n = log2above(desc);\n+\ttmpl->rxq.elts = NULL;\n+\ttmpl->rxq.mr_ctrl.cache_bh = (struct mlx5_mr_btree) { 0 };\n+\ttmpl->hairpin_conf = *hairpin_conf;\n+\ttmpl->rxq.idx = idx;\n+\trte_atomic32_inc(&tmpl->refcnt);\n+\tLIST_INSERT_HEAD(&priv->rxqsctrl, tmpl, next);\n+\treturn tmpl;\n+}\n+\n+/**\n  * Get a Rx queue.\n  *\n  * @param dev\n@@ -1841,7 +2062,8 @@ struct mlx5_rxq_ctrl *\n \t\tif (rxq_ctrl->dbr_umem_id_valid)\n \t\t\tclaim_zero(mlx5_release_dbr(dev, rxq_ctrl->dbr_umem_id,\n \t\t\t\t\t\t    rxq_ctrl->dbr_offset));\n-\t\tmlx5_mr_btree_free(&rxq_ctrl->rxq.mr_ctrl.cache_bh);\n+\t\tif (rxq_ctrl->type == MLX5_RXQ_TYPE_STANDARD)\n+\t\t\tmlx5_mr_btree_free(&rxq_ctrl->rxq.mr_ctrl.cache_bh);\n \t\tLIST_REMOVE(rxq_ctrl, next);\n \t\trte_free(rxq_ctrl);\n \t\t(*priv->rxqs)[idx] = NULL;\ndiff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h\nindex 4bb28a4..13fdc38 100644\n--- a/drivers/net/mlx5/mlx5_rxtx.h\n+++ b/drivers/net/mlx5/mlx5_rxtx.h\n@@ -159,6 +159,13 @@ struct mlx5_rxq_data {\n enum mlx5_rxq_obj_type {\n \tMLX5_RXQ_OBJ_TYPE_IBV,\t\t/* mlx5_rxq_obj with ibv_wq. */\n \tMLX5_RXQ_OBJ_TYPE_DEVX_RQ,\t/* mlx5_rxq_obj with mlx5_devx_rq. */\n+\tMLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN,\n+\t/* mlx5_rxq_obj with mlx5_devx_rq and hairpin support. */\n+};\n+\n+enum mlx5_rxq_type {\n+\tMLX5_RXQ_TYPE_STANDARD, /* Standard Rx queue. */\n+\tMLX5_RXQ_TYPE_HAIRPIN, /* Hairpin Rx queue. */\n };\n \n /* Verbs/DevX Rx queue elements. */\n@@ -183,6 +190,7 @@ struct mlx5_rxq_ctrl {\n \trte_atomic32_t refcnt; /* Reference counter. */\n \tstruct mlx5_rxq_obj *obj; /* Verbs/DevX elements. */\n \tstruct mlx5_priv *priv; /* Back pointer to private data. */\n+\tenum mlx5_rxq_type type; /* Rxq type. */\n \tunsigned int socket; /* CPU socket ID for allocations. */\n \tunsigned int irq:1; /* Whether IRQ is enabled. */\n \tunsigned int dbr_umem_id_valid:1; /* dbr_umem_id holds a valid value. */\n@@ -193,6 +201,7 @@ struct mlx5_rxq_ctrl {\n \tuint32_t dbr_umem_id; /* Storing door-bell information, */\n \tuint64_t dbr_offset;  /* needed when freeing door-bell. */\n \tstruct mlx5dv_devx_umem *wq_umem; /* WQ buffer registration info. */\n+\tstruct rte_eth_hairpin_conf hairpin_conf; /* Hairpin configuration. */\n };\n \n enum mlx5_ind_tbl_type {\n@@ -339,6 +348,9 @@ struct mlx5_txq_ctrl {\n int mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n \t\t\tunsigned int socket, const struct rte_eth_rxconf *conf,\n \t\t\tstruct rte_mempool *mp);\n+int mlx5_rx_hairpin_queue_setup\n+\t(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n+\t const struct rte_eth_hairpin_conf *hairpin_conf);\n void mlx5_rx_queue_release(void *dpdk_rxq);\n int mlx5_rx_intr_vec_enable(struct rte_eth_dev *dev);\n void mlx5_rx_intr_vec_disable(struct rte_eth_dev *dev);\n@@ -351,6 +363,9 @@ struct mlx5_rxq_ctrl *mlx5_rxq_new(struct rte_eth_dev *dev, uint16_t idx,\n \t\t\t\t   uint16_t desc, unsigned int socket,\n \t\t\t\t   const struct rte_eth_rxconf *conf,\n \t\t\t\t   struct rte_mempool *mp);\n+struct mlx5_rxq_ctrl *mlx5_rxq_hairpin_new\n+\t(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n+\t const struct rte_eth_hairpin_conf *hairpin_conf);\n struct mlx5_rxq_ctrl *mlx5_rxq_get(struct rte_eth_dev *dev, uint16_t idx);\n int mlx5_rxq_release(struct rte_eth_dev *dev, uint16_t idx);\n int mlx5_rxq_verify(struct rte_eth_dev *dev);\ndiff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c\nindex 122f31c..cb31ae2 100644\n--- a/drivers/net/mlx5/mlx5_trigger.c\n+++ b/drivers/net/mlx5/mlx5_trigger.c\n@@ -118,6 +118,13 @@\n \n \t\tif (!rxq_ctrl)\n \t\t\tcontinue;\n+\t\tif (rxq_ctrl->type == MLX5_RXQ_TYPE_HAIRPIN) {\n+\t\t\trxq_ctrl->obj = mlx5_rxq_obj_new\n+\t\t\t\t(dev, i, MLX5_RXQ_OBJ_TYPE_DEVX_HAIRPIN);\n+\t\t\tif (!rxq_ctrl->obj)\n+\t\t\t\tgoto error;\n+\t\t\tcontinue;\n+\t\t}\n \t\t/* Pre-register Rx mempool. */\n \t\tmp = mlx5_rxq_mprq_enabled(&rxq_ctrl->rxq) ?\n \t\t     rxq_ctrl->rxq.mprq_mp : rxq_ctrl->rxq.mp;\n",
    "prefixes": [
        "v3",
        "03/14"
    ]
}