get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 30606,
    "url": "http://patchwork.ozlabs.org/api/patches/30606/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20090803171807.17268.49836.stgit@dev.haskins.net/",
    "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": "<20090803171807.17268.49836.stgit@dev.haskins.net>",
    "list_archive_url": null,
    "date": "2009-08-03T17:18:07",
    "name": "[7/7] venet: add scatter-gather/GSO support",
    "commit_ref": null,
    "pull_url": null,
    "state": "rfc",
    "archived": true,
    "hash": "69f6dee81458dfa98689c102d1b73854b5686841",
    "submitter": {
        "id": 642,
        "url": "http://patchwork.ozlabs.org/api/people/642/?format=api",
        "name": "Gregory Haskins",
        "email": "ghaskins@novell.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/20090803171807.17268.49836.stgit@dev.haskins.net/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/30606/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/30606/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "patchwork-incoming@ozlabs.org"
        ],
        "Received": [
            "from ozlabs.org (ozlabs.org [203.10.76.45])\n\t(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\n\t(Client CN \"mx.ozlabs.org\",\n\tIssuer \"CA Cert Signing Authority\" (verified OK))\n\tby bilbo.ozlabs.org (Postfix) with ESMTPS id 08565B6F31\n\tfor <patchwork-incoming@bilbo.ozlabs.org>;\n\tTue,  4 Aug 2009 03:21:23 +1000 (EST)",
            "by ozlabs.org (Postfix)\n\tid EF140DDDB6; Tue,  4 Aug 2009 03:21:22 +1000 (EST)",
            "from vger.kernel.org (vger.kernel.org [209.132.176.167])\n\tby ozlabs.org (Postfix) with ESMTP id 758ADDDDA2\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue,  4 Aug 2009 03:21:22 +1000 (EST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1752637AbZHCRSX (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tMon, 3 Aug 2009 13:18:23 -0400",
            "(majordomo@vger.kernel.org) by vger.kernel.org id S1752621AbZHCRSV\n\t(ORCPT <rfc822;netdev-outgoing>); Mon, 3 Aug 2009 13:18:21 -0400",
            "from victor.provo.novell.com ([137.65.250.26]:40696 \"EHLO\n\tvictor.provo.novell.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1752616AbZHCRSR (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Mon, 3 Aug 2009 13:18:17 -0400",
            "from dev.haskins.net (prv-ext-foundry1int.gns.novell.com\n\t[137.65.251.240])\n\tby victor.provo.novell.com with ESMTP (TLS encrypted);\n\tMon, 03 Aug 2009 11:18:13 -0600",
            "from dev.haskins.net (localhost [127.0.0.1])\n\tby dev.haskins.net (Postfix) with ESMTP id 6E3D7464244;\n\tMon,  3 Aug 2009 13:18:07 -0400 (EDT)"
        ],
        "From": "Gregory Haskins <ghaskins@novell.com>",
        "Subject": "[PATCH 7/7] venet: add scatter-gather/GSO support",
        "To": "linux-kernel@vger.kernel.org",
        "Cc": "alacrityvm-devel@lists.sourceforge.net, netdev@vger.kernel.org",
        "Date": "Mon, 03 Aug 2009 13:18:07 -0400",
        "Message-ID": "<20090803171807.17268.49836.stgit@dev.haskins.net>",
        "In-Reply-To": "<20090803171030.17268.26962.stgit@dev.haskins.net>",
        "References": "<20090803171030.17268.26962.stgit@dev.haskins.net>",
        "User-Agent": "StGIT/0.14.3",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "SG/GSO significantly enhance the performance of network traffic under\ncertain circumstances.  We implement this feature as a separate patch\nto avoid intially complicating the baseline venet driver.  This will\npresumably make the review process slightly easier, since we can\nfocus on the basic interface first.\n\nSigned-off-by: Gregory Haskins <ghaskins@novell.com>\n---\n\n drivers/net/vbus-enet.c |  249 +++++++++++++++++++++++++++++++++++++++++++++--\n include/linux/venet.h   |   39 +++++++\n 2 files changed, 275 insertions(+), 13 deletions(-)\n\n\n--\nTo unsubscribe from this list: send the line \"unsubscribe netdev\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html",
    "diff": "diff --git a/drivers/net/vbus-enet.c b/drivers/net/vbus-enet.c\nindex 8fcc2d6..5aa56ff 100644\n--- a/drivers/net/vbus-enet.c\n+++ b/drivers/net/vbus-enet.c\n@@ -42,6 +42,8 @@ static int rx_ringlen = 256;\n module_param(rx_ringlen, int, 0444);\n static int tx_ringlen = 256;\n module_param(tx_ringlen, int, 0444);\n+static int sg_enabled = 1;\n+module_param(sg_enabled, int, 0444);\n \n #define PDEBUG(_dev, fmt, args...) dev_dbg(&(_dev)->dev, fmt, ## args)\n \n@@ -58,8 +60,17 @@ struct vbus_enet_priv {\n \tstruct vbus_enet_queue     rxq;\n \tstruct vbus_enet_queue     txq;\n \tstruct tasklet_struct      txtask;\n+\tstruct {\n+\t\tint                sg:1;\n+\t\tint                tso:1;\n+\t\tint                ufo:1;\n+\t\tint                tso6:1;\n+\t\tint                ecn:1;\n+\t} flags;\n };\n \n+static void vbus_enet_tx_reap(struct vbus_enet_priv *priv, int force);\n+\n static struct vbus_enet_priv *\n napi_to_priv(struct napi_struct *napi)\n {\n@@ -193,6 +204,93 @@ rx_teardown(struct vbus_enet_priv *priv)\n \t}\n }\n \n+static int\n+tx_setup(struct vbus_enet_priv *priv)\n+{\n+\tstruct ioq *ioq = priv->txq.queue;\n+\tstruct ioq_iterator iter;\n+\tint i;\n+\tint ret;\n+\n+\tif (!priv->flags.sg)\n+\t\t/*\n+\t\t * There is nothing to do for a ring that is not using\n+\t\t * scatter-gather\n+\t\t */\n+\t\treturn 0;\n+\n+\tret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);\n+\tBUG_ON(ret < 0);\n+\n+\tret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);\n+\tBUG_ON(ret < 0);\n+\n+\t/*\n+\t * Now populate each descriptor with an empty SG descriptor\n+\t */\n+\tfor (i = 0; i < tx_ringlen; i++) {\n+\t\tstruct venet_sg *vsg;\n+\t\tsize_t iovlen = sizeof(struct venet_iov) * (MAX_SKB_FRAGS-1);\n+\t\tsize_t len = sizeof(*vsg) + iovlen;\n+\n+\t\tvsg = kzalloc(len, GFP_KERNEL);\n+\t\tif (!vsg)\n+\t\t\treturn -ENOMEM;\n+\n+\t\titer.desc->cookie = (u64)vsg;\n+\t\titer.desc->len    = len;\n+\t\titer.desc->ptr    = (u64)__pa(vsg);\n+\n+\t\tret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);\n+\t\tBUG_ON(ret < 0);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+tx_teardown(struct vbus_enet_priv *priv)\n+{\n+\tstruct ioq *ioq = priv->txq.queue;\n+\tstruct ioq_iterator iter;\n+\tint ret;\n+\n+\t/* forcefully free all outstanding transmissions */\n+\tvbus_enet_tx_reap(priv, 1);\n+\n+\tif (!priv->flags.sg)\n+\t\t/*\n+\t\t * There is nothing else to do for a ring that is not using\n+\t\t * scatter-gather\n+\t\t */\n+\t\treturn;\n+\n+\tret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);\n+\tBUG_ON(ret < 0);\n+\n+\t/* seek to position 0 */\n+\tret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);\n+\tBUG_ON(ret < 0);\n+\n+\t/*\n+\t * free each valid descriptor\n+\t */\n+\twhile (iter.desc->cookie) {\n+\t\tstruct venet_sg *vsg = (struct venet_sg *)iter.desc->cookie;\n+\n+\t\titer.desc->valid = 0;\n+\t\twmb();\n+\n+\t\titer.desc->ptr = 0;\n+\t\titer.desc->cookie = 0;\n+\n+\t\tret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);\n+\t\tBUG_ON(ret < 0);\n+\n+\t\tkfree(vsg);\n+\t}\n+}\n+\n /*\n  * Open and close\n  */\n@@ -396,14 +494,67 @@ vbus_enet_tx_start(struct sk_buff *skb, struct net_device *dev)\n \tBUG_ON(ret < 0);\n \tBUG_ON(iter.desc->sown);\n \n-\t/*\n-\t * We simply put the skb right onto the ring.  We will get an interrupt\n-\t * later when the data has been consumed and we can reap the pointers\n-\t * at that time\n-\t */\n-\titer.desc->cookie = (u64)skb;\n-\titer.desc->len = (u64)skb->len;\n-\titer.desc->ptr = (u64)__pa(skb->data);\n+\tif (priv->flags.sg) {\n+\t\tstruct venet_sg *vsg = (struct venet_sg *)iter.desc->cookie;\n+\t\tstruct scatterlist sgl[MAX_SKB_FRAGS+1];\n+\t\tstruct scatterlist *sg;\n+\t\tint count, maxcount = ARRAY_SIZE(sgl);\n+\n+\t\tsg_init_table(sgl, maxcount);\n+\n+\t\tmemset(vsg, 0, sizeof(*vsg));\n+\n+\t\tvsg->cookie = (u64)skb;\n+\t\tvsg->len    = skb->len;\n+\n+\t\tif (skb->ip_summed == CHECKSUM_PARTIAL) {\n+\t\t\tvsg->flags      |= VENET_SG_FLAG_NEEDS_CSUM;\n+\t\t\tvsg->csum.start  = skb->csum_start - skb_headroom(skb);\n+\t\t\tvsg->csum.offset = skb->csum_offset;\n+\t\t}\n+\n+\t\tif (skb_is_gso(skb)) {\n+\t\t\tstruct skb_shared_info *sinfo = skb_shinfo(skb);\n+\n+\t\t\tvsg->flags |= VENET_SG_FLAG_GSO;\n+\n+\t\t\tvsg->gso.hdrlen = skb_transport_header(skb) - skb->data;\n+\t\t\tvsg->gso.size = sinfo->gso_size;\n+\t\t\tif (sinfo->gso_type & SKB_GSO_TCPV4)\n+\t\t\t\tvsg->gso.type = VENET_GSO_TYPE_TCPV4;\n+\t\t\telse if (sinfo->gso_type & SKB_GSO_TCPV6)\n+\t\t\t\tvsg->gso.type = VENET_GSO_TYPE_TCPV6;\n+\t\t\telse if (sinfo->gso_type & SKB_GSO_UDP)\n+\t\t\t\tvsg->gso.type = VENET_GSO_TYPE_UDP;\n+\t\t\telse\n+\t\t\t\tpanic(\"Virtual-Ethernet: unknown GSO type \" \\\n+\t\t\t\t      \"0x%x\\n\", sinfo->gso_type);\n+\n+\t\t\tif (sinfo->gso_type & SKB_GSO_TCP_ECN)\n+\t\t\t\tvsg->flags |= VENET_SG_FLAG_ECN;\n+\t\t}\n+\n+\t\tcount = skb_to_sgvec(skb, sgl, 0, skb->len);\n+\n+\t\tBUG_ON(count > maxcount);\n+\n+\t\tfor (sg = &sgl[0]; sg; sg = sg_next(sg)) {\n+\t\t\tstruct venet_iov *iov = &vsg->iov[vsg->count++];\n+\n+\t\t\tiov->len = sg->length;\n+\t\t\tiov->ptr = (u64)sg_phys(sg);\n+\t\t}\n+\n+\t} else {\n+\t\t/*\n+\t\t * non scatter-gather mode: simply put the skb right onto the\n+\t\t * ring.\n+\t\t */\n+\t\titer.desc->cookie = (u64)skb;\n+\t\titer.desc->len = (u64)skb->len;\n+\t\titer.desc->ptr = (u64)__pa(skb->data);\n+\t}\n+\n \titer.desc->valid  = 1;\n \n \tpriv->dev->stats.tx_packets++;\n@@ -459,7 +610,17 @@ vbus_enet_tx_reap(struct vbus_enet_priv *priv, int force)\n \t * owned by the south-side\n \t */\n \twhile (iter.desc->valid && (!iter.desc->sown || force)) {\n-\t\tstruct sk_buff *skb = (struct sk_buff *)iter.desc->cookie;\n+\t\tstruct sk_buff *skb;\n+\n+\t\tif (priv->flags.sg) {\n+\t\t\tstruct venet_sg *vsg;\n+\n+\t\t\tvsg = (struct venet_sg *)iter.desc->cookie;\n+\t\t\tskb = (struct sk_buff *)vsg->cookie;\n+\n+\t\t} else {\n+\t\t\tskb = (struct sk_buff *)iter.desc->cookie;\n+\t\t}\n \n \t\tPDEBUG(priv->dev, \"completed sending %d bytes\\n\", skb->len);\n \n@@ -538,6 +699,47 @@ tx_isr(struct ioq_notifier *notifier)\n        tasklet_schedule(&priv->txtask);\n }\n \n+static int\n+vbus_enet_negcap(struct vbus_enet_priv *priv)\n+{\n+\tint ret;\n+\tstruct venet_capabilities caps;\n+\n+\tmemset(&caps, 0, sizeof(caps));\n+\n+\tif (sg_enabled) {\n+\t\tcaps.gid = VENET_CAP_GROUP_SG;\n+\t\tcaps.bits |= (VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6\n+\t\t\t      |VENET_CAP_ECN);\n+\t\t/* note: exclude UFO for now due to stack bug */\n+\t}\n+\n+\tret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tif (caps.bits & VENET_CAP_SG) {\n+\t\tpriv->flags.sg = true;\n+\n+\t\tif (caps.bits & VENET_CAP_TSO4)\n+\t\t\tpriv->flags.tso = true;\n+\t\tif (caps.bits & VENET_CAP_TSO6)\n+\t\t\tpriv->flags.tso6 = true;\n+\t\tif (caps.bits & VENET_CAP_UFO)\n+\t\t\tpriv->flags.ufo = true;\n+\t\tif (caps.bits & VENET_CAP_ECN)\n+\t\t\tpriv->flags.ecn = true;\n+\n+\t\tdev_info(&priv->dev->dev, \"Detected GSO features %s%s%s%s\\n\",\n+\t\t\t priv->flags.tso  ? \"t\" : \"-\",\n+\t\t\t priv->flags.tso6 ? \"T\" : \"-\",\n+\t\t\t priv->flags.ufo  ? \"u\" : \"-\",\n+\t\t\t priv->flags.ecn  ? \"e\" : \"-\");\n+\t}\n+\n+\treturn 0;\n+}\n+\n static const struct net_device_ops vbus_enet_netdev_ops = {\n \t.ndo_open          = vbus_enet_open,\n \t.ndo_stop          = vbus_enet_stop,\n@@ -574,12 +776,21 @@ vbus_enet_probe(struct vbus_device_proxy *vdev)\n \tpriv->dev  = dev;\n \tpriv->vdev = vdev;\n \n+\tret = vbus_enet_negcap(priv);\n+\tif (ret < 0) {\n+\t\tprintk(KERN_INFO \"VENET: Error negotiating capabilities for \" \\\n+\t\t       \"%lld\\n\",\n+\t\t       priv->vdev->id);\n+\t\tgoto out_free;\n+\t}\n+\n \ttasklet_init(&priv->txtask, deferred_tx_isr, (unsigned long)priv);\n \n \tqueue_init(priv, &priv->rxq, VENET_QUEUE_RX, rx_ringlen, rx_isr);\n \tqueue_init(priv, &priv->txq, VENET_QUEUE_TX, tx_ringlen, tx_isr);\n \n \trx_setup(priv);\n+\ttx_setup(priv);\n \n \tioq_notify_enable(priv->rxq.queue, 0);  /* enable interrupts */\n \tioq_notify_enable(priv->txq.queue, 0);\n@@ -599,6 +810,22 @@ vbus_enet_probe(struct vbus_device_proxy *vdev)\n \n \tdev->features |= NETIF_F_HIGHDMA;\n \n+\tif (priv->flags.sg) {\n+\t\tdev->features |= NETIF_F_SG|NETIF_F_HW_CSUM|NETIF_F_FRAGLIST;\n+\n+\t\tif (priv->flags.tso)\n+\t\t\tdev->features |= NETIF_F_TSO;\n+\n+\t\tif (priv->flags.ufo)\n+\t\t\tdev->features |= NETIF_F_UFO;\n+\n+\t\tif (priv->flags.tso6)\n+\t\t\tdev->features |= NETIF_F_TSO6;\n+\n+\t\tif (priv->flags.ecn)\n+\t\t\tdev->features |= NETIF_F_TSO_ECN;\n+\t}\n+\n \tret = register_netdev(dev);\n \tif (ret < 0) {\n \t\tprintk(KERN_INFO \"VENET: error %i registering device \\\"%s\\\"\\n\",\n@@ -626,9 +853,9 @@ vbus_enet_remove(struct vbus_device_proxy *vdev)\n \tnapi_disable(&priv->napi);\n \n \trx_teardown(priv);\n-\tvbus_enet_tx_reap(priv, 1);\n-\n \tioq_put(priv->rxq.queue);\n+\n+\ttx_teardown(priv);\n \tioq_put(priv->txq.queue);\n \n \tdev->ops->close(dev, 0);\ndiff --git a/include/linux/venet.h b/include/linux/venet.h\nindex 586be40..47ed37d 100644\n--- a/include/linux/venet.h\n+++ b/include/linux/venet.h\n@@ -37,8 +37,43 @@ struct venet_capabilities {\n \t__u32 bits;\n };\n \n-/* CAPABILITIES-GROUP 0 */\n-/* #define VENET_CAP_FOO    0   (No capabilities defined yet, for now) */\n+#define VENET_CAP_GROUP_SG 0\n+\n+/* CAPABILITIES-GROUP SG */\n+#define VENET_CAP_SG     (1 << 0)\n+#define VENET_CAP_TSO4   (1 << 1)\n+#define VENET_CAP_TSO6   (1 << 2)\n+#define VENET_CAP_ECN    (1 << 3)\n+#define VENET_CAP_UFO    (1 << 4)\n+\n+struct venet_iov {\n+\t__u32 len;\n+\t__u64 ptr;\n+};\n+\n+#define VENET_SG_FLAG_NEEDS_CSUM (1 << 0)\n+#define VENET_SG_FLAG_GSO        (1 << 1)\n+#define VENET_SG_FLAG_ECN        (1 << 2)\n+\n+struct venet_sg {\n+\t__u64            cookie;\n+\t__u32            flags;\n+\t__u32            len;     /* total length of all iovs */\n+\tstruct {\n+\t\t__u16    start;\t  /* csum starting position */\n+\t\t__u16    offset;  /* offset to place csum */\n+\t} csum;\n+\tstruct {\n+#define VENET_GSO_TYPE_TCPV4\t0\t/* IPv4 TCP (TSO) */\n+#define VENET_GSO_TYPE_UDP\t1\t/* IPv4 UDP (UFO) */\n+#define VENET_GSO_TYPE_TCPV6\t2\t/* IPv6 TCP */\n+\t\t__u8     type;\n+\t\t__u16    hdrlen;\n+\t\t__u16    size;\n+\t} gso;\n+\t__u32            count;   /* nr of iovs */\n+\tstruct venet_iov iov[1];\n+};\n \n #define VENET_FUNC_LINKUP   0\n #define VENET_FUNC_LINKDOWN 1\n",
    "prefixes": [
        "7/7"
    ]
}