get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 80538,
    "url": "http://patches.dpdk.org/api/patches/80538/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1602596753-32282-18-git-send-email-arybchenko@solarflare.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": "<1602596753-32282-18-git-send-email-arybchenko@solarflare.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1602596753-32282-18-git-send-email-arybchenko@solarflare.com",
    "date": "2020-10-13T13:45:34",
    "name": "[17/36] net/sfc: implement EF100 native Tx datapath",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "8b726b35c7ab4ff29c8762d7b5e8a126612b768b",
    "submitter": {
        "id": 607,
        "url": "http://patches.dpdk.org/api/people/607/?format=api",
        "name": "Andrew Rybchenko",
        "email": "arybchenko@solarflare.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1602596753-32282-18-git-send-email-arybchenko@solarflare.com/mbox/",
    "series": [
        {
            "id": 12916,
            "url": "http://patches.dpdk.org/api/series/12916/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=12916",
            "date": "2020-10-13T13:45:18",
            "name": "net/sfc: add EF100 support",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/12916/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/80538/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/80538/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 dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 329DCA04B7;\n\tTue, 13 Oct 2020 15:56:48 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id BDE101DC51;\n\tTue, 13 Oct 2020 15:46:49 +0200 (CEST)",
            "from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com\n [67.231.154.164]) by dpdk.org (Postfix) with ESMTP id AE2601DB91\n for <dev@dpdk.org>; Tue, 13 Oct 2020 15:46:04 +0200 (CEST)",
            "from mx1-us1.ppe-hosted.com (unknown [10.110.50.137])\n by dispatch1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id\n 0679F20060 for <dev@dpdk.org>; Tue, 13 Oct 2020 13:46:03 +0000 (UTC)",
            "from us4-mdac16-55.at1.mdlocal (unknown [10.110.50.140])\n by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTP id 035096009B\n for <dev@dpdk.org>; Tue, 13 Oct 2020 13:46:03 +0000 (UTC)",
            "from mx1-us1.ppe-hosted.com (unknown [10.110.50.7])\n by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTPS id\n 696E122004D\n for <dev@dpdk.org>; Tue, 13 Oct 2020 13:46:02 +0000 (UTC)",
            "from webmail.solarflare.com (uk.solarflare.com [193.34.186.16])\n (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits))\n (No client certificate requested)\n by mx1-us1.ppe-hosted.com (PPE Hosted ESMTP Server) with ESMTPS id\n 310A84C0068\n for <dev@dpdk.org>; Tue, 13 Oct 2020 13:46:02 +0000 (UTC)",
            "from ukex01.SolarFlarecom.com (10.17.10.4) by\n ukex01.SolarFlarecom.com (10.17.10.4) with Microsoft SMTP Server (TLS) id\n 15.0.1497.2; Tue, 13 Oct 2020 14:45:56 +0100",
            "from opal.uk.solarflarecom.com (10.17.10.1) by\n ukex01.SolarFlarecom.com (10.17.10.4) with Microsoft SMTP Server id\n 15.0.1497.2 via Frontend Transport; Tue, 13 Oct 2020 14:45:56 +0100",
            "from ukv-loginhost.uk.solarflarecom.com\n (ukv-loginhost.uk.solarflarecom.com [10.17.10.39])\n by opal.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id 09DDju5n006052\n for <dev@dpdk.org>; Tue, 13 Oct 2020 14:45:56 +0100",
            "from ukv-loginhost.uk.solarflarecom.com (localhost [127.0.0.1])\n by ukv-loginhost.uk.solarflarecom.com (Postfix) with ESMTP id 268151613A9\n for <dev@dpdk.org>; Tue, 13 Oct 2020 14:45:56 +0100 (BST)"
        ],
        "X-Virus-Scanned": "Proofpoint Essentials engine",
        "From": "Andrew Rybchenko <arybchenko@solarflare.com>",
        "To": "<dev@dpdk.org>",
        "Date": "Tue, 13 Oct 2020 14:45:34 +0100",
        "Message-ID": "<1602596753-32282-18-git-send-email-arybchenko@solarflare.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1602596753-32282-1-git-send-email-arybchenko@solarflare.com>",
        "References": "<1602596753-32282-1-git-send-email-arybchenko@solarflare.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-TM-AS-Product-Ver": "SMEX-12.5.0.1300-8.6.1012-25722.003",
        "X-TM-AS-Result": "No-12.751400-8.000000-10",
        "X-TMASE-MatchedRID": "XFXJQP7ttEHMdO/aI0cjorsHVDDM5xAPP6Tki+9nU39XiLrvhpKLfEAc\n 6DyoS2rITvVMSfL26EnHF4kGAhQkOe4oGFq8y69jlTsGW3DmpUtJaD67iKvY06soAw12Y1UTCHd\n 5jBGO6G/Jr0HV7DF7bQNezODO/fMl+NnOs+tfvVvvWGhFrXKaNqQFk5omY4gNfkiy7TTogYYVLG\n IPVP4OQb/YkCk00rZtSFcZfOxgQydCXWyUERykyl+c+CiOA1/A4FBhMAaXjUweeOmdPBXZbl1o7\n wPE6VhYj7NfJ0vFpC4awjO0i2hiKgGbJEIeoS19ZdbZXmGFLieVLkhtDy7dOkFungmhsSsC33pX\n Y2CsQeIPXG0SrrPadbI2bT94ZMbKWSN6uGsJ4KlZMZ6MZ0H1UpnaxzJFBx6vFBQ5IKls/A7xvWZ\n dOp62bA64zb/LCJTkr21BqqRD0iaNyQcaCtPu/Bo8wYJxWb0O4F58RPNYsrHAJMh4mAwEG/Vl5v\n soSSso+6i+CPdDD137fVAndB8aVrMVOeQNlCMhdXu122+iJtpX6LfNVtReyNSVUkz9BPXe+9RqU\n r/gzAw65uzS9sK5ErDScieRW8xZFqZOUNu5k1iEv01fZOqaQBACJh4BWAPen7jOJQ+rgvHBAaxO\n 5QHlTm7R4YbMNOKDl1fLlMpsKPPt6o75WkYNjXYZxYoZm58FCCo+lsDuynW2TkeS9tjW4xyVfgV\n UFnGntVh33ut48A5qNIDF3xjqhrFgYrBx+llbVvRU70CYUV35tdwICq/3BaRea8wUAdQ6RQD5XO\n FRjEKq4xFUReVAUwWBbD+OXvMgX03PAgSXgGSeAiCmPx4NwJuJ+Pb8n/VxSnQ4MjwaO9cqtq5d3\n cxkNRoDQTxR2s/qBhC/Iv895+6ti/lpvjxs9PI3kXgK1pK8Am+4b9RkUBs=",
        "X-TM-AS-User-Approved-Sender": "Yes",
        "X-TM-AS-User-Blocked-Sender": "No",
        "X-TMASE-Result": "10--12.751400-8.000000",
        "X-TMASE-Version": "SMEX-12.5.0.1300-8.6.1012-25722.003",
        "X-MDID": "1602596762-0ZqVLKeZjtAM",
        "X-PPE-DISP": "1602596762;0ZqVLKeZjtAM",
        "Subject": "[dpdk-dev] [PATCH 17/36] net/sfc: implement EF100 native Tx datapath",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "No offloads support yet including multi-segment (Tx gather).\n\nSigned-off-by: Andrew Rybchenko <arybchenko@solarflare.com>\n---\n doc/guides/nics/sfc_efx.rst    |   5 +-\n drivers/net/sfc/meson.build    |   1 +\n drivers/net/sfc/sfc_dp_tx.h    |   1 +\n drivers/net/sfc/sfc_ef100_tx.c | 546 +++++++++++++++++++++++++++++++++\n drivers/net/sfc/sfc_ethdev.c   |   1 +\n drivers/net/sfc/sfc_kvargs.h   |   3 +-\n 6 files changed, 555 insertions(+), 2 deletions(-)\n create mode 100644 drivers/net/sfc/sfc_ef100_tx.c",
    "diff": "diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst\nindex c05c565275..726d653fa8 100644\n--- a/doc/guides/nics/sfc_efx.rst\n+++ b/doc/guides/nics/sfc_efx.rst\n@@ -311,7 +311,7 @@ boolean parameters value.\n   **ef100** chooses EF100 native datapath which is the only supported\n   Rx datapath for EF100 architecture based NICs.\n \n-- ``tx_datapath`` [auto|efx|ef10|ef10_simple] (default **auto**)\n+- ``tx_datapath`` [auto|efx|ef10|ef10_simple|ef100] (default **auto**)\n \n   Choose transmit datapath implementation.\n   **auto** allows the driver itself to make a choice based on firmware\n@@ -320,6 +320,7 @@ boolean parameters value.\n   (full-feature firmware variant only), TSO and multi-segment mbufs.\n   Mbuf segments may come from different mempools, and mbuf reference\n   counters are treated responsibly.\n+  Supported for SFN7xxx, SFN8xxx and X2xxx family adapters only.\n   **ef10** chooses EF10 (SFN7xxx, SFN8xxx, X2xxx) native datapath which is\n   more efficient than libefx-based but has no VLAN insertion support yet.\n   Mbuf segments may come from different mempools, and mbuf reference\n@@ -327,6 +328,8 @@ boolean parameters value.\n   **ef10_simple** chooses EF10 (SFN7xxx, SFN8xxx, X2xxx) native datapath which\n   is even more faster then **ef10** but does not support multi-segment\n   mbufs, disallows multiple mempools and neglects mbuf reference counters.\n+  **ef100** chooses EF100 native datapath which does not support multi-segment\n+  mbufs and any offloads.\n \n - ``perf_profile`` [auto|throughput|low-latency] (default **throughput**)\n \ndiff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build\nindex 604c67cddd..589f7863ae 100644\n--- a/drivers/net/sfc/meson.build\n+++ b/drivers/net/sfc/meson.build\n@@ -53,4 +53,5 @@ sources = files(\n \t'sfc_ef10_essb_rx.c',\n \t'sfc_ef10_tx.c',\n \t'sfc_ef100_rx.c',\n+\t'sfc_ef100_tx.c',\n )\ndiff --git a/drivers/net/sfc/sfc_dp_tx.h b/drivers/net/sfc/sfc_dp_tx.h\nindex dcad4fe585..67aa398b7f 100644\n--- a/drivers/net/sfc/sfc_dp_tx.h\n+++ b/drivers/net/sfc/sfc_dp_tx.h\n@@ -289,6 +289,7 @@ sfc_dp_tx_prepare_pkt(struct rte_mbuf *m,\n extern struct sfc_dp_tx sfc_efx_tx;\n extern struct sfc_dp_tx sfc_ef10_tx;\n extern struct sfc_dp_tx sfc_ef10_simple_tx;\n+extern struct sfc_dp_tx sfc_ef100_tx;\n \n #ifdef __cplusplus\n }\ndiff --git a/drivers/net/sfc/sfc_ef100_tx.c b/drivers/net/sfc/sfc_ef100_tx.c\nnew file mode 100644\nindex 0000000000..20b7c786cc\n--- /dev/null\n+++ b/drivers/net/sfc/sfc_ef100_tx.c\n@@ -0,0 +1,546 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ *\n+ * Copyright(c) 2019-2020 Xilinx, Inc.\n+ * Copyright(c) 2018-2019 Solarflare Communications Inc.\n+ *\n+ * This software was jointly developed between OKTET Labs (under contract\n+ * for Solarflare) and Solarflare Communications, Inc.\n+ */\n+\n+#include <stdbool.h>\n+\n+#include <rte_mbuf.h>\n+#include <rte_io.h>\n+\n+#include \"efx.h\"\n+#include \"efx_types.h\"\n+#include \"efx_regs.h\"\n+#include \"efx_regs_ef100.h\"\n+\n+#include \"sfc_debug.h\"\n+#include \"sfc_dp_tx.h\"\n+#include \"sfc_tweak.h\"\n+#include \"sfc_kvargs.h\"\n+#include \"sfc_ef100.h\"\n+\n+\n+#define sfc_ef100_tx_err(_txq, ...) \\\n+\tSFC_DP_LOG(SFC_KVARG_DATAPATH_EF100, ERR, &(_txq)->dp.dpq, __VA_ARGS__)\n+\n+#define sfc_ef100_tx_debug(_txq, ...) \\\n+\tSFC_DP_LOG(SFC_KVARG_DATAPATH_EF100, DEBUG, &(_txq)->dp.dpq, \\\n+\t\t   __VA_ARGS__)\n+\n+\n+/** Maximum length of the send descriptor data */\n+#define SFC_EF100_TX_SEND_DESC_LEN_MAX \\\n+\t((1u << ESF_GZ_TX_SEND_LEN_WIDTH) - 1)\n+\n+/**\n+ * Maximum number of descriptors/buffers in the Tx ring.\n+ * It should guarantee that corresponding event queue never overfill.\n+ * EF100 native datapath uses event queue of the same size as Tx queue.\n+ * Maximum number of events on datapath can be estimated as number of\n+ * Tx queue entries (one event per Tx buffer in the worst case) plus\n+ * Tx error and flush events.\n+ */\n+#define SFC_EF100_TXQ_LIMIT(_ndesc) \\\n+\t((_ndesc) - 1 /* head must not step on tail */ - \\\n+\t 1 /* Rx error */ - 1 /* flush */)\n+\n+struct sfc_ef100_tx_sw_desc {\n+\tstruct rte_mbuf\t\t\t*mbuf;\n+};\n+\n+struct sfc_ef100_txq {\n+\tunsigned int\t\t\tflags;\n+#define SFC_EF100_TXQ_STARTED\t\t0x1\n+#define SFC_EF100_TXQ_NOT_RUNNING\t0x2\n+#define SFC_EF100_TXQ_EXCEPTION\t\t0x4\n+\n+\tunsigned int\t\t\tptr_mask;\n+\tunsigned int\t\t\tadded;\n+\tunsigned int\t\t\tcompleted;\n+\tunsigned int\t\t\tmax_fill_level;\n+\tunsigned int\t\t\tfree_thresh;\n+\tstruct sfc_ef100_tx_sw_desc\t*sw_ring;\n+\tefx_oword_t\t\t\t*txq_hw_ring;\n+\tvolatile void\t\t\t*doorbell;\n+\n+\t/* Completion/reap */\n+\tunsigned int\t\t\tevq_read_ptr;\n+\tunsigned int\t\t\tevq_phase_bit_shift;\n+\tvolatile efx_qword_t\t\t*evq_hw_ring;\n+\n+\t/* Datapath transmit queue anchor */\n+\tstruct sfc_dp_txq\t\tdp;\n+};\n+\n+static inline struct sfc_ef100_txq *\n+sfc_ef100_txq_by_dp_txq(struct sfc_dp_txq *dp_txq)\n+{\n+\treturn container_of(dp_txq, struct sfc_ef100_txq, dp);\n+}\n+\n+static bool\n+sfc_ef100_tx_get_event(struct sfc_ef100_txq *txq, efx_qword_t *ev)\n+{\n+\tvolatile efx_qword_t *evq_hw_ring = txq->evq_hw_ring;\n+\n+\t/*\n+\t * Exception flag is set when reap is done.\n+\t * It is never done twice per packet burst get, and absence of\n+\t * the flag is checked on burst get entry.\n+\t */\n+\tSFC_ASSERT((txq->flags & SFC_EF100_TXQ_EXCEPTION) == 0);\n+\n+\t*ev = evq_hw_ring[txq->evq_read_ptr & txq->ptr_mask];\n+\n+\tif (!sfc_ef100_ev_present(ev,\n+\t\t\t(txq->evq_read_ptr >> txq->evq_phase_bit_shift) & 1))\n+\t\treturn false;\n+\n+\tif (unlikely(!sfc_ef100_ev_type_is(ev,\n+\t\t\t\t\t   ESE_GZ_EF100_EV_TX_COMPLETION))) {\n+\t\t/*\n+\t\t * Do not move read_ptr to keep the event for exception\n+\t\t * handling by the control path.\n+\t\t */\n+\t\ttxq->flags |= SFC_EF100_TXQ_EXCEPTION;\n+\t\tsfc_ef100_tx_err(txq,\n+\t\t\t\"TxQ exception at EvQ ptr %u(%#x), event %08x:%08x\",\n+\t\t\ttxq->evq_read_ptr, txq->evq_read_ptr & txq->ptr_mask,\n+\t\t\tEFX_QWORD_FIELD(*ev, EFX_DWORD_1),\n+\t\t\tEFX_QWORD_FIELD(*ev, EFX_DWORD_0));\n+\t\treturn false;\n+\t}\n+\n+\tsfc_ef100_tx_debug(txq, \"TxQ got event %08x:%08x at %u (%#x)\",\n+\t\t\t   EFX_QWORD_FIELD(*ev, EFX_DWORD_1),\n+\t\t\t   EFX_QWORD_FIELD(*ev, EFX_DWORD_0),\n+\t\t\t   txq->evq_read_ptr,\n+\t\t\t   txq->evq_read_ptr & txq->ptr_mask);\n+\n+\ttxq->evq_read_ptr++;\n+\treturn true;\n+}\n+\n+static unsigned int\n+sfc_ef100_tx_process_events(struct sfc_ef100_txq *txq)\n+{\n+\tunsigned int num_descs = 0;\n+\tefx_qword_t tx_ev;\n+\n+\twhile (sfc_ef100_tx_get_event(txq, &tx_ev))\n+\t\tnum_descs += EFX_QWORD_FIELD(tx_ev, ESF_GZ_EV_TXCMPL_NUM_DESC);\n+\n+\treturn num_descs;\n+}\n+\n+static void\n+sfc_ef100_tx_reap_num_descs(struct sfc_ef100_txq *txq, unsigned int num_descs)\n+{\n+\tif (num_descs > 0) {\n+\t\tunsigned int completed = txq->completed;\n+\t\tunsigned int pending = completed + num_descs;\n+\t\tstruct rte_mbuf *bulk[SFC_TX_REAP_BULK_SIZE];\n+\t\tunsigned int nb = 0;\n+\n+\t\tdo {\n+\t\t\tstruct sfc_ef100_tx_sw_desc *txd;\n+\t\t\tstruct rte_mbuf *m;\n+\n+\t\t\ttxd = &txq->sw_ring[completed & txq->ptr_mask];\n+\t\t\tif (txd->mbuf == NULL)\n+\t\t\t\tcontinue;\n+\n+\t\t\tm = rte_pktmbuf_prefree_seg(txd->mbuf);\n+\t\t\tif (m == NULL)\n+\t\t\t\tcontinue;\n+\n+\t\t\ttxd->mbuf = NULL;\n+\n+\t\t\tif (nb == RTE_DIM(bulk) ||\n+\t\t\t    (nb != 0 && m->pool != bulk[0]->pool)) {\n+\t\t\t\trte_mempool_put_bulk(bulk[0]->pool,\n+\t\t\t\t\t\t     (void *)bulk, nb);\n+\t\t\t\tnb = 0;\n+\t\t\t}\n+\n+\t\t\tbulk[nb++] = m;\n+\t\t} while (++completed != pending);\n+\n+\t\tif (nb != 0)\n+\t\t\trte_mempool_put_bulk(bulk[0]->pool, (void *)bulk, nb);\n+\n+\t\ttxq->completed = completed;\n+\t}\n+}\n+\n+static void\n+sfc_ef100_tx_reap(struct sfc_ef100_txq *txq)\n+{\n+\tsfc_ef100_tx_reap_num_descs(txq, sfc_ef100_tx_process_events(txq));\n+}\n+\n+static void\n+sfc_ef100_tx_qdesc_send_create(const struct rte_mbuf *m, efx_oword_t *tx_desc)\n+{\n+\tEFX_POPULATE_OWORD_4(*tx_desc,\n+\t\t\tESF_GZ_TX_SEND_ADDR, rte_mbuf_data_iova(m),\n+\t\t\tESF_GZ_TX_SEND_LEN, rte_pktmbuf_data_len(m),\n+\t\t\tESF_GZ_TX_SEND_NUM_SEGS, 1,\n+\t\t\tESF_GZ_TX_DESC_TYPE, ESE_GZ_TX_DESC_TYPE_SEND);\n+}\n+\n+static inline void\n+sfc_ef100_tx_qpush(struct sfc_ef100_txq *txq, unsigned int added)\n+{\n+\tefx_dword_t dword;\n+\n+\tEFX_POPULATE_DWORD_1(dword, ERF_GZ_TX_RING_PIDX, added & txq->ptr_mask);\n+\n+\t/* DMA sync to device is not required */\n+\n+\t/*\n+\t * rte_write32() has rte_io_wmb() which guarantees that the STORE\n+\t * operations (i.e. Rx and event descriptor updates) that precede\n+\t * the rte_io_wmb() call are visible to NIC before the STORE\n+\t * operations that follow it (i.e. doorbell write).\n+\t */\n+\trte_write32(dword.ed_u32[0], txq->doorbell);\n+\n+\tsfc_ef100_tx_debug(txq, \"TxQ pushed doorbell at pidx %u (added=%u)\",\n+\t\t\t   EFX_DWORD_FIELD(dword, ERF_GZ_TX_RING_PIDX),\n+\t\t\t   added);\n+}\n+\n+static unsigned int\n+sfc_ef100_tx_pkt_descs_max(const struct rte_mbuf *m)\n+{\n+/** Maximum length of an mbuf segment data */\n+#define SFC_MBUF_SEG_LEN_MAX\t\tUINT16_MAX\n+\tRTE_BUILD_BUG_ON(sizeof(m->data_len) != 2);\n+\n+\t/*\n+\t * mbuf segment cannot be bigger than maximum segnment length and\n+\t * maximum packet length since TSO is not supported yet.\n+\t * Make sure that the first segment does not need fragmentation\n+\t * (split into many Tx descriptors).\n+\t */\n+\tRTE_BUILD_BUG_ON(SFC_EF100_TX_SEND_DESC_LEN_MAX <\n+\t\tRTE_MIN((unsigned int)EFX_MAC_PDU_MAX, SFC_MBUF_SEG_LEN_MAX));\n+\n+\tSFC_ASSERT(m->nb_segs == 1);\n+\treturn 1;\n+}\n+\n+static uint16_t\n+sfc_ef100_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n+{\n+\tstruct sfc_ef100_txq * const txq = sfc_ef100_txq_by_dp_txq(tx_queue);\n+\tunsigned int added;\n+\tunsigned int dma_desc_space;\n+\tbool reap_done;\n+\tstruct rte_mbuf **pktp;\n+\tstruct rte_mbuf **pktp_end;\n+\n+\tif (unlikely(txq->flags &\n+\t\t     (SFC_EF100_TXQ_NOT_RUNNING | SFC_EF100_TXQ_EXCEPTION)))\n+\t\treturn 0;\n+\n+\tadded = txq->added;\n+\tdma_desc_space = txq->max_fill_level - (added - txq->completed);\n+\n+\treap_done = (dma_desc_space < txq->free_thresh);\n+\tif (reap_done) {\n+\t\tsfc_ef100_tx_reap(txq);\n+\t\tdma_desc_space = txq->max_fill_level - (added - txq->completed);\n+\t}\n+\n+\tfor (pktp = &tx_pkts[0], pktp_end = &tx_pkts[nb_pkts];\n+\t     pktp != pktp_end;\n+\t     ++pktp) {\n+\t\tstruct rte_mbuf *m_seg = *pktp;\n+\t\tunsigned int pkt_start = added;\n+\t\tunsigned int id;\n+\n+\t\tif (likely(pktp + 1 != pktp_end))\n+\t\t\trte_mbuf_prefetch_part1(pktp[1]);\n+\n+\t\tif (sfc_ef100_tx_pkt_descs_max(m_seg) > dma_desc_space) {\n+\t\t\tif (reap_done)\n+\t\t\t\tbreak;\n+\n+\t\t\t/* Push already prepared descriptors before polling */\n+\t\t\tif (added != txq->added) {\n+\t\t\t\tsfc_ef100_tx_qpush(txq, added);\n+\t\t\t\ttxq->added = added;\n+\t\t\t}\n+\n+\t\t\tsfc_ef100_tx_reap(txq);\n+\t\t\treap_done = true;\n+\t\t\tdma_desc_space = txq->max_fill_level -\n+\t\t\t\t(added - txq->completed);\n+\t\t\tif (sfc_ef100_tx_pkt_descs_max(m_seg) > dma_desc_space)\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\tid = added++ & txq->ptr_mask;\n+\t\tsfc_ef100_tx_qdesc_send_create(m_seg, &txq->txq_hw_ring[id]);\n+\n+\t\t/*\n+\t\t * rte_pktmbuf_free() is commonly used in DPDK for\n+\t\t * recycling packets - the function checks every\n+\t\t * segment's reference counter and returns the\n+\t\t * buffer to its pool whenever possible;\n+\t\t * nevertheless, freeing mbuf segments one by one\n+\t\t * may entail some performance decline;\n+\t\t * from this point, sfc_efx_tx_reap() does the same job\n+\t\t * on its own and frees buffers in bulks (all mbufs\n+\t\t * within a bulk belong to the same pool);\n+\t\t * from this perspective, individual segment pointers\n+\t\t * must be associated with the corresponding SW\n+\t\t * descriptors independently so that only one loop\n+\t\t * is sufficient on reap to inspect all the buffers\n+\t\t */\n+\t\ttxq->sw_ring[id].mbuf = m_seg;\n+\n+\t\tdma_desc_space -= (added - pkt_start);\n+\t}\n+\n+\tif (likely(added != txq->added)) {\n+\t\tsfc_ef100_tx_qpush(txq, added);\n+\t\ttxq->added = added;\n+\t}\n+\n+#if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE\n+\tif (!reap_done)\n+\t\tsfc_ef100_tx_reap(txq);\n+#endif\n+\n+\treturn pktp - &tx_pkts[0];\n+}\n+\n+static sfc_dp_tx_get_dev_info_t sfc_ef100_get_dev_info;\n+static void\n+sfc_ef100_get_dev_info(struct rte_eth_dev_info *dev_info)\n+{\n+\t/*\n+\t * Number of descriptors just defines maximum number of pushed\n+\t * descriptors (fill level).\n+\t */\n+\tdev_info->tx_desc_lim.nb_min = 1;\n+\tdev_info->tx_desc_lim.nb_align = 1;\n+}\n+\n+static sfc_dp_tx_qsize_up_rings_t sfc_ef100_tx_qsize_up_rings;\n+static int\n+sfc_ef100_tx_qsize_up_rings(uint16_t nb_tx_desc,\n+\t\t\t   struct sfc_dp_tx_hw_limits *limits,\n+\t\t\t   unsigned int *txq_entries,\n+\t\t\t   unsigned int *evq_entries,\n+\t\t\t   unsigned int *txq_max_fill_level)\n+{\n+\t/*\n+\t * rte_ethdev API guarantees that the number meets min, max and\n+\t * alignment requirements.\n+\t */\n+\tif (nb_tx_desc <= limits->txq_min_entries)\n+\t\t*txq_entries = limits->txq_min_entries;\n+\telse\n+\t\t*txq_entries = rte_align32pow2(nb_tx_desc);\n+\n+\t*evq_entries = *txq_entries;\n+\n+\t*txq_max_fill_level = RTE_MIN(nb_tx_desc,\n+\t\t\t\t      SFC_EF100_TXQ_LIMIT(*evq_entries));\n+\treturn 0;\n+}\n+\n+static sfc_dp_tx_qcreate_t sfc_ef100_tx_qcreate;\n+static int\n+sfc_ef100_tx_qcreate(uint16_t port_id, uint16_t queue_id,\n+\t\t    const struct rte_pci_addr *pci_addr, int socket_id,\n+\t\t    const struct sfc_dp_tx_qcreate_info *info,\n+\t\t    struct sfc_dp_txq **dp_txqp)\n+{\n+\tstruct sfc_ef100_txq *txq;\n+\tint rc;\n+\n+\trc = EINVAL;\n+\tif (info->txq_entries != info->evq_entries)\n+\t\tgoto fail_bad_args;\n+\n+\trc = ENOMEM;\n+\ttxq = rte_zmalloc_socket(\"sfc-ef100-txq\", sizeof(*txq),\n+\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (txq == NULL)\n+\t\tgoto fail_txq_alloc;\n+\n+\tsfc_dp_queue_init(&txq->dp.dpq, port_id, queue_id, pci_addr);\n+\n+\trc = ENOMEM;\n+\ttxq->sw_ring = rte_calloc_socket(\"sfc-ef100-txq-sw_ring\",\n+\t\t\t\t\t info->txq_entries,\n+\t\t\t\t\t sizeof(*txq->sw_ring),\n+\t\t\t\t\t RTE_CACHE_LINE_SIZE, socket_id);\n+\tif (txq->sw_ring == NULL)\n+\t\tgoto fail_sw_ring_alloc;\n+\n+\ttxq->flags = SFC_EF100_TXQ_NOT_RUNNING;\n+\ttxq->ptr_mask = info->txq_entries - 1;\n+\ttxq->max_fill_level = info->max_fill_level;\n+\ttxq->free_thresh = info->free_thresh;\n+\ttxq->evq_phase_bit_shift = rte_bsf32(info->evq_entries);\n+\ttxq->txq_hw_ring = info->txq_hw_ring;\n+\ttxq->doorbell = (volatile uint8_t *)info->mem_bar +\n+\t\t\tER_GZ_TX_RING_DOORBELL_OFST +\n+\t\t\t(info->hw_index << info->vi_window_shift);\n+\ttxq->evq_hw_ring = info->evq_hw_ring;\n+\n+\tsfc_ef100_tx_debug(txq, \"TxQ doorbell is %p\", txq->doorbell);\n+\n+\t*dp_txqp = &txq->dp;\n+\treturn 0;\n+\n+fail_sw_ring_alloc:\n+\trte_free(txq);\n+\n+fail_txq_alloc:\n+fail_bad_args:\n+\treturn rc;\n+}\n+\n+static sfc_dp_tx_qdestroy_t sfc_ef100_tx_qdestroy;\n+static void\n+sfc_ef100_tx_qdestroy(struct sfc_dp_txq *dp_txq)\n+{\n+\tstruct sfc_ef100_txq *txq = sfc_ef100_txq_by_dp_txq(dp_txq);\n+\n+\trte_free(txq->sw_ring);\n+\trte_free(txq);\n+}\n+\n+static sfc_dp_tx_qstart_t sfc_ef100_tx_qstart;\n+static int\n+sfc_ef100_tx_qstart(struct sfc_dp_txq *dp_txq, unsigned int evq_read_ptr,\n+\t\t   unsigned int txq_desc_index)\n+{\n+\tstruct sfc_ef100_txq *txq = sfc_ef100_txq_by_dp_txq(dp_txq);\n+\n+\ttxq->evq_read_ptr = evq_read_ptr;\n+\ttxq->added = txq->completed = txq_desc_index;\n+\n+\ttxq->flags |= SFC_EF100_TXQ_STARTED;\n+\ttxq->flags &= ~(SFC_EF100_TXQ_NOT_RUNNING | SFC_EF100_TXQ_EXCEPTION);\n+\n+\treturn 0;\n+}\n+\n+static sfc_dp_tx_qstop_t sfc_ef100_tx_qstop;\n+static void\n+sfc_ef100_tx_qstop(struct sfc_dp_txq *dp_txq, unsigned int *evq_read_ptr)\n+{\n+\tstruct sfc_ef100_txq *txq = sfc_ef100_txq_by_dp_txq(dp_txq);\n+\n+\ttxq->flags |= SFC_EF100_TXQ_NOT_RUNNING;\n+\n+\t*evq_read_ptr = txq->evq_read_ptr;\n+}\n+\n+static sfc_dp_tx_qtx_ev_t sfc_ef100_tx_qtx_ev;\n+static bool\n+sfc_ef100_tx_qtx_ev(struct sfc_dp_txq *dp_txq, unsigned int num_descs)\n+{\n+\tstruct sfc_ef100_txq *txq = sfc_ef100_txq_by_dp_txq(dp_txq);\n+\n+\tSFC_ASSERT(txq->flags & SFC_EF100_TXQ_NOT_RUNNING);\n+\n+\tsfc_ef100_tx_reap_num_descs(txq, num_descs);\n+\n+\treturn false;\n+}\n+\n+static sfc_dp_tx_qreap_t sfc_ef100_tx_qreap;\n+static void\n+sfc_ef100_tx_qreap(struct sfc_dp_txq *dp_txq)\n+{\n+\tstruct sfc_ef100_txq *txq = sfc_ef100_txq_by_dp_txq(dp_txq);\n+\tunsigned int completed;\n+\n+\tfor (completed = txq->completed; completed != txq->added; ++completed) {\n+\t\tstruct sfc_ef100_tx_sw_desc *txd;\n+\n+\t\ttxd = &txq->sw_ring[completed & txq->ptr_mask];\n+\t\tif (txd->mbuf != NULL) {\n+\t\t\trte_pktmbuf_free_seg(txd->mbuf);\n+\t\t\ttxd->mbuf = NULL;\n+\t\t}\n+\t}\n+\n+\ttxq->flags &= ~SFC_EF100_TXQ_STARTED;\n+}\n+\n+static unsigned int\n+sfc_ef100_tx_qdesc_npending(struct sfc_ef100_txq *txq)\n+{\n+\tconst unsigned int evq_old_read_ptr = txq->evq_read_ptr;\n+\tunsigned int npending = 0;\n+\tefx_qword_t tx_ev;\n+\n+\tif (unlikely(txq->flags &\n+\t\t     (SFC_EF100_TXQ_NOT_RUNNING | SFC_EF100_TXQ_EXCEPTION)))\n+\t\treturn 0;\n+\n+\twhile (sfc_ef100_tx_get_event(txq, &tx_ev))\n+\t\tnpending += EFX_QWORD_FIELD(tx_ev, ESF_GZ_EV_TXCMPL_NUM_DESC);\n+\n+\t/*\n+\t * The function does not process events, so return event queue read\n+\t * pointer to the original position to allow the events that were\n+\t * read to be processed later\n+\t */\n+\ttxq->evq_read_ptr = evq_old_read_ptr;\n+\n+\treturn npending;\n+}\n+\n+static sfc_dp_tx_qdesc_status_t sfc_ef100_tx_qdesc_status;\n+static int\n+sfc_ef100_tx_qdesc_status(struct sfc_dp_txq *dp_txq, uint16_t offset)\n+{\n+\tstruct sfc_ef100_txq *txq = sfc_ef100_txq_by_dp_txq(dp_txq);\n+\tunsigned int pushed = txq->added - txq->completed;\n+\n+\tif (unlikely(offset > txq->ptr_mask))\n+\t\treturn -EINVAL;\n+\n+\tif (unlikely(offset >= txq->max_fill_level))\n+\t\treturn RTE_ETH_TX_DESC_UNAVAIL;\n+\n+\treturn (offset >= pushed ||\n+\t\toffset < sfc_ef100_tx_qdesc_npending(txq)) ?\n+\t\tRTE_ETH_TX_DESC_DONE : RTE_ETH_TX_DESC_FULL;\n+}\n+\n+struct sfc_dp_tx sfc_ef100_tx = {\n+\t.dp = {\n+\t\t.name\t\t= SFC_KVARG_DATAPATH_EF100,\n+\t\t.type\t\t= SFC_DP_TX,\n+\t\t.hw_fw_caps\t= SFC_DP_HW_FW_CAP_EF100,\n+\t},\n+\t.features\t\t= SFC_DP_TX_FEAT_MULTI_PROCESS,\n+\t.dev_offload_capa\t= 0,\n+\t.queue_offload_capa\t= 0,\n+\t.get_dev_info\t\t= sfc_ef100_get_dev_info,\n+\t.qsize_up_rings\t\t= sfc_ef100_tx_qsize_up_rings,\n+\t.qcreate\t\t= sfc_ef100_tx_qcreate,\n+\t.qdestroy\t\t= sfc_ef100_tx_qdestroy,\n+\t.qstart\t\t\t= sfc_ef100_tx_qstart,\n+\t.qtx_ev\t\t\t= sfc_ef100_tx_qtx_ev,\n+\t.qstop\t\t\t= sfc_ef100_tx_qstop,\n+\t.qreap\t\t\t= sfc_ef100_tx_qreap,\n+\t.qdesc_status\t\t= sfc_ef100_tx_qdesc_status,\n+\t.pkt_burst\t\t= sfc_ef100_xmit_pkts,\n+};\ndiff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c\nindex e1db9236e9..165776b652 100644\n--- a/drivers/net/sfc/sfc_ethdev.c\n+++ b/drivers/net/sfc/sfc_ethdev.c\n@@ -2156,6 +2156,7 @@ sfc_register_dp(void)\n \t\tsfc_dp_register(&sfc_dp_head, &sfc_ef10_rx.dp);\n \t\tsfc_dp_register(&sfc_dp_head, &sfc_efx_rx.dp);\n \n+\t\tsfc_dp_register(&sfc_dp_head, &sfc_ef100_tx.dp);\n \t\tsfc_dp_register(&sfc_dp_head, &sfc_ef10_tx.dp);\n \t\tsfc_dp_register(&sfc_dp_head, &sfc_efx_tx.dp);\n \t\tsfc_dp_register(&sfc_dp_head, &sfc_ef10_simple_tx.dp);\ndiff --git a/drivers/net/sfc/sfc_kvargs.h b/drivers/net/sfc/sfc_kvargs.h\nindex cc3f4a353e..0c3660890c 100644\n--- a/drivers/net/sfc/sfc_kvargs.h\n+++ b/drivers/net/sfc/sfc_kvargs.h\n@@ -47,7 +47,8 @@ extern \"C\" {\n #define SFC_KVARG_VALUES_TX_DATAPATH \\\n \t\"[\" SFC_KVARG_DATAPATH_EFX \"|\" \\\n \t    SFC_KVARG_DATAPATH_EF10 \"|\" \\\n-\t    SFC_KVARG_DATAPATH_EF10_SIMPLE \"]\"\n+\t    SFC_KVARG_DATAPATH_EF10_SIMPLE \"|\" \\\n+\t    SFC_KVARG_DATAPATH_EF100 \"]\"\n \n #define SFC_KVARG_FW_VARIANT\t\t\"fw_variant\"\n \n",
    "prefixes": [
        "17/36"
    ]
}