get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 350343,
    "url": "http://patchwork.ozlabs.org/api/patches/350343/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/1400518800-6111-10-git-send-email-ezequiel.garcia@free-electrons.com/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1400518800-6111-10-git-send-email-ezequiel.garcia@free-electrons.com>",
    "list_archive_url": null,
    "date": "2014-05-19T17:00:00",
    "name": "[9/9] net: mv643xx_eth: Implement software TSO",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "1691516c4e6221a27c259f1b6d18af38f5e2520e",
    "submitter": {
        "id": 20433,
        "url": "http://patchwork.ozlabs.org/api/people/20433/?format=api",
        "name": "Ezequiel Garcia",
        "email": "ezequiel.garcia@free-electrons.com"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/1400518800-6111-10-git-send-email-ezequiel.garcia@free-electrons.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/350343/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/350343/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id E2E75140082\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 20 May 2014 03:01:36 +1000 (EST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S964859AbaESRB3 (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tMon, 19 May 2014 13:01:29 -0400",
            "from top.free-electrons.com ([176.31.233.9]:53633 \"EHLO\n\tmail.free-electrons.com\" rhost-flags-OK-OK-OK-FAIL) by\n\tvger.kernel.org with ESMTP id S964837AbaESRBZ (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Mon, 19 May 2014 13:01:25 -0400",
            "by mail.free-electrons.com (Postfix, from userid 106)\n\tid EBADD8BD; Mon, 19 May 2014 19:01:28 +0200 (CEST)",
            "from localhost.localdomain (unknown [190.2.108.30])\n\tby mail.free-electrons.com (Postfix) with ESMTPSA id 725C87EB;\n\tMon, 19 May 2014 19:01:25 +0200 (CEST)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.3.2 (2011-06-06) on\n\tmail.free-electrons.com",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT\n\tshortcircuit=ham autolearn=disabled version=3.3.2",
        "From": "Ezequiel Garcia <ezequiel.garcia@free-electrons.com>",
        "To": "<netdev@vger.kernel.org>, David Miller <davem@davemloft.net>,\n\tEric Dumazet <eric.dumazet@gmail.com>",
        "Cc": "Willy Tarreau <w@1wt.eu>,\n\tThomas Petazzoni <thomas.petazzoni@free-electrons.com>,\n\tGregory Clement <gregory.clement@free-electrons.com>,\n\tSebastian Hesselbarth <sebastian.hesselbarth@gmail.com>,\n\tTawfik Bayouk <tawfik@marvell.com>, Lior Amsalem <alior@marvell.com>,\n\tEzequiel Garcia <ezequiel.garcia@free-electrons.com>",
        "Subject": "[PATCH 9/9] net: mv643xx_eth: Implement software TSO",
        "Date": "Mon, 19 May 2014 14:00:00 -0300",
        "Message-Id": "<1400518800-6111-10-git-send-email-ezequiel.garcia@free-electrons.com>",
        "X-Mailer": "git-send-email 1.9.1",
        "In-Reply-To": "<1400518800-6111-1-git-send-email-ezequiel.garcia@free-electrons.com>",
        "References": "<1400518800-6111-1-git-send-email-ezequiel.garcia@free-electrons.com>",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "Now that the TSO helper API has been introduced, this commit makes use\nof it to add support for software TSO in this driver.\n\nThis feature allows to improve outbound throughput performance significantly.\nRunning iperf tests shows a 30% improvement, tested on a Kirkwood Openblocks\nA6 board.\n\n$ ethtool -K eth0 tso off\n$ iperf -c 192.168.0.45 -t 3\n------------------------------------------------------------\nClient connecting to 192.168.0.45, TCP port 5001\nTCP window size: 43.8 KByte (default)\n------------------------------------------------------------\n[  3] local 192.168.0.159 port 46389 connected with 192.168.0.45 port 5001\n[ ID] Interval       Transfer     Bandwidth\n[  3]  0.0- 3.0 sec   217 MBytes   607 Mbits/sec\n\n$ ethtool -K eth0 tso on\n$ iperf -c 192.168.0.45 -t 3\n------------------------------------------------------------\nClient connecting to 192.168.0.45, TCP port 5001\nTCP window size: 43.8 KByte (default)\n------------------------------------------------------------\n[  3] local 192.168.0.159 port 46390 connected with 192.168.0.45 port 5001\n[ ID] Interval       Transfer     Bandwidth\n[  3]  0.0- 3.0 sec   336 MBytes   938 Mbits/sec\n\nThis commit is just an example of the usage of the TSO API, it works fine\nbut needs some more work. In particular, the descriptor unmapping path must\navoid unmapping the TSO headers.\n\nSigned-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>\n---\n drivers/net/ethernet/marvell/mv643xx_eth.c | 164 ++++++++++++++++++++++++++++-\n 1 file changed, 160 insertions(+), 4 deletions(-)",
    "diff": "diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c\nindex 8854751..3b0f818 100644\n--- a/drivers/net/ethernet/marvell/mv643xx_eth.c\n+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c\n@@ -42,6 +42,7 @@\n #include <linux/dma-mapping.h>\n #include <linux/in.h>\n #include <linux/ip.h>\n+#include <net/tso.h>\n #include <linux/tcp.h>\n #include <linux/udp.h>\n #include <linux/etherdevice.h>\n@@ -179,9 +180,10 @@ static char mv643xx_eth_driver_version[] = \"1.4\";\n  * Misc definitions.\n  */\n #define DEFAULT_RX_QUEUE_SIZE\t128\n-#define DEFAULT_TX_QUEUE_SIZE\t256\n+#define DEFAULT_TX_QUEUE_SIZE\t512\n #define SKB_DMA_REALIGN\t\t((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES)\n \n+#define TSO_HEADER_SIZE\t\t128\n \n /*\n  * RX/TX descriptors.\n@@ -346,6 +348,9 @@ struct tx_queue {\n \tint tx_curr_desc;\n \tint tx_used_desc;\n \n+\tchar *tso_hdrs;\n+\tdma_addr_t tso_hdrs_dma;\n+\n \tstruct tx_desc *tx_desc_area;\n \tdma_addr_t tx_desc_dma;\n \tint tx_desc_area_size;\n@@ -722,6 +727,138 @@ no_csum:\n \treturn 0;\n }\n \n+static inline int\n+txq_put_data_tso(struct net_device *dev, struct tx_queue *txq,\n+\t\t struct sk_buff *skb, char *data, int length,\n+\t\t bool last_tcp, bool is_last)\n+{\n+\tint tx_index;\n+\tu32 cmd_sts;\n+\tstruct tx_desc *desc;\n+\n+\ttx_index = txq->tx_curr_desc++;\n+\tif (txq->tx_curr_desc == txq->tx_ring_size)\n+\t\ttxq->tx_curr_desc = 0;\n+\tdesc = &txq->tx_desc_area[tx_index];\n+\n+\tdesc->l4i_chk = 0;\n+\tdesc->byte_cnt = length;\n+\tdesc->buf_ptr = dma_map_single(dev->dev.parent, data,\n+\t\t\t\t       length, DMA_TO_DEVICE);\n+\tif (unlikely(dma_mapping_error(dev->dev.parent, desc->buf_ptr))) {\n+\t\tWARN(1, \"dma_map_single failed!\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tcmd_sts = BUFFER_OWNED_BY_DMA;\n+\tif (last_tcp) {\n+\t\t/* last descriptor in the TCP packet */\n+\t\tcmd_sts |= ZERO_PADDING | TX_LAST_DESC;\n+\t\t/* last descriptor in SKB */\n+\t\tif (is_last)\n+\t\t\tcmd_sts |= TX_ENABLE_INTERRUPT;\n+\t}\n+\tdesc->cmd_sts = cmd_sts;\n+\treturn 0;\n+}\n+\n+static inline void\n+txq_put_hdr_tso(struct sk_buff *skb, struct tx_queue *txq, int length)\n+{\n+\tstruct mv643xx_eth_private *mp = txq_to_mp(txq);\n+\tint hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);\n+\tint tx_index;\n+\tstruct tx_desc *desc;\n+\tint ret;\n+\tu32 cmd_csum = 0;\n+\tu16 l4i_chk = 0;\n+\n+\ttx_index = txq->tx_curr_desc;\n+\tdesc = &txq->tx_desc_area[tx_index];\n+\n+\tret = skb_tx_csum(mp, skb, &l4i_chk, &cmd_csum, length);\n+\tif (ret)\n+\t\tWARN(1, \"failed to prepare checksum!\");\n+\n+\t/* Should we set this? Can't use the value from skb_tx_csum()\n+\t * as it's not the correct initial L4 checksum to use. */\n+\tdesc->l4i_chk = 0;\n+\n+\tdesc->byte_cnt = hdr_len;\n+\tdesc->buf_ptr = txq->tso_hdrs_dma +\n+\t\t\ttxq->tx_curr_desc * TSO_HEADER_SIZE;\n+\tdesc->cmd_sts = cmd_csum | BUFFER_OWNED_BY_DMA  | TX_FIRST_DESC |\n+\t\t\t\t   GEN_CRC;\n+\n+\ttxq->tx_curr_desc++;\n+\tif (txq->tx_curr_desc == txq->tx_ring_size)\n+\t\ttxq->tx_curr_desc = 0;\n+}\n+\n+static int txq_submit_tso(struct tx_queue *txq, struct sk_buff *skb,\n+\t\t\t  struct net_device *dev)\n+{\n+\tstruct mv643xx_eth_private *mp = txq_to_mp(txq);\n+\tint total_len, data_left, ret;\n+\tint desc_count = 0;\n+\tstruct tso_t tso;\n+\tint hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);\n+\n+\t/* Count needed descriptors */\n+\tif ((txq->tx_desc_count + tso_count_descs(skb)) >= txq->tx_ring_size) {\n+\t\tnetdev_dbg(dev, \"not enough descriptors for TSO!\\n\");\n+\t\treturn -EBUSY;\n+\t}\n+\n+\t/* Initialize the TSO handler, and prepare the first payload */\n+\ttso_start(skb, &tso);\n+\n+\ttotal_len = skb->len - hdr_len;\n+\twhile (total_len > 0) {\n+\t\tchar *hdr;\n+\n+\t\tdata_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);\n+\t\ttotal_len -= data_left;\n+\t\tdesc_count++;\n+\n+\t\t/* prepare packet headers: MAC + IP + TCP */\n+\t\thdr = txq->tso_hdrs + txq->tx_curr_desc * TSO_HEADER_SIZE;\n+\t\ttso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);\n+\t\ttxq_put_hdr_tso(skb, txq, data_left);\n+\n+\t\twhile (data_left > 0) {\n+\t\t\tint size;\n+\t\t\tdesc_count++;\n+\n+\t\t\tsize = min_t(int, tso.size, data_left);\n+\t\t\tret = txq_put_data_tso(dev, txq, skb, tso.data, size,\n+\t\t\t\t\t       size == data_left,\n+\t\t\t\t\t       total_len == 0);\n+\t\t\tif (ret)\n+\t\t\t\tgoto err_release;\n+\t\t\tdata_left -= size;\n+\t\t\ttso_build_data(skb, &tso, size);\n+\t\t}\n+\t}\n+\n+\t__skb_queue_tail(&txq->tx_skb, skb);\n+\tskb_tx_timestamp(skb);\n+\n+\t/* clear TX_END status */\n+\tmp->work_tx_end &= ~(1 << txq->index);\n+\n+\t/* ensure all descriptors are written before poking hardware */\n+\twmb();\n+\ttxq_enable(txq);\n+\ttxq->tx_desc_count += desc_count;\n+\treturn 0;\n+err_release:\n+\t/* TODO: Release all used data descriptors; header descriptors must not\n+\t * be DMA-unmapped.\n+\t */\n+\treturn ret;\n+}\n+\n static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)\n {\n \tstruct mv643xx_eth_private *mp = txq_to_mp(txq);\n@@ -821,7 +958,7 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)\n static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)\n {\n \tstruct mv643xx_eth_private *mp = netdev_priv(dev);\n-\tint length, queue;\n+\tint length, queue, ret;\n \tstruct tx_queue *txq;\n \tstruct netdev_queue *nq;\n \n@@ -845,7 +982,11 @@ static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)\n \n \tlength = skb->len;\n \n-\tif (!txq_submit_skb(txq, skb)) {\n+\tif (skb_is_gso(skb))\n+\t\tret = txq_submit_tso(txq, skb, dev);\n+\telse\n+\t\tret = txq_submit_skb(txq, skb);\n+\tif (!ret) {\n \t\tint entries_left;\n \n \t\ttxq->tx_bytes += length;\n@@ -854,6 +995,8 @@ static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)\n \t\tentries_left = txq->tx_ring_size - txq->tx_desc_count;\n \t\tif (entries_left < MAX_SKB_FRAGS + 1)\n \t\t\tnetif_tx_stop_queue(nq);\n+\t} else if (ret == -EBUSY) {\n+\t\treturn NETDEV_TX_BUSY;\n \t}\n \n \treturn NETDEV_TX_OK;\n@@ -1885,6 +2028,15 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)\n \t\t\t\t\tnexti * sizeof(struct tx_desc);\n \t}\n \n+\t/* Allocate DMA buffers for TSO MAC/IP/TCP headers */\n+\ttxq->tso_hdrs = dma_alloc_coherent(mp->dev->dev.parent,\n+\t\t\t\t\t   txq->tx_ring_size * TSO_HEADER_SIZE,\n+\t\t\t\t\t   &txq->tso_hdrs_dma, GFP_KERNEL);\n+\tif (txq->tso_hdrs == NULL) {\n+\t\tdma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,\n+\t\t\t\t  txq->tx_desc_area, txq->tx_desc_dma);\n+\t\treturn -ENOMEM;\n+\t}\n \tskb_queue_head_init(&txq->tx_skb);\n \n \treturn 0;\n@@ -1905,6 +2057,10 @@ static void txq_deinit(struct tx_queue *txq)\n \telse\n \t\tdma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,\n \t\t\t\t  txq->tx_desc_area, txq->tx_desc_dma);\n+\tif (txq->tso_hdrs)\n+\t\tdma_free_coherent(mp->dev->dev.parent,\n+\t\t\t\t  txq->tx_ring_size * TSO_HEADER_SIZE,\n+\t\t\t\t  txq->tso_hdrs, txq->tso_hdrs_dma);\n }\n \n \n@@ -2935,7 +3091,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)\n \tdev->watchdog_timeo = 2 * HZ;\n \tdev->base_addr = 0;\n \n-\tdev->features = NETIF_F_SG | NETIF_F_IP_CSUM;\n+\tdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;\n \tdev->vlan_features = dev->features;\n \n \tdev->features |= NETIF_F_RXCSUM;\n",
    "prefixes": [
        "9/9"
    ]
}