Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/584322/?format=api
{ "id": 584322, "url": "http://patchwork.ozlabs.org/api/patches/584322/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20160217190249.10339.3566.stgit@localhost.localdomain/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20160217190249.10339.3566.stgit@localhost.localdomain>", "list_archive_url": null, "date": "2016-02-17T19:02:50", "name": "[next,2/4] i40e/i40evf: Rewrite logic for 8 descriptor per packet check", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "6ab436924ae934da332301d230ba091988c1a9af", "submitter": { "id": 67293, "url": "http://patchwork.ozlabs.org/api/people/67293/?format=api", "name": "Alexander Duyck", "email": "aduyck@mirantis.com" }, "delegate": { "id": 68, "url": "http://patchwork.ozlabs.org/api/users/68/?format=api", "username": "jtkirshe", "first_name": "Jeff", "last_name": "Kirsher", "email": "jeffrey.t.kirsher@intel.com" }, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20160217190249.10339.3566.stgit@localhost.localdomain/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/584322/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/584322/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<intel-wired-lan-bounces@lists.osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Received": [ "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ozlabs.org (Postfix) with ESMTP id BBF881401CA\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 18 Feb 2016 06:02:55 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 139E7A5E04;\n\tWed, 17 Feb 2016 19:02:55 +0000 (UTC)", "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 0-i04QHyiszS; Wed, 17 Feb 2016 19:02:54 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 23A98A5E94;\n\tWed, 17 Feb 2016 19:02:54 +0000 (UTC)", "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id E6A901C0BC2\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 17 Feb 2016 19:02:52 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id E2097A5E42\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 17 Feb 2016 19:02:52 +0000 (UTC)", "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id WVov19WAILTz for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 17 Feb 2016 19:02:51 +0000 (UTC)", "from mail-pf0-f178.google.com (mail-pf0-f178.google.com\n\t[209.85.192.178])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id C29C6A5E04\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 17 Feb 2016 19:02:51 +0000 (UTC)", "by mail-pf0-f178.google.com with SMTP id e127so16130131pfe.3\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 17 Feb 2016 11:02:51 -0800 (PST)", "from localhost.localdomain\n\t(static-50-53-29-36.bvtn.or.frontiernet.net. [50.53.29.36])\n\tby smtp.gmail.com with ESMTPSA id\n\tqy7sm1333272pab.34.2016.02.17.11.02.50\n\tfor <intel-wired-lan@lists.osuosl.org>\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tWed, 17 Feb 2016 11:02:50 -0800 (PST)" ], "Authentication-Results": "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=mirantis.com header.i=@mirantis.com\n\theader.b=hHhlP5T5; dkim-atps=neutral", "X-Virus-Scanned": [ "amavisd-new at osuosl.org", "amavisd-new at osuosl.org" ], "X-Greylist": "from auto-whitelisted by SQLgrey-1.7.6", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=mirantis.com;\n\ts=google; \n\th=subject:from:to:date:message-id:in-reply-to:references:user-agent\n\t:mime-version:content-type:content-transfer-encoding;\n\tbh=YzD+Csvd4njApHLX61+hs1GvJ7TaANY+hzqlzLh8WRE=;\n\tb=hHhlP5T5YqyOvs78dzGb8UsxmxDqNZQy95DnThqe3llA0carYBtNsgZQorHJPOFrKb\n\t+Kj3QkqLAhtdjiUVl2pVW95FdjSphhx5QK6WzozLuFUsXFuwNeABeNK0osbc7q8lBUj8\n\t72gx/Da/uIwW7Q0nE4EoIGmS7v45+LWdciZmI=", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20130820;\n\th=x-gm-message-state:subject:from:to:date:message-id:in-reply-to\n\t:references:user-agent:mime-version:content-type\n\t:content-transfer-encoding;\n\tbh=YzD+Csvd4njApHLX61+hs1GvJ7TaANY+hzqlzLh8WRE=;\n\tb=bi76INXnF2x2+K6Webc16DJSn8PQUW7UomPZVe4DkYHCd+yJjuwLyODdKkfeUvX0fV\n\tAn4WgfyD/2bI0WqCx9Or8OvE/w1aB76gZxdidCCm/2cKAxM2qwZzW+7p7hHvdjPdG+7F\n\tudwM5a8UDGtjHECC/5JX9hoYmdSgGU0ebLniNduIaRiMthON26eu9YrcBM+C10rqvzTc\n\tah5GY0Qy3SdXssRUaCayTdzTPh87C4ZTulPc/da973dRvNpNySe5px6Vi7MY0OM8QGmk\n\tVc7/lQdldyT44QKNjTdLn5RlBiqY33vCNYTnbteHkZx8MX3+DTiYprUaWRuwuNNP+MPf\n\t98Pg==", "X-Gm-Message-State": "AG10YOTu2A/m1K4EoIxICmKyYGB9qjhDwlE480R4P3TxSVqZyEAsCXmheSJSWjk5hlYqKRuc", "X-Received": "by 10.98.13.86 with SMTP id v83mr4371120pfi.162.1455735771536;\n\tWed, 17 Feb 2016 11:02:51 -0800 (PST)", "From": "Alexander Duyck <aduyck@mirantis.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Wed, 17 Feb 2016 11:02:50 -0800", "Message-ID": "<20160217190249.10339.3566.stgit@localhost.localdomain>", "In-Reply-To": "<20160217185838.10339.68543.stgit@localhost.localdomain>", "References": "<20160217185838.10339.68543.stgit@localhost.localdomain>", "User-Agent": "StGit/0.17.1-dirty", "MIME-Version": "1.0", "Subject": "[Intel-wired-lan] [next PATCH 2/4] i40e/i40evf: Rewrite logic for 8\n\tdescriptor per packet check", "X-BeenThere": "intel-wired-lan@lists.osuosl.org", "X-Mailman-Version": "2.1.18-1", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.lists.osuosl.org>", "List-Unsubscribe": "<http://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@lists.osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@lists.osuosl.org?subject=help>", "List-Subscribe": "<http://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=subscribe>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "intel-wired-lan-bounces@lists.osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@lists.osuosl.org>" }, "content": "This patch is meant to rewrite the logic for how we determine if we can\ntransmit the frame or if it needs to be linearized.\n\nThe previous code for this function was using a mix of division and modulus\ndivision as a part of computing if we need to take the slow path. Instead\nI have replaced this by simply working with a sliding window which will\ntell us if the frame would be capable of causing a single packet to span\nseveral descriptors.\n\nThe logic for the scan is fairly simple. If any given group of 6 fragments\nis less than gso_size - 1 then it is possible for us to have one byte\ncoming out of the first fragment, 6 fragments, and one or more bytes coming\nout of the last fragment. This gives us a total of 8 fragments\nwhich exceeds what we can allow so we send such frames to be linearized.\n\nArguably the use of modulus might be more exact as the approach I propose\nmay generate some false positives. However the liklihood of us taking much\nof a hit for those false positives is fairly low, and I would rather not\nadd more overhead in the case where we are receiving a frame composed of 4K\npages.\n\nSigned-off-by: Alexander Duyck <aduyck@mirantis.com>\n---\n drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 6 +\n drivers/net/ethernet/intel/i40e/i40e_txrx.c | 105 ++++++++++++++-----------\n drivers/net/ethernet/intel/i40e/i40e_txrx.h | 19 +++++\n drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 105 ++++++++++++++-----------\n drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 19 +++++\n 5 files changed, 162 insertions(+), 92 deletions(-)", "diff": "diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c\nindex 518d72ea1059..052df93f1da4 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c\n@@ -1368,6 +1368,12 @@ static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb,\n \t\tgoto out_drop;\n \n \tcount = i40e_xmit_descriptor_count(skb);\n+\tif (i40e_chk_linearize(skb, count)) {\n+\t\tif (__skb_linearize(skb))\n+\t\t\tgoto out_drop;\n+\t\tcount = TXD_USE_COUNT(skb->len);\n+\t\ttx_ring->tx_stats.tx_linearize++;\n+\t}\n \n \t/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,\n \t * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\nindex f03657022b0f..5123646a895f 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c\n@@ -2593,59 +2593,71 @@ int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)\n }\n \n /**\n- * i40e_chk_linearize - Check if there are more than 8 fragments per packet\n+ * __i40e_chk_linearize - Check if there are more than 8 fragments per packet\n * @skb: send buffer\n- * @tx_flags: collected send information\n *\n * Note: Our HW can't scatter-gather more than 8 fragments to build\n * a packet on the wire and so we need to figure out the cases where we\n * need to linearize the skb.\n **/\n-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)\n+bool __i40e_chk_linearize(struct sk_buff *skb)\n {\n-\tstruct skb_frag_struct *frag;\n-\tbool linearize = false;\n-\tunsigned int size = 0;\n-\tu16 num_frags;\n-\tu16 gso_segs;\n+\tconst struct skb_frag_struct *frag, *stale;\n+\tint gso_size, nr_frags, sum;\n \n-\tnum_frags = skb_shinfo(skb)->nr_frags;\n-\tgso_segs = skb_shinfo(skb)->gso_segs;\n+\t/* check to see if TSO is enabled, if so we may get a repreive */\n+\tgso_size = skb_shinfo(skb)->gso_size;\n+\tif (unlikely(!gso_size))\n+\t\treturn true;\n \n-\tif (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {\n-\t\tu16 j = 0;\n+\t/* no need to check if number of frags is less than 8 */\n+\tnr_frags = skb_shinfo(skb)->nr_frags;\n+\tif (nr_frags < I40E_MAX_BUFFER_TXD)\n+\t\treturn false;\n \n-\t\tif (num_frags < (I40E_MAX_BUFFER_TXD))\n-\t\t\tgoto linearize_chk_done;\n-\t\t/* try the simple math, if we have too many frags per segment */\n-\t\tif (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >\n-\t\t I40E_MAX_BUFFER_TXD) {\n-\t\t\tlinearize = true;\n-\t\t\tgoto linearize_chk_done;\n-\t\t}\n-\t\tfrag = &skb_shinfo(skb)->frags[0];\n-\t\t/* we might still have more fragments per segment */\n-\t\tdo {\n-\t\t\tsize += skb_frag_size(frag);\n-\t\t\tfrag++; j++;\n-\t\t\tif ((size >= skb_shinfo(skb)->gso_size) &&\n-\t\t\t (j < I40E_MAX_BUFFER_TXD)) {\n-\t\t\t\tsize = (size % skb_shinfo(skb)->gso_size);\n-\t\t\t\tj = (size) ? 1 : 0;\n-\t\t\t}\n-\t\t\tif (j == I40E_MAX_BUFFER_TXD) {\n-\t\t\t\tlinearize = true;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tnum_frags--;\n-\t\t} while (num_frags);\n-\t} else {\n-\t\tif (num_frags >= I40E_MAX_BUFFER_TXD)\n-\t\t\tlinearize = true;\n+\t/* We need to walk through the list and validate that each group\n+\t * of 6 fragments totals at least gso_size. However we don't need\n+\t * to perform such validation on the first or last 6 since the first\n+\t * 6 cannot inherit any data from a descriptor before them, and the\n+\t * last 6 cannot inherit any data from a descriptor after them.\n+\t */\n+\tnr_frags -= I40E_MAX_BUFFER_TXD - 1;\n+\tfrag = &skb_shinfo(skb)->frags[0];\n+\n+\t/* Initialize size to the negative value of gso_size minus 1. We\n+\t * use this as the worst case scenerio in which the frag ahead\n+\t * of us only provides one byte which is why we are limited to 6\n+\t * descriptors for a single transmit as the header and previous\n+\t * fragment are already consuming 2 descriptors.\n+\t */\n+\tsum = 1 - gso_size;\n+\n+\t/* Add size of frags 1 through 5 to create our initial sum */\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\n+\t/* Walk through fragments adding latest fragment, testing it, and\n+\t * then removing stale fragments from the sum.\n+\t */\n+\tstale = &skb_shinfo(skb)->frags[0];\n+\tfor (;;) {\n+\t\tsum += skb_frag_size(++frag);\n+\n+\t\t/* if sum is negative we failed to make sufficient progress */\n+\t\tif (sum < 0)\n+\t\t\treturn true;\n+\n+\t\t/* use pre-decrement to avoid processing last fragment */\n+\t\tif (!--nr_frags)\n+\t\t\tbreak;\n+\n+\t\tsum -= skb_frag_size(++stale);\n \t}\n \n-linearize_chk_done:\n-\treturn linearize;\n+\treturn false;\n }\n \n /**\n@@ -2876,6 +2888,12 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,\n \tprefetch(skb->data);\n \n \tcount = i40e_xmit_descriptor_count(skb);\n+\tif (i40e_chk_linearize(skb, count)) {\n+\t\tif (__skb_linearize(skb))\n+\t\t\tgoto out_drop;\n+\t\tcount = TXD_USE_COUNT(skb->len);\n+\t\ttx_ring->tx_stats.tx_linearize++;\n+\t}\n \n \t/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,\n \t * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,\n@@ -2916,11 +2934,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,\n \tif (tsyn)\n \t\ttx_flags |= I40E_TX_FLAGS_TSYN;\n \n-\tif (i40e_chk_linearize(skb, tx_flags)) {\n-\t\tif (skb_linearize(skb))\n-\t\t\tgoto out_drop;\n-\t\ttx_ring->tx_stats.tx_linearize++;\n-\t}\n \tskb_tx_timestamp(skb);\n \n \t/* always enable CRC insertion offload */\ndiff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h\nindex 48a2ab8a8ec7..8a3a163cc475 100644\n--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h\n+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h\n@@ -337,6 +337,7 @@ int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,\n void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);\n u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);\n int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);\n+bool __i40e_chk_linearize(struct sk_buff *skb);\n \n /**\n * i40e_get_head - Retrieve head from head writeback\n@@ -392,4 +393,22 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)\n \t\treturn 0;\n \treturn __i40e_maybe_stop_tx(tx_ring, size);\n }\n+\n+/**\n+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet\n+ * @skb: send buffer\n+ * @count: number of buffers used\n+ *\n+ * Note: Our HW can't scatter-gather more than 8 fragments to build\n+ * a packet on the wire and so we need to figure out the cases where we\n+ * need to linearize the skb.\n+ **/\n+static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)\n+{\n+\t/* we can only support up to 8 data buffers for a single send */\n+\tif (likely(count <= I40E_MAX_BUFFER_TXD))\n+\t\treturn false;\n+\n+\treturn __i40e_chk_linearize(skb);\n+}\n #endif /* _I40E_TXRX_H_ */\ndiff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c\nindex 78d9ce4693c6..1dd1cc12304b 100644\n--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c\n+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c\n@@ -1794,59 +1794,71 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,\n }\n \n /**\n- * i40e_chk_linearize - Check if there are more than 8 fragments per packet\n+ * __i40evf_chk_linearize - Check if there are more than 8 fragments per packet\n * @skb: send buffer\n- * @tx_flags: collected send information\n *\n * Note: Our HW can't scatter-gather more than 8 fragments to build\n * a packet on the wire and so we need to figure out the cases where we\n * need to linearize the skb.\n **/\n-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)\n+bool __i40evf_chk_linearize(struct sk_buff *skb)\n {\n-\tstruct skb_frag_struct *frag;\n-\tbool linearize = false;\n-\tunsigned int size = 0;\n-\tu16 num_frags;\n-\tu16 gso_segs;\n+\tconst struct skb_frag_struct *frag, *stale;\n+\tint gso_size, nr_frags, sum;\n \n-\tnum_frags = skb_shinfo(skb)->nr_frags;\n-\tgso_segs = skb_shinfo(skb)->gso_segs;\n+\t/* check to see if TSO is enabled, if so we may get a repreive */\n+\tgso_size = skb_shinfo(skb)->gso_size;\n+\tif (unlikely(!gso_size))\n+\t\treturn true;\n \n-\tif (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {\n-\t\tu16 j = 0;\n+\t/* no need to check if number of frags is less than 8 */\n+\tnr_frags = skb_shinfo(skb)->nr_frags;\n+\tif (nr_frags < I40E_MAX_BUFFER_TXD)\n+\t\treturn false;\n \n-\t\tif (num_frags < (I40E_MAX_BUFFER_TXD))\n-\t\t\tgoto linearize_chk_done;\n-\t\t/* try the simple math, if we have too many frags per segment */\n-\t\tif (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >\n-\t\t I40E_MAX_BUFFER_TXD) {\n-\t\t\tlinearize = true;\n-\t\t\tgoto linearize_chk_done;\n-\t\t}\n-\t\tfrag = &skb_shinfo(skb)->frags[0];\n-\t\t/* we might still have more fragments per segment */\n-\t\tdo {\n-\t\t\tsize += skb_frag_size(frag);\n-\t\t\tfrag++; j++;\n-\t\t\tif ((size >= skb_shinfo(skb)->gso_size) &&\n-\t\t\t (j < I40E_MAX_BUFFER_TXD)) {\n-\t\t\t\tsize = (size % skb_shinfo(skb)->gso_size);\n-\t\t\t\tj = (size) ? 1 : 0;\n-\t\t\t}\n-\t\t\tif (j == I40E_MAX_BUFFER_TXD) {\n-\t\t\t\tlinearize = true;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tnum_frags--;\n-\t\t} while (num_frags);\n-\t} else {\n-\t\tif (num_frags >= I40E_MAX_BUFFER_TXD)\n-\t\t\tlinearize = true;\n+\t/* We need to walk through the list and validate that each group\n+\t * of 6 fragments totals at least gso_size. However we don't need\n+\t * to perform such validation on the first or last 6 since the first\n+\t * 6 cannot inherit any data from a descriptor before them, and the\n+\t * last 6 cannot inherit any data from a descriptor after them.\n+\t */\n+\tnr_frags -= I40E_MAX_BUFFER_TXD - 1;\n+\tfrag = &skb_shinfo(skb)->frags[0];\n+\n+\t/* Initialize size to the negative value of gso_size minus 1. We\n+\t * use this as the worst case scenerio in which the frag ahead\n+\t * of us only provides one byte which is why we are limited to 6\n+\t * descriptors for a single transmit as the header and previous\n+\t * fragment are already consuming 2 descriptors.\n+\t */\n+\tsum = 1 - gso_size;\n+\n+\t/* Add size of frags 1 through 5 to create our initial sum */\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\tsum += skb_frag_size(++frag);\n+\n+\t/* Walk through fragments adding latest fragment, testing it, and\n+\t * then removing stale fragments from the sum.\n+\t */\n+\tstale = &skb_shinfo(skb)->frags[0];\n+\tfor (;;) {\n+\t\tsum += skb_frag_size(++frag);\n+\n+\t\t/* if sum is negative we failed to make sufficient progress */\n+\t\tif (sum < 0)\n+\t\t\treturn true;\n+\n+\t\t/* use pre-decrement to avoid processing last fragment */\n+\t\tif (!--nr_frags)\n+\t\t\tbreak;\n+\n+\t\tsum -= skb_frag_size(++stale);\n \t}\n \n-linearize_chk_done:\n-\treturn linearize;\n+\treturn false;\n }\n \n /**\n@@ -2093,6 +2105,12 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,\n \tprefetch(skb->data);\n \n \tcount = i40e_xmit_descriptor_count(skb);\n+\tif (i40e_chk_linearize(skb, count)) {\n+\t\tif (__skb_linearize(skb))\n+\t\t\tgoto out_drop;\n+\t\tcount = TXD_USE_COUNT(skb->len);\n+\t\ttx_ring->tx_stats.tx_linearize++;\n+\t}\n \n \t/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,\n \t * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,\n@@ -2128,11 +2146,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,\n \telse if (tso)\n \t\ttx_flags |= I40E_TX_FLAGS_TSO;\n \n-\tif (i40e_chk_linearize(skb, tx_flags)) {\n-\t\tif (skb_linearize(skb))\n-\t\t\tgoto out_drop;\n-\t\ttx_ring->tx_stats.tx_linearize++;\n-\t}\n \tskb_tx_timestamp(skb);\n \n \t/* always enable CRC insertion offload */\ndiff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h\nindex 228cc76be6f6..8c5da4f89fd0 100644\n--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h\n+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h\n@@ -327,6 +327,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget);\n void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);\n u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw);\n int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size);\n+bool __i40evf_chk_linearize(struct sk_buff *skb);\n \n /**\n * i40e_get_head - Retrieve head from head writeback\n@@ -382,4 +383,22 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)\n \t\treturn 0;\n \treturn __i40evf_maybe_stop_tx(tx_ring, size);\n }\n+\n+/**\n+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet\n+ * @skb: send buffer\n+ * @count: number of buffers used\n+ *\n+ * Note: Our HW can't scatter-gather more than 8 fragments to build\n+ * a packet on the wire and so we need to figure out the cases where we\n+ * need to linearize the skb.\n+ **/\n+static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)\n+{\n+\t/* we can only support up to 8 data buffers for a single send */\n+\tif (likely(count <= I40E_MAX_BUFFER_TXD))\n+\t\treturn false;\n+\n+\treturn __i40evf_chk_linearize(skb);\n+}\n #endif /* _I40E_TXRX_H_ */\n", "prefixes": [ "next", "2/4" ] }