get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 46179,
    "url": "http://patches.dpdk.org/api/patches/46179/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1538750823-26291-3-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": "<1538750823-26291-3-git-send-email-arybchenko@solarflare.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1538750823-26291-3-git-send-email-arybchenko@solarflare.com",
    "date": "2018-10-05T14:47:02",
    "name": "[2/3] net/sfc: support TSO in EF10 Tx datapath",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "016518a55c276cfe4db09efafb2a66978aa19e9c",
    "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/1538750823-26291-3-git-send-email-arybchenko@solarflare.com/mbox/",
    "series": [
        {
            "id": 1721,
            "url": "http://patches.dpdk.org/api/series/1721/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=1721",
            "date": "2018-10-05T14:47:00",
            "name": "net/sfc: support more features in EF10 Tx",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/1721/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/46179/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/46179/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 87F5E1B3A0;\n\tFri,  5 Oct 2018 16:47:19 +0200 (CEST)",
            "from dispatch1-us1.ppe-hosted.com (dispatch1-us1.ppe-hosted.com\n\t[148.163.129.52]) by dpdk.org (Postfix) with ESMTP id 828551B17B\n\tfor <dev@dpdk.org>; Fri,  5 Oct 2018 16:47:12 +0200 (CEST)",
            "from webmail.solarflare.com (webmail.solarflare.com\n\t[12.187.104.26])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby mx1-us3.ppe-hosted.com (Proofpoint Essentials ESMTP Server) with\n\tESMTPS id 4676FB40071; Fri,  5 Oct 2018 14:47:11 +0000 (UTC)",
            "from ocex03.SolarFlarecom.com (10.20.40.36) by\n\tocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server\n\t(TLS) id 15.0.1395.4; Fri, 5 Oct 2018 07:47:08 -0700",
            "from opal.uk.solarflarecom.com (10.17.10.1) by\n\tocex03.SolarFlarecom.com (10.20.40.36) with Microsoft SMTP Server\n\t(TLS) id\n\t15.0.1395.4 via Frontend Transport; Fri, 5 Oct 2018 07:47:07 -0700",
            "from ukv-loginhost.uk.solarflarecom.com\n\t(ukv-loginhost.uk.solarflarecom.com [10.17.10.39])\n\tby opal.uk.solarflarecom.com (8.13.8/8.13.8) with ESMTP id\n\tw95El6P8018897; Fri, 5 Oct 2018 15:47:06 +0100",
            "from ukv-loginhost.uk.solarflarecom.com (localhost [127.0.0.1])\n\tby ukv-loginhost.uk.solarflarecom.com (Postfix) with ESMTP id\n\t6521F1626D1; Fri,  5 Oct 2018 15:47:06 +0100 (BST)"
        ],
        "X-Virus-Scanned": "Proofpoint Essentials engine",
        "From": "Andrew Rybchenko <arybchenko@solarflare.com>",
        "To": "<dev@dpdk.org>",
        "CC": "Igor Romanov <Igor.Romanov@oktetlabs.ru>",
        "Date": "Fri, 5 Oct 2018 15:47:02 +0100",
        "Message-ID": "<1538750823-26291-3-git-send-email-arybchenko@solarflare.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1538750823-26291-1-git-send-email-arybchenko@solarflare.com>",
        "References": "<1538750823-26291-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.5.1010-24136.004",
        "X-TM-AS-Result": "No-17.547200-4.000000-10",
        "X-TMASE-MatchedRID": "VOCUlxS4+Q/GWQHDiYaPQMOD5TU1KZy5sWUZQBVIt+W5ZjHyzYrpGjf3\n\tppjXzWfdvQNocDPyarbvt57xoellcEo1MXxuaHLxMIiU395I8H1x/YI+Z5QJkiz+5QCTrE/s+Vi\n\thXqn9xLE9lr5QDEf+LU6nIMfjRtNUId18tSp0CERtzb3s8Aa1Zlg3VqSTJ7SowDR44lliPu0z8p\n\t/PnuqNlcNBH0RyPgywQYEHGIEz/klHOh+HtZFlz+KXavbHY/C11ieB39bGM2Q67wHukzcC5T6VD\n\tdX4IXNTdiHZeSOUI2q0PGZ4gU7Knzf6GcWCp0/iwCZxkTHxccnaoFJAcCHymEsHGbVW/dGwTRx2\n\t+897huywTuiGw3cLx0VGecLf1yNM1r+MhmhnIoVCnGIuUMP0VWEN005hkpAW82HMiBe0UlWTFEi\n\tsFTBWjBcsek2O+rdpW1Gv3YQwcku8gZ3CDqQ7fEhwlOfYeSqx7Le741QScwhaW2Ktn+I8/oEpJR\n\tcbelqdADXE8V3mpEUqkD/wgzJ7Tpjgdm4pKakwx/nZUPmsnJmjkoGZwmjMNiS30GKAkBxWOATXk\n\tqj2pKGUWIvu9WZqyWecCQkJfD9t9dXaIcOJDZ/robZps+Pq2H0tCKdnhB589yM15V5aWpj6C0eP\n\ts7A07QKmARN5PTKc",
        "X-TM-AS-User-Approved-Sender": "No",
        "X-TM-AS-User-Blocked-Sender": "No",
        "X-TMASE-Result": "10--17.547200-4.000000",
        "X-TMASE-Version": "SMEX-12.5.0.1300-8.5.1010-24136.004",
        "X-MDID": "1538750831-2Ihij5kYsn3e",
        "Subject": "[dpdk-dev] [PATCH 2/3] net/sfc: support TSO in EF10 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\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Igor Romanov <Igor.Romanov@oktetlabs.ru>\n\nImplementation includes following limitations:\n\n1) Paket's header length must be less than 256 (SFC_TSOH_STD_LEN);\n2) Offset of the TCP header must be less than 208\n   (EF10_TCP_HEADER_OFFSET_LIMIT);\n3) Number of Tx descriptors must be not less than number of descriptors\n   needed for TSO settings plus header plus one data segment.\n\nIf above conditions are not met, the packet is dropped.\n\nIf the maximum descriptor space is insufficient to hold entire TSO packet,\nonly a part of the packet is sent.\n\nSigned-off-by: Igor Romanov <Igor.Romanov@oktetlabs.ru>\nSigned-off-by: Andrew Rybchenko <arybchenko@solarflare.com>\n---\n doc/guides/nics/sfc_efx.rst            |   3 +-\n doc/guides/rel_notes/release_18_11.rst |   1 +\n drivers/net/sfc/sfc_dp_tx.h            |   5 +\n drivers/net/sfc/sfc_ef10_tx.c          | 321 ++++++++++++++++++++++++-\n drivers/net/sfc/sfc_tso.h              |   6 +\n drivers/net/sfc/sfc_tx.c               |   2 +\n 6 files changed, 335 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst\nindex a241f00bc..40065284b 100644\n--- a/doc/guides/nics/sfc_efx.rst\n+++ b/doc/guides/nics/sfc_efx.rst\n@@ -337,8 +337,7 @@ boolean parameters value.\n   Mbuf segments may come from different mempools, and mbuf reference\n   counters are treated responsibly.\n   **ef10** chooses EF10 (SFN7xxx, SFN8xxx, X2xxx) native datapath which is\n-  more efficient than libefx-based but has no VLAN insertion and TSO\n-  support yet.\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   counters are treated responsibly.\n   **ef10_simple** chooses EF10 (SFN7xxx, SFN8xxx, X2xxx) native datapath which\ndiff --git a/doc/guides/rel_notes/release_18_11.rst b/doc/guides/rel_notes/release_18_11.rst\nindex 89ca3317f..cbf08a76e 100644\n--- a/doc/guides/rel_notes/release_18_11.rst\n+++ b/doc/guides/rel_notes/release_18_11.rst\n@@ -88,6 +88,7 @@ New Features\n \n   * Added support for Rx scatter in EF10 datapath implementation.\n   * Added support for Rx descriptor status API in EF10 datapath implementation.\n+  * Added support for TSO in EF10 datapath implementation.\n \n * **Updated failsafe driver.**\n \ndiff --git a/drivers/net/sfc/sfc_dp_tx.h b/drivers/net/sfc/sfc_dp_tx.h\nindex eda9676c8..c246871cd 100644\n--- a/drivers/net/sfc/sfc_dp_tx.h\n+++ b/drivers/net/sfc/sfc_dp_tx.h\n@@ -57,6 +57,11 @@ struct sfc_dp_tx_qcreate_info {\n \tvolatile void\t\t*mem_bar;\n \t/** VI window size shift */\n \tunsigned int\t\tvi_window_shift;\n+\t/**\n+\t * Maximum number of bytes into the packet the TCP header can start for\n+\t * the hardware to apply TSO packet edits.\n+\t */\n+\tuint16_t\t\ttso_tcp_header_offset_limit;\n };\n \n /**\ndiff --git a/drivers/net/sfc/sfc_ef10_tx.c b/drivers/net/sfc/sfc_ef10_tx.c\nindex d0daa3b3f..c97e3bad0 100644\n--- a/drivers/net/sfc/sfc_ef10_tx.c\n+++ b/drivers/net/sfc/sfc_ef10_tx.c\n@@ -11,6 +11,8 @@\n \n #include <rte_mbuf.h>\n #include <rte_io.h>\n+#include <rte_ip.h>\n+#include <rte_tcp.h>\n \n #include \"efx.h\"\n #include \"efx_types.h\"\n@@ -21,6 +23,7 @@\n #include \"sfc_tweak.h\"\n #include \"sfc_kvargs.h\"\n #include \"sfc_ef10.h\"\n+#include \"sfc_tso.h\"\n \n #define sfc_ef10_tx_err(dpq, ...) \\\n \tSFC_DP_LOG(SFC_KVARG_DATAPATH_EF10, ERR, dpq, __VA_ARGS__)\n@@ -62,6 +65,9 @@ struct sfc_ef10_txq {\n \tefx_qword_t\t\t\t*txq_hw_ring;\n \tvolatile void\t\t\t*doorbell;\n \tefx_qword_t\t\t\t*evq_hw_ring;\n+\tuint8_t\t\t\t\t*tsoh;\n+\trte_iova_t\t\t\ttsoh_iova;\n+\tuint16_t\t\t\ttso_tcp_header_offset_limit;\n \n \t/* Datapath transmit queue anchor */\n \tstruct sfc_dp_txq\t\tdp;\n@@ -184,6 +190,30 @@ sfc_ef10_tx_qdesc_dma_create(rte_iova_t addr, uint16_t size, bool eop,\n \t\t\t     ESF_DZ_TX_KER_BUF_ADDR, addr);\n }\n \n+static void\n+sfc_ef10_tx_qdesc_tso2_create(struct sfc_ef10_txq * const txq,\n+\t\t\t      unsigned int added, uint16_t ipv4_id,\n+\t\t\t      uint16_t outer_ipv4_id, uint32_t tcp_seq,\n+\t\t\t      uint16_t tcp_mss)\n+{\n+\tEFX_POPULATE_QWORD_5(txq->txq_hw_ring[added & txq->ptr_mask],\n+\t\t\t    ESF_DZ_TX_DESC_IS_OPT, 1,\n+\t\t\t    ESF_DZ_TX_OPTION_TYPE,\n+\t\t\t    ESE_DZ_TX_OPTION_DESC_TSO,\n+\t\t\t    ESF_DZ_TX_TSO_OPTION_TYPE,\n+\t\t\t    ESE_DZ_TX_TSO_OPTION_DESC_FATSO2A,\n+\t\t\t    ESF_DZ_TX_TSO_IP_ID, ipv4_id,\n+\t\t\t    ESF_DZ_TX_TSO_TCP_SEQNO, tcp_seq);\n+\tEFX_POPULATE_QWORD_5(txq->txq_hw_ring[(added + 1) & txq->ptr_mask],\n+\t\t\t    ESF_DZ_TX_DESC_IS_OPT, 1,\n+\t\t\t    ESF_DZ_TX_OPTION_TYPE,\n+\t\t\t    ESE_DZ_TX_OPTION_DESC_TSO,\n+\t\t\t    ESF_DZ_TX_TSO_OPTION_TYPE,\n+\t\t\t    ESE_DZ_TX_TSO_OPTION_DESC_FATSO2B,\n+\t\t\t    ESF_DZ_TX_TSO_TCP_MSS, tcp_mss,\n+\t\t\t    ESF_DZ_TX_TSO_OUTER_IPID, outer_ipv4_id);\n+}\n+\n static inline void\n sfc_ef10_tx_qpush(struct sfc_ef10_txq *txq, unsigned int added,\n \t\t  unsigned int pushed)\n@@ -263,6 +293,252 @@ sfc_ef10_tx_pkt_descs_max(const struct rte_mbuf *m)\n \t\t\t\t    extra_descs_per_pkt);\n }\n \n+static bool\n+sfc_ef10_try_reap(struct sfc_ef10_txq * const txq, unsigned int added,\n+\t\t  unsigned int needed_desc, unsigned int *dma_desc_space,\n+\t\t  bool *reap_done)\n+{\n+\tif (*reap_done)\n+\t\treturn false;\n+\n+\tif (added != txq->added) {\n+\t\tsfc_ef10_tx_qpush(txq, added, txq->added);\n+\t\ttxq->added = added;\n+\t}\n+\n+\tsfc_ef10_tx_reap(txq);\n+\t*reap_done = true;\n+\n+\t/*\n+\t * Recalculate DMA descriptor space since Tx reap may change\n+\t * the number of completed descriptors\n+\t */\n+\t*dma_desc_space = txq->max_fill_level -\n+\t\t(added - txq->completed);\n+\n+\treturn (needed_desc <= *dma_desc_space);\n+}\n+\n+static int\n+sfc_ef10_xmit_tso_pkt(struct sfc_ef10_txq * const txq, struct rte_mbuf *m_seg,\n+\t\t      unsigned int *added, unsigned int *dma_desc_space,\n+\t\t      bool *reap_done)\n+{\n+\tsize_t iph_off = m_seg->l2_len;\n+\tsize_t tcph_off = m_seg->l2_len + m_seg->l3_len;\n+\tsize_t header_len = m_seg->l2_len + m_seg->l3_len + m_seg->l4_len;\n+\t/* Offset of the payload in the last segment that contains the header */\n+\tsize_t in_off = 0;\n+\tconst struct tcp_hdr *th;\n+\tuint16_t packet_id;\n+\tuint32_t sent_seq;\n+\tuint8_t *hdr_addr;\n+\trte_iova_t hdr_iova;\n+\tstruct rte_mbuf *first_m_seg = m_seg;\n+\tunsigned int pkt_start = *added;\n+\tunsigned int needed_desc;\n+\tstruct rte_mbuf *m_seg_to_free_up_to = first_m_seg;\n+\tbool eop;\n+\n+\t/* Both checks may be done, so use bit OR to have only one branching */\n+\tif (unlikely((header_len > SFC_TSOH_STD_LEN) |\n+\t\t     (tcph_off > txq->tso_tcp_header_offset_limit)))\n+\t\treturn EMSGSIZE;\n+\n+\t/*\n+\t * Preliminary estimation of required DMA descriptors, including extra\n+\t * descriptor for TSO header that is needed when the header is\n+\t * separated from payload in one segment. It does not include\n+\t * extra descriptors that may appear when a big segment is split across\n+\t * several descriptors.\n+\t */\n+\tneeded_desc = m_seg->nb_segs +\n+\t\t\t(unsigned int)SFC_TSO_OPT_DESCS_NUM +\n+\t\t\t(unsigned int)SFC_TSO_HDR_DESCS_NUM;\n+\n+\tif (needed_desc > *dma_desc_space &&\n+\t    !sfc_ef10_try_reap(txq, pkt_start, needed_desc,\n+\t\t\t       dma_desc_space, reap_done)) {\n+\t\t/*\n+\t\t * If a future Tx reap may increase available DMA descriptor\n+\t\t * space, do not try to send the packet.\n+\t\t */\n+\t\tif (txq->completed != pkt_start)\n+\t\t\treturn ENOSPC;\n+\t\t/*\n+\t\t * Do not allow to send packet if the maximum DMA\n+\t\t * descriptor space is not sufficient to hold TSO\n+\t\t * descriptors, header descriptor and at least 1\n+\t\t * segment descriptor.\n+\t\t */\n+\t\tif (*dma_desc_space < SFC_TSO_OPT_DESCS_NUM +\n+\t\t\t\tSFC_TSO_HDR_DESCS_NUM + 1)\n+\t\t\treturn EMSGSIZE;\n+\t}\n+\n+\t/* Check if the header is not fragmented */\n+\tif (rte_pktmbuf_data_len(m_seg) >= header_len) {\n+\t\thdr_addr = rte_pktmbuf_mtod(m_seg, uint8_t *);\n+\t\thdr_iova = rte_mbuf_data_iova(m_seg);\n+\t\tif (rte_pktmbuf_data_len(m_seg) == header_len) {\n+\t\t\t/*\n+\t\t\t * Associate header mbuf with header descriptor\n+\t\t\t * which is located after TSO descriptors.\n+\t\t\t */\n+\t\t\ttxq->sw_ring[(pkt_start + SFC_TSO_OPT_DESCS_NUM) &\n+\t\t\t\t     txq->ptr_mask].mbuf = m_seg;\n+\t\t\tm_seg = m_seg->next;\n+\t\t\tin_off = 0;\n+\n+\t\t\t/*\n+\t\t\t * If there is no payload offset (payload starts at the\n+\t\t\t * beginning of a segment) then an extra descriptor for\n+\t\t\t * separated header is not needed.\n+\t\t\t */\n+\t\t\tneeded_desc--;\n+\t\t} else {\n+\t\t\tin_off = header_len;\n+\t\t}\n+\t} else {\n+\t\tunsigned int copied_segs;\n+\t\tunsigned int hdr_addr_off = (*added & txq->ptr_mask) *\n+\t\t\t\tSFC_TSOH_STD_LEN;\n+\n+\t\thdr_addr = txq->tsoh + hdr_addr_off;\n+\t\thdr_iova = txq->tsoh_iova + hdr_addr_off;\n+\t\tcopied_segs = sfc_tso_prepare_header(hdr_addr, header_len,\n+\t\t\t\t\t\t     &m_seg, &in_off);\n+\n+\t\tm_seg_to_free_up_to = m_seg;\n+\t\t/*\n+\t\t * Reduce the number of needed descriptors by the number of\n+\t\t * segments that entirely consist of header data.\n+\t\t */\n+\t\tneeded_desc -= copied_segs;\n+\n+\t\t/* Extra descriptor for separated header is not needed */\n+\t\tif (in_off == 0)\n+\t\t\tneeded_desc--;\n+\t}\n+\n+\tswitch (first_m_seg->ol_flags & (PKT_TX_IPV4 | PKT_TX_IPV6)) {\n+\tcase PKT_TX_IPV4: {\n+\t\tconst struct ipv4_hdr *iphe4;\n+\n+\t\tiphe4 = (const struct ipv4_hdr *)(hdr_addr + iph_off);\n+\t\trte_memcpy(&packet_id, &iphe4->packet_id, sizeof(uint16_t));\n+\t\tpacket_id = rte_be_to_cpu_16(packet_id);\n+\t\tbreak;\n+\t}\n+\tcase PKT_TX_IPV6:\n+\t\tpacket_id = 0;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn EINVAL;\n+\t}\n+\n+\tth = (const struct tcp_hdr *)(hdr_addr + tcph_off);\n+\trte_memcpy(&sent_seq, &th->sent_seq, sizeof(uint32_t));\n+\tsent_seq = rte_be_to_cpu_32(sent_seq);\n+\n+\tsfc_ef10_tx_qdesc_tso2_create(txq, *added, packet_id, 0, sent_seq,\n+\t\t\tfirst_m_seg->tso_segsz);\n+\t(*added) += SFC_TSO_OPT_DESCS_NUM;\n+\n+\tsfc_ef10_tx_qdesc_dma_create(hdr_iova, header_len, false,\n+\t\t\t&txq->txq_hw_ring[(*added) & txq->ptr_mask]);\n+\t(*added)++;\n+\n+\tdo {\n+\t\trte_iova_t next_frag = rte_mbuf_data_iova(m_seg);\n+\t\tunsigned int seg_len = rte_pktmbuf_data_len(m_seg);\n+\t\tunsigned int id;\n+\n+\t\tnext_frag += in_off;\n+\t\tseg_len -= in_off;\n+\t\tin_off = 0;\n+\n+\t\tdo {\n+\t\t\trte_iova_t frag_addr = next_frag;\n+\t\t\tsize_t frag_len;\n+\n+\t\t\tfrag_len = RTE_MIN(seg_len,\n+\t\t\t\t\t   SFC_EF10_TX_DMA_DESC_LEN_MAX);\n+\n+\t\t\tnext_frag += frag_len;\n+\t\t\tseg_len -= frag_len;\n+\n+\t\t\teop = (seg_len == 0 && m_seg->next == NULL);\n+\n+\t\t\tid = (*added) & txq->ptr_mask;\n+\t\t\t(*added)++;\n+\n+\t\t\t/*\n+\t\t\t * Initially we assume that one DMA descriptor is needed\n+\t\t\t * for every segment. When the segment is split across\n+\t\t\t * several DMA descriptors, increase the estimation.\n+\t\t\t */\n+\t\t\tneeded_desc += (seg_len != 0);\n+\n+\t\t\t/*\n+\t\t\t * When no more descriptors can be added, but not all\n+\t\t\t * segments are processed.\n+\t\t\t */\n+\t\t\tif (*added - pkt_start == *dma_desc_space &&\n+\t\t\t    !eop &&\n+\t\t\t    !sfc_ef10_try_reap(txq, pkt_start, needed_desc,\n+\t\t\t\t\t\tdma_desc_space, reap_done)) {\n+\t\t\t\tstruct rte_mbuf *m;\n+\t\t\t\tstruct rte_mbuf *m_next;\n+\n+\t\t\t\tif (txq->completed != pkt_start) {\n+\t\t\t\t\tunsigned int i;\n+\n+\t\t\t\t\t/*\n+\t\t\t\t\t * Reset mbuf associations with added\n+\t\t\t\t\t * descriptors.\n+\t\t\t\t\t */\n+\t\t\t\t\tfor (i = pkt_start; i != *added; i++) {\n+\t\t\t\t\t\tid = i & txq->ptr_mask;\n+\t\t\t\t\t\ttxq->sw_ring[id].mbuf = NULL;\n+\t\t\t\t\t}\n+\t\t\t\t\treturn ENOSPC;\n+\t\t\t\t}\n+\n+\t\t\t\t/* Free the segments that cannot be sent */\n+\t\t\t\tfor (m = m_seg->next; m != NULL; m = m_next) {\n+\t\t\t\t\tm_next = m->next;\n+\t\t\t\t\trte_pktmbuf_free_seg(m);\n+\t\t\t\t}\n+\t\t\t\teop = true;\n+\t\t\t\t/* Ignore the rest of the segment */\n+\t\t\t\tseg_len = 0;\n+\t\t\t}\n+\n+\t\t\tsfc_ef10_tx_qdesc_dma_create(frag_addr, frag_len,\n+\t\t\t\t\teop, &txq->txq_hw_ring[id]);\n+\n+\t\t} while (seg_len != 0);\n+\n+\t\ttxq->sw_ring[id].mbuf = m_seg;\n+\n+\t\tm_seg = m_seg->next;\n+\t} while (!eop);\n+\n+\t/*\n+\t * Free segments which content was entirely copied to the TSO header\n+\t * memory space of Tx queue\n+\t */\n+\tfor (m_seg = first_m_seg; m_seg != m_seg_to_free_up_to;) {\n+\t\tstruct rte_mbuf *seg_to_free = m_seg;\n+\n+\t\tm_seg = m_seg->next;\n+\t\trte_pktmbuf_free_seg(seg_to_free);\n+\t}\n+\n+\treturn 0;\n+}\n+\n static uint16_t\n sfc_ef10_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n {\n@@ -296,6 +572,30 @@ sfc_ef10_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n \t\tif (likely(pktp + 1 != pktp_end))\n \t\t\trte_mbuf_prefetch_part1(pktp[1]);\n \n+\t\tif (m_seg->ol_flags & PKT_TX_TCP_SEG) {\n+\t\t\tint rc;\n+\n+\t\t\trc = sfc_ef10_xmit_tso_pkt(txq, m_seg, &added,\n+\t\t\t\t\t&dma_desc_space, &reap_done);\n+\t\t\tif (rc != 0) {\n+\t\t\t\tadded = pkt_start;\n+\n+\t\t\t\t/* Packet can be sent in following xmit calls */\n+\t\t\t\tif (likely(rc == ENOSPC))\n+\t\t\t\t\tbreak;\n+\n+\t\t\t\t/*\n+\t\t\t\t * Packet cannot be sent, tell RTE that\n+\t\t\t\t * it is sent, but actually drop it and\n+\t\t\t\t * continue with another packet\n+\t\t\t\t */\n+\t\t\t\trte_pktmbuf_free(*pktp);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tgoto dma_desc_space_update;\n+\t\t}\n+\n \t\tif (sfc_ef10_tx_pkt_descs_max(m_seg) > dma_desc_space) {\n \t\t\tif (reap_done)\n \t\t\t\tbreak;\n@@ -349,6 +649,7 @@ sfc_ef10_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)\n \n \t\t} while ((m_seg = m_seg->next) != 0);\n \n+dma_desc_space_update:\n \t\tdma_desc_space -= (added - pkt_start);\n \t}\n \n@@ -524,6 +825,18 @@ sfc_ef10_tx_qcreate(uint16_t port_id, uint16_t queue_id,\n \tif (txq->sw_ring == NULL)\n \t\tgoto fail_sw_ring_alloc;\n \n+\tif (info->offloads & DEV_TX_OFFLOAD_TCP_TSO) {\n+\t\ttxq->tsoh = rte_calloc_socket(\"sfc-ef10-txq-tsoh\",\n+\t\t\t\t\t      info->txq_entries,\n+\t\t\t\t\t      SFC_TSOH_STD_LEN,\n+\t\t\t\t\t      RTE_CACHE_LINE_SIZE,\n+\t\t\t\t\t      socket_id);\n+\t\tif (txq->tsoh == NULL)\n+\t\t\tgoto fail_tsoh_alloc;\n+\n+\t\ttxq->tsoh_iova = rte_malloc_virt2iova(txq->tsoh);\n+\t}\n+\n \ttxq->flags = SFC_EF10_TXQ_NOT_RUNNING;\n \ttxq->ptr_mask = info->txq_entries - 1;\n \ttxq->max_fill_level = info->max_fill_level;\n@@ -533,10 +846,14 @@ sfc_ef10_tx_qcreate(uint16_t port_id, uint16_t queue_id,\n \t\t\tER_DZ_TX_DESC_UPD_REG_OFST +\n \t\t\t(info->hw_index << info->vi_window_shift);\n \ttxq->evq_hw_ring = info->evq_hw_ring;\n+\ttxq->tso_tcp_header_offset_limit = info->tso_tcp_header_offset_limit;\n \n \t*dp_txqp = &txq->dp;\n \treturn 0;\n \n+fail_tsoh_alloc:\n+\trte_free(txq->sw_ring);\n+\n fail_sw_ring_alloc:\n \trte_free(txq);\n \n@@ -551,6 +868,7 @@ sfc_ef10_tx_qdestroy(struct sfc_dp_txq *dp_txq)\n {\n \tstruct sfc_ef10_txq *txq = sfc_ef10_txq_by_dp_txq(dp_txq);\n \n+\trte_free(txq->tsoh);\n \trte_free(txq->sw_ring);\n \trte_free(txq);\n }\n@@ -632,7 +950,8 @@ struct sfc_dp_tx sfc_ef10_tx = {\n \t\t.type\t\t= SFC_DP_TX,\n \t\t.hw_fw_caps\t= SFC_DP_HW_FW_CAP_EF10,\n \t},\n-\t.features\t\t= SFC_DP_TX_FEAT_MULTI_SEG |\n+\t.features\t\t= SFC_DP_TX_FEAT_TSO |\n+\t\t\t\t  SFC_DP_TX_FEAT_MULTI_SEG |\n \t\t\t\t  SFC_DP_TX_FEAT_MULTI_POOL |\n \t\t\t\t  SFC_DP_TX_FEAT_REFCNT |\n \t\t\t\t  SFC_DP_TX_FEAT_MULTI_PROCESS,\ndiff --git a/drivers/net/sfc/sfc_tso.h b/drivers/net/sfc/sfc_tso.h\nindex e8b558f50..3d2faf549 100644\n--- a/drivers/net/sfc/sfc_tso.h\n+++ b/drivers/net/sfc/sfc_tso.h\n@@ -13,5 +13,11 @@\n /** The number of TSO option descriptors that precede the packet descriptors */\n #define SFC_TSO_OPT_DESCS_NUM\t2\n \n+/**\n+ * The number of DMA descriptors for TSO header that may or may not precede the\n+ * packet's payload descriptors\n+ */\n+#define SFC_TSO_HDR_DESCS_NUM\t1\n+\n unsigned int sfc_tso_prepare_header(uint8_t *tsoh, size_t header_len,\n \t\t\t\t    struct rte_mbuf **in_seg, size_t *in_off);\ndiff --git a/drivers/net/sfc/sfc_tx.c b/drivers/net/sfc/sfc_tx.c\nindex 12665d813..147f93365 100644\n--- a/drivers/net/sfc/sfc_tx.c\n+++ b/drivers/net/sfc/sfc_tx.c\n@@ -190,6 +190,8 @@ sfc_tx_qinit(struct sfc_adapter *sa, unsigned int sw_index,\n \tinfo.hw_index = txq->hw_index;\n \tinfo.mem_bar = sa->mem_bar.esb_base;\n \tinfo.vi_window_shift = encp->enc_vi_window_shift;\n+\tinfo.tso_tcp_header_offset_limit =\n+\t\tencp->enc_tx_tso_tcp_header_offset_limit;\n \n \trc = sa->dp_tx->qcreate(sa->eth_dev->data->port_id, sw_index,\n \t\t\t\t&RTE_ETH_DEV_TO_PCI(sa->eth_dev)->addr,\n",
    "prefixes": [
        "2/3"
    ]
}