get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 27374,
    "url": "http://patches.dpdk.org/api/patches/27374/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/8665c7e875ddcdd954322a8b42fa36d22939069a.1501681927.git.nelio.laranjeiro@6wind.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": "<8665c7e875ddcdd954322a8b42fa36d22939069a.1501681927.git.nelio.laranjeiro@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/8665c7e875ddcdd954322a8b42fa36d22939069a.1501681927.git.nelio.laranjeiro@6wind.com",
    "date": "2017-08-02T14:10:24",
    "name": "[dpdk-dev,v1,08/21] net/mlx5: separate DPDK from Verbs Rx queue objects",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "099321ff0860dd72323de37f6b9173190b764b61",
    "submitter": {
        "id": 243,
        "url": "http://patches.dpdk.org/api/people/243/?format=api",
        "name": "Nélio Laranjeiro",
        "email": "nelio.laranjeiro@6wind.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/8665c7e875ddcdd954322a8b42fa36d22939069a.1501681927.git.nelio.laranjeiro@6wind.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/27374/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/27374/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 [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 6C03EA176;\n\tWed,  2 Aug 2017 16:11:24 +0200 (CEST)",
            "from mail-wm0-f48.google.com (mail-wm0-f48.google.com\n\t[74.125.82.48]) by dpdk.org (Postfix) with ESMTP id F1756A0C2\n\tfor <dev@dpdk.org>; Wed,  2 Aug 2017 16:11:07 +0200 (CEST)",
            "by mail-wm0-f48.google.com with SMTP id m85so42753601wma.1\n\tfor <dev@dpdk.org>; Wed, 02 Aug 2017 07:11:07 -0700 (PDT)",
            "from ping.dev.6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\td53sm39449552wrd.81.2017.08.02.07.11.05\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 02 Aug 2017 07:11:05 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:in-reply-to:references;\n\tbh=hyzVvOIYLh0h6Z1j+jdyjSlBlDqs3xazFeT2Co2wUlY=;\n\tb=aThtRbOBrunu8neH7gVPgUphqAVn5UexTea1CRoMqVr4lJZQnDAaUOI1iRd8beegYY\n\tqcWC28EJ+4p91dTSGECbOwxttrR8lDYZJAJ+YSDs5pFPQ/uuwjaHAbKsM5kuF3czV4k9\n\tVz/mDzlsHI+HNTgzHAjCIt1zaVTNWH5s5G58CsfgWBLigf+74jIGlBaEvsuvbUTfEbub\n\tnIew8+N47rM43XFMhNTfNUcmqXiyRV78mKYK4FcuzqxzOmZ/X1cj3CVydEqwexxl/ev1\n\tTMg5nUO5hvNug/7jIDyDfgi3/M3otV2vPdjF6v/qQQK8CBHpl6l2g+tpzpreB7m+3QGU\n\t+ABQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:in-reply-to:references;\n\tbh=hyzVvOIYLh0h6Z1j+jdyjSlBlDqs3xazFeT2Co2wUlY=;\n\tb=tTRCbU8SGS6T2noijfZHu9fKT7/N2j9t1YuWFLyXrJ11b7o4MflqP/9f0enFwP1vKz\n\t+VAKgrXiU4ctncu6E4ywLxKc4tdC7AI0v1WhF6TYIn7L/IqzIU4KbCRtqpkKnpGS7s4e\n\tVaU5AlsOQcygLhBQXJ57/zPzSiG2G7sADpttewivQbRZTPeS7D7moiR0O1RPIHIUFnX/\n\tP439Ai9LIAzT1A/3fFCzw83yYjaS4+G4qDoQpgMEwdC+TA8rJ1sNDPiC3HQjQwvPKXkH\n\t2JPc5VSXgBOzOptyAN4k7UZ+zJ1HGEE36mKS1J2+iUzl83FgDXV0XHi/X+NivchSoZ5D\n\tv7tA==",
        "X-Gm-Message-State": "AIVw112oZaX1AlOqRAFk2HoXI2WkDqsTzcCH5p1emoZlItcBGExeH1G8\n\tzclkCuXuMk2rbSUtUqRwdg==",
        "X-Received": "by 10.28.71.91 with SMTP id u88mr3908445wma.44.1501683066247;\n\tWed, 02 Aug 2017 07:11:06 -0700 (PDT)",
        "From": "Nelio Laranjeiro <nelio.laranjeiro@6wind.com>",
        "To": "dev@dpdk.org",
        "Cc": "adrien.mazarguil@6wind.com",
        "Date": "Wed,  2 Aug 2017 16:10:24 +0200",
        "Message-Id": "<8665c7e875ddcdd954322a8b42fa36d22939069a.1501681927.git.nelio.laranjeiro@6wind.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": [
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>",
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>"
        ],
        "References": [
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>",
            "<cover.1501681927.git.nelio.laranjeiro@6wind.com>"
        ],
        "Subject": "[dpdk-dev] [PATCH v1 08/21] net/mlx5: separate DPDK from Verbs Rx\n\tqueue objects",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>\n---\n drivers/net/mlx5/mlx5.c      |   3 +\n drivers/net/mlx5/mlx5.h      |   2 +-\n drivers/net/mlx5/mlx5_flow.c |  97 +++-----\n drivers/net/mlx5/mlx5_rxq.c  | 564 ++++++++++++++++++++++++++-----------------\n drivers/net/mlx5/mlx5_rxtx.h |  26 +-\n drivers/net/mlx5/mlx5_vlan.c |   2 +-\n 6 files changed, 401 insertions(+), 293 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 0d8ca52..c158d8e 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -200,6 +200,9 @@ mlx5_dev_close(struct rte_eth_dev *dev)\n \t}\n \tif (priv->reta_idx != NULL)\n \t\trte_free(priv->reta_idx);\n+\ti = mlx5_priv_rxq_ibv_verify(priv);\n+\tif (i)\n+\t\tWARN(\"%p: some Verbs Rx queue still remain\", (void*)priv);\n \ti = priv_flow_verify(priv);\n \tif (i)\n \t\tWARN(\"%p: some flows still remain\", (void*)priv);\ndiff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h\nindex 1ae5f59..228fd34 100644\n--- a/drivers/net/mlx5/mlx5.h\n+++ b/drivers/net/mlx5/mlx5.h\n@@ -146,6 +146,7 @@ struct priv {\n \tstruct rte_flow_drop *flow_drop_queue; /* Flow drop queue. */\n \tTAILQ_HEAD(mlx5_flows, rte_flow) flows; /* RTE Flow rules. */\n \tLIST_HEAD(mr, mlx5_mr) mr; /* Memory region. */\n+\tLIST_HEAD(rxqibv, mlx5_rxq_ibv) rxqsibv; /* Verbs Rx queues. */\n \tuint32_t link_speed_capa; /* Link speed capabilities. */\n \tstruct mlx5_xstats_ctrl xstats_ctrl; /* Extended stats control. */\n \trte_spinlock_t lock; /* Lock for control functions. */\n@@ -287,7 +288,6 @@ int mlx5_flow_flush(struct rte_eth_dev *, struct rte_flow_error *);\n int mlx5_flow_isolate(struct rte_eth_dev *, int, struct rte_flow_error *);\n int priv_flow_start(struct priv *);\n void priv_flow_stop(struct priv *);\n-int priv_flow_rxq_in_use(struct priv *, struct mlx5_rxq_data *);\n int priv_flow_verify(struct priv *);\n \n /* mlx5_mr.c */\ndiff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c\nindex bcbb984..9ed8d05 100644\n--- a/drivers/net/mlx5/mlx5_flow.c\n+++ b/drivers/net/mlx5/mlx5_flow.c\n@@ -95,11 +95,11 @@ struct rte_flow {\n \tstruct ibv_exp_flow *ibv_flow; /**< Verbs flow. */\n \tstruct ibv_exp_wq *wq; /**< Verbs work queue. */\n \tstruct ibv_cq *cq; /**< Verbs completion queue. */\n-\tuint16_t rxqs_n; /**< Number of queues in this flow, 0 if drop queue. */\n \tuint32_t mark:1; /**< Set if the flow is marked. */\n \tuint32_t drop:1; /**< Drop queue. */\n \tuint64_t hash_fields; /**< Fields that participate in the hash. */\n-\tstruct mlx5_rxq_data *rxqs[]; /**< Pointer to the queues array. */\n+\tuint16_t queues[RTE_MAX_QUEUES_PER_PORT]; /**< List of queues. */\n+\tuint16_t queues_n; /**< Number of queues in the list. */\n };\n \n /** Static initializer for items. */\n@@ -1097,23 +1097,21 @@ priv_flow_create_action_queue(struct priv *priv,\n \tassert(priv->pd);\n \tassert(priv->ctx);\n \tassert(!flow->actions.drop);\n-\trte_flow = rte_calloc(__func__, 1, sizeof(*rte_flow) +\n-\t\t\t      sizeof(*rte_flow->rxqs) * flow->actions.queues_n,\n-\t\t\t      0);\n+\trte_flow = rte_calloc(__func__, 1, sizeof(*rte_flow), 0);\n \tif (!rte_flow) {\n \t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,\n \t\t\t\t   NULL, \"cannot allocate flow memory\");\n \t\treturn NULL;\n \t}\n \tfor (i = 0; i < flow->actions.queues_n; ++i) {\n-\t\tstruct mlx5_rxq_ctrl *rxq;\n+\t\tstruct mlx5_rxq_ibv *rxq =\n+\t\t\tmlx5_priv_rxq_ibv_get(priv, flow->actions.queues[i]);\n \n-\t\trxq = container_of((*priv->rxqs)[flow->actions.queues[i]],\n-\t\t\t\t   struct mlx5_rxq_ctrl, rxq);\n \t\twqs[i] = rxq->wq;\n-\t\trte_flow->rxqs[i] = &rxq->rxq;\n-\t\t++rte_flow->rxqs_n;\n-\t\trxq->rxq.mark |= flow->actions.mark;\n+\t\trte_flow->queues[i] = flow->actions.queues[i];\n+\t\t++rte_flow->queues_n;\n+\t\t(*priv->rxqs)[flow->actions.queues[i]]->mark |=\n+\t\t\tflow->actions.mark;\n \t}\n \t/* finalise indirection table. */\n \tfor (j = 0; i < wqs_n; ++i, ++j) {\n@@ -1294,6 +1292,8 @@ static void\n priv_flow_destroy(struct priv *priv,\n \t\t  struct rte_flow *flow)\n {\n+\tunsigned int i;\n+\n \tTAILQ_REMOVE(&priv->flows, flow, next);\n \tif (flow->ibv_flow)\n \t\tclaim_zero(ibv_exp_destroy_flow(flow->ibv_flow));\n@@ -1303,37 +1303,33 @@ priv_flow_destroy(struct priv *priv,\n \t\tclaim_zero(ibv_destroy_qp(flow->qp));\n \tif (flow->ind_table)\n \t\tclaim_zero(ibv_exp_destroy_rwq_ind_table(flow->ind_table));\n-\tif (flow->mark) {\n+\tfor (i = 0; i != flow->queues_n; ++i) {\n \t\tstruct rte_flow *tmp;\n-\t\tstruct mlx5_rxq_data *rxq;\n-\t\tuint32_t mark_n = 0;\n-\t\tuint32_t queue_n;\n+\t\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[flow->queues[i]];\n+\t\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n+\t\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n \n \t\t/*\n \t\t * To remove the mark from the queue, the queue must not be\n \t\t * present in any other marked flow (RSS or not).\n \t\t */\n-\t\tfor (queue_n = 0; queue_n < flow->rxqs_n; ++queue_n) {\n-\t\t\trxq = flow->rxqs[queue_n];\n-\t\t\tfor (tmp = TAILQ_FIRST(&priv->flows);\n-\t\t\t     tmp;\n-\t\t\t     tmp = TAILQ_NEXT(tmp, next)) {\n-\t\t\t\tuint32_t tqueue_n;\n+\t\tif (flow->mark) {\n+\t\t\tint mark = 0;\n+\n+\t\t\tTAILQ_FOREACH(tmp, &priv->flows, next) {\n+\t\t\t\tunsigned int j;\n \n \t\t\t\tif (tmp->drop)\n \t\t\t\t\tcontinue;\n-\t\t\t\tfor (tqueue_n = 0;\n-\t\t\t\t     tqueue_n < tmp->rxqs_n;\n-\t\t\t\t     ++tqueue_n) {\n-\t\t\t\t\tstruct mlx5_rxq_data *trxq;\n-\n-\t\t\t\t\ttrxq = tmp->rxqs[tqueue_n];\n-\t\t\t\t\tif (rxq == trxq)\n-\t\t\t\t\t\t++mark_n;\n-\t\t\t\t}\n+\t\t\t\tif (!tmp->mark)\n+\t\t\t\t\tcontinue;\n+\t\t\t\tfor (j = 0; (j != tmp->queues_n) && !mark; j++)\n+\t\t\t\t\tif (tmp->queues[j] == flow->queues[i])\n+\t\t\t\t\t\tmark = 1;\n \t\t\t}\n-\t\t\trxq->mark = !!mark_n;\n+\t\t\trxq->mark = mark;\n \t\t}\n+\t\tmlx5_priv_rxq_ibv_release(priv, rxq_ctrl->ibv);\n \t}\n free:\n \trte_free(flow->ibv_attr);\n@@ -1532,8 +1528,8 @@ priv_flow_stop(struct priv *priv)\n \t\tif (flow->mark) {\n \t\t\tunsigned int n;\n \n-\t\t\tfor (n = 0; n < flow->rxqs_n; ++n)\n-\t\t\t\tflow->rxqs[n]->mark = 0;\n+\t\t\tfor (n = 0; n < flow->queues_n; ++n)\n+\t\t\t\t(*priv->rxqs)[flow->queues[n]]->mark = 0;\n \t\t}\n \t\tDEBUG(\"Flow %p removed\", (void *)flow);\n \t}\n@@ -1575,39 +1571,8 @@ priv_flow_start(struct priv *priv)\n \t\tif (flow->mark) {\n \t\t\tunsigned int n;\n \n-\t\t\tfor (n = 0; n < flow->rxqs_n; ++n)\n-\t\t\t\tflow->rxqs[n]->mark = 1;\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n- * Verify if the Rx queue is used in a flow.\n- *\n- * @param priv\n- *   Pointer to private structure.\n- * @param rxq\n- *   Pointer to the queue to search.\n- *\n- * @return\n- *   Nonzero if the queue is used by a flow.\n- */\n-int\n-priv_flow_rxq_in_use(struct priv *priv, struct mlx5_rxq_data *rxq)\n-{\n-\tstruct rte_flow *flow;\n-\n-\tfor (flow = TAILQ_FIRST(&priv->flows);\n-\t     flow;\n-\t     flow = TAILQ_NEXT(flow, next)) {\n-\t\tunsigned int n;\n-\n-\t\tif (flow->drop)\n-\t\t\tcontinue;\n-\t\tfor (n = 0; n < flow->rxqs_n; ++n) {\n-\t\t\tif (flow->rxqs[n] == rxq)\n-\t\t\t\treturn 1;\n+\t\t\tfor (n = 0; n < flow->queues_n; ++n)\n+\t\t\t\t(*priv->rxqs)[flow->queues[n]]->mark = 1;\n \t\t}\n \t}\n \treturn 0;\ndiff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c\nindex 80cfd96..1663734 100644\n--- a/drivers/net/mlx5/mlx5_rxq.c\n+++ b/drivers/net/mlx5/mlx5_rxq.c\n@@ -378,7 +378,7 @@ priv_create_hash_rxqs(struct priv *priv)\n \n \t\trxq_ctrl = container_of((*priv->rxqs)[(*priv->reta_idx)[i]],\n \t\t\t\t\tstruct mlx5_rxq_ctrl, rxq);\n-\t\twqs[i] = rxq_ctrl->wq;\n+\t\twqs[i] = rxq_ctrl->ibv->wq;\n \t}\n \t/* Get number of hash RX queues to configure. */\n \tfor (i = 0, hash_rxqs_n = 0; (i != ind_tables_n); ++i)\n@@ -647,8 +647,6 @@ rxq_alloc_elts(struct mlx5_rxq_ctrl *rxq_ctrl, unsigned int elts_n)\n \t/* Iterate on segments. */\n \tfor (i = 0; (i != elts_n); ++i) {\n \t\tstruct rte_mbuf *buf;\n-\t\tvolatile struct mlx5_wqe_data_seg *scat =\n-\t\t\t&(*rxq_ctrl->rxq.wqes)[i];\n \n \t\tbuf = rte_pktmbuf_alloc(rxq_ctrl->rxq.mp);\n \t\tif (buf == NULL) {\n@@ -669,13 +667,6 @@ rxq_alloc_elts(struct mlx5_rxq_ctrl *rxq_ctrl, unsigned int elts_n)\n \t\tDATA_LEN(buf) = rte_pktmbuf_tailroom(buf);\n \t\tPKT_LEN(buf) = DATA_LEN(buf);\n \t\tNB_SEGS(buf) = 1;\n-\t\t/* scat->addr must be able to store a pointer. */\n-\t\tassert(sizeof(scat->addr) >= sizeof(uintptr_t));\n-\t\t*scat = (struct mlx5_wqe_data_seg){\n-\t\t\t.addr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)),\n-\t\t\t.byte_count = htonl(DATA_LEN(buf)),\n-\t\t\t.lkey = rxq_ctrl->mr->lkey,\n-\t\t};\n \t\t(*rxq_ctrl->rxq.elts)[i] = buf;\n \t}\n \tif (rxq_check_vec_support(&rxq_ctrl->rxq) > 0) {\n@@ -761,65 +752,12 @@ mlx5_rxq_cleanup(struct mlx5_rxq_ctrl *rxq_ctrl)\n {\n \tDEBUG(\"cleaning up %p\", (void *)rxq_ctrl);\n \trxq_free_elts(rxq_ctrl);\n-\tif (rxq_ctrl->wq != NULL)\n-\t\tclaim_zero(ibv_exp_destroy_wq(rxq_ctrl->wq));\n-\tif (rxq_ctrl->cq != NULL)\n-\t\tclaim_zero(ibv_destroy_cq(rxq_ctrl->cq));\n-\tif (rxq_ctrl->channel != NULL)\n-\t\tclaim_zero(ibv_destroy_comp_channel(rxq_ctrl->channel));\n-\tif (rxq_ctrl->mr != NULL)\n-\t\tpriv_mr_release(rxq_ctrl->priv, rxq_ctrl->mr);\n+\tif (rxq_ctrl->ibv)\n+\t\tmlx5_priv_rxq_ibv_release(rxq_ctrl->priv, rxq_ctrl->ibv);\n \tmemset(rxq_ctrl, 0, sizeof(*rxq_ctrl));\n }\n \n /**\n- * Initialize RX queue.\n- *\n- * @param tmpl\n- *   Pointer to RX queue control template.\n- *\n- * @return\n- *   0 on success, errno value on failure.\n- */\n-static inline int\n-rxq_setup(struct mlx5_rxq_ctrl *tmpl)\n-{\n-\tstruct ibv_cq *ibcq = tmpl->cq;\n-\tstruct ibv_mlx5_cq_info cq_info;\n-\tstruct mlx5_rwq *rwq = container_of(tmpl->wq, struct mlx5_rwq, wq);\n-\tconst uint16_t desc_n =\n-\t\t(1 << tmpl->rxq.elts_n) + tmpl->priv->rx_vec_en *\n-\t\tMLX5_VPMD_DESCS_PER_LOOP;\n-\tstruct rte_mbuf *(*elts)[desc_n] =\n-\t\trte_calloc_socket(\"RXQ\", 1, sizeof(*elts), 0, tmpl->socket);\n-\tif (ibv_mlx5_exp_get_cq_info(ibcq, &cq_info)) {\n-\t\tERROR(\"Unable to query CQ info. check your OFED.\");\n-\t\treturn ENOTSUP;\n-\t}\n-\tif (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {\n-\t\tERROR(\"Wrong MLX5_CQE_SIZE environment variable value: \"\n-\t\t      \"it should be set to %u\", RTE_CACHE_LINE_SIZE);\n-\t\treturn EINVAL;\n-\t}\n-\tif (elts == NULL)\n-\t\treturn ENOMEM;\n-\ttmpl->rxq.rq_db = rwq->rq.db;\n-\ttmpl->rxq.cqe_n = log2above(cq_info.cqe_cnt);\n-\ttmpl->rxq.cq_ci = 0;\n-\ttmpl->rxq.rq_ci = 0;\n-\ttmpl->rxq.rq_pi = 0;\n-\ttmpl->rxq.cq_db = cq_info.dbrec;\n-\ttmpl->rxq.wqes =\n-\t\t(volatile struct mlx5_wqe_data_seg (*)[])\n-\t\t(uintptr_t)rwq->rq.buff;\n-\ttmpl->rxq.cqes =\n-\t\t(volatile struct mlx5_cqe (*)[])\n-\t\t(uintptr_t)cq_info.buf;\n-\ttmpl->rxq.elts = elts;\n-\treturn 0;\n-}\n-\n-/**\n  * Configure a RX queue.\n  *\n  * @param dev\n@@ -848,25 +786,24 @@ mlx5_rxq_ctrl_setup(struct rte_eth_dev *dev, struct mlx5_rxq_ctrl *rxq_ctrl,\n \t\t.priv = priv,\n \t\t.socket = socket,\n \t\t.rxq = {\n+\t\t\t.elts = rte_calloc_socket(\"RXQ\", 1,\n+\t\t\t\t\t\t  desc *\n+\t\t\t\t\t\t  sizeof(struct rte_mbuf *), 0,\n+\t\t\t\t\t\t  socket),\n \t\t\t.elts_n = log2above(desc),\n \t\t\t.mp = mp,\n \t\t\t.rss_hash = priv->rxqs_n > 1,\n \t\t},\n \t};\n-\tstruct ibv_exp_wq_attr mod;\n-\tunion {\n-\t\tstruct ibv_exp_cq_init_attr cq;\n-\t\tstruct ibv_exp_wq_init_attr wq;\n-\t\tstruct ibv_exp_cq_attr cq_attr;\n-\t} attr;\n \tunsigned int mb_len = rte_pktmbuf_data_room_size(mp);\n-\tunsigned int cqe_n = desc - 1;\n \tconst uint16_t desc_n =\n \t\tdesc + priv->rx_vec_en * MLX5_VPMD_DESCS_PER_LOOP;\n \tstruct rte_mbuf *(*elts)[desc_n] = NULL;\n \tint ret = 0;\n \n \t(void)conf; /* Thresholds configuration (ignored). */\n+\tif (dev->data->dev_conf.intr_conf.rxq)\n+\t\ttmpl.memory_channel = 1;\n \t/* Enable scattered packets support for this queue if necessary. */\n \tassert(mb_len >= RTE_PKTMBUF_HEADROOM);\n \tif (dev->data->dev_conf.rxmode.max_rx_pkt_len <=\n@@ -919,78 +856,13 @@ mlx5_rxq_ctrl_setup(struct rte_eth_dev *dev, struct mlx5_rxq_ctrl *rxq_ctrl,\n \tif (priv->hw_csum_l2tun)\n \t\ttmpl.rxq.csum_l2tun =\n \t\t\t!!dev->data->dev_conf.rxmode.hw_ip_checksum;\n-\t/* Use the entire RX mempool as the memory region. */\n-\ttmpl.mr = priv_mr_get(priv, mp);\n-\tif (tmpl.mr == NULL) {\n-\t\ttmpl.mr = priv_mr_new(priv, mp);\n-\t\tif (tmpl.mr == NULL) {\n-\t\t\tret = EINVAL;\n-\t\t\tERROR(\"%p: MR creation failure: %s\",\n-\t\t\t      (void *)dev, strerror(ret));\n-\t\t\tgoto error;\n-\t\t}\n-\t}\n-\tif (dev->data->dev_conf.intr_conf.rxq) {\n-\t\ttmpl.channel = ibv_create_comp_channel(priv->ctx);\n-\t\tif (tmpl.channel == NULL) {\n-\t\t\tret = ENOMEM;\n-\t\t\tERROR(\"%p: Rx interrupt completion channel creation\"\n-\t\t\t      \" failure: %s\",\n-\t\t\t      (void *)dev, strerror(ret));\n-\t\t\tgoto error;\n-\t\t}\n-\t}\n-\tattr.cq = (struct ibv_exp_cq_init_attr){\n-\t\t.comp_mask = 0,\n-\t};\n-\tif (priv->cqe_comp) {\n-\t\tattr.cq.comp_mask |= IBV_EXP_CQ_INIT_ATTR_FLAGS;\n-\t\tattr.cq.flags |= IBV_EXP_CQ_COMPRESSED_CQE;\n-\t\t/*\n-\t\t * For vectorized Rx, it must not be doubled in order to\n-\t\t * make cq_ci and rq_ci aligned.\n-\t\t */\n-\t\tif (rxq_check_vec_support(&tmpl.rxq) < 0)\n-\t\t\tcqe_n = (desc * 2) - 1; /* Double the number of CQEs. */\n-\t}\n-\ttmpl.cq = ibv_exp_create_cq(priv->ctx, cqe_n, NULL, tmpl.channel, 0,\n-\t\t\t\t    &attr.cq);\n-\tif (tmpl.cq == NULL) {\n-\t\tret = ENOMEM;\n-\t\tERROR(\"%p: CQ creation failure: %s\",\n-\t\t      (void *)dev, strerror(ret));\n-\t\tgoto error;\n-\t}\n-\tDEBUG(\"priv->device_attr.max_qp_wr is %d\",\n-\t      priv->device_attr.max_qp_wr);\n-\tDEBUG(\"priv->device_attr.max_sge is %d\",\n-\t      priv->device_attr.max_sge);\n \t/* Configure VLAN stripping. */\n \ttmpl.rxq.vlan_strip = (priv->hw_vlan_strip &&\n \t\t\t       !!dev->data->dev_conf.rxmode.hw_vlan_strip);\n-\tattr.wq = (struct ibv_exp_wq_init_attr){\n-\t\t.wq_context = NULL, /* Could be useful in the future. */\n-\t\t.wq_type = IBV_EXP_WQT_RQ,\n-\t\t/* Max number of outstanding WRs. */\n-\t\t.max_recv_wr = desc >> tmpl.rxq.sges_n,\n-\t\t/* Max number of scatter/gather elements in a WR. */\n-\t\t.max_recv_sge = 1 << tmpl.rxq.sges_n,\n-\t\t.pd = priv->pd,\n-\t\t.cq = tmpl.cq,\n-\t\t.comp_mask =\n-\t\t\tIBV_EXP_CREATE_WQ_VLAN_OFFLOADS |\n-\t\t\t0,\n-\t\t.vlan_offloads = (tmpl.rxq.vlan_strip ?\n-\t\t\t\t  IBV_EXP_RECEIVE_WQ_CVLAN_STRIP :\n-\t\t\t\t  0),\n-\t};\n \t/* By default, FCS (CRC) is stripped by hardware. */\n \tif (dev->data->dev_conf.rxmode.hw_strip_crc) {\n \t\ttmpl.rxq.crc_present = 0;\n \t} else if (priv->hw_fcs_strip) {\n-\t\t/* Ask HW/Verbs to leave CRC in place when supported. */\n-\t\tattr.wq.flags |= IBV_EXP_CREATE_WQ_FLAG_SCATTER_FCS;\n-\t\tattr.wq.comp_mask |= IBV_EXP_CREATE_WQ_FLAGS;\n \t\ttmpl.rxq.crc_present = 1;\n \t} else {\n \t\tWARN(\"%p: CRC stripping has been disabled but will still\"\n@@ -1004,59 +876,9 @@ mlx5_rxq_ctrl_setup(struct rte_eth_dev *dev, struct mlx5_rxq_ctrl *rxq_ctrl,\n \t      (void *)dev,\n \t      tmpl.rxq.crc_present ? \"disabled\" : \"enabled\",\n \t      tmpl.rxq.crc_present << 2);\n-\tif (!mlx5_getenv_int(\"MLX5_PMD_ENABLE_PADDING\"))\n-\t\t; /* Nothing else to do. */\n-\telse if (priv->hw_padding) {\n-\t\tINFO(\"%p: enabling packet padding on queue %p\",\n-\t\t     (void *)dev, (void *)rxq_ctrl);\n-\t\tattr.wq.flags |= IBV_EXP_CREATE_WQ_FLAG_RX_END_PADDING;\n-\t\tattr.wq.comp_mask |= IBV_EXP_CREATE_WQ_FLAGS;\n-\t} else\n-\t\tWARN(\"%p: packet padding has been requested but is not\"\n-\t\t     \" supported, make sure MLNX_OFED and firmware are\"\n-\t\t     \" up to date\",\n-\t\t     (void *)dev);\n-\n-\ttmpl.wq = ibv_exp_create_wq(priv->ctx, &attr.wq);\n-\tif (tmpl.wq == NULL) {\n-\t\tret = (errno ? errno : EINVAL);\n-\t\tERROR(\"%p: WQ creation failure: %s\",\n-\t\t      (void *)dev, strerror(ret));\n-\t\tgoto error;\n-\t}\n-\t/*\n-\t * Make sure number of WRs*SGEs match expectations since a queue\n-\t * cannot allocate more than \"desc\" buffers.\n-\t */\n-\tif (((int)attr.wq.max_recv_wr != (desc >> tmpl.rxq.sges_n)) ||\n-\t    ((int)attr.wq.max_recv_sge != (1 << tmpl.rxq.sges_n))) {\n-\t\tERROR(\"%p: requested %u*%u but got %u*%u WRs*SGEs\",\n-\t\t      (void *)dev,\n-\t\t      (desc >> tmpl.rxq.sges_n), (1 << tmpl.rxq.sges_n),\n-\t\t      attr.wq.max_recv_wr, attr.wq.max_recv_sge);\n-\t\tret = EINVAL;\n-\t\tgoto error;\n-\t}\n \t/* Save port ID. */\n \ttmpl.rxq.port_id = dev->data->port_id;\n \tDEBUG(\"%p: RTE port ID: %u\", (void *)rxq_ctrl, tmpl.rxq.port_id);\n-\t/* Change queue state to ready. */\n-\tmod = (struct ibv_exp_wq_attr){\n-\t\t.attr_mask = IBV_EXP_WQ_ATTR_STATE,\n-\t\t.wq_state = IBV_EXP_WQS_RDY,\n-\t};\n-\tret = ibv_exp_modify_wq(tmpl.wq, &mod);\n-\tif (ret) {\n-\t\tERROR(\"%p: WQ state to IBV_EXP_WQS_RDY failed: %s\",\n-\t\t      (void *)dev, strerror(ret));\n-\t\tgoto error;\n-\t}\n-\tret = rxq_setup(&tmpl);\n-\tif (ret) {\n-\t\tERROR(\"%p: cannot initialize RX queue structure: %s\",\n-\t\t      (void *)dev, strerror(ret));\n-\t\tgoto error;\n-\t}\n \tret = rxq_alloc_elts(&tmpl, desc);\n \tif (ret) {\n \t\tERROR(\"%p: RXQ allocation failed: %s\",\n@@ -1075,17 +897,12 @@ mlx5_rxq_ctrl_setup(struct rte_eth_dev *dev, struct mlx5_rxq_ctrl *rxq_ctrl,\n \trte_free(tmpl.rxq.elts);\n \ttmpl.rxq.elts = elts;\n \t*rxq_ctrl = tmpl;\n-\t/* Update doorbell counter. */\n-\trxq_ctrl->rxq.rq_ci = desc >> rxq_ctrl->rxq.sges_n;\n-\trte_wmb();\n-\t*rxq_ctrl->rxq.rq_db = htonl(rxq_ctrl->rxq.rq_ci);\n \tDEBUG(\"%p: rxq updated with %p\", (void *)rxq_ctrl, (void *)&tmpl);\n \tassert(ret == 0);\n \treturn 0;\n error:\n-\telts = tmpl.rxq.elts;\n+\trte_free(tmpl.rxq.elts);\n \tmlx5_rxq_cleanup(&tmpl);\n-\trte_free(elts);\n \tassert(ret > 0);\n \treturn ret;\n }\n@@ -1175,14 +992,20 @@ mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,\n \t\t}\n \t}\n \tret = mlx5_rxq_ctrl_setup(dev, rxq_ctrl, desc, socket, conf, mp);\n-\tif (ret)\n+\tif (ret) {\n \t\trte_free(rxq_ctrl);\n-\telse {\n-\t\trxq_ctrl->rxq.stats.idx = idx;\n-\t\tDEBUG(\"%p: adding RX queue %p to list\",\n-\t\t      (void *)dev, (void *)rxq_ctrl);\n-\t\t(*priv->rxqs)[idx] = &rxq_ctrl->rxq;\n+\t\tgoto out;\n \t}\n+\trxq_ctrl->rxq.stats.idx = idx;\n+\tDEBUG(\"%p: adding RX queue %p to list\",\n+\t      (void *)dev, (void *)rxq_ctrl);\n+\t(*priv->rxqs)[idx] = &rxq_ctrl->rxq;\n+\trxq_ctrl->ibv = mlx5_priv_rxq_ibv_new(priv, idx);\n+\tif (!rxq_ctrl->ibv) {\n+\t\tret = EAGAIN;\n+\t\tgoto out;\n+\t}\n+out:\n \tpriv_unlock(priv);\n \treturn -ret;\n }\n@@ -1209,7 +1032,7 @@ mlx5_rx_queue_release(void *dpdk_rxq)\n \trxq_ctrl = container_of(rxq, struct mlx5_rxq_ctrl, rxq);\n \tpriv = rxq_ctrl->priv;\n \tpriv_lock(priv);\n-\tif (priv_flow_rxq_in_use(priv, rxq))\n+\tif (!mlx5_priv_rxq_ibv_releasable(priv, rxq_ctrl->ibv))\n \t\trte_panic(\"Rx queue %p is still used by a flow and cannot be\"\n \t\t\t  \" removed\\n\", (void *)rxq_ctrl);\n \tfor (i = 0; (i != priv->rxqs_n); ++i)\n@@ -1253,15 +1076,14 @@ priv_rx_intr_vec_enable(struct priv *priv)\n \t}\n \tintr_handle->type = RTE_INTR_HANDLE_EXT;\n \tfor (i = 0; i != n; ++i) {\n-\t\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[i];\n-\t\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n-\t\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\t\t/* This rxq ibv must not be released in this function. */\n+\t\tstruct mlx5_rxq_ibv *rxq = mlx5_priv_rxq_ibv_get(priv, i);\n \t\tint fd;\n \t\tint flags;\n \t\tint rc;\n \n \t\t/* Skip queues that cannot request interrupts. */\n-\t\tif (!rxq || !rxq_ctrl->channel) {\n+\t\tif (!rxq || !rxq->channel) {\n \t\t\t/* Use invalid intr_vec[] index to disable entry. */\n \t\t\tintr_handle->intr_vec[i] =\n \t\t\t\tRTE_INTR_VEC_RXTX_OFFSET +\n@@ -1275,7 +1097,7 @@ priv_rx_intr_vec_enable(struct priv *priv)\n \t\t\tpriv_rx_intr_vec_disable(priv);\n \t\t\treturn -1;\n \t\t}\n-\t\tfd = rxq_ctrl->channel->fd;\n+\t\tfd = rxq->channel->fd;\n \t\tflags = fcntl(fd, F_GETFL);\n \t\trc = fcntl(fd, F_SETFL, flags | O_NONBLOCK);\n \t\tif (rc < 0) {\n@@ -1305,7 +1127,27 @@ void\n priv_rx_intr_vec_disable(struct priv *priv)\n {\n \tstruct rte_intr_handle *intr_handle = priv->dev->intr_handle;\n+\tunsigned int i;\n+\tunsigned int rxqs_n = priv->rxqs_n;\n+\tunsigned int n = RTE_MIN(rxqs_n, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);\n \n+\tif (!priv->dev->data->dev_conf.intr_conf.rxq)\n+\t\treturn;\n+\tfor (i = 0; i != n; ++i) {\n+\t\tstruct mlx5_rxq_ctrl *ctrl;\n+\t\tstruct mlx5_rxq_data *rxq;\n+\n+\t\tif (intr_handle->intr_vec[i] == RTE_INTR_VEC_RXTX_OFFSET +\n+\t\t    RTE_MAX_RXTX_INTR_VEC_ID)\n+\t\t\tcontinue;\n+\t\t/**\n+\t\t * Need to access directly the queue to release the reference\n+\t\t * kept in priv_rx_intr_vec_enable().\n+\t\t */\n+\t\trxq = (*priv->rxqs)[i];\n+\t\tctrl = container_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\t\tmlx5_priv_rxq_ibv_release(priv, ctrl->ibv);\n+\t}\n \trte_intr_free_epoll_fd(intr_handle);\n \tfree(intr_handle->intr_vec);\n \tintr_handle->nb_efd = 0;\n@@ -1329,19 +1171,19 @@ int\n mlx5_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id)\n {\n \tstruct priv *priv = mlx5_get_priv(dev);\n-\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[rx_queue_id];\n-\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n-\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\tstruct mlx5_rxq_ibv *rxq = mlx5_priv_rxq_ibv_get(priv, rx_queue_id);\n \tint ret;\n \n-\tif (!rxq || !rxq_ctrl->channel) {\n+\tif (!rxq || !rxq->channel) {\n \t\tret = EINVAL;\n \t} else {\n-\t\tibv_mlx5_exp_update_cq_ci(rxq_ctrl->cq, rxq->cq_ci);\n-\t\tret = ibv_req_notify_cq(rxq_ctrl->cq, 0);\n+\t\tibv_mlx5_exp_update_cq_ci(rxq->cq,\n+\t\t\t\t\t  (*priv->rxqs)[rx_queue_id]->cq_ci);\n+\t\tret = ibv_req_notify_cq(rxq->cq, 0);\n \t}\n \tif (ret)\n \t\tWARN(\"unable to arm interrupt on rx queue %d\", rx_queue_id);\n+\tmlx5_priv_rxq_ibv_release(priv, rxq);\n \treturn -ret;\n }\n \n@@ -1360,26 +1202,312 @@ int\n mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id)\n {\n \tstruct priv *priv = mlx5_get_priv(dev);\n-\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[rx_queue_id];\n-\tstruct mlx5_rxq_ctrl *rxq_ctrl =\n-\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\tstruct mlx5_rxq_ibv *rxq = mlx5_priv_rxq_ibv_get(priv, rx_queue_id);\n \tstruct ibv_cq *ev_cq;\n \tvoid *ev_ctx;\n \tint ret;\n \n-\tif (!rxq || !rxq_ctrl->channel) {\n+\tif (!rxq || !rxq->channel) {\n \t\tret = EINVAL;\n \t} else {\n-\t\tret = ibv_get_cq_event(rxq_ctrl->cq->channel, &ev_cq, &ev_ctx);\n-\t\tif (ret || ev_cq != rxq_ctrl->cq)\n+\t\tret = ibv_get_cq_event(rxq->cq->channel, &ev_cq, &ev_ctx);\n+\t\tif (ret || ev_cq != rxq->cq)\n \t\t\tret = EINVAL;\n \t}\n \tif (ret)\n \t\tWARN(\"unable to disable interrupt on rx queue %d\",\n \t\t     rx_queue_id);\n \telse\n-\t\tibv_ack_cq_events(rxq_ctrl->cq, 1);\n+\t\tibv_ack_cq_events(rxq->cq, 1);\n+\tmlx5_priv_rxq_ibv_release(priv, rxq);\n \treturn -ret;\n }\n \n #endif /* HAVE_UPDATE_CQ_CI */\n+\n+/**\n+ * Create the Rx queue Verbs object.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param idx\n+ *   Queue index in DPDK Rx queue array\n+ *\n+ * @return\n+ *   The Verbs object initialised if it can be created.\n+ */\n+struct mlx5_rxq_ibv*\n+mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx)\n+{\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+\tstruct ibv_exp_wq_attr mod;\n+\tunion {\n+\t\tstruct ibv_exp_cq_init_attr cq;\n+\t\tstruct ibv_exp_wq_init_attr wq;\n+\t\tstruct ibv_exp_cq_attr cq_attr;\n+\t} attr;\n+\tunsigned int cqe_n = (1 << rxq->elts_n) - 1;\n+\tstruct mlx5_rxq_ibv *tmpl;\n+\tstruct ibv_mlx5_cq_info cq_info;\n+\tstruct mlx5_rwq *rwq;\n+\tunsigned int i;\n+\tint ret = 0;\n+\n+\tassert(!rxq_ctrl->ibv);\n+\ttmpl = rte_calloc_socket(__func__, 1, sizeof(*tmpl), 0,\n+\t\t\t\t rxq_ctrl->socket);\n+\tif (!tmpl) {\n+\t\tERROR(\"%p: cannot allocate verbs ressources\",\n+\t\t       (void*)rxq_ctrl);\n+\t\tgoto error;\n+\t}\n+\t/* Use the entire RX mempool as the memory region. */\n+\ttmpl->mr = priv_mr_get(priv, rxq->mp);\n+\tif (!tmpl->mr) {\n+\t\ttmpl->mr = priv_mr_new(priv, rxq->mp);\n+\t\tif (!tmpl->mr) {\n+\t\t\tERROR(\"%p: MR creation failure\", (void *)rxq_ctrl);\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\tif (rxq_ctrl->memory_channel) {\n+\t\ttmpl->channel = ibv_create_comp_channel(priv->ctx);\n+\t\tif (!tmpl->channel) {\n+\t\t\tERROR(\"%p: Comp Channel creation failure\",\n+\t\t\t      (void *)rxq_ctrl);\n+\t\t\tgoto error;\n+\t\t}\n+\t}\n+\tattr.cq = (struct ibv_exp_cq_init_attr){\n+\t\t.comp_mask = 0,\n+\t};\n+\tif (priv->cqe_comp) {\n+\t\tattr.cq.comp_mask |= IBV_EXP_CQ_INIT_ATTR_FLAGS;\n+\t\tattr.cq.flags |= IBV_EXP_CQ_COMPRESSED_CQE;\n+\t\t/*\n+\t\t * For vectorized Rx, it must not be doubled in order to\n+\t\t * make cq_ci and rq_ci aligned.\n+\t\t */\n+\t\tif (rxq_check_vec_support(rxq) < 0)\n+\t\t\tcqe_n *= 2;\n+\t}\n+\ttmpl->cq = ibv_exp_create_cq(priv->ctx, cqe_n, NULL, tmpl->channel, 0,\n+\t\t\t\t     &attr.cq);\n+\tif (tmpl->cq == NULL) {\n+\t\tERROR(\"%p: CQ creation failure\", (void *)rxq_ctrl);\n+\t\tgoto error;\n+\t}\n+\tif (ibv_mlx5_exp_get_cq_info(tmpl->cq, &cq_info)) {\n+\t\tERROR(\"Unable to query CQ info. check your OFED.\");\n+\t\tgoto error;\n+\t}\n+\tif (cq_info.cqe_size != RTE_CACHE_LINE_SIZE) {\n+\t\tERROR(\"Wrong MLX5_CQE_SIZE environment variable value: \"\n+\t\t      \"it should be set to %u\", RTE_CACHE_LINE_SIZE);\n+\t\tgoto error;\n+\t}\n+\tDEBUG(\"priv->device_attr.max_qp_wr is %d\",\n+\t      priv->device_attr.max_qp_wr);\n+\tDEBUG(\"priv->device_attr.max_sge is %d\",\n+\t      priv->device_attr.max_sge);\n+\tattr.wq = (struct ibv_exp_wq_init_attr){\n+\t\t.wq_context = NULL, /* Could be useful in the future. */\n+\t\t.wq_type = IBV_EXP_WQT_RQ,\n+\t\t/* Max number of outstanding WRs. */\n+\t\t.max_recv_wr = (1 << rxq->elts_n) >> rxq->sges_n,\n+\t\t/* Max number of scatter/gather elements in a WR. */\n+\t\t.max_recv_sge = 1 << rxq->sges_n,\n+\t\t.pd = priv->pd,\n+\t\t.cq = tmpl->cq,\n+\t\t.comp_mask =\n+\t\t\tIBV_EXP_CREATE_WQ_VLAN_OFFLOADS |\n+\t\t\t0,\n+\t\t.vlan_offloads = (rxq->vlan_strip ?\n+\t\t\t\t  IBV_EXP_RECEIVE_WQ_CVLAN_STRIP :\n+\t\t\t\t  0),\n+\t};\n+\t/* By default, FCS (CRC) is stripped by hardware. */\n+\tif (rxq->crc_present) {\n+\t\tattr.wq.flags |= IBV_EXP_CREATE_WQ_FLAG_SCATTER_FCS;\n+\t\tattr.wq.comp_mask |= IBV_EXP_CREATE_WQ_FLAGS;\n+\t}\n+\tif (priv->hw_padding) {\n+\t\tattr.wq.flags |= IBV_EXP_CREATE_WQ_FLAG_RX_END_PADDING;\n+\t\tattr.wq.comp_mask |= IBV_EXP_CREATE_WQ_FLAGS;\n+\t}\n+\ttmpl->wq = ibv_exp_create_wq(priv->ctx, &attr.wq);\n+\tif (tmpl->wq == NULL) {\n+\t\tERROR(\"%p: WQ creation failure\", (void *)rxq_ctrl);\n+\t\tgoto error;\n+\t}\n+\t/*\n+\t * Make sure number of WRs*SGEs match expectations since a queue\n+\t * cannot allocate more than \"desc\" buffers.\n+\t */\n+\tif (((int)attr.wq.max_recv_wr != ((1 << rxq->elts_n) >> rxq->sges_n)) ||\n+\t    ((int)attr.wq.max_recv_sge != (1 << rxq->sges_n))) {\n+\t\tERROR(\"%p: requested %u*%u but got %u*%u WRs*SGEs\",\n+\t\t      (void *)rxq_ctrl,\n+\t\t      ((1 << rxq->elts_n) >> rxq->sges_n),\n+\t\t      (1 << rxq->sges_n),\n+\t\t      attr.wq.max_recv_wr, attr.wq.max_recv_sge);\n+\t\tgoto error;\n+\t}\n+\t/* Change queue state to ready. */\n+\tmod = (struct ibv_exp_wq_attr){\n+\t\t.attr_mask = IBV_EXP_WQ_ATTR_STATE,\n+\t\t.wq_state = IBV_EXP_WQS_RDY,\n+\t};\n+\tret = ibv_exp_modify_wq(tmpl->wq, &mod);\n+\tif (ret) {\n+\t\tERROR(\"%p: WQ state to IBV_EXP_WQS_RDY failed\",\n+\t\t      (void *)rxq_ctrl);\n+\t\tgoto error;\n+\t}\n+\t/* Fill the rings. */\n+\trwq = container_of(tmpl->wq, struct mlx5_rwq, wq);\n+\trxq->wqes = (volatile struct mlx5_wqe_data_seg (*)[])\n+\t\t(uintptr_t)rwq->rq.buff;\n+\tfor (i = 0; (i != (unsigned int)(1 << rxq->elts_n)); ++i) {\n+\t\tstruct rte_mbuf *buf = (*rxq->elts)[i];\n+\t\tvolatile struct mlx5_wqe_data_seg *scat = &(*rxq->wqes)[i];\n+\n+\t\t/* scat->addr must be able to store a pointer. */\n+\t\tassert(sizeof(scat->addr) >= sizeof(uintptr_t));\n+\t\t*scat = (struct mlx5_wqe_data_seg){\n+\t\t\t.addr = htonll(rte_pktmbuf_mtod(buf, uintptr_t)),\n+\t\t\t.byte_count = htonl(DATA_LEN(buf)),\n+\t\t\t.lkey = tmpl->mr->lkey,\n+\t\t};\n+\t}\n+\trxq->rq_db = rwq->rq.db;\n+\trxq->cqe_n = log2above(cq_info.cqe_cnt);\n+\trxq->cq_ci = 0;\n+\trxq->rq_ci = 0;\n+\trxq->cq_db = cq_info.dbrec;\n+\trxq->cqes = (volatile struct mlx5_cqe (*)[])(uintptr_t)cq_info.buf;\n+\t/* Update doorbell counter. */\n+\trxq->rq_ci = (1 << rxq->elts_n) >> rxq->sges_n;\n+\trte_wmb();\n+\t*rxq->rq_db = htonl(rxq->rq_ci);\n+\tDEBUG(\"%p: rxq updated with %p\", (void *)rxq_ctrl, (void *)&tmpl);\n+\trte_atomic32_inc(&tmpl->refcnt);\n+\tDEBUG(\"%p: Verbs Rx queue %p: refcnt %d\", (void*)priv,\n+\t      (void*)tmpl, rte_atomic32_read(&tmpl->refcnt));\n+\tLIST_INSERT_HEAD(&priv->rxqsibv, tmpl, next);\n+\treturn tmpl;\n+error:\n+\tif (tmpl->wq)\n+\t\tclaim_zero(ibv_exp_destroy_wq(tmpl->wq));\n+\tif (tmpl->cq)\n+\t\tclaim_zero(ibv_destroy_cq(tmpl->cq));\n+\tif (tmpl->channel)\n+\t\tclaim_zero(ibv_destroy_comp_channel(tmpl->channel));\n+\tif (tmpl->mr)\n+\t\tpriv_mr_release(priv, tmpl->mr);\n+\treturn NULL;\n+\n+}\n+\n+/**\n+ * Get an Rx queue Verbs object.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param idx\n+ *   Queue index in DPDK Rx queue array\n+ *\n+ * @return\n+ *   The Verbs object if it exists.\n+ */\n+struct mlx5_rxq_ibv*\n+mlx5_priv_rxq_ibv_get(struct priv *priv, uint16_t idx)\n+{\n+\tstruct mlx5_rxq_data *rxq = (*priv->rxqs)[idx];\n+\tstruct mlx5_rxq_ctrl *ctrl =\n+\t\tcontainer_of(rxq, struct mlx5_rxq_ctrl, rxq);\n+\tstruct mlx5_mr *mr __rte_unused;\n+\n+\tif (ctrl->ibv) {\n+\t\tmr = priv_mr_get(priv, rxq->mp);\n+\t\trte_atomic32_inc(&ctrl->ibv->refcnt);\n+\t\tDEBUG(\"%p: Verbs Rx queue %p: refcnt %d\", (void*)priv,\n+\t\t      (void*)ctrl->ibv, rte_atomic32_read(&ctrl->ibv->refcnt));\n+\t}\n+\treturn ctrl->ibv;\n+}\n+\n+/**\n+ * Release an Rx verbs queue object.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param rxq\n+ *   Verbs Rx queue object.\n+ *\n+ * @return\n+ *   0 on success, errno value on failure.\n+ */\n+int\n+mlx5_priv_rxq_ibv_release(struct priv *priv, struct mlx5_rxq_ibv *rxq)\n+{\n+\tint ret;\n+\n+\tassert(rxq->wq);\n+\tassert(rxq->cq);\n+\tassert(rxq->mr);\n+\tret = priv_mr_release(priv, rxq->mr);\n+\tif (!ret)\n+\t\trxq->mr = NULL;\n+\tDEBUG(\"%p: Verbs Rx queue %p: refcnt %d\", (void*)priv,\n+\t      (void*)rxq, rte_atomic32_read(&rxq->refcnt));\n+\tif (rte_atomic32_dec_and_test(&rxq->refcnt)) {\n+\t\tclaim_zero(ibv_exp_destroy_wq(rxq->wq));\n+\t\tclaim_zero(ibv_destroy_cq(rxq->cq));\n+\t\tif (rxq->channel)\n+\t\t\tclaim_zero(ibv_destroy_comp_channel(rxq->channel));\n+\t\tLIST_REMOVE(rxq, next);\n+\t\trte_free(rxq);\n+\t\treturn 0;\n+\t}\n+\treturn EBUSY;\n+}\n+\n+/**\n+ * Verify the Verbs Rx queue list is empty\n+ *\n+ * @param priv\n+ *  Pointer to private structure.\n+ *\n+ * @return the number of object not released.\n+ */\n+int\n+mlx5_priv_rxq_ibv_verify(struct priv *priv)\n+{\n+\tint ret = 0;\n+\tstruct mlx5_rxq_ibv *rxq;\n+\n+\tLIST_FOREACH(rxq, &priv->rxqsibv, next) {\n+\t\tDEBUG(\"%p: Verbs Rx queue %p still referenced\", (void*)priv,\n+\t\t      (void*)rxq);\n+\t\t++ret;\n+\t}\n+\treturn ret;\n+}\n+\n+/**\n+ * Return true if a single reference exists on the object.\n+ *\n+ * @param priv\n+ *   Pointer to private structure.\n+ * @param rxq\n+ *   Verbs Rx queue object.\n+ */\n+int\n+mlx5_priv_rxq_ibv_releasable(struct priv *priv, struct mlx5_rxq_ibv *rxq)\n+{\n+\t(void)priv;\n+\treturn (rte_atomic32_read(&rxq->refcnt) == 1);\n+}\ndiff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h\nindex c7c7518..abdbf6a 100644\n--- a/drivers/net/mlx5/mlx5_rxtx.h\n+++ b/drivers/net/mlx5/mlx5_rxtx.h\n@@ -130,15 +130,24 @@ struct mlx5_rxq_data {\n \tstruct rte_mbuf fake_mbuf; /* elts padding for vectorized Rx. */\n } __rte_cache_aligned;\n \n-/* RX queue control descriptor. */\n-struct mlx5_rxq_ctrl {\n-\tstruct priv *priv; /* Back pointer to private data. */\n+/* Verbs Rx queue elements. */\n+struct mlx5_rxq_ibv {\n+\tLIST_ENTRY(mlx5_rxq_ibv) next; /* Pointer to the next element. */\n+\trte_atomic32_t refcnt; /* Reference counter. */\n+\tstruct mlx5_rxq_ctrl *rxq_ctrl; /* Back pointer to parent. */\n \tstruct ibv_cq *cq; /* Completion Queue. */\n \tstruct ibv_exp_wq *wq; /* Work Queue. */\n-\tstruct mlx5_mr *mr; /* Memory Region (for mp). */\n \tstruct ibv_comp_channel *channel;\n-\tunsigned int socket; /* CPU socket ID for allocations. */\n+\tstruct mlx5_mr *mr; /* Memory Region (for mp). */\n+};\n+\n+/* RX queue control descriptor. */\n+struct mlx5_rxq_ctrl {\n+\tstruct priv *priv; /* Back pointer to private data. */\n+\tstruct mlx5_rxq_ibv *ibv; /* Verbs elements. */\n \tstruct mlx5_rxq_data rxq; /* Data path structure. */\n+\tunsigned int socket; /* CPU socket ID for allocations. */\n+\tunsigned int memory_channel:1; /* Need memory channel. */\n };\n \n /* Hash RX queue types. */\n@@ -298,7 +307,6 @@ void priv_destroy_hash_rxqs(struct priv *);\n int priv_allow_flow_type(struct priv *, enum hash_rxq_flow_type);\n int priv_rehash_flows(struct priv *);\n void mlx5_rxq_cleanup(struct mlx5_rxq_ctrl *);\n-int mlx5_rxq_rehash(struct rte_eth_dev *, struct mlx5_rxq_ctrl *);\n int mlx5_rxq_ctrl_setup(struct rte_eth_dev *, struct mlx5_rxq_ctrl *,\n \t\t\tuint16_t, unsigned int, const struct rte_eth_rxconf *,\n \t\t\tstruct rte_mempool *);\n@@ -311,6 +319,11 @@ void priv_rx_intr_vec_disable(struct priv *priv);\n int mlx5_rx_intr_enable(struct rte_eth_dev *dev, uint16_t rx_queue_id);\n int mlx5_rx_intr_disable(struct rte_eth_dev *dev, uint16_t rx_queue_id);\n #endif /* HAVE_UPDATE_CQ_CI */\n+struct mlx5_rxq_ibv* mlx5_priv_rxq_ibv_new(struct priv *priv, uint16_t idx);\n+struct mlx5_rxq_ibv* mlx5_priv_rxq_ibv_get(struct priv *priv, uint16_t idx);\n+int mlx5_priv_rxq_ibv_release(struct priv *priv, struct mlx5_rxq_ibv *rxq);\n+int mlx5_priv_rxq_ibv_releasable(struct priv *priv, struct mlx5_rxq_ibv *rxq);\n+int mlx5_priv_rxq_ibv_verify(struct priv *priv);\n \n /* mlx5_txq.c */\n \n@@ -347,7 +360,6 @@ uint16_t mlx5_rx_burst_vec(void *, struct rte_mbuf **, uint16_t);\n \n /* mlx5_mr.c */\n \n-struct ibv_mr *mlx5_mp2mr(struct ibv_pd *, struct rte_mempool *);\n void mlx5_txq_mp2mr_iter(struct rte_mempool *, void *);\n uint32_t mlx5_txq_mp2mr_reg(struct mlx5_txq_data *, struct rte_mempool *,\n \t\t\t    unsigned int);\ndiff --git a/drivers/net/mlx5/mlx5_vlan.c b/drivers/net/mlx5/mlx5_vlan.c\nindex 512052a..dffa1cd 100644\n--- a/drivers/net/mlx5/mlx5_vlan.c\n+++ b/drivers/net/mlx5/mlx5_vlan.c\n@@ -153,7 +153,7 @@ priv_vlan_strip_queue_set(struct priv *priv, uint16_t idx, int on)\n \t\t.vlan_offloads = vlan_offloads,\n \t};\n \n-\terr = ibv_exp_modify_wq(rxq_ctrl->wq, &mod);\n+\terr = ibv_exp_modify_wq(rxq_ctrl->ibv->wq, &mod);\n \tif (err) {\n \t\tERROR(\"%p: failed to modified stripping mode: %s\",\n \t\t      (void *)priv, strerror(err));\n",
    "prefixes": [
        "dpdk-dev",
        "v1",
        "08/21"
    ]
}