get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 105253,
    "url": "http://patches.dpdk.org/api/patches/105253/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/600043103a745391c369c703b38251ad1cd0d54f.1639636621.git.songyl@ramaxel.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": "<600043103a745391c369c703b38251ad1cd0d54f.1639636621.git.songyl@ramaxel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/600043103a745391c369c703b38251ad1cd0d54f.1639636621.git.songyl@ramaxel.com",
    "date": "2021-12-18T02:51:39",
    "name": "[v1,12/25] net/spnic: support mbuf handling of Tx/Rx",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "e3ac1c0bc23ce0943cdee4078d24cb578c6548ab",
    "submitter": {
        "id": 2455,
        "url": "http://patches.dpdk.org/api/people/2455/?format=api",
        "name": "Yanling Song",
        "email": "songyl@ramaxel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/600043103a745391c369c703b38251ad1cd0d54f.1639636621.git.songyl@ramaxel.com/mbox/",
    "series": [
        {
            "id": 20973,
            "url": "http://patches.dpdk.org/api/series/20973/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=20973",
            "date": "2021-12-18T02:51:28",
            "name": "Net/SPNIC: support SPNIC into DPDK 22.03",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/20973/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/105253/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/105253/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 8871DA04A4;\n\tSat, 18 Dec 2021 03:54:10 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 76B8341C28;\n\tSat, 18 Dec 2021 03:52:40 +0100 (CET)",
            "from VLXDG1SPAM1.ramaxel.com (email.unionmem.com [221.4.138.186])\n by mails.dpdk.org (Postfix) with ESMTP id AA2EA411DB\n for <dev@dpdk.org>; Sat, 18 Dec 2021 03:52:36 +0100 (CET)",
            "from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local\n [172.26.18.31])\n by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BI2q1bZ010342\n (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL);\n Sat, 18 Dec 2021 10:52:01 +0800 (GMT-8)\n (envelope-from songyl@ramaxel.com)",
            "from localhost.localdomain (10.64.9.47) by V12DG1MBS01.ramaxel.local\n (172.26.18.31) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2308.14; Sat, 18\n Dec 2021 10:52:00 +0800"
        ],
        "From": "Yanling Song <songyl@ramaxel.com>",
        "To": "<dev@dpdk.org>",
        "CC": "<songyl@ramaxel.com>, <yanling.song@linux.dev>, <yanggan@ramaxel.com>,\n <ferruh.yigit@intel.com>",
        "Subject": "[PATCH v1 12/25] net/spnic: support mbuf handling of Tx/Rx",
        "Date": "Sat, 18 Dec 2021 10:51:39 +0800",
        "Message-ID": "\n <600043103a745391c369c703b38251ad1cd0d54f.1639636621.git.songyl@ramaxel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<cover.1639636621.git.songyl@ramaxel.com>",
        "References": "<cover.1639636621.git.songyl@ramaxel.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.64.9.47]",
        "X-ClientProxiedBy": "V12DG1MBS01.ramaxel.local (172.26.18.31) To\n V12DG1MBS01.ramaxel.local (172.26.18.31)",
        "X-DNSRBL": "",
        "X-MAIL": "VLXDG1SPAM1.ramaxel.com 1BI2q1bZ010342",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <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 <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "This patch defines a wqe data structure for hardware to\nlearn the sge info and offload info of packet. Furthermore,\nthis commit implements the interfaces to fill wqe with DPDK mbuf.\n\nSigned-off-by: Yanling Song <songyl@ramaxel.com>\n---\n drivers/net/spnic/base/spnic_nic_cfg.c |  23 ++\n drivers/net/spnic/base/spnic_nic_cfg.h |  23 ++\n drivers/net/spnic/meson.build          |   2 +\n drivers/net/spnic/spnic_ethdev.c       | 502 ++++++++++++++++++++++++-\n drivers/net/spnic/spnic_rx.c           | 302 +++++++++++++++\n drivers/net/spnic/spnic_rx.h           |  41 ++\n drivers/net/spnic/spnic_tx.c           | 334 ++++++++++++++++\n drivers/net/spnic/spnic_tx.h           | 228 +++++++++++\n 8 files changed, 1454 insertions(+), 1 deletion(-)\n create mode 100644 drivers/net/spnic/spnic_rx.c\n create mode 100644 drivers/net/spnic/spnic_tx.c",
    "diff": "diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c b/drivers/net/spnic/base/spnic_nic_cfg.c\nindex 25d98d67dd..f6914f6f6d 100644\n--- a/drivers/net/spnic/base/spnic_nic_cfg.c\n+++ b/drivers/net/spnic/base/spnic_nic_cfg.c\n@@ -378,6 +378,29 @@ int spnic_set_port_enable(void *hwdev, bool enable)\n \treturn 0;\n }\n \n+int spnic_flush_qps_res(void *hwdev)\n+{\n+\tstruct spnic_cmd_clear_qp_resource sq_res;\n+\tu16 out_size = sizeof(sq_res);\n+\tint err;\n+\n+\tif (!hwdev)\n+\t\treturn -EINVAL;\n+\n+\tmemset(&sq_res, 0, sizeof(sq_res));\n+\tsq_res.func_id = spnic_global_func_id(hwdev);\n+\n+\terr = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CLEAR_QP_RESOURCE, &sq_res,\n+\t\t\t\t     sizeof(sq_res), &sq_res, &out_size);\n+\tif (err || !out_size || sq_res.msg_head.status) {\n+\t\tPMD_DRV_LOG(ERR, \"Clear sq resources failed, err: %d, status: 0x%x, out size: 0x%x\",\n+\t\t\t    err, sq_res.msg_head.status, out_size);\n+\t\treturn -EIO;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int spnic_set_function_table(void *hwdev, u32 cfg_bitmap,\n \t\t\t\t     struct spnic_func_tbl_cfg *cfg)\n {\ndiff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h\nindex ce9792f8ee..746c1c342d 100644\n--- a/drivers/net/spnic/base/spnic_nic_cfg.h\n+++ b/drivers/net/spnic/base/spnic_nic_cfg.h\n@@ -255,6 +255,17 @@ struct spnic_cmd_register_vf {\n \tu8 rsvd[39];\n };\n \n+\n+struct spnic_cmd_set_rq_flush {\n+\tunion {\n+\t\tstruct {\n+\t\t\tu16 global_rq_id;\n+\t\t\tu16 local_rq_id;\n+\t\t};\n+\t\tu32 value;\n+\t};\n+};\n+\n int l2nic_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size,\n \t\t\t   void *buf_out, u16 *out_size);\n \n@@ -381,6 +392,18 @@ int spnic_set_port_enable(void *hwdev, bool enable);\n  */\n int spnic_get_link_state(void *hwdev, u8 *link_state);\n \n+/**\n+ * Flush queue pairs resource in hardware\n+ *\n+ * @param[in] hwdev\n+ *   Device pointer to hwdev\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+int spnic_flush_qps_res(void *hwdev);\n+\n+\n /**\n  * Init nic hwdev\n  *\ndiff --git a/drivers/net/spnic/meson.build b/drivers/net/spnic/meson.build\nindex 20d5151a8d..cd8f316366 100644\n--- a/drivers/net/spnic/meson.build\n+++ b/drivers/net/spnic/meson.build\n@@ -7,6 +7,8 @@ objs = [base_objs]\n sources = files(\n \t'spnic_ethdev.c',\n \t'spnic_io.c',\n+\t'spnic_rx.c',\n+\t'spnic_tx.c'\n )\n \n includes += include_directories('base')\ndiff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c\nindex 4205ab43a4..27942e5d68 100644\n--- a/drivers/net/spnic/spnic_ethdev.c\n+++ b/drivers/net/spnic/spnic_ethdev.c\n@@ -139,6 +139,468 @@ static int spnic_link_update(struct rte_eth_dev *dev, int wait_to_complete)\n \treturn rte_eth_linkstatus_set(dev, &link);\n }\n \n+static void spnic_reset_rx_queue(struct rte_eth_dev *dev)\n+{\n+\tstruct spnic_rxq *rxq = NULL;\n+\tstruct spnic_nic_dev *nic_dev;\n+\tint q_id = 0;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\n+\tfor (q_id = 0; q_id < nic_dev->num_rqs; q_id++) {\n+\t\trxq = nic_dev->rxqs[q_id];\n+\n+\t\trxq->cons_idx = 0;\n+\t\trxq->prod_idx = 0;\n+\t\trxq->delta = rxq->q_depth;\n+\t\trxq->next_to_update = 0;\n+\t}\n+}\n+\n+static void spnic_reset_tx_queue(struct rte_eth_dev *dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev;\n+\tstruct spnic_txq *txq = NULL;\n+\tint q_id = 0;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\n+\tfor (q_id = 0; q_id < nic_dev->num_sqs; q_id++) {\n+\t\ttxq = nic_dev->txqs[q_id];\n+\n+\t\ttxq->cons_idx = 0;\n+\t\ttxq->prod_idx = 0;\n+\t\ttxq->owner = 1;\n+\n+\t\t/* Clear hardware ci */\n+\t\t*(u16 *)txq->ci_vaddr_base = 0;\n+\t}\n+}\n+\n+/**\n+ * Create the receive queue.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] qid\n+ *   Receive queue index.\n+ * @param[in] nb_desc\n+ *   Number of descriptors for receive queue.\n+ * @param[in] socket_id\n+ *   Socket index on which memory must be allocated.\n+ * @param rx_conf\n+ *   Thresholds parameters (unused_).\n+ * @param mp\n+ *   Memory pool for buffer allocations.\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+static int spnic_rx_queue_setup(struct rte_eth_dev *dev, uint16_t qid,\n+\t\t\tuint16_t nb_desc, unsigned int socket_id,\n+\t\t\t__rte_unused const struct rte_eth_rxconf *rx_conf,\n+\t\t\tstruct rte_mempool *mp)\n+{\n+\tstruct spnic_nic_dev *nic_dev;\n+\tstruct spnic_rxq *rxq = NULL;\n+\tconst struct rte_memzone *rq_mz = NULL;\n+\tconst struct rte_memzone *cqe_mz = NULL;\n+\tconst struct rte_memzone *pi_mz = NULL;\n+\tu16 rq_depth, rx_free_thresh;\n+\tu32 queue_buf_size, mb_buf_size;\n+\tvoid *db_addr = NULL;\n+\tint wqe_count;\n+\tu32 buf_size;\n+\tint err;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\n+\t/* Queue depth must be power of 2, otherwise will be aligned up */\n+\trq_depth = (nb_desc & (nb_desc - 1)) ?\n+\t\t   ((u16)(1U << (ilog2(nb_desc) + 1))) : nb_desc;\n+\n+\t/*\n+\t * Validate number of receive descriptors.\n+\t * It must not exceed hardware maximum and minimum.\n+\t */\n+\tif (rq_depth > SPNIC_MAX_QUEUE_DEPTH ||\n+\t    rq_depth < SPNIC_MIN_QUEUE_DEPTH) {\n+\t\tPMD_DRV_LOG(ERR, \"RX queue depth is out of range from %d to %d,\"\n+\t\t\t    \"(nb_desc: %d, q_depth: %d, port: %d queue: %d)\",\n+\t\t\t    SPNIC_MIN_QUEUE_DEPTH, SPNIC_MAX_QUEUE_DEPTH,\n+\t\t\t    (int)nb_desc, (int)rq_depth,\n+\t\t\t    (int)dev->data->port_id, (int)qid);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/*\n+\t * The RX descriptor ring will be cleaned after rxq->rx_free_thresh\n+\t * descriptors are used or if the number of descriptors required\n+\t * to transmit a packet is greater than the number of free RX\n+\t * descriptors.\n+\t * The following constraints must be satisfied:\n+\t *  -rx_free_thresh must be greater than 0.\n+\t *  -rx_free_thresh must be less than the size of the ring minus 1.\n+\t * When set to zero use default values.\n+\t */\n+\trx_free_thresh = (u16)((rx_conf->rx_free_thresh) ?\n+\t\t\trx_conf->rx_free_thresh : SPNIC_DEFAULT_RX_FREE_THRESH);\n+\tif (rx_free_thresh >= (rq_depth - 1)) {\n+\t\tPMD_DRV_LOG(ERR, \"rx_free_thresh must be less than the number \"\n+\t\t\t    \"of RX descriptors minus 1, rx_free_thresh: %u port: %d queue: %d)\",\n+\t\t\t    (unsigned int)rx_free_thresh,\n+\t\t\t    (int)dev->data->port_id, (int)qid);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\trxq = rte_zmalloc_socket(\"spnic_rq\", sizeof(struct spnic_rxq),\n+\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (!rxq) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate rxq[%d] failed, dev_name: %s\",\n+\t\t\t    qid, dev->data->name);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\t/* Init rq parameters */\n+\trxq->nic_dev = nic_dev;\n+\tnic_dev->rxqs[qid] = rxq;\n+\trxq->mb_pool = mp;\n+\trxq->q_id = qid;\n+\trxq->next_to_update = 0;\n+\trxq->q_depth = rq_depth;\n+\trxq->q_mask = rq_depth - 1;\n+\trxq->delta = rq_depth;\n+\trxq->cons_idx = 0;\n+\trxq->prod_idx = 0;\n+\trxq->wqe_type = SPNIC_NORMAL_RQ_WQE;\n+\trxq->wqebb_shift = SPNIC_RQ_WQEBB_SHIFT + rxq->wqe_type;\n+\trxq->wqebb_size = (u16)BIT(rxq->wqebb_shift);\n+\trxq->rx_free_thresh = rx_free_thresh;\n+\trxq->rxinfo_align_end = rxq->q_depth - rxq->rx_free_thresh;\n+\trxq->port_id = dev->data->port_id;\n+\n+\t/* If buf_len used for function table, need to translated */\n+\tmb_buf_size = rte_pktmbuf_data_room_size(rxq->mb_pool) -\n+\t\t      RTE_PKTMBUF_HEADROOM;\n+\terr = spnic_convert_rx_buf_size(mb_buf_size, &buf_size);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Adjust buf size failed, dev_name: %s\",\n+\t\t\t    dev->data->name);\n+\t\tgoto adjust_bufsize_fail;\n+\t}\n+\n+\trxq->buf_len = buf_size;\n+\trxq->rx_buff_shift = ilog2(rxq->buf_len);\n+\n+\tpi_mz = rte_eth_dma_zone_reserve(dev, \"spnic_rq_pi\", qid,\n+\t\t\t\t\t RTE_PGSIZE_4K, RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t socket_id);\n+\tif (!pi_mz) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate rxq[%d] pi_mz failed, dev_name: %s\",\n+\t\t\t    qid, dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_pi_mz_fail;\n+\t}\n+\trxq->pi_mz = pi_mz;\n+\trxq->pi_dma_addr = pi_mz->iova;\n+\trxq->pi_virt_addr = pi_mz->addr;\n+\n+\t/* Rxq doesn't use direct wqe */\n+\terr = spnic_alloc_db_addr(nic_dev->hwdev, &db_addr, NULL);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Alloc rq doorbell addr failed\");\n+\t\tgoto alloc_db_err_fail;\n+\t}\n+\trxq->db_addr = db_addr;\n+\n+\tqueue_buf_size = BIT(rxq->wqebb_shift) * rq_depth;\n+\trq_mz = rte_eth_dma_zone_reserve(dev, \"spnic_rq_mz\", qid,\n+\t\t\t\t\t queue_buf_size, RTE_PGSIZE_256K,\n+\t\t\t\t\t socket_id);\n+\tif (!rq_mz) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate rxq[%d] rq_mz failed, dev_name: %s\",\n+\t\t\t    qid, dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_rq_mz_fail;\n+\t}\n+\n+\tmemset(rq_mz->addr, 0, queue_buf_size);\n+\trxq->rq_mz = rq_mz;\n+\trxq->queue_buf_paddr = rq_mz->iova;\n+\trxq->queue_buf_vaddr = rq_mz->addr;\n+\n+\trxq->rx_info = rte_zmalloc_socket(\"rx_info\",\n+\t\t\t\t\t  rq_depth * sizeof(*rxq->rx_info),\n+\t\t\t\t\t  RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (!rxq->rx_info) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate rx_info failed, dev_name: %s\",\n+\t\t\tdev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_rx_info_fail;\n+\t}\n+\n+\tcqe_mz = rte_eth_dma_zone_reserve(dev, \"spnic_cqe_mz\", qid,\n+\t\t\t\t\t  rq_depth * sizeof(*rxq->rx_cqe),\n+\t\t\t\t\t  RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (!cqe_mz) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate cqe mem zone failed, dev_name: %s\",\n+\t\t\t    dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_cqe_mz_fail;\n+\t}\n+\tmemset(cqe_mz->addr, 0, rq_depth * sizeof(*rxq->rx_cqe));\n+\trxq->cqe_mz = cqe_mz;\n+\trxq->cqe_start_paddr = cqe_mz->iova;\n+\trxq->cqe_start_vaddr = cqe_mz->addr;\n+\trxq->rx_cqe = (struct spnic_rq_cqe *)rxq->cqe_start_vaddr;\n+\n+\twqe_count = spnic_rx_fill_wqe(rxq);\n+\tif (wqe_count != rq_depth) {\n+\t\tPMD_DRV_LOG(ERR, \"Fill rx wqe failed, wqe_count: %d, dev_name: %s\",\n+\t\t\t    wqe_count, dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto fill_rx_wqe_fail;\n+\t}\n+\n+\t/* Record rxq pointer in rte_eth rx_queues */\n+\tdev->data->rx_queues[qid] = rxq;\n+\n+\treturn 0;\n+\n+fill_rx_wqe_fail:\n+\trte_memzone_free(rxq->cqe_mz);\n+alloc_cqe_mz_fail:\n+\trte_free(rxq->rx_info);\n+\n+alloc_rx_info_fail:\n+\trte_memzone_free(rxq->rq_mz);\n+\n+alloc_rq_mz_fail:\n+\tspnic_free_db_addr(nic_dev->hwdev, rxq->db_addr, NULL);\n+\n+alloc_db_err_fail:\n+\trte_memzone_free(rxq->pi_mz);\n+\n+alloc_pi_mz_fail:\n+adjust_bufsize_fail:\n+\n+\trte_free(rxq);\n+\tnic_dev->rxqs[qid] = NULL;\n+\n+\treturn err;\n+}\n+\n+/**\n+ * Create the transmit queue.\n+ *\n+ * @param[in] dev\n+ *   Pointer to ethernet device structure.\n+ * @param[in] queue_idx\n+ *   Transmit queue index.\n+ * @param[in] nb_desc\n+ *   Number of descriptors for transmit queue.\n+ * @param[in] socket_id\n+ *   Socket index on which memory must be allocated.\n+ * @param[in] tx_conf\n+ *   Tx queue configuration parameters (unused_).\n+ *\n+ * @retval zero : Success\n+ * @retval non-zero : Failure\n+ */\n+static int spnic_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid,\n+\t\t\t uint16_t nb_desc, unsigned int socket_id,\n+\t\t\t __rte_unused const struct rte_eth_txconf *tx_conf)\n+{\n+\tstruct spnic_nic_dev *nic_dev;\n+\tstruct spnic_hwdev *hwdev;\n+\tstruct spnic_txq *txq = NULL;\n+\tconst struct rte_memzone *sq_mz = NULL;\n+\tconst struct rte_memzone *ci_mz = NULL;\n+\tvoid *db_addr = NULL;\n+\tu16 sq_depth, tx_free_thresh;\n+\tu32 queue_buf_size;\n+\tint err;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\thwdev = nic_dev->hwdev;\n+\n+\t/* Queue depth must be power of 2, otherwise will be aligned up */\n+\tsq_depth = (nb_desc & (nb_desc - 1)) ?\n+\t\t   ((u16)(1U << (ilog2(nb_desc) + 1))) : nb_desc;\n+\n+\t/*\n+\t * Validate number of transmit descriptors.\n+\t * It must not exceed hardware maximum and minimum.\n+\t */\n+\tif (sq_depth > SPNIC_MAX_QUEUE_DEPTH ||\n+\t\tsq_depth < SPNIC_MIN_QUEUE_DEPTH) {\n+\t\tPMD_DRV_LOG(ERR, \"TX queue depth is out of range from %d to %d,\"\n+\t\t\t    \"(nb_desc: %d, q_depth: %d, port: %d queue: %d)\",\n+\t\t\t    SPNIC_MIN_QUEUE_DEPTH, SPNIC_MAX_QUEUE_DEPTH,\n+\t\t\t    (int)nb_desc, (int)sq_depth,\n+\t\t\t    (int)dev->data->port_id, (int)qid);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/*\n+\t * The TX descriptor ring will be cleaned after txq->tx_free_thresh\n+\t * descriptors are used or if the number of descriptors required\n+\t * to transmit a packet is greater than the number of free TX\n+\t * descriptors.\n+\t * The following constraints must be satisfied:\n+\t *  -tx_free_thresh must be greater than 0.\n+\t *  -tx_free_thresh must be less than the size of the ring minus 1.\n+\t * When set to zero use default values.\n+\t */\n+\ttx_free_thresh = (u16)((tx_conf->tx_free_thresh) ?\n+\t\ttx_conf->tx_free_thresh : SPNIC_DEFAULT_TX_FREE_THRESH);\n+\tif (tx_free_thresh >= (sq_depth - 1)) {\n+\t\tPMD_DRV_LOG(ERR, \"tx_free_thresh must be less than the number of tx \"\n+\t\t\t    \"descriptors minus 1, tx_free_thresh: %u port: %d queue: %d\",\n+\t\t\t    (unsigned int)tx_free_thresh,\n+\t\t\t    (int)dev->data->port_id, (int)qid);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\ttxq = rte_zmalloc_socket(\"spnic_tx_queue\", sizeof(struct spnic_txq),\n+\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (!txq) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate txq[%d] failed, dev_name: %s\",\n+\t\t\t    qid, dev->data->name);\n+\t\treturn -ENOMEM;\n+\t}\n+\tnic_dev->txqs[qid] = txq;\n+\ttxq->nic_dev = nic_dev;\n+\ttxq->q_id = qid;\n+\ttxq->q_depth = sq_depth;\n+\ttxq->q_mask = sq_depth - 1;\n+\ttxq->cons_idx = 0;\n+\ttxq->prod_idx = 0;\n+\ttxq->wqebb_shift = SPNIC_SQ_WQEBB_SHIFT;\n+\ttxq->wqebb_size = (u16)BIT(txq->wqebb_shift);\n+\ttxq->tx_free_thresh = tx_free_thresh;\n+\ttxq->owner = 1;\n+\ttxq->cos = nic_dev->default_cos;\n+\n+\tci_mz = rte_eth_dma_zone_reserve(dev, \"spnic_sq_ci\", qid,\n+\t\t\t\t\t SPNIC_CI_Q_ADDR_SIZE,\n+\t\t\t\t\t SPNIC_CI_Q_ADDR_SIZE, socket_id);\n+\tif (!ci_mz) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate txq[%d] ci_mz failed, dev_name: %s\",\n+\t\t\t    qid, dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_ci_mz_fail;\n+\t}\n+\ttxq->ci_mz = ci_mz;\n+\ttxq->ci_dma_base = ci_mz->iova;\n+\ttxq->ci_vaddr_base = ci_mz->addr;\n+\n+\tqueue_buf_size = BIT(txq->wqebb_shift) * sq_depth;\n+\tsq_mz = rte_eth_dma_zone_reserve(dev, \"spnic_sq_mz\", qid,\n+\t\t\t\t\t queue_buf_size, RTE_PGSIZE_256K,\n+\t\t\t\t\t socket_id);\n+\tif (!sq_mz) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate txq[%d] sq_mz failed, dev_name: %s\",\n+\t\t\t    qid, dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_sq_mz_fail;\n+\t}\n+\tmemset(sq_mz->addr, 0, queue_buf_size);\n+\ttxq->sq_mz = sq_mz;\n+\ttxq->queue_buf_paddr = sq_mz->iova;\n+\ttxq->queue_buf_vaddr = sq_mz->addr;\n+\ttxq->sq_head_addr = (u64)txq->queue_buf_vaddr;\n+\ttxq->sq_bot_sge_addr = txq->sq_head_addr + queue_buf_size;\n+\n+\t/* Sq doesn't use direct wqe */\n+\terr = spnic_alloc_db_addr(hwdev, &db_addr, NULL);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Alloc sq doorbell addr failed\");\n+\t\tgoto alloc_db_err_fail;\n+\t}\n+\ttxq->db_addr = db_addr;\n+\n+\ttxq->tx_info = rte_zmalloc_socket(\"tx_info\",\n+\t\t\t\t\t  sq_depth * sizeof(*txq->tx_info),\n+\t\t\t\t\t  RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (!txq->tx_info) {\n+\t\tPMD_DRV_LOG(ERR, \"Allocate tx_info failed, dev_name: %s\",\n+\t\t\t    dev->data->name);\n+\t\terr = -ENOMEM;\n+\t\tgoto alloc_tx_info_fail;\n+\t}\n+\n+\t/* Record txq pointer in rte_eth tx_queues */\n+\tdev->data->tx_queues[qid] = txq;\n+\n+\treturn 0;\n+\n+alloc_tx_info_fail:\n+\tspnic_free_db_addr(hwdev, txq->db_addr, NULL);\n+\n+alloc_db_err_fail:\n+\trte_memzone_free(txq->sq_mz);\n+\n+alloc_sq_mz_fail:\n+\trte_memzone_free(txq->ci_mz);\n+\n+alloc_ci_mz_fail:\n+\trte_free(txq);\n+\n+\treturn err;\n+}\n+\n+static void spnic_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)\n+{\n+\tstruct spnic_rxq *rxq = dev->data->rx_queues[qid];\n+\tstruct spnic_nic_dev *nic_dev;\n+\n+\tif (!rxq) {\n+\t\tPMD_DRV_LOG(WARNING, \"Rxq is null when release\");\n+\t\treturn;\n+\t}\n+\tnic_dev = rxq->nic_dev;\n+\n+\tspnic_free_rxq_mbufs(rxq);\n+\n+\trte_memzone_free(rxq->cqe_mz);\n+\n+\trte_free(rxq->rx_info);\n+\n+\trte_memzone_free(rxq->rq_mz);\n+\n+\trte_memzone_free(rxq->pi_mz);\n+\n+\tnic_dev->rxqs[rxq->q_id] = NULL;\n+\trte_free(rxq);\n+}\n+\n+static void spnic_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)\n+{\n+\tstruct spnic_txq *txq = dev->data->tx_queues[qid];\n+\tstruct spnic_nic_dev *nic_dev;\n+\n+\tif (!txq) {\n+\t\tPMD_DRV_LOG(WARNING, \"Txq is null when release\");\n+\t\treturn;\n+\t}\n+\tnic_dev = txq->nic_dev;\n+\n+\tspnic_free_txq_mbufs(txq);\n+\n+\trte_free(txq->tx_info);\n+\ttxq->tx_info = NULL;\n+\n+\tspnic_free_db_addr(nic_dev->hwdev, txq->db_addr, NULL);\n+\n+\trte_memzone_free(txq->sq_mz);\n+\n+\trte_memzone_free(txq->ci_mz);\n+\n+\tnic_dev->txqs[txq->q_id] = NULL;\n+\trte_free(txq);\n+}\n+\n static void spnic_delete_mc_addr_list(struct spnic_nic_dev *nic_dev);\n \n /**\n@@ -235,6 +697,7 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)\n \n \tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n \n+\tspnic_get_func_rx_buf_size(nic_dev);\n \terr = spnic_init_function_table(nic_dev->hwdev, nic_dev->rx_buff_len);\n \tif (err) {\n \t\tPMD_DRV_LOG(ERR, \"Init function table failed, dev_name: %s\",\n@@ -253,6 +716,9 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)\n \t\tgoto get_feature_err;\n \t}\n \n+\t/* reset rx and tx queue */\n+\tspnic_reset_rx_queue(eth_dev);\n+\tspnic_reset_tx_queue(eth_dev);\n \n \t/* Init txq and rxq context */\n \terr = spnic_init_qp_ctxts(nic_dev);\n@@ -270,6 +736,15 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)\n \t\tgoto set_mtu_fail;\n \t}\n \n+\terr = spnic_start_all_rqs(eth_dev);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Set rx config failed, dev_name: %s\",\n+\t\t\t    eth_dev->data->name);\n+\t\tgoto start_rqs_fail;\n+\t}\n+\n+\tspnic_start_all_sqs(eth_dev);\n+\n \t/* Update eth_dev link status */\n \tif (eth_dev->data->dev_conf.intr_conf.lsc != 0)\n \t\t(void)spnic_link_update(eth_dev, 0);\n@@ -278,6 +753,7 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)\n \n \treturn 0;\n \n+start_rqs_fail:\n set_mtu_fail:\n \tspnic_free_qp_ctxts(nic_dev->hwdev);\n \n@@ -313,9 +789,17 @@ static int spnic_dev_stop(struct rte_eth_dev *dev)\n \tmemset(&link, 0, sizeof(link));\n \t(void)rte_eth_linkstatus_set(dev, &link);\n \n+\t/* Flush pending io request */\n+\tspnic_flush_txqs(nic_dev);\n+\n+\tspnic_flush_qps_res(nic_dev->hwdev);\n \t/* Clean root context */\n \tspnic_free_qp_ctxts(nic_dev->hwdev);\n \n+\t/* Free all tx and rx mbufs */\n+\tspnic_free_all_txq_mbufs(nic_dev);\n+\tspnic_free_all_rxq_mbufs(nic_dev);\n+\n \treturn 0;\n }\n \n@@ -329,6 +813,7 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n {\n \tstruct spnic_nic_dev *nic_dev =\n \tSPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\tint qid;\n \n \tif (rte_bit_relaxed_test_and_set32(SPNIC_DEV_CLOSE, &nic_dev->dev_status)) {\n \t\tPMD_DRV_LOG(WARNING, \"Device %s already closed\",\n@@ -338,6 +823,13 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n \n \tspnic_dev_stop(eth_dev);\n \n+\t/* Release io resource */\n+\tfor (qid = 0; qid < nic_dev->num_sqs; qid++)\n+\t\tspnic_tx_queue_release(eth_dev, qid);\n+\n+\tfor (qid = 0; qid < nic_dev->num_rqs; qid++)\n+\t\tspnic_rx_queue_release(eth_dev, qid);\n+\n \tspnic_deinit_sw_rxtxqs(nic_dev);\n \tspnic_deinit_mac_addr(eth_dev);\n \trte_free(nic_dev->mc_list);\n@@ -581,6 +1073,10 @@ static const struct eth_dev_ops spnic_pmd_ops = {\n \t.dev_set_link_up               = spnic_dev_set_link_up,\n \t.dev_set_link_down             = spnic_dev_set_link_down,\n \t.link_update                   = spnic_link_update,\n+\t.rx_queue_setup                = spnic_rx_queue_setup,\n+\t.tx_queue_setup                = spnic_tx_queue_setup,\n+\t.rx_queue_release              = spnic_rx_queue_release,\n+\t.tx_queue_release              = spnic_tx_queue_release,\n \t.dev_start                     = spnic_dev_start,\n \t.dev_stop                      = spnic_dev_stop,\n \t.dev_close                     = spnic_dev_close,\n@@ -592,8 +1088,12 @@ static const struct eth_dev_ops spnic_pmd_ops = {\n };\n \n static const struct eth_dev_ops spnic_pmd_vf_ops = {\n-\t.link_update                   = spnic_link_update,\n+\t.rx_queue_setup                = spnic_rx_queue_setup,\n+\t.tx_queue_setup                = spnic_tx_queue_setup,\n \t.dev_start                     = spnic_dev_start,\n+\t.link_update                   = spnic_link_update,\n+\t.rx_queue_release              = spnic_rx_queue_release,\n+\t.tx_queue_release              = spnic_tx_queue_release,\n \t.dev_stop                      = spnic_dev_stop,\n \t.dev_close                     = spnic_dev_close,\n \t.mtu_set                       = spnic_dev_set_mtu,\ndiff --git a/drivers/net/spnic/spnic_rx.c b/drivers/net/spnic/spnic_rx.c\nnew file mode 100644\nindex 0000000000..20cd50c0c4\n--- /dev/null\n+++ b/drivers/net/spnic/spnic_rx.c\n@@ -0,0 +1,302 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd\n+ */\n+\n+#include <rte_ether.h>\n+#include <rte_mbuf.h>\n+#include <ethdev_driver.h>\n+\n+#include \"base/spnic_compat.h\"\n+#include \"base/spnic_cmd.h\"\n+#include \"base/spnic_hwif.h\"\n+#include \"base/spnic_hwdev.h\"\n+#include \"base/spnic_wq.h\"\n+#include \"base/spnic_mgmt.h\"\n+#include \"base/spnic_nic_cfg.h\"\n+#include \"spnic_io.h\"\n+#include \"spnic_rx.h\"\n+#include \"spnic_ethdev.h\"\n+\n+/**\n+ * Get receive queue wqe\n+ *\n+ * @param[in] rxq\n+ *   Receive queue\n+ * @param[out] pi\n+ *   Return current pi\n+ * @return\n+ *   RX wqe base address\n+ */\n+static inline void *spnic_get_rq_wqe(struct spnic_rxq *rxq, u16 *pi)\n+{\n+\t*pi = MASKED_QUEUE_IDX(rxq, rxq->prod_idx);\n+\n+\t/* Get only one rq wqe for once */\n+\trxq->prod_idx++;\n+\trxq->delta--;\n+\n+\treturn NIC_WQE_ADDR(rxq, *pi);\n+}\n+\n+/**\n+ * Put receive queue wqe\n+ *\n+ * @param[in] rxq\n+ *   Receive queue\n+ * @param[in] wqe_cnt\n+ *   Wqebb counters\n+ */\n+static inline void spnic_put_rq_wqe(struct spnic_rxq *rxq, u16 wqe_cnt)\n+{\n+\trxq->delta += wqe_cnt;\n+\trxq->prod_idx -= wqe_cnt;\n+}\n+\n+/**\n+ * Get receive queue local pi\n+ *\n+ * @param[in] rxq\n+ *   Receive queue\n+ * @return\n+ *   Receive queue local pi\n+ */\n+static inline u16 spnic_get_rq_local_pi(struct spnic_rxq *rxq)\n+{\n+\treturn MASKED_QUEUE_IDX(rxq, rxq->prod_idx);\n+}\n+\n+/**\n+ * Update receive queue hardware pi\n+ *\n+ * @param[in] rxq\n+ *   Receive queue\n+ * @param[in] pi\n+ *   Receive queue pi to update\n+ */\n+static inline void spnic_update_rq_hw_pi(struct spnic_rxq *rxq, u16 pi)\n+{\n+\t*rxq->pi_virt_addr = cpu_to_be16((pi & rxq->q_mask) << rxq->wqe_type);\n+}\n+\n+int spnic_rx_fill_wqe(struct spnic_rxq *rxq)\n+{\n+\tstruct spnic_rq_wqe *rq_wqe = NULL;\n+\tstruct spnic_nic_dev *nic_dev = rxq->nic_dev;\n+\trte_iova_t cqe_dma;\n+\tu16 pi = 0;\n+\tint i;\n+\n+\tcqe_dma = rxq->cqe_start_paddr;\n+\tfor (i = 0; i < rxq->q_depth; i++) {\n+\t\trq_wqe = spnic_get_rq_wqe(rxq, &pi);\n+\t\tif (!rq_wqe) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Get rq wqe failed, rxq id: %d, wqe id: %d\",\n+\t\t\t\t    rxq->q_id, i);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (rxq->wqe_type == SPNIC_EXTEND_RQ_WQE) {\n+\t\t\t/* Unit of cqe length is 16B */\n+\t\t\tspnic_set_sge(&rq_wqe->extend_wqe.cqe_sect.sge,\n+\t\t\t\t       cqe_dma,\n+\t\t\t\t       sizeof(struct spnic_rq_cqe) >>\n+\t\t\t\t       SPNIC_CQE_SIZE_SHIFT);\n+\t\t\t/* Use fixed len */\n+\t\t\trq_wqe->extend_wqe.buf_desc.sge.len =\n+\t\t\t\t\t\t\tnic_dev->rx_buff_len;\n+\t\t} else {\n+\t\t\trq_wqe->normal_wqe.cqe_hi_addr = upper_32_bits(cqe_dma);\n+\t\t\trq_wqe->normal_wqe.cqe_lo_addr = lower_32_bits(cqe_dma);\n+\t\t}\n+\n+\t\tcqe_dma += sizeof(struct spnic_rq_cqe);\n+\t}\n+\n+\tspnic_put_rq_wqe(rxq, (u16)i);\n+\n+\treturn i;\n+}\n+\n+static struct rte_mbuf *spnic_rx_alloc_mbuf(struct spnic_rxq *rxq,\n+\t\t\t\t\t    rte_iova_t *dma_addr)\n+{\n+\tstruct rte_mbuf *mbuf = NULL;\n+\n+\tif (unlikely(rte_pktmbuf_alloc_bulk(rxq->mb_pool, &mbuf, 1) != 0))\n+\t\treturn NULL;\n+\n+\t*dma_addr = rte_mbuf_data_iova_default(mbuf);\n+\n+\treturn mbuf;\n+}\n+\n+u32 spnic_rx_fill_buffers(struct spnic_rxq *rxq)\n+{\n+\tstruct spnic_rq_wqe *rq_wqe = NULL;\n+\tstruct spnic_rx_info *rx_info = NULL;\n+\tstruct rte_mbuf *mb = NULL;\n+\trte_iova_t dma_addr;\n+\tint i, free_wqebbs;\n+\n+\tfree_wqebbs = rxq->delta - 1;\n+\tfor (i = 0; i < free_wqebbs; i++) {\n+\t\trx_info = &rxq->rx_info[rxq->next_to_update];\n+\n+\t\tmb = spnic_rx_alloc_mbuf(rxq, &dma_addr);\n+\t\tif (!mb) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Alloc mbuf failed\");\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\trx_info->mbuf = mb;\n+\n+\t\trq_wqe = NIC_WQE_ADDR(rxq, rxq->next_to_update);\n+\n+\t\t/* Fill buffer address only */\n+\t\tif (rxq->wqe_type == SPNIC_EXTEND_RQ_WQE) {\n+\t\t\trq_wqe->extend_wqe.buf_desc.sge.hi_addr = upper_32_bits(dma_addr);\n+\t\t\trq_wqe->extend_wqe.buf_desc.sge.lo_addr = lower_32_bits(dma_addr);\n+\t\t} else {\n+\t\t\trq_wqe->normal_wqe.buf_hi_addr = upper_32_bits(dma_addr);\n+\t\t\trq_wqe->normal_wqe.buf_lo_addr = lower_32_bits(dma_addr);\n+\t\t}\n+\n+\t\trxq->next_to_update = (rxq->next_to_update + 1) & rxq->q_mask;\n+\t}\n+\n+\tif (likely(i > 0)) {\n+\t\tspnic_write_db(rxq->db_addr, rxq->q_id, 0, RQ_CFLAG_DP,\n+\t\t\t\trxq->next_to_update << rxq->wqe_type);\n+\t\t/* Init rq contxet used, need to optimization */\n+\t\trxq->prod_idx = rxq->next_to_update;\n+\t\trxq->delta -= i;\n+\t} else {\n+\t\tPMD_DRV_LOG(ERR, \"Alloc rx buffers failed, rxq_id: %d\",\n+\t\t\t    rxq->q_id);\n+\t}\n+\n+\treturn i;\n+}\n+\n+void spnic_free_rxq_mbufs(struct spnic_rxq *rxq)\n+{\n+\tstruct spnic_rx_info *rx_info = NULL;\n+\tint free_wqebbs = spnic_get_rq_free_wqebb(rxq) + 1;\n+\tvolatile struct spnic_rq_cqe *rx_cqe = NULL;\n+\tu16 ci;\n+\n+\twhile (free_wqebbs++ < rxq->q_depth) {\n+\t\tci = spnic_get_rq_local_ci(rxq);\n+\n+\t\trx_cqe = &rxq->rx_cqe[ci];\n+\n+\t\t/* Clear done bit */\n+\t\trx_cqe->status = 0;\n+\n+\t\trx_info = &rxq->rx_info[ci];\n+\t\trte_pktmbuf_free(rx_info->mbuf);\n+\t\trx_info->mbuf = NULL;\n+\n+\t\tspnic_update_rq_local_ci(rxq, 1);\n+\t}\n+}\n+\n+void spnic_free_all_rxq_mbufs(struct spnic_nic_dev *nic_dev)\n+{\n+\tu16 qid;\n+\n+\tfor (qid = 0; qid < nic_dev->num_rqs; qid++)\n+\t\tspnic_free_rxq_mbufs(nic_dev->rxqs[qid]);\n+}\n+\n+static inline u32 spnic_rx_alloc_mbuf_bulk(struct spnic_rxq *rxq,\n+\t\t\t\t\t   struct rte_mbuf **mbufs,\n+\t\t\t\t\t   u32 exp_mbuf_cnt)\n+{\n+\tu32 avail_cnt;\n+\tint err;\n+\n+\terr = rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, exp_mbuf_cnt);\n+\tif (likely(err == 0)) {\n+\t\tavail_cnt = exp_mbuf_cnt;\n+\t} else {\n+\t\tavail_cnt = 0;\n+\t\trxq->rxq_stats.rx_nombuf += exp_mbuf_cnt;\n+\t}\n+\n+\treturn avail_cnt;\n+}\n+\n+static inline void spnic_rearm_rxq_mbuf(struct spnic_rxq *rxq)\n+{\n+\tstruct spnic_rq_wqe *rq_wqe = NULL;\n+\tstruct rte_mbuf **rearm_mbufs;\n+\tu32 i, free_wqebbs, rearm_wqebbs, exp_wqebbs;\n+\trte_iova_t dma_addr;\n+\tu16 pi;\n+\n+\t/* Check free wqebb cnt fo rearm */\n+\tfree_wqebbs = spnic_get_rq_free_wqebb(rxq);\n+\tif (unlikely(free_wqebbs < rxq->rx_free_thresh))\n+\t\treturn;\n+\n+\t/* Get rearm mbuf array */\n+\tpi = spnic_get_rq_local_pi(rxq);\n+\trearm_mbufs = (struct rte_mbuf **)(&rxq->rx_info[pi]);\n+\n+\t/* Check rxq free wqebbs turn around */\n+\texp_wqebbs = rxq->q_depth - pi;\n+\tif (free_wqebbs < exp_wqebbs)\n+\t\texp_wqebbs = free_wqebbs;\n+\n+\t/* Alloc mbuf in bulk */\n+\trearm_wqebbs = spnic_rx_alloc_mbuf_bulk(rxq, rearm_mbufs, exp_wqebbs);\n+\tif (unlikely(rearm_wqebbs == 0))\n+\t\treturn;\n+\n+\t/* Rearm rx mbuf */\n+\trq_wqe = NIC_WQE_ADDR(rxq, pi);\n+\tfor (i = 0; i < rearm_wqebbs; i++) {\n+\t\tdma_addr = rte_mbuf_data_iova_default(rearm_mbufs[i]);\n+\n+\t\t/* Fill buffer address only */\n+\t\tif (rxq->wqe_type == SPNIC_EXTEND_RQ_WQE) {\n+\t\t\trq_wqe->extend_wqe.buf_desc.sge.hi_addr = upper_32_bits(dma_addr);\n+\t\t\trq_wqe->extend_wqe.buf_desc.sge.lo_addr = lower_32_bits(dma_addr);\n+\t\t} else {\n+\t\t\trq_wqe->normal_wqe.buf_hi_addr = upper_32_bits(dma_addr);\n+\t\t\trq_wqe->normal_wqe.buf_lo_addr = lower_32_bits(dma_addr);\n+\t\t}\n+\n+\t\trq_wqe = (struct spnic_rq_wqe *)((u64)rq_wqe +\n+\t\t\t rxq->wqebb_size);\n+\t}\n+\trxq->prod_idx += rearm_wqebbs;\n+\trxq->delta -= rearm_wqebbs;\n+\n+#ifndef SPNIC_RQ_DB\n+\tspnic_write_db(rxq->db_addr, rxq->q_id, 0, RQ_CFLAG_DP,\n+\t\t\t((pi + rearm_wqebbs) & rxq->q_mask) << rxq->wqe_type);\n+#else\n+\t/* Update rq hw_pi */\n+\trte_wmb();\n+\tspnic_update_rq_hw_pi(rxq, pi + rearm_wqebbs);\n+#endif\n+}\n+\n+int spnic_start_all_rqs(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev = NULL;\n+\tstruct spnic_rxq *rxq = NULL;\n+\tint i;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\n+\tfor (i = 0; i < nic_dev->num_rqs; i++) {\n+\t\trxq = eth_dev->data->rx_queues[i];\n+\t\tspnic_rearm_rxq_mbuf(rxq);\n+\t\teth_dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/spnic/spnic_rx.h b/drivers/net/spnic/spnic_rx.h\nindex b2f0052533..46f4e1276d 100644\n--- a/drivers/net/spnic/spnic_rx.h\n+++ b/drivers/net/spnic/spnic_rx.h\n@@ -110,4 +110,45 @@ struct spnic_rxq {\n \tstruct spnic_rxq_stats\trxq_stats;\n } __rte_cache_aligned;\n \n+int spnic_rx_fill_wqe(struct spnic_rxq *rxq);\n+\n+u32 spnic_rx_fill_buffers(struct spnic_rxq *rxq);\n+\n+void spnic_free_rxq_mbufs(struct spnic_rxq *rxq);\n+\n+void spnic_free_all_rxq_mbufs(struct spnic_nic_dev *nic_dev);\n+\n+int spnic_start_all_rqs(struct rte_eth_dev *eth_dev);\n+/**\n+ * Get receive queue local ci\n+ *\n+ * @param[in] rxq\n+ *   Receive queue\n+ * @return\n+ *   Receive queue local ci\n+ */\n+static inline u16 spnic_get_rq_local_ci(struct spnic_rxq *rxq)\n+{\n+\treturn MASKED_QUEUE_IDX(rxq, rxq->cons_idx);\n+}\n+\n+static inline u16 spnic_get_rq_free_wqebb(struct spnic_rxq *rxq)\n+{\n+\treturn rxq->delta - 1;\n+}\n+\n+/**\n+ * Update receive queue local ci\n+ *\n+ * @param[in] rxq\n+ *   Receive queue\n+ * @param[in] wqe_cnt\n+ *   Wqebb counters\n+ */\n+static inline void spnic_update_rq_local_ci(struct spnic_rxq *rxq,\n+\t\t\t\t\t     u16 wqe_cnt)\n+{\n+\trxq->cons_idx += wqe_cnt;\n+\trxq->delta += wqe_cnt;\n+}\n #endif /* _SPNIC_RX_H_ */\ndiff --git a/drivers/net/spnic/spnic_tx.c b/drivers/net/spnic/spnic_tx.c\nnew file mode 100644\nindex 0000000000..d905879412\n--- /dev/null\n+++ b/drivers/net/spnic/spnic_tx.c\n@@ -0,0 +1,334 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd\n+ */\n+\n+#include <rte_ether.h>\n+#include <rte_mbuf.h>\n+#include <rte_io.h>\n+#include <ethdev_driver.h>\n+\n+#include \"base/spnic_compat.h\"\n+#include \"base/spnic_cmd.h\"\n+#include \"base/spnic_wq.h\"\n+#include \"base/spnic_mgmt.h\"\n+#include \"base/spnic_hwdev.h\"\n+#include \"base/spnic_nic_cfg.h\"\n+#include \"spnic_io.h\"\n+#include \"spnic_tx.h\"\n+#include \"spnic_ethdev.h\"\n+\n+#define SPNIC_TX_TASK_WRAPPED\t\t1\n+#define SPNIC_TX_BD_DESC_WRAPPED\t2\n+\n+#define TX_MSS_DEFAULT\t\t\t0x3E00\n+#define TX_MSS_MIN\t\t\t0x50\n+\n+#define SPNIC_MAX_TX_FREE_BULK\t\t64\n+\n+#define\tMAX_PAYLOAD_OFFSET\t\t221\n+\n+#define SPNIC_TX_OUTER_CHECKSUM_FLAG_SET       1\n+#define SPNIC_TX_OUTER_CHECKSUM_FLAG_NO_SET    0\n+\n+/**\n+ * Get send queue free wqebb cnt\n+ *\n+ * @param[in] sq\n+ *   Send queue\n+ * @return\n+ *   Number of free wqebb\n+ */\n+static inline u16 spnic_get_sq_free_wqebbs(struct spnic_txq *sq)\n+{\n+\treturn (sq->q_depth -\n+\t\t((sq->prod_idx - sq->cons_idx + sq->q_depth) & sq->q_mask) - 1);\n+}\n+\n+/**\n+ * Update send queue local ci\n+ *\n+ * @param[in] sq\n+ *   Send queue\n+ * @param[in] wqe_cnt\n+ *   Number of wqebb\n+ */\n+static inline void spnic_update_sq_local_ci(struct spnic_txq *sq, u16 wqe_cnt)\n+{\n+\tsq->cons_idx += wqe_cnt;\n+}\n+\n+/**\n+ * Get send queue local ci\n+ *\n+ * @param[in] sq\n+ *   Send queue\n+ * @return\n+ *   Local ci\n+ */\n+static inline u16 spnic_get_sq_local_ci(struct spnic_txq *sq)\n+{\n+\treturn MASKED_QUEUE_IDX(sq, sq->cons_idx);\n+}\n+\n+/**\n+ * Get send queue hardware ci\n+ *\n+ * @param[in] sq\n+ *   Send queue\n+ * @return\n+ *   Hardware ci\n+ */\n+static inline u16 spnic_get_sq_hw_ci(struct spnic_txq *sq)\n+{\n+\treturn MASKED_QUEUE_IDX(sq, *(u16 *)sq->ci_vaddr_base);\n+}\n+\n+/**\n+ * Get send queue wqe\n+ *\n+ * @param[in] sq\n+ *   Send queue\n+ * @param[in] wqebb_cnt\n+ *   Num of wqebb counter\n+ * @param[out] pi\n+ *   Return current pi\n+ * @param[out] owner\n+ *   Owner bit for hardware\n+ * @param[out] wrapped\n+ *   Indicate whether wqe is wrapped\n+ * @return\n+ *   Send queue wqe base address\n+ */\n+static inline void *spnic_get_sq_wqe(struct spnic_txq *sq,\n+\t\t\t\t     struct spnic_wqe_info *wqe_info)\n+{\n+\tu16 cur_pi = MASKED_QUEUE_IDX(sq, sq->prod_idx);\n+\tu32 end_pi;\n+\n+\tend_pi = cur_pi + wqe_info->wqebb_cnt;\n+\tsq->prod_idx += wqe_info->wqebb_cnt;\n+\n+\twqe_info->owner = sq->owner;\n+\twqe_info->pi = cur_pi;\n+\twqe_info->wrapped = 0;\n+\n+\tif (unlikely(end_pi >= sq->q_depth)) {\n+\t\tsq->owner = !sq->owner;\n+\n+\t\tif (likely(end_pi > sq->q_depth))\n+\t\t\twqe_info->wrapped = sq->q_depth - cur_pi;\n+\t}\n+\n+\treturn NIC_WQE_ADDR(sq, cur_pi);\n+}\n+\n+/**\n+ * Put send queue wqe\n+ *\n+ * @param[in] sq\n+ *   Send queue\n+ * @param[in] wqebb_cnt\n+ *   Num of wqebb counter\n+ * @param[out] owner\n+ *   Owner bit for hardware\n+ */\n+static inline void spnic_put_sq_wqe(struct spnic_txq *sq,\n+\t\t\t\t    struct spnic_wqe_info *wqe_info)\n+{\n+\tif (wqe_info->owner != sq->owner)\n+\t\tsq->owner = wqe_info->owner;\n+\n+\tsq->prod_idx -= wqe_info->wqebb_cnt;\n+}\n+\n+static inline void spnic_set_wqe_combo(struct spnic_txq *txq,\n+\t\t\t\t    struct spnic_sq_wqe_combo *wqe_combo,\n+\t\t\t\t\tstruct spnic_sq_wqe *wqe,\n+\t\t\t\t\tstruct spnic_wqe_info *wqe_info)\n+{\n+\twqe_combo->hdr = &wqe->compact_wqe.wqe_desc;\n+\n+\tif (wqe_info->offload) {\n+\t\tif (wqe_info->wrapped == SPNIC_TX_TASK_WRAPPED) {\n+\t\t\twqe_combo->task = (struct spnic_sq_task *)\n+\t\t\t\t(void *)txq->sq_head_addr;\n+\t\t\twqe_combo->bds_head = (struct spnic_sq_bufdesc *)\n+\t\t\t\t(void *)(txq->sq_head_addr + txq->wqebb_size);\n+\t\t} else if (wqe_info->wrapped == SPNIC_TX_BD_DESC_WRAPPED) {\n+\t\t\twqe_combo->task = &wqe->extend_wqe.task;\n+\t\t\twqe_combo->bds_head = (struct spnic_sq_bufdesc *)\n+\t\t\t\t(void *)(txq->sq_head_addr);\n+\t\t} else {\n+\t\t\twqe_combo->task = &wqe->extend_wqe.task;\n+\t\t\twqe_combo->bds_head = wqe->extend_wqe.buf_desc;\n+\t\t}\n+\n+\t\twqe_combo->wqe_type = SQ_WQE_EXTENDED_TYPE;\n+\t\twqe_combo->task_type = SQ_WQE_TASKSECT_16BYTES;\n+\t\treturn;\n+\t}\n+\n+\tif (wqe_info->wrapped == SPNIC_TX_TASK_WRAPPED) {\n+\t\twqe_combo->bds_head = (struct spnic_sq_bufdesc *)\n+\t\t\t\t(void *)(txq->sq_head_addr);\n+\t} else {\n+\t\twqe_combo->bds_head =\n+\t\t\t(struct spnic_sq_bufdesc *)(&wqe->extend_wqe.task);\n+\t}\n+\n+\tif (wqe_info->wqebb_cnt > 1) {\n+\t\twqe_combo->wqe_type = SQ_WQE_EXTENDED_TYPE;\n+\t\twqe_combo->task_type = SQ_WQE_TASKSECT_46BITS;\n+\t\t/* This section used as vlan insert, needs to clear */\n+\t\twqe_combo->bds_head->rsvd = 0;\n+\t} else {\n+\t\twqe_combo->wqe_type = SQ_WQE_COMPACT_TYPE;\n+\t}\n+}\n+\n+void spnic_free_txq_mbufs(struct spnic_txq *txq)\n+{\n+\tstruct spnic_tx_info *tx_info = NULL;\n+\tu16 free_wqebbs;\n+\tu16 ci;\n+\n+\tfree_wqebbs = spnic_get_sq_free_wqebbs(txq) + 1;\n+\n+\twhile (free_wqebbs < txq->q_depth) {\n+\t\tci = spnic_get_sq_local_ci(txq);\n+\n+\t\ttx_info = &txq->tx_info[ci];\n+\n+\t\trte_pktmbuf_free(tx_info->mbuf);\n+\t\tspnic_update_sq_local_ci(txq, tx_info->wqebb_cnt);\n+\n+\t\tfree_wqebbs += tx_info->wqebb_cnt;\n+\t\ttx_info->mbuf = NULL;\n+\t}\n+}\n+\n+void spnic_free_all_txq_mbufs(struct spnic_nic_dev *nic_dev)\n+{\n+\tu16 qid;\n+\n+\tfor (qid = 0; qid < nic_dev->num_sqs; qid++)\n+\t\tspnic_free_txq_mbufs(nic_dev->txqs[qid]);\n+}\n+\n+int spnic_start_all_sqs(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct spnic_nic_dev *nic_dev = NULL;\n+\tint i;\n+\n+\tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);\n+\n+\tfor (i = 0; i < nic_dev->num_rqs; i++)\n+\t\teth_dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;\n+\n+\treturn 0;\n+}\n+static inline int spnic_xmit_mbuf_cleanup(struct spnic_txq *txq, u32 free_cnt)\n+{\n+\tstruct spnic_tx_info *tx_info = NULL;\n+\tstruct rte_mbuf *mbuf = NULL;\n+\tstruct rte_mbuf *mbuf_temp = NULL;\n+\tstruct rte_mbuf *mbuf_free[SPNIC_MAX_TX_FREE_BULK];\n+\tint nb_free = 0;\n+\tint wqebb_cnt = 0;\n+\tu16 hw_ci, sw_ci, sq_mask;\n+\tu32 i;\n+\n+\thw_ci = spnic_get_sq_hw_ci(txq);\n+\tsw_ci = spnic_get_sq_local_ci(txq);\n+\tsq_mask = txq->q_mask;\n+\n+\tfor (i = 0; i < free_cnt; ++i) {\n+\t\ttx_info = &txq->tx_info[sw_ci];\n+\t\tif (hw_ci == sw_ci ||\n+\t\t    (((hw_ci - sw_ci) & sq_mask) < tx_info->wqebb_cnt))\n+\t\t\tbreak;\n+\n+\t\tsw_ci = (sw_ci + tx_info->wqebb_cnt) & sq_mask;\n+\n+\t\twqebb_cnt += tx_info->wqebb_cnt;\n+\t\tmbuf = tx_info->mbuf;\n+\n+\t\tif (likely(mbuf->nb_segs == 1)) {\n+\t\t\tmbuf_temp = rte_pktmbuf_prefree_seg(mbuf);\n+\t\t\ttx_info->mbuf = NULL;\n+\n+\t\t\tif (unlikely(mbuf_temp == NULL))\n+\t\t\t\tcontinue;\n+\n+\t\t\tmbuf_free[nb_free++] = mbuf_temp;\n+\t\t\tif (unlikely(mbuf_temp->pool != mbuf_free[0]->pool ||\n+\t\t\t    nb_free >= SPNIC_MAX_TX_FREE_BULK)) {\n+\t\t\t\trte_mempool_put_bulk(mbuf_free[0]->pool,\n+\t\t\t\t\t(void **)mbuf_free, (nb_free - 1));\n+\t\t\t\tnb_free = 0;\n+\t\t\t\tmbuf_free[nb_free++] = mbuf_temp;\n+\t\t\t}\n+\t\t} else {\n+\t\t\trte_pktmbuf_free(mbuf);\n+\t\t\ttx_info->mbuf = NULL;\n+\t\t}\n+\t}\n+\n+\tif (nb_free > 0)\n+\t\trte_mempool_put_bulk(mbuf_free[0]->pool, (void **)mbuf_free,\n+\t\t\t\t     nb_free);\n+\n+\tspnic_update_sq_local_ci(txq, wqebb_cnt);\n+\treturn i;\n+}\n+\n+static int spnic_tx_done_cleanup(void *txq, u32 free_cnt)\n+{\n+\tstruct spnic_txq *tx_queue = txq;\n+\tu32 try_free_cnt = !free_cnt ? tx_queue->q_depth : free_cnt;\n+\n+\treturn spnic_xmit_mbuf_cleanup(tx_queue, try_free_cnt);\n+}\n+int spnic_stop_sq(struct spnic_txq *txq)\n+{\n+\tstruct spnic_nic_dev *nic_dev = txq->nic_dev;\n+\tunsigned long timeout;\n+\tint err = -EFAULT;\n+\tint free_wqebbs;\n+\n+\ttimeout = msecs_to_jiffies(SPNIC_FLUSH_QUEUE_TIMEOUT) + jiffies;\n+\tdo {\n+\t\tspnic_tx_done_cleanup(txq, 0);\n+\t\tfree_wqebbs = spnic_get_sq_free_wqebbs(txq) + 1;\n+\t\tif (free_wqebbs == txq->q_depth) {\n+\t\t\terr = 0;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\trte_delay_us(1);\n+\t} while (time_before(jiffies, timeout));\n+\n+\tif (err)\n+\t\tPMD_DRV_LOG(WARNING, \"%s Wait sq empty timeout, queue_idx: %u, sw_ci: %u, \"\n+\t\t\t    \"hw_ci: %u, sw_pi: %u, free_wqebbs: %u, q_depth:%u\\n\",\n+\t\t\t    nic_dev->dev_name, txq->q_id,\n+\t\t\t    spnic_get_sq_local_ci(txq),\n+\t\t\t    spnic_get_sq_hw_ci(txq),\n+\t\t\t    MASKED_QUEUE_IDX(txq, txq->prod_idx),\n+\t\t\t    free_wqebbs, txq->q_depth);\n+\n+\treturn err;\n+}\n+\n+/* Should stop transmiting any packets before calling this function */\n+void spnic_flush_txqs(struct spnic_nic_dev *nic_dev)\n+{\n+\tu16 qid;\n+\tint err;\n+\n+\tfor (qid = 0; qid < nic_dev->num_sqs; qid++) {\n+\t\terr = spnic_stop_sq(nic_dev->txqs[qid]);\n+\t\tif (err)\n+\t\t\tPMD_DRV_LOG(ERR, \"Stop sq%d failed\", qid);\n+\t}\n+}\ndiff --git a/drivers/net/spnic/spnic_tx.h b/drivers/net/spnic/spnic_tx.h\nindex 7528b27bd9..d770b15c21 100644\n--- a/drivers/net/spnic/spnic_tx.h\n+++ b/drivers/net/spnic/spnic_tx.h\n@@ -4,6 +4,224 @@\n \n #ifndef _SPNIC_TX_H_\n #define _SPNIC_TX_H_\n+/* Tx offload info */\n+struct spnic_tx_offload_info {\n+\tu8 outer_l2_len;\n+\tu8 outer_l3_type;\n+\tu16 outer_l3_len;\n+\n+\tu8 inner_l2_len;\n+\tu8 inner_l3_type;\n+\tu16 inner_l3_len;\n+\n+\tu8 tunnel_length;\n+\tu8 tunnel_type;\n+\tu8 inner_l4_type;\n+\tu8 inner_l4_len;\n+\n+\tu16 payload_offset;\n+\tu8 inner_l4_tcp_udp;\n+\tu8 rsvd0;\n+};\n+\n+/* tx wqe ctx */\n+struct spnic_wqe_info {\n+\tu8 around;\n+\tu8 cpy_mbuf_cnt;\n+\tu16 sge_cnt;\n+\n+\tu8 offload;\n+\tu8 rsvd0;\n+\tu16 payload_offset;\n+\n+\tu8 wrapped;\n+\tu8 owner;\n+\tu16 pi;\n+\n+\tu16 wqebb_cnt;\n+\tu16 rsvd1;\n+\n+\tu32 queue_info;\n+};\n+struct spnic_sq_wqe_desc {\n+\tu32 ctrl_len;\n+\tu32 queue_info;\n+\tu32 hi_addr;\n+\tu32 lo_addr;\n+};\n+\n+/*\n+ * Engine only pass first 12B TS field directly to uCode through metadata,\n+ * vlan_offoad is used for hardware when vlan insert in tx\n+ */\n+struct spnic_sq_task {\n+\tu32 pkt_info0;\n+\tu32 ip_identify;\n+\tu32 pkt_info2; /* Rsvd for ipsec spi */\n+\tu32 vlan_offload;\n+};\n+\n+struct spnic_sq_bufdesc {\n+\tu32 len; /* 31-bits Length, L2NIC only use length[17:0] */\n+\tu32 rsvd;\n+\tu32 hi_addr;\n+\tu32 lo_addr;\n+};\n+\n+struct spnic_sq_compact_wqe {\n+\tstruct spnic_sq_wqe_desc wqe_desc;\n+};\n+\n+struct spnic_sq_extend_wqe {\n+\tstruct spnic_sq_wqe_desc wqe_desc;\n+\tstruct spnic_sq_task task;\n+\tstruct spnic_sq_bufdesc buf_desc[0];\n+};\n+\n+struct spnic_sq_wqe {\n+\tunion {\n+\t\tstruct spnic_sq_compact_wqe compact_wqe;\n+\t\tstruct spnic_sq_extend_wqe extend_wqe;\n+\t};\n+};\n+\n+/* Use section pointer to support non continuous wqe */\n+struct spnic_sq_wqe_combo {\n+\tstruct spnic_sq_wqe_desc *hdr;\n+\tstruct spnic_sq_task *task;\n+\tstruct spnic_sq_bufdesc *bds_head;\n+\tu32 wqe_type;\n+\tu32 task_type;\n+};\n+\n+/* SQ ctrl info */\n+enum sq_wqe_data_format {\n+\tSQ_NORMAL_WQE = 0,\n+};\n+\n+enum sq_wqe_ec_type {\n+\tSQ_WQE_COMPACT_TYPE = 0,\n+\tSQ_WQE_EXTENDED_TYPE = 1,\n+};\n+\n+#define COMPACT_WQE_MAX_CTRL_LEN 0x3FFF\n+\n+enum sq_wqe_tasksect_len_type {\n+\tSQ_WQE_TASKSECT_46BITS = 0,\n+\tSQ_WQE_TASKSECT_16BYTES = 1,\n+};\n+\n+#define SQ_CTRL_BD0_LEN_SHIFT\t\t\t0\n+#define SQ_CTRL_RSVD_SHIFT\t\t\t18\n+#define SQ_CTRL_BUFDESC_NUM_SHIFT\t\t19\n+#define SQ_CTRL_TASKSECT_LEN_SHIFT\t\t27\n+#define SQ_CTRL_DATA_FORMAT_SHIFT\t\t28\n+#define SQ_CTRL_DIRECT_SHIFT\t\t\t29\n+#define SQ_CTRL_EXTENDED_SHIFT\t\t\t30\n+#define SQ_CTRL_OWNER_SHIFT\t\t\t31\n+\n+#define SQ_CTRL_BD0_LEN_MASK\t\t\t0x3FFFFU\n+#define SQ_CTRL_RSVD_MASK\t\t\t0x1U\n+#define SQ_CTRL_BUFDESC_NUM_MASK\t\t0xFFU\n+#define SQ_CTRL_TASKSECT_LEN_MASK\t\t0x1U\n+#define SQ_CTRL_DATA_FORMAT_MASK\t\t0x1U\n+#define SQ_CTRL_DIRECT_MASK\t\t\t0x1U\n+#define SQ_CTRL_EXTENDED_MASK\t\t\t0x1U\n+#define SQ_CTRL_OWNER_MASK\t\t\t0x1U\n+\n+#define SQ_CTRL_SET(val, member)\t(((u32)(val) & \\\n+\t\t\t\t\t SQ_CTRL_##member##_MASK) << \\\n+\t\t\t\t\t SQ_CTRL_##member##_SHIFT)\n+\n+#define SQ_CTRL_GET(val, member)\t(((val) >> SQ_CTRL_##member##_SHIFT) \\\n+\t\t\t\t\t& SQ_CTRL_##member##_MASK)\n+\n+#define SQ_CTRL_CLEAR(val, member)\t((val) & \\\n+\t\t\t\t\t(~(SQ_CTRL_##member##_MASK << \\\n+\t\t\t\t\tSQ_CTRL_##member##_SHIFT)))\n+\n+#define SQ_CTRL_QUEUE_INFO_PKT_TYPE_SHIFT\t\t0\n+#define SQ_CTRL_QUEUE_INFO_PLDOFF_SHIFT\t\t\t2\n+#define SQ_CTRL_QUEUE_INFO_UFO_SHIFT\t\t\t10\n+#define SQ_CTRL_QUEUE_INFO_TSO_SHIFT\t\t\t11\n+#define SQ_CTRL_QUEUE_INFO_TCPUDP_CS_SHIFT\t\t12\n+#define SQ_CTRL_QUEUE_INFO_MSS_SHIFT\t\t\t13\n+#define SQ_CTRL_QUEUE_INFO_SCTP_SHIFT\t\t\t27\n+#define SQ_CTRL_QUEUE_INFO_UC_SHIFT\t\t\t28\n+#define SQ_CTRL_QUEUE_INFO_PRI_SHIFT\t\t\t29\n+\n+#define SQ_CTRL_QUEUE_INFO_PKT_TYPE_MASK\t\t0x3U\n+#define SQ_CTRL_QUEUE_INFO_PLDOFF_MASK\t\t\t0xFFU\n+#define SQ_CTRL_QUEUE_INFO_UFO_MASK\t\t\t0x1U\n+#define SQ_CTRL_QUEUE_INFO_TSO_MASK\t\t\t0x1U\n+#define SQ_CTRL_QUEUE_INFO_TCPUDP_CS_MASK\t\t0x1U\n+#define SQ_CTRL_QUEUE_INFO_MSS_MASK\t\t\t0x3FFFU\n+#define SQ_CTRL_QUEUE_INFO_SCTP_MASK\t\t\t0x1U\n+#define SQ_CTRL_QUEUE_INFO_UC_MASK\t\t\t0x1U\n+#define SQ_CTRL_QUEUE_INFO_PRI_MASK\t\t\t0x7U\n+\n+#define SQ_CTRL_QUEUE_INFO_SET(val, member)\t\\\n+\t(((u32)(val) & SQ_CTRL_QUEUE_INFO_##member##_MASK) \\\n+\t<< SQ_CTRL_QUEUE_INFO_##member##_SHIFT)\n+\n+#define SQ_CTRL_QUEUE_INFO_GET(val, member)\t\\\n+\t(((val) >> SQ_CTRL_QUEUE_INFO_##member##_SHIFT) \\\n+\t& SQ_CTRL_QUEUE_INFO_##member##_MASK)\n+\n+#define SQ_CTRL_QUEUE_INFO_CLEAR(val, member)\t\\\n+\t((val) & (~(SQ_CTRL_QUEUE_INFO_##member##_MASK << \\\n+\tSQ_CTRL_QUEUE_INFO_##member##_SHIFT)))\n+\n+#define\tSQ_TASK_INFO0_TUNNEL_FLAG_SHIFT\t\t19\n+#define\tSQ_TASK_INFO0_ESP_NEXT_PROTO_SHIFT\t22\n+#define\tSQ_TASK_INFO0_INNER_L4_EN_SHIFT\t\t24\n+#define\tSQ_TASK_INFO0_INNER_L3_EN_SHIFT\t\t25\n+#define\tSQ_TASK_INFO0_INNER_L4_PSEUDO_SHIFT\t26\n+#define\tSQ_TASK_INFO0_OUT_L4_EN_SHIFT\t\t27\n+#define\tSQ_TASK_INFO0_OUT_L3_EN_SHIFT\t\t28\n+#define\tSQ_TASK_INFO0_OUT_L4_PSEUDO_SHIFT\t29\n+#define\tSQ_TASK_INFO0_ESP_OFFLOAD_SHIFT\t\t30\n+#define\tSQ_TASK_INFO0_IPSEC_PROTO_SHIFT\t\t31\n+\n+#define\tSQ_TASK_INFO0_TUNNEL_FLAG_MASK\t\t0x1U\n+#define\tSQ_TASK_INFO0_ESP_NEXT_PROTO_MASK\t0x3U\n+#define\tSQ_TASK_INFO0_INNER_L4_EN_MASK\t\t0x1U\n+#define\tSQ_TASK_INFO0_INNER_L3_EN_MASK\t\t0x1U\n+#define\tSQ_TASK_INFO0_INNER_L4_PSEUDO_MASK\t0x1U\n+#define\tSQ_TASK_INFO0_OUT_L4_EN_MASK\t\t0x1U\n+#define\tSQ_TASK_INFO0_OUT_L3_EN_MASK\t\t0x1U\n+#define\tSQ_TASK_INFO0_OUT_L4_PSEUDO_MASK\t0x1U\n+#define\tSQ_TASK_INFO0_ESP_OFFLOAD_MASK\t\t0x1U\n+#define\tSQ_TASK_INFO0_IPSEC_PROTO_MASK\t\t0x1U\n+\n+#define SQ_TASK_INFO0_SET(val, member)\t\t\t\\\n+\t\t(((u32)(val) & SQ_TASK_INFO0_##member##_MASK) <<\t\\\n+\t\tSQ_TASK_INFO0_##member##_SHIFT)\n+#define SQ_TASK_INFO0_GET(val, member)\t\t\t\\\n+\t\t(((val) >> SQ_TASK_INFO0_##member##_SHIFT) &\t\\\n+\t\tSQ_TASK_INFO0_##member##_MASK)\n+\n+#define SQ_TASK_INFO1_SET(val, member)\t\t\t\\\n+\t\t(((val) & SQ_TASK_INFO1_##member##_MASK) <<\t\\\n+\t\tSQ_TASK_INFO1_##member##_SHIFT)\n+#define SQ_TASK_INFO1_GET(val, member)\t\t\t\\\n+\t\t(((val) >> SQ_TASK_INFO1_##member##_SHIFT) &\t\\\n+\t\tSQ_TASK_INFO1_##member##_MASK)\n+\n+#define\tSQ_TASK_INFO3_VLAN_TAG_SHIFT\t\t0\n+#define\tSQ_TASK_INFO3_VLAN_TYPE_SHIFT\t\t16\n+#define\tSQ_TASK_INFO3_VLAN_TAG_VALID_SHIFT\t19\n+\n+#define\tSQ_TASK_INFO3_VLAN_TAG_MASK\t\t0xFFFFU\n+#define\tSQ_TASK_INFO3_VLAN_TYPE_MASK\t\t0x7U\n+#define\tSQ_TASK_INFO3_VLAN_TAG_VALID_MASK\t0x1U\n+\n+#define SQ_TASK_INFO3_SET(val, member)\t\t\t\\\n+\t\t(((val) & SQ_TASK_INFO3_##member##_MASK) <<\t\\\n+\t\tSQ_TASK_INFO3_##member##_SHIFT)\n+#define SQ_TASK_INFO3_GET(val, member)\t\t\t\\\n+\t\t(((val) >> SQ_TASK_INFO3_##member##_SHIFT) &\t\\\n+\t\tSQ_TASK_INFO3_##member##_MASK)\n \n /* Txq info */\n struct spnic_txq_stats {\n@@ -59,4 +277,14 @@ struct spnic_txq {\n \tstruct spnic_txq_stats txq_stats;\n } __rte_cache_aligned;\n \n+void spnic_flush_txqs(struct spnic_nic_dev *nic_dev);\n+\n+void spnic_free_txq_mbufs(struct spnic_txq *txq);\n+\n+void spnic_free_all_txq_mbufs(struct spnic_nic_dev *nic_dev);\n+\n+u16 spnic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, u16 nb_pkts);\n+\n+int spnic_stop_sq(struct spnic_txq *txq);\n+int spnic_start_all_sqs(struct rte_eth_dev *eth_dev);\n #endif /* _SPNIC_TX_H_ */\n",
    "prefixes": [
        "v1",
        "12/25"
    ]
}