get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 105255,
    "url": "http://patches.dpdk.org/api/patches/105255/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/43c18694d8e072ced3f9dfdc3917f04c0547da80.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": "<43c18694d8e072ced3f9dfdc3917f04c0547da80.1639636621.git.songyl@ramaxel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/43c18694d8e072ced3f9dfdc3917f04c0547da80.1639636621.git.songyl@ramaxel.com",
    "date": "2021-12-18T02:51:42",
    "name": "[v1,15/25] net/spnic: support IO packets handling",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "935f44262ae28f0ffe65bad298126fda33621b36",
    "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/43c18694d8e072ced3f9dfdc3917f04c0547da80.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/105255/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/105255/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 94FA0A04A4;\n\tSat, 18 Dec 2021 03:54:27 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id EB224426E0;\n\tSat, 18 Dec 2021 03:52:42 +0100 (CET)",
            "from VLXDG1SPAM1.ramaxel.com (email.ramaxel.com [221.4.138.186])\n by mails.dpdk.org (Postfix) with ESMTP id 6D5DB411FE\n for <dev@dpdk.org>; Sat, 18 Dec 2021 03:52:38 +0100 (CET)",
            "from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local\n [172.26.18.31])\n by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BI2q1hZ010344\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:01 +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 15/25] net/spnic: support IO packets handling",
        "Date": "Sat, 18 Dec 2021 10:51:42 +0800",
        "Message-ID": "\n <43c18694d8e072ced3f9dfdc3917f04c0547da80.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 1BI2q1hZ010344",
        "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 implements rx_pkt_burst() and tx_pkt_burst()\nto hanld IO packets.\n\nFor Tx packets, this commit implements parsing ol_flags of\nmbuf and filling those offload info on wqe so that hardware\ncan process the packets correctly. Furthermore, this commit\nallocates a mempool to cover scenes with too many mbufs for\none packet.\n\nFor Rx packets, this commit implements filling ol_flags of\nmbuf and rearming new mbuf and rq wqe.\n\nSigned-off-by: Yanling Song <songyl@ramaxel.com>\n---\n drivers/net/spnic/spnic_ethdev.c |  48 +++\n drivers/net/spnic/spnic_ethdev.h |   7 +\n drivers/net/spnic/spnic_rx.c     | 209 ++++++++++++\n drivers/net/spnic/spnic_rx.h     | 137 ++++++++\n drivers/net/spnic/spnic_tx.c     | 524 +++++++++++++++++++++++++++++++\n drivers/net/spnic/spnic_tx.h     |   7 +\n 6 files changed, 932 insertions(+)",
    "diff": "diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c\nindex 826a34f7fc..b4d20e1a6f 100644\n--- a/drivers/net/spnic/spnic_ethdev.c\n+++ b/drivers/net/spnic/spnic_ethdev.c\n@@ -970,6 +970,32 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)\n \treturn err;\n }\n \n+static int spnic_copy_mempool_init(struct spnic_nic_dev *nic_dev)\n+{\n+\tnic_dev->cpy_mpool = rte_mempool_lookup(nic_dev->dev_name);\n+\tif (nic_dev->cpy_mpool == NULL) {\n+\t\tnic_dev->cpy_mpool =\n+\t\trte_pktmbuf_pool_create(nic_dev->dev_name,\n+\t\t\t\t\tSPNIC_COPY_MEMPOOL_DEPTH, 0, 0,\n+\t\t\t\t\tSPNIC_COPY_MBUF_SIZE, rte_socket_id());\n+\t\tif (nic_dev->cpy_mpool == NULL) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Create copy mempool failed, errno: %d, dev_name: %s\",\n+\t\t\t\t    rte_errno, nic_dev->dev_name);\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void spnic_copy_mempool_uninit(struct spnic_nic_dev *nic_dev)\n+{\n+\tif (nic_dev->cpy_mpool != NULL) {\n+\t\trte_mempool_free(nic_dev->cpy_mpool);\n+\t\tnic_dev->cpy_mpool = NULL;\n+\t}\n+}\n+\n /**\n  * Stop the device.\n  *\n@@ -986,6 +1012,9 @@ static int spnic_dev_stop(struct rte_eth_dev *dev)\n \tint err;\n \n \tnic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);\n+\tif (!nic_dev || !spnic_support_nic(nic_dev->hwdev))\n+\t\treturn 0;\n+\n \tif (!rte_bit_relaxed_test_and_clear32(SPNIC_DEV_START, &nic_dev->dev_status)) {\n \t\tPMD_DRV_LOG(INFO, \"Device %s already stopped\",\n \t\t\t    nic_dev->dev_name);\n@@ -1014,6 +1043,11 @@ static int spnic_dev_stop(struct rte_eth_dev *dev)\n \n \tspnic_flush_qps_res(nic_dev->hwdev);\n \n+\t/*\n+\t * After set vport disable 100ms, no packets will be send to host\n+\t */\n+\trte_delay_ms(100);\n+\n \t/* Clean RSS table and rx_mode */\n \tspnic_remove_rxtx_configure(dev);\n \n@@ -1054,6 +1088,7 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n \tfor (qid = 0; qid < nic_dev->num_rqs; qid++)\n \t\tspnic_rx_queue_release(eth_dev, qid);\n \n+\tspnic_copy_mempool_uninit(nic_dev);\n \tspnic_deinit_sw_rxtxqs(nic_dev);\n \tspnic_deinit_mac_addr(eth_dev);\n \trte_free(nic_dev->mc_list);\n@@ -1067,6 +1102,8 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)\n \tspnic_free_nic_hwdev(nic_dev->hwdev);\n \tspnic_free_hwdev(nic_dev->hwdev);\n \n+\teth_dev->rx_pkt_burst = NULL;\n+\teth_dev->tx_pkt_burst = NULL;\n \teth_dev->dev_ops = NULL;\n \n \trte_free(nic_dev->hwdev);\n@@ -1548,6 +1585,13 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \t\tgoto set_default_feature_fail;\n \t}\n \n+\terr = spnic_copy_mempool_init(nic_dev);\n+\tif (err) {\n+\t\tPMD_DRV_LOG(ERR, \"Create copy mempool failed, dev_name: %s\",\n+\t\t\t eth_dev->data->name);\n+\t\tgoto init_mpool_fail;\n+\t}\n+\n \tspnic_mutex_init(&nic_dev->rx_mode_mutex, NULL);\n \n \trte_bit_relaxed_set32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);\n@@ -1558,6 +1602,7 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev)\n \n \treturn 0;\n \n+init_mpool_fail:\n set_default_feature_fail:\n \tspnic_deinit_mac_addr(eth_dev);\n \n@@ -1602,6 +1647,9 @@ static int spnic_dev_init(struct rte_eth_dev *eth_dev)\n \t\t    (rte_eal_process_type() == RTE_PROC_PRIMARY) ?\n \t\t    \"primary\" : \"secondary\");\n \n+\teth_dev->rx_pkt_burst = spnic_recv_pkts;\n+\teth_dev->tx_pkt_burst = spnic_xmit_pkts;\n+\n \treturn spnic_func_init(eth_dev);\n }\n \ndiff --git a/drivers/net/spnic/spnic_ethdev.h b/drivers/net/spnic/spnic_ethdev.h\nindex 996b4e4b8f..2b59886942 100644\n--- a/drivers/net/spnic/spnic_ethdev.h\n+++ b/drivers/net/spnic/spnic_ethdev.h\n@@ -4,6 +4,9 @@\n \n #ifndef _SPNIC_ETHDEV_H_\n #define _SPNIC_ETHDEV_H_\n+\n+#define SPNIC_COPY_MEMPOOL_DEPTH\t128\n+#define SPNIC_COPY_MBUF_SIZE\t\t4096\n #define SPNIC_DEV_NAME_LEN\t\t32\n \n #define SPNIC_UINT32_BIT_SIZE\t\t(CHAR_BIT * sizeof(uint32_t))\n@@ -17,6 +20,10 @@ enum spnic_dev_status {\n \tSPNIC_DEV_INTR_EN\n };\n \n+enum spnic_tx_cvlan_type {\n+\tSPNIC_TX_TPID0,\n+};\n+\n enum nic_feature_cap {\n \tNIC_F_CSUM = BIT(0),\n \tNIC_F_SCTP_CRC = BIT(1),\ndiff --git a/drivers/net/spnic/spnic_rx.c b/drivers/net/spnic/spnic_rx.c\nindex 4d8c6c7e60..5af836ed41 100644\n--- a/drivers/net/spnic/spnic_rx.c\n+++ b/drivers/net/spnic/spnic_rx.c\n@@ -486,6 +486,117 @@ void spnic_remove_rq_from_rx_queue_list(struct spnic_nic_dev *nic_dev,\n \tnic_dev->num_rss = rss_queue_count;\n }\n \n+\n+static inline uint64_t spnic_rx_vlan(uint32_t offload_type, uint32_t vlan_len,\n+\t\t\t\t      uint16_t *vlan_tci)\n+{\n+\tuint16_t vlan_tag;\n+\n+\tvlan_tag = SPNIC_GET_RX_VLAN_TAG(vlan_len);\n+\tif (!SPNIC_GET_RX_VLAN_OFFLOAD_EN(offload_type) || vlan_tag == 0) {\n+\t\t*vlan_tci = 0;\n+\t\treturn 0;\n+\t}\n+\n+\t*vlan_tci = vlan_tag;\n+\n+\treturn RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;\n+}\n+\n+static inline uint64_t spnic_rx_csum(uint32_t status, struct spnic_rxq *rxq)\n+{\n+\tstruct spnic_nic_dev *nic_dev = rxq->nic_dev;\n+\tuint32_t csum_err;\n+\tuint64_t flags;\n+\n+\tif (unlikely(!(nic_dev->rx_csum_en & SPNIC_DEFAULT_RX_CSUM_OFFLOAD)))\n+\t\treturn RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN;\n+\n+\t/* Most case checksum is ok */\n+\tcsum_err = SPNIC_GET_RX_CSUM_ERR(status);\n+\tif (likely(csum_err == 0))\n+\t\treturn (RTE_MBUF_F_RX_IP_CKSUM_GOOD | RTE_MBUF_F_RX_L4_CKSUM_GOOD);\n+\n+\t/*\n+\t * If bypass bit is set, all other err status indications should be\n+\t * ignored\n+\t */\n+\tif (unlikely(csum_err & SPNIC_RX_CSUM_HW_CHECK_NONE))\n+\t\treturn RTE_MBUF_F_RX_IP_CKSUM_UNKNOWN;\n+\n+\tflags = 0;\n+\n+\t/* IP checksum error */\n+\tif (csum_err & SPNIC_RX_CSUM_IP_CSUM_ERR) {\n+\t\tflags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;\n+\t\trxq->rxq_stats.errors++;\n+\t}\n+\n+\t/* L4 checksum error */\n+\tif (csum_err & SPNIC_RX_CSUM_TCP_CSUM_ERR ||\n+\t    csum_err & SPNIC_RX_CSUM_UDP_CSUM_ERR ||\n+\t    csum_err & SPNIC_RX_CSUM_SCTP_CRC_ERR) {\n+\t\tflags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;\n+\t\trxq->rxq_stats.errors++;\n+\t}\n+\n+\tif (unlikely(csum_err == SPNIC_RX_CSUM_IPSU_OTHER_ERR))\n+\t\trxq->rxq_stats.other_errors++;\n+\n+\treturn flags;\n+}\n+\n+static inline uint64_t spnic_rx_rss_hash(uint32_t offload_type,\n+\t\t\t\t\t uint32_t rss_hash_value,\n+\t\t\t\t\t uint32_t *rss_hash)\n+{\n+\tuint32_t rss_type;\n+\n+\trss_type = SPNIC_GET_RSS_TYPES(offload_type);\n+\tif (likely(rss_type != 0)) {\n+\t\t*rss_hash = rss_hash_value;\n+\t\treturn RTE_MBUF_F_RX_RSS_HASH;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void spnic_recv_jumbo_pkt(struct spnic_rxq *rxq,\n+\t\t\t\t struct rte_mbuf *head_mbuf,\n+\t\t\t\t u32 remain_pkt_len)\n+{\n+\tstruct rte_mbuf *cur_mbuf = NULL;\n+\tstruct rte_mbuf *rxm = NULL;\n+\tstruct spnic_rx_info *rx_info = NULL;\n+\tu16 sw_ci, rx_buf_len = rxq->buf_len;\n+\tu32 pkt_len;\n+\n+\twhile (remain_pkt_len > 0) {\n+\t\tsw_ci = spnic_get_rq_local_ci(rxq);\n+\t\trx_info = &rxq->rx_info[sw_ci];\n+\n+\t\tspnic_update_rq_local_ci(rxq, 1);\n+\n+\t\tpkt_len = remain_pkt_len > rx_buf_len ?\n+\t\t\trx_buf_len : remain_pkt_len;\n+\t\tremain_pkt_len -= pkt_len;\n+\n+\t\tcur_mbuf = rx_info->mbuf;\n+\t\tcur_mbuf->data_len = (u16)pkt_len;\n+\t\tcur_mbuf->next = NULL;\n+\n+\t\thead_mbuf->pkt_len += cur_mbuf->data_len;\n+\t\thead_mbuf->nb_segs++;\n+\n+\t\tif (!rxm)\n+\t\t\thead_mbuf->next = cur_mbuf;\n+\t\telse\n+\t\t\trxm->next = cur_mbuf;\n+\n+\t\trxm = cur_mbuf;\n+\t}\n+}\n+\n int spnic_start_all_rqs(struct rte_eth_dev *eth_dev)\n {\n \tstruct spnic_nic_dev *nic_dev = NULL;\n@@ -521,3 +632,101 @@ int spnic_start_all_rqs(struct rte_eth_dev *eth_dev)\n \t}\n \treturn err;\n }\n+\n+u16 spnic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts)\n+{\n+\tstruct spnic_rxq *rxq = rx_queue;\n+\tstruct spnic_rx_info *rx_info = NULL;\n+\tvolatile struct spnic_rq_cqe *rx_cqe = NULL;\n+\tstruct rte_mbuf *rxm = NULL;\n+\tu16 sw_ci, wqebb_cnt = 0;\n+\tu32 status, pkt_len, vlan_len, offload_type, hash_value;\n+\tu32 lro_num;\n+\tu64 rx_bytes = 0;\n+\tu16 rx_buf_len, pkts = 0;\n+\n+\trx_buf_len = rxq->buf_len;\n+\tsw_ci = spnic_get_rq_local_ci(rxq);\n+\n+\twhile (pkts < nb_pkts) {\n+\t\trx_cqe = &rxq->rx_cqe[sw_ci];\n+\t\tstatus = rx_cqe->status;\n+\t\tif (!SPNIC_GET_RX_DONE(status))\n+\t\t\tbreak;\n+\n+\t\t/* Make sure rx_done is read before packet length */\n+\t\trte_rmb();\n+\n+\t\tvlan_len = rx_cqe->vlan_len;\n+\t\tpkt_len = SPNIC_GET_RX_PKT_LEN(vlan_len);\n+\n+\t\trx_info = &rxq->rx_info[sw_ci];\n+\t\trxm = rx_info->mbuf;\n+\n+\t\t/* 1. Next ci point and prefetch */\n+\t\tsw_ci++;\n+\t\tsw_ci &= rxq->q_mask;\n+\n+\t\t/* 2. Prefetch next mbuf first 64B */\n+\t\trte_prefetch0(rxq->rx_info[sw_ci].mbuf);\n+\n+\t\t/* 3. Jumbo frame process */\n+\t\tif (likely(pkt_len <= rx_buf_len)) {\n+\t\t\trxm->data_len = pkt_len;\n+\t\t\trxm->pkt_len = pkt_len;\n+\t\t\twqebb_cnt++;\n+\t\t} else {\n+\t\t\trxm->data_len = rx_buf_len;\n+\t\t\trxm->pkt_len = rx_buf_len;\n+\n+\t\t\t/* If receive jumbo, updating ci will be done by\n+\t\t\t * spnic_recv_jumbo_pkt function.\n+\t\t\t */\n+\t\t\tspnic_update_rq_local_ci(rxq, wqebb_cnt + 1);\n+\t\t\twqebb_cnt = 0;\n+\t\t\tspnic_recv_jumbo_pkt(rxq, rxm, pkt_len - rx_buf_len);\n+\t\t\tsw_ci = spnic_get_rq_local_ci(rxq);\n+\t\t}\n+\n+\t\trxm->data_off = RTE_PKTMBUF_HEADROOM;\n+\t\trxm->port = rxq->port_id;\n+\n+\t\t/* 4. Rx checksum offload */\n+\t\trxm->ol_flags |= spnic_rx_csum(status, rxq);\n+\n+\t\t/* 5. Vlan offload */\n+\t\toffload_type = rx_cqe->offload_type;\n+\t\trxm->ol_flags |= spnic_rx_vlan(offload_type, vlan_len,\n+\t\t\t\t\t\t&rxm->vlan_tci);\n+\t\t/* 6. RSS */\n+\t\thash_value = rx_cqe->hash_val;\n+\t\trxm->ol_flags |= spnic_rx_rss_hash(offload_type, hash_value,\n+\t\t\t\t\t\t    &rxm->hash.rss);\n+\t\t/* 7. LRO */\n+\t\tlro_num = SPNIC_GET_RX_NUM_LRO(status);\n+\t\tif (unlikely(lro_num != 0)) {\n+\t\t\trxm->ol_flags |= RTE_MBUF_F_RX_LRO;\n+\t\t\trxm->tso_segsz = pkt_len / lro_num;\n+\t\t}\n+\n+\t\trx_cqe->status = 0;\n+\n+\t\trx_bytes += pkt_len;\n+\t\trx_pkts[pkts++] = rxm;\n+\t}\n+\n+\tif (pkts) {\n+\t\t/* 8. Update local ci */\n+\t\tspnic_update_rq_local_ci(rxq, wqebb_cnt);\n+\n+\t\t/* Update packet stats */\n+\t\trxq->rxq_stats.packets += pkts;\n+\t\trxq->rxq_stats.bytes += rx_bytes;\n+\t}\n+\trxq->rxq_stats.burst_pkts = pkts;\n+\n+\t/* 9. Rearm mbuf to rxq */\n+\tspnic_rearm_rxq_mbuf(rxq);\n+\n+\treturn pkts;\n+}\ndiff --git a/drivers/net/spnic/spnic_rx.h b/drivers/net/spnic/spnic_rx.h\nindex 0b534f1904..5ae4b5f1ab 100644\n--- a/drivers/net/spnic/spnic_rx.h\n+++ b/drivers/net/spnic/spnic_rx.h\n@@ -5,6 +5,135 @@\n #ifndef _SPNIC_RX_H_\n #define _SPNIC_RX_H_\n \n+#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_SHIFT\t\t0\n+#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_SHIFT\t\t19\n+#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_SHIFT\t\t21\n+#define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_SHIFT\t\t24\n+\n+#define RQ_CQE_OFFOLAD_TYPE_PKT_TYPE_MASK\t\t0xFFFU\n+#define RQ_CQE_OFFOLAD_TYPE_PKT_UMBCAST_MASK\t\t0x3U\n+#define RQ_CQE_OFFOLAD_TYPE_VLAN_EN_MASK\t\t0x1U\n+#define RQ_CQE_OFFOLAD_TYPE_RSS_TYPE_MASK\t\t0xFFU\n+\n+#define RQ_CQE_OFFOLAD_TYPE_GET(val, member)\t\t(((val) >> \\\n+\t\t\t\tRQ_CQE_OFFOLAD_TYPE_##member##_SHIFT) & \\\n+\t\t\t\tRQ_CQE_OFFOLAD_TYPE_##member##_MASK)\n+\n+#define SPNIC_GET_RX_PKT_TYPE(offload_type)\t\\\n+\t\tRQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)\n+\n+#define SPNIC_GET_RX_PKT_UMBCAST(offload_type)\t\\\n+\t\tRQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_UMBCAST)\n+\n+#define SPNIC_GET_RX_VLAN_OFFLOAD_EN(offload_type)\t\\\n+\t\tRQ_CQE_OFFOLAD_TYPE_GET(offload_type, VLAN_EN)\n+\n+#define SPNIC_GET_RSS_TYPES(offload_type)\t\\\n+\t\tRQ_CQE_OFFOLAD_TYPE_GET(offload_type, RSS_TYPE)\n+\n+#define RQ_CQE_SGE_VLAN_SHIFT\t\t\t\t0\n+#define RQ_CQE_SGE_LEN_SHIFT\t\t\t\t16\n+\n+#define RQ_CQE_SGE_VLAN_MASK\t\t\t\t0xFFFFU\n+#define RQ_CQE_SGE_LEN_MASK\t\t\t\t0xFFFFU\n+\n+#define RQ_CQE_SGE_GET(val, member)\t\t\t(((val) >> \\\n+\t\t\t\t\tRQ_CQE_SGE_##member##_SHIFT) & \\\n+\t\t\t\t\tRQ_CQE_SGE_##member##_MASK)\n+\n+#define SPNIC_GET_RX_VLAN_TAG(vlan_len)\tRQ_CQE_SGE_GET(vlan_len, VLAN)\n+\n+#define SPNIC_GET_RX_PKT_LEN(vlan_len)\t\tRQ_CQE_SGE_GET(vlan_len, LEN)\n+\n+#define RQ_CQE_STATUS_CSUM_ERR_SHIFT\t\t0\n+#define RQ_CQE_STATUS_NUM_LRO_SHIFT\t\t16\n+#define RQ_CQE_STATUS_LRO_PUSH_SHIFT\t\t25\n+#define RQ_CQE_STATUS_LRO_ENTER_SHIFT\t\t26\n+#define RQ_CQE_STATUS_LRO_INTR_SHIFT\t\t27\n+\n+#define RQ_CQE_STATUS_BP_EN_SHIFT\t\t30\n+#define RQ_CQE_STATUS_RXDONE_SHIFT\t\t31\n+#define RQ_CQE_STATUS_DECRY_PKT_SHIFT\t\t29\n+#define RQ_CQE_STATUS_FLUSH_SHIFT\t\t28\n+\n+#define RQ_CQE_STATUS_CSUM_ERR_MASK\t\t0xFFFFU\n+#define RQ_CQE_STATUS_NUM_LRO_MASK\t\t0xFFU\n+#define RQ_CQE_STATUS_LRO_PUSH_MASK\t\t0X1U\n+#define RQ_CQE_STATUS_LRO_ENTER_MASK\t\t0X1U\n+#define RQ_CQE_STATUS_LRO_INTR_MASK\t\t0X1U\n+#define RQ_CQE_STATUS_BP_EN_MASK\t\t0X1U\n+#define RQ_CQE_STATUS_RXDONE_MASK\t\t0x1U\n+#define RQ_CQE_STATUS_FLUSH_MASK\t\t0x1U\n+#define RQ_CQE_STATUS_DECRY_PKT_MASK\t\t0x1U\n+\n+#define RQ_CQE_STATUS_GET(val, member)\t\t\t(((val) >> \\\n+\t\t\t\t\tRQ_CQE_STATUS_##member##_SHIFT) & \\\n+\t\t\t\t\tRQ_CQE_STATUS_##member##_MASK)\n+\n+#define SPNIC_GET_RX_CSUM_ERR(status)\tRQ_CQE_STATUS_GET(status, CSUM_ERR)\n+\n+#define SPNIC_GET_RX_DONE(status)\tRQ_CQE_STATUS_GET(status, RXDONE)\n+\n+#define SPNIC_GET_RX_FLUSH(status)\tRQ_CQE_STATUS_GET(status, FLUSH)\n+\n+#define SPNIC_GET_RX_BP_EN(status)\tRQ_CQE_STATUS_GET(status, BP_EN)\n+\n+#define SPNIC_GET_RX_NUM_LRO(status)\tRQ_CQE_STATUS_GET(status, NUM_LRO)\n+\n+#define SPNIC_RX_IS_DECRY_PKT(status)\tRQ_CQE_STATUS_GET(status, DECRY_PKT)\n+\n+#define RQ_CQE_SUPER_CQE_EN_SHIFT\t\t\t0\n+#define RQ_CQE_PKT_NUM_SHIFT\t\t\t\t1\n+#define RQ_CQE_PKT_LAST_LEN_SHIFT\t\t\t6\n+#define RQ_CQE_PKT_FIRST_LEN_SHIFT\t\t\t19\n+\n+#define RQ_CQE_SUPER_CQE_EN_MASK\t\t\t0x1\n+#define RQ_CQE_PKT_NUM_MASK\t\t\t\t0x1FU\n+#define RQ_CQE_PKT_FIRST_LEN_MASK\t\t\t0x1FFFU\n+#define RQ_CQE_PKT_LAST_LEN_MASK\t\t\t0x1FFFU\n+\n+#define RQ_CQE_PKT_NUM_GET(val, member)\t\t\t(((val) >> \\\n+\t\t\t\t\tRQ_CQE_PKT_##member##_SHIFT) & \\\n+\t\t\t\t\tRQ_CQE_PKT_##member##_MASK)\n+#define SPNIC_GET_RQ_CQE_PKT_NUM(pkt_info) RQ_CQE_PKT_NUM_GET(pkt_info, NUM)\n+\n+#define RQ_CQE_SUPER_CQE_EN_GET(val, member)\t\t(((val) >> \\\n+\t\t\t\t\tRQ_CQE_##member##_SHIFT) & \\\n+\t\t\t\t\tRQ_CQE_##member##_MASK)\n+#define SPNIC_GET_SUPER_CQE_EN(pkt_info)\t\\\n+\tRQ_CQE_SUPER_CQE_EN_GET(pkt_info, SUPER_CQE_EN)\n+\n+#define RQ_CQE_PKT_LEN_GET(val, member)\t\t\t(((val) >> \\\n+\t\t\t\t\t\tRQ_CQE_PKT_##member##_SHIFT) & \\\n+\t\t\t\t\t\tRQ_CQE_PKT_##member##_MASK)\n+\n+#define RQ_CQE_DECRY_INFO_DECRY_STATUS_SHIFT\t8\n+#define RQ_CQE_DECRY_INFO_ESP_NEXT_HEAD_SHIFT\t0\n+\n+#define RQ_CQE_DECRY_INFO_DECRY_STATUS_MASK\t0xFFU\n+#define RQ_CQE_DECRY_INFO_ESP_NEXT_HEAD_MASK\t0xFFU\n+\n+#define RQ_CQE_DECRY_INFO_GET(val, member)\t\t(((val) >> \\\n+\t\t\t\tRQ_CQE_DECRY_INFO_##member##_SHIFT) & \\\n+\t\t\t\tRQ_CQE_DECRY_INFO_##member##_MASK)\n+\n+#define SPNIC_GET_DECRYPT_STATUS(decry_info)\t\\\n+\tRQ_CQE_DECRY_INFO_GET(decry_info, DECRY_STATUS)\n+\n+#define SPNIC_GET_ESP_NEXT_HEAD(decry_info)\t\\\n+\tRQ_CQE_DECRY_INFO_GET(decry_info, ESP_NEXT_HEAD)\n+\n+/* Rx cqe checksum err */\n+#define SPNIC_RX_CSUM_IP_CSUM_ERR\tBIT(0)\n+#define SPNIC_RX_CSUM_TCP_CSUM_ERR\tBIT(1)\n+#define SPNIC_RX_CSUM_UDP_CSUM_ERR\tBIT(2)\n+#define SPNIC_RX_CSUM_IGMP_CSUM_ERR\tBIT(3)\n+#define SPNIC_RX_CSUM_ICMPv4_CSUM_ERR\tBIT(4)\n+#define SPNIC_RX_CSUM_ICMPv6_CSUM_ERR\tBIT(5)\n+#define SPNIC_RX_CSUM_SCTP_CRC_ERR\tBIT(6)\n+#define SPNIC_RX_CSUM_HW_CHECK_NONE\tBIT(7)\n+#define SPNIC_RX_CSUM_IPSU_OTHER_ERR\tBIT(8)\n+\n #define SPNIC_DEFAULT_RX_CSUM_OFFLOAD\t0xFFF\n \n #define SPNIC_RSS_OFFLOAD_ALL ( \\\n@@ -138,8 +267,16 @@ void spnic_free_all_rxq_mbufs(struct spnic_nic_dev *nic_dev);\n int spnic_update_rss_config(struct rte_eth_dev *dev,\n \t\t\t    struct rte_eth_rss_conf *rss_conf);\n \n+int spnic_poll_rq_empty(struct spnic_rxq *rxq);\n+\n+void spnic_dump_cqe_status(struct spnic_rxq *rxq, u32 *cqe_done_cnt,\n+\t\t\t    u32 *cqe_hole_cnt, u32 *head_ci,\n+\t\t\t    u32 *head_done);\n+\n int spnic_start_all_rqs(struct rte_eth_dev *eth_dev);\n \n+u16 spnic_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, u16 nb_pkts);\n+\n void spnic_add_rq_to_rx_queue_list(struct spnic_nic_dev *nic_dev,\n \t\t\t\t    u16 queue_id);\n \ndiff --git a/drivers/net/spnic/spnic_tx.c b/drivers/net/spnic/spnic_tx.c\nindex d905879412..0772d4929f 100644\n--- a/drivers/net/spnic/spnic_tx.c\n+++ b/drivers/net/spnic/spnic_tx.c\n@@ -30,6 +30,18 @@\n #define SPNIC_TX_OUTER_CHECKSUM_FLAG_SET       1\n #define SPNIC_TX_OUTER_CHECKSUM_FLAG_NO_SET    0\n \n+#define SPNIC_TX_OFFLOAD_MASK (\t\\\n+\t\tSPNIC_TX_CKSUM_OFFLOAD_MASK | \\\n+\t\tRTE_MBUF_F_TX_VLAN)\n+\n+#define SPNIC_TX_CKSUM_OFFLOAD_MASK ( \\\n+\t\tRTE_MBUF_F_TX_IP_CKSUM | \\\n+\t\tRTE_MBUF_F_TX_TCP_CKSUM | \\\n+\t\tRTE_MBUF_F_TX_UDP_CKSUM | \\\n+\t\tRTE_MBUF_F_TX_SCTP_CKSUM | \\\n+\t\tRTE_MBUF_F_TX_OUTER_IP_CKSUM | \\\n+\t\tRTE_MBUF_F_TX_TCP_SEG)\n+\n /**\n  * Get send queue free wqebb cnt\n  *\n@@ -289,6 +301,518 @@ static int spnic_tx_done_cleanup(void *txq, u32 free_cnt)\n \n \treturn spnic_xmit_mbuf_cleanup(tx_queue, try_free_cnt);\n }\n+\n+static inline int spnic_tx_offload_pkt_prepare(struct rte_mbuf *mbuf,\n+\t\t\t\t\t       u16 *inner_l3_offset)\n+{\n+\tuint64_t ol_flags = mbuf->ol_flags;\n+\n+\t/* Only support vxlan offload */\n+\tif ((ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) &&\n+\t\t(!(ol_flags & RTE_MBUF_F_TX_TUNNEL_VXLAN)))\n+\t\treturn -EINVAL;\n+\n+#ifdef RTE_LIBRTE_ETHDEV_DEBUG\n+\tif (rte_validate_tx_offload(mbuf) != 0)\n+\t\treturn -EINVAL;\n+#endif\n+\tif ((ol_flags & RTE_MBUF_F_TX_TUNNEL_VXLAN))  {\n+\t\tif ((ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM) ||\n+\t\t    (ol_flags & RTE_MBUF_F_TX_OUTER_IPV6) ||\n+\t\t    (ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {\n+\t\t\t/*\n+\t\t\t * For this senmatic, l2_len of mbuf means\n+\t\t\t * len(out_udp + vxlan + in_eth)\n+\t\t\t */\n+\t\t\t*inner_l3_offset = mbuf->l2_len + mbuf->outer_l2_len +\n+\t\t\t\t\t   mbuf->outer_l3_len;\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * For this senmatic, l2_len of mbuf means\n+\t\t\t * len(out_eth + out_ip + out_udp + vxlan + in_eth)\n+\t\t\t */\n+\t\t\t*inner_l3_offset = mbuf->l2_len;\n+\t\t}\n+\t} else {\n+\t\t/* For non-tunnel type pkts */\n+\t\t*inner_l3_offset = mbuf->l2_len;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Set vlan offload info\n+ *\n+ * @param[in] task\n+ *   Send queue wqe task section\n+ * @param[in] vlan_tag\n+ *   Vlan tag info\n+ * @param[in] vlan_type\n+ *   Vlan type in hardware\n+ */\n+static inline void spnic_set_vlan_tx_offload(struct spnic_sq_task *task,\n+\t\t\t\t\t     u16 vlan_tag, u8 vlan_type)\n+{\n+\ttask->vlan_offload = SQ_TASK_INFO3_SET(vlan_tag, VLAN_TAG) |\n+\t\t\t     SQ_TASK_INFO3_SET(vlan_type, VLAN_TYPE) |\n+\t\t\t     SQ_TASK_INFO3_SET(1U, VLAN_TAG_VALID);\n+}\n+\n+static inline int spnic_set_tx_offload(struct rte_mbuf *mbuf,\n+\t\t\t\t       struct spnic_sq_task *task,\n+\t\t\t\t       struct spnic_wqe_info *wqe_info)\n+{\n+\tuint64_t ol_flags = mbuf->ol_flags;\n+\tu16 pld_offset = 0;\n+\tu32 queue_info = 0;\n+\tu16 vlan_tag;\n+\n+\ttask->pkt_info0 = 0;\n+\ttask->ip_identify = 0;\n+\ttask->pkt_info2 = 0;\n+\ttask->vlan_offload = 0;\n+\n+\t/* Vlan offload */\n+\tif (unlikely(ol_flags & RTE_MBUF_F_TX_VLAN)) {\n+\t\tvlan_tag = mbuf->vlan_tci;\n+\t\tspnic_set_vlan_tx_offload(task, vlan_tag, SPNIC_TX_TPID0);\n+\t}\n+\n+\tif (!(ol_flags & SPNIC_TX_CKSUM_OFFLOAD_MASK))\n+\t\treturn 0;\n+\n+\t/* Tso offload */\n+\tif (ol_flags & RTE_MBUF_F_TX_TCP_SEG) {\n+\t\tpld_offset = wqe_info->payload_offset;\n+\t\tif ((pld_offset >> 1) > MAX_PAYLOAD_OFFSET)\n+\t\t\treturn -EINVAL;\n+\n+\t\ttask->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L4_EN);\n+\t\ttask->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L3_EN);\n+\n+\t\tqueue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, TSO);\n+\t\tqueue_info |= SQ_CTRL_QUEUE_INFO_SET(pld_offset >> 1, PLDOFF);\n+\n+\t\t/* Set MSS value */\n+\t\tqueue_info = SQ_CTRL_QUEUE_INFO_CLEAR(queue_info, MSS);\n+\t\tqueue_info |= SQ_CTRL_QUEUE_INFO_SET(mbuf->tso_segsz, MSS);\n+\t} else {\n+\t\tif (ol_flags & RTE_MBUF_F_TX_IP_CKSUM)\n+\t\t\ttask->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L3_EN);\n+\n+\t\tswitch (ol_flags & RTE_MBUF_F_TX_L4_MASK) {\n+\t\tcase RTE_MBUF_F_TX_TCP_CKSUM:\n+\t\tcase RTE_MBUF_F_TX_UDP_CKSUM:\n+\t\tcase RTE_MBUF_F_TX_SCTP_CKSUM:\n+\t\t\ttask->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L4_EN);\n+\n+\t\t\tbreak;\n+\n+\t\tcase RTE_MBUF_F_TX_L4_NO_CKSUM:\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tPMD_DRV_LOG(INFO, \"not support pkt type\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\t/* For vxlan, also can support PKT_TX_TUNNEL_GRE, etc */\n+\tswitch (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {\n+\tcase RTE_MBUF_F_TX_TUNNEL_VXLAN:\n+\t\ttask->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG);\n+\t\tbreak;\n+\n+\tcase 0:\n+\t\tbreak;\n+\n+\tdefault:\n+\t\t/* For non UDP/GRE tunneling, drop the tunnel packet */\n+\t\tPMD_DRV_LOG(INFO, \"not support tunnel pkt type\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)\n+\t\ttask->pkt_info0 |= SQ_TASK_INFO0_SET(1U, OUT_L3_EN);\n+\n+\twqe_info->queue_info = queue_info;\n+\treturn 0;\n+}\n+\n+static inline bool spnic_is_tso_sge_valid(struct rte_mbuf *mbuf,\n+\t\t\t\t\t   struct spnic_wqe_info *wqe_info)\n+{\n+\tu32 total_len, limit_len, checked_len, left_len, adjust_mss;\n+\tu32 i, max_sges, left_sges, first_len;\n+\tstruct rte_mbuf *mbuf_head, *mbuf_pre, *mbuf_first;\n+\n+\tleft_sges = mbuf->nb_segs;\n+\tmbuf_head = mbuf;\n+\tmbuf_first = mbuf;\n+\n+\t/* tso sge number validation */\n+\tif (unlikely(left_sges >= SPNIC_NONTSO_PKT_MAX_SGE)) {\n+\t\tchecked_len = 0;\n+\t\ttotal_len = 0;\n+\t\tfirst_len = 0;\n+\t\tadjust_mss = mbuf->tso_segsz >= TX_MSS_MIN ?\n+\t\t\t     mbuf->tso_segsz : TX_MSS_MIN;\n+\t\tmax_sges = SPNIC_NONTSO_PKT_MAX_SGE - 1;\n+\t\tlimit_len = adjust_mss + wqe_info->payload_offset;\n+\n+\t\tfor (i = 0; (i < max_sges) && (total_len < limit_len); i++) {\n+\t\t\ttotal_len += mbuf->data_len;\n+\t\t\tmbuf_pre = mbuf;\n+\t\t\tmbuf = mbuf->next;\n+\t\t}\n+\n+\t\twhile (left_sges >= SPNIC_NONTSO_PKT_MAX_SGE) {\n+\t\t\tif (total_len >= limit_len) {\n+\t\t\t\t/* update the limit len */\n+\t\t\t\tlimit_len = adjust_mss;\n+\t\t\t\t/* update checked len */\n+\t\t\t\tchecked_len += first_len;\n+\t\t\t\t/* record the first len */\n+\t\t\t\tfirst_len = mbuf_first->data_len;\n+\t\t\t\t/* first mbuf move to the next */\n+\t\t\t\tmbuf_first = mbuf_first->next;\n+\t\t\t\t/* update total len */\n+\t\t\t\ttotal_len -= first_len;\n+\t\t\t\tleft_sges--;\n+\t\t\t\ti--;\n+\t\t\t\tfor (; (i < max_sges) &&\n+\t\t\t\t     (total_len < limit_len); i++) {\n+\t\t\t\t\ttotal_len += mbuf->data_len;\n+\t\t\t\t\tmbuf_pre = mbuf;\n+\t\t\t\t\tmbuf = mbuf->next;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\t/* try to copy if not valid */\n+\t\t\t\tchecked_len += (total_len - mbuf_pre->data_len);\n+\n+\t\t\t\tleft_len = mbuf_head->pkt_len - checked_len;\n+\t\t\t\tif (left_len > SPNIC_COPY_MBUF_SIZE)\n+\t\t\t\t\treturn false;\n+\t\t\t\twqe_info->sge_cnt = (u16)(mbuf_head->nb_segs +\n+\t\t\t\t\t\t    i - left_sges);\n+\t\t\t\twqe_info->cpy_mbuf_cnt = 1;\n+\n+\t\t\t\treturn true;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\twqe_info->sge_cnt = mbuf_head->nb_segs;\n+\treturn true;\n+}\n+\n+static inline int spnic_get_tx_offload(struct rte_mbuf *mbuf,\n+\t\t\t\t\tstruct spnic_wqe_info *wqe_info)\n+{\n+\tuint64_t ol_flags = mbuf->ol_flags;\n+\tu16 i, total_len, inner_l3_offset = 0;\n+\tstruct rte_mbuf *mbuf_pkt = NULL;\n+\tint err;\n+\n+\twqe_info->sge_cnt = mbuf->nb_segs;\n+\tif (!(ol_flags & SPNIC_TX_OFFLOAD_MASK)) {\n+\t\twqe_info->offload = 0;\n+\t\treturn 0;\n+\t}\n+\n+\twqe_info->offload = 1;\n+\terr = spnic_tx_offload_pkt_prepare(mbuf, &inner_l3_offset);\n+\tif (err)\n+\t\treturn err;\n+\n+\t/* non tso mbuf */\n+\tif (likely(!(mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG))) {\n+\t\tif (unlikely(mbuf->pkt_len > MAX_SINGLE_SGE_SIZE))\n+\t\t\treturn -EINVAL;\n+\n+\t\tif (likely(SPNIC_NONTSO_SEG_NUM_VALID(mbuf->nb_segs)))\n+\t\t\treturn 0;\n+\n+\t\ttotal_len = 0;\n+\t\tmbuf_pkt = mbuf;\n+\t\tfor (i = 0; i < (SPNIC_NONTSO_PKT_MAX_SGE - 1); i++) {\n+\t\t\ttotal_len += mbuf_pkt->data_len;\n+\t\t\tmbuf_pkt = mbuf_pkt->next;\n+\t\t}\n+\n+\t\tif ((u32)(total_len + (u16)SPNIC_COPY_MBUF_SIZE) <\n+\t\t    mbuf->pkt_len)\n+\t\t\treturn -EINVAL;\n+\n+\t\twqe_info->sge_cnt = SPNIC_NONTSO_PKT_MAX_SGE;\n+\t\twqe_info->cpy_mbuf_cnt = 1;\n+\t\treturn 0;\n+\t}\n+\n+\t/* tso mbuf */\n+\twqe_info->payload_offset = inner_l3_offset + mbuf->l3_len +\n+\t\t\t\t   mbuf->l4_len;\n+\n+\tif (unlikely(SPNIC_TSO_SEG_NUM_INVALID(mbuf->nb_segs)))\n+\t\treturn -EINVAL;\n+\n+\tif (unlikely(!spnic_is_tso_sge_valid(mbuf, wqe_info)))\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+static inline void spnic_set_buf_desc(struct spnic_sq_bufdesc *buf_descs,\n+\t\t\t\t      rte_iova_t addr, u32 len)\n+{\n+\tbuf_descs->hi_addr = upper_32_bits(addr);\n+\tbuf_descs->lo_addr = lower_32_bits(addr);\n+\tbuf_descs->len  = len;\n+}\n+\n+static inline void *spnic_copy_tx_mbuf(struct spnic_nic_dev *nic_dev,\n+\t\t\t\t\tstruct rte_mbuf *mbuf, u16 sge_cnt)\n+{\n+\tstruct rte_mbuf *dst_mbuf;\n+\tu32 offset = 0;\n+\tu16 i;\n+\n+\tif (unlikely(!nic_dev->cpy_mpool))\n+\t\treturn NULL;\n+\n+\tdst_mbuf = rte_pktmbuf_alloc(nic_dev->cpy_mpool);\n+\tif (unlikely(!dst_mbuf))\n+\t\treturn NULL;\n+\n+\tdst_mbuf->data_off = 0;\n+\tdst_mbuf->data_len = 0;\n+\tfor (i = 0; i < sge_cnt; i++) {\n+\t\trte_memcpy((u8 *)dst_mbuf->buf_addr + offset,\n+\t\t\t   (u8 *)mbuf->buf_addr + mbuf->data_off,\n+\t\t\t   mbuf->data_len);\n+\t\tdst_mbuf->data_len += mbuf->data_len;\n+\t\toffset += mbuf->data_len;\n+\t\tmbuf = mbuf->next;\n+\t}\n+\tdst_mbuf->pkt_len = dst_mbuf->data_len;\n+\treturn dst_mbuf;\n+}\n+\n+static int spnic_mbuf_dma_map_sge(struct spnic_txq *txq, struct rte_mbuf *mbuf,\n+\t\t\t\t  struct spnic_sq_wqe_combo *wqe_combo,\n+\t\t\t\t  struct spnic_wqe_info *wqe_info)\n+{\n+\tstruct spnic_sq_wqe_desc *wqe_desc = wqe_combo->hdr;\n+\tstruct spnic_sq_bufdesc *buf_desc = wqe_combo->bds_head;\n+\tuint16_t nb_segs = wqe_info->sge_cnt - wqe_info->cpy_mbuf_cnt;\n+\tuint16_t real_segs = mbuf->nb_segs;\n+\n+\trte_iova_t dma_addr;\n+\tu32 i;\n+\n+\tfor (i = 0; i < nb_segs; i++) {\n+\t\tif (unlikely(mbuf == NULL)) {\n+\t\t\ttxq->txq_stats.mbuf_null++;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (unlikely(mbuf->data_len == 0)) {\n+\t\t\ttxq->txq_stats.sge_len0++;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tdma_addr = rte_mbuf_data_iova(mbuf);\n+\t\tif (i == 0) {\n+\t\t\tif (wqe_combo->wqe_type == SQ_WQE_COMPACT_TYPE &&\n+\t\t\t    mbuf->data_len > COMPACT_WQE_MAX_CTRL_LEN) {\n+\t\t\t\ttxq->txq_stats.sge_len_too_large++;\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\twqe_desc->hi_addr = upper_32_bits(dma_addr);\n+\t\t\twqe_desc->lo_addr = lower_32_bits(dma_addr);\n+\t\t\twqe_desc->ctrl_len = mbuf->data_len;\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * Parts of wqe is in sq bottom while parts\n+\t\t\t * of wqe is in sq head\n+\t\t\t */\n+\t\t\tif (unlikely(wqe_info->wrapped &&\n+\t\t\t    (u64)buf_desc == txq->sq_bot_sge_addr))\n+\t\t\t\tbuf_desc = (struct spnic_sq_bufdesc *)\n+\t\t\t\t\t   (void *)txq->sq_head_addr;\n+\n+\t\t\tspnic_set_buf_desc(buf_desc, dma_addr, mbuf->data_len);\n+\t\t\tbuf_desc++;\n+\t\t}\n+\n+\t\tmbuf = mbuf->next;\n+\t}\n+\n+\tif (unlikely(wqe_info->cpy_mbuf_cnt != 0)) {\n+\t\t/* copy invalid mbuf segs to a valid buffer, lost performance */\n+\t\ttxq->txq_stats.cpy_pkts += 1;\n+\t\tmbuf = spnic_copy_tx_mbuf(txq->nic_dev, mbuf,\n+\t\t\t\t\t   real_segs - nb_segs);\n+\t\tif (unlikely(!mbuf))\n+\t\t\treturn -EINVAL;\n+\n+\t\ttxq->tx_info[wqe_info->pi].cpy_mbuf = mbuf;\n+\n+\t\t/* deal with the last mbuf */\n+\t\tdma_addr = rte_mbuf_data_iova(mbuf);\n+\t\tif (unlikely(mbuf->data_len == 0)) {\n+\t\t\ttxq->txq_stats.sge_len0++;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (unlikely(wqe_info->wrapped &&\n+\t\t    ((u64)buf_desc == txq->sq_bot_sge_addr)))\n+\t\t\tbuf_desc =\n+\t\t\t\t(struct spnic_sq_bufdesc *)txq->sq_head_addr;\n+\n+\t\tspnic_set_buf_desc(buf_desc, dma_addr, mbuf->data_len);\n+\t}\n+\treturn 0;\n+}\n+\n+static inline void spnic_prepare_sq_ctrl(struct spnic_sq_wqe_combo *wqe_combo,\n+\t\t\t\t\t struct spnic_wqe_info *wqe_info)\n+{\n+\tstruct spnic_sq_wqe_desc *wqe_desc = wqe_combo->hdr;\n+\n+\tif (wqe_combo->wqe_type == SQ_WQE_COMPACT_TYPE) {\n+\t\twqe_desc->ctrl_len |= SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |\n+\t\t\t\tSQ_CTRL_SET(wqe_combo->wqe_type, EXTENDED) |\n+\t\t\t\tSQ_CTRL_SET(wqe_info->owner, OWNER);\n+\t\t/* Compact wqe queue_info will transfer to ucode */\n+\t\twqe_desc->queue_info = 0;\n+\t\treturn;\n+\t}\n+\n+\twqe_desc->ctrl_len |= SQ_CTRL_SET(wqe_info->sge_cnt, BUFDESC_NUM) |\n+\t\t\tSQ_CTRL_SET(wqe_combo->task_type, TASKSECT_LEN) |\n+\t\t\tSQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |\n+\t\t\tSQ_CTRL_SET(wqe_combo->wqe_type, EXTENDED) |\n+\t\t\tSQ_CTRL_SET(wqe_info->owner, OWNER);\n+\n+\twqe_desc->queue_info = wqe_info->queue_info;\n+\twqe_desc->queue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, UC);\n+\n+\tif (!SQ_CTRL_QUEUE_INFO_GET(wqe_desc->queue_info, MSS)) {\n+\t\twqe_desc->queue_info |=\n+\t\t\tSQ_CTRL_QUEUE_INFO_SET(TX_MSS_DEFAULT, MSS);\n+\t} else if (SQ_CTRL_QUEUE_INFO_GET(wqe_desc->queue_info, MSS) <\n+\t\t   TX_MSS_MIN) {\n+\t\t/* Mss should not less than 80 */\n+\t\twqe_desc->queue_info =\n+\t\t\tSQ_CTRL_QUEUE_INFO_CLEAR(wqe_desc->queue_info, MSS);\n+\t\twqe_desc->queue_info |= SQ_CTRL_QUEUE_INFO_SET(TX_MSS_MIN, MSS);\n+\t}\n+}\n+\n+u16 spnic_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, u16 nb_pkts)\n+{\n+\tstruct spnic_txq *txq = tx_queue;\n+\tstruct spnic_tx_info *tx_info = NULL;\n+\tstruct rte_mbuf *mbuf_pkt = NULL;\n+\tstruct spnic_sq_wqe_combo wqe_combo = {0};\n+\tstruct spnic_sq_wqe *sq_wqe = NULL;\n+\tstruct spnic_wqe_info wqe_info = {0};\n+\tu32 offload_err, free_cnt;\n+\tu64 tx_bytes = 0;\n+\tu16 free_wqebb_cnt, nb_tx;\n+\tint err;\n+\n+\tfree_cnt = txq->tx_free_thresh;\n+\t/* Reclaim tx mbuf before xmit new packets */\n+\tspnic_xmit_mbuf_cleanup(txq, free_cnt);\n+\n+\t/* Tx loop routine */\n+\tfor (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {\n+\t\tmbuf_pkt = *tx_pkts++;\n+\t\tif (spnic_get_tx_offload(mbuf_pkt, &wqe_info)) {\n+\t\t\ttxq->txq_stats.off_errs++;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!wqe_info.offload)\n+\t\t\t/*\n+\t\t\t * Use extended sq wqe with small TS, which can include\n+\t\t\t * multi sges, or compact sq normal wqe, which just\n+\t\t\t * supports one sge\n+\t\t\t */\n+\t\t\twqe_info.wqebb_cnt = mbuf_pkt->nb_segs;\n+\t\telse\n+\t\t\t/* Use extended sq wqe with normal TS */\n+\t\t\twqe_info.wqebb_cnt = mbuf_pkt->nb_segs + 1;\n+\n+\t\tfree_wqebb_cnt = spnic_get_sq_free_wqebbs(txq);\n+\t\tif (unlikely(wqe_info.wqebb_cnt > free_wqebb_cnt)) {\n+\t\t\t/* Reclaim again */\n+\t\t\tspnic_xmit_mbuf_cleanup(txq, free_cnt);\n+\t\t\tfree_wqebb_cnt = spnic_get_sq_free_wqebbs(txq);\n+\t\t\tif (unlikely(wqe_info.wqebb_cnt > free_wqebb_cnt)) {\n+\t\t\t\ttxq->txq_stats.tx_busy += (nb_pkts - nb_tx);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Get sq wqe address from wqe_page */\n+\t\tsq_wqe = spnic_get_sq_wqe(txq, &wqe_info);\n+\t\tif (unlikely(!sq_wqe)) {\n+\t\t\ttxq->txq_stats.tx_busy++;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Task or bd section maybe warpped for one wqe */\n+\t\tspnic_set_wqe_combo(txq, &wqe_combo, sq_wqe, &wqe_info);\n+\n+\t\twqe_info.queue_info = 0;\n+\t\t/* Fill tx packet offload into qsf and task field */\n+\t\tif (wqe_info.offload) {\n+\t\t\toffload_err = spnic_set_tx_offload(mbuf_pkt,\n+\t\t\t\t\t\t\t   wqe_combo.task,\n+\t\t\t\t\t\t\t   &wqe_info);\n+\t\t\tif (unlikely(offload_err)) {\n+\t\t\t\tspnic_put_sq_wqe(txq, &wqe_info);\n+\t\t\t\ttxq->txq_stats.off_errs++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Fill sq_wqe buf_desc and bd_desc */\n+\t\terr = spnic_mbuf_dma_map_sge(txq, mbuf_pkt, &wqe_combo,\n+\t\t\t\t\t     &wqe_info);\n+\t\tif (err) {\n+\t\t\tspnic_put_sq_wqe(txq, &wqe_info);\n+\t\t\ttxq->txq_stats.off_errs++;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Record tx info */\n+\t\ttx_info = &txq->tx_info[wqe_info.pi];\n+\t\ttx_info->mbuf = mbuf_pkt;\n+\t\ttx_info->wqebb_cnt = wqe_info.wqebb_cnt;\n+\n+\t\tspnic_prepare_sq_ctrl(&wqe_combo, &wqe_info);\n+\n+\t\tspnic_write_db(txq->db_addr, txq->q_id, txq->cos, SQ_CFLAG_DP,\n+\t\t\t       MASKED_QUEUE_IDX(txq, txq->prod_idx));\n+\n+\t\ttx_bytes += mbuf_pkt->pkt_len;\n+\t}\n+\n+\t/* Update txq stats */\n+\tif (nb_tx) {\n+\t\ttxq->txq_stats.packets += nb_tx;\n+\t\ttxq->txq_stats.bytes += tx_bytes;\n+\t}\n+\ttxq->txq_stats.burst_pkts = nb_tx;\n+\n+\treturn nb_tx;\n+}\n+\n int spnic_stop_sq(struct spnic_txq *txq)\n {\n \tstruct spnic_nic_dev *nic_dev = txq->nic_dev;\ndiff --git a/drivers/net/spnic/spnic_tx.h b/drivers/net/spnic/spnic_tx.h\nindex d770b15c21..4c2d587104 100644\n--- a/drivers/net/spnic/spnic_tx.h\n+++ b/drivers/net/spnic/spnic_tx.h\n@@ -4,6 +4,13 @@\n \n #ifndef _SPNIC_TX_H_\n #define _SPNIC_TX_H_\n+#define MAX_SINGLE_SGE_SIZE\t\t65536\n+#define SPNIC_NONTSO_PKT_MAX_SGE\t38\n+#define SPNIC_NONTSO_SEG_NUM_VALID(num)\t\\\n+\t((num) <= SPNIC_NONTSO_PKT_MAX_SGE)\n+\n+#define SPNIC_TSO_PKT_MAX_SGE\t\t127\n+#define SPNIC_TSO_SEG_NUM_INVALID(num)\t((num) > SPNIC_TSO_PKT_MAX_SGE)\n /* Tx offload info */\n struct spnic_tx_offload_info {\n \tu8 outer_l2_len;\n",
    "prefixes": [
        "v1",
        "15/25"
    ]
}