{"id":30606,"url":"http://patchwork.ozlabs.org/api/patches/30606/?format=json","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=json","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=json","name":"Gregory Haskins","email":"ghaskins@novell.com"},"delegate":{"id":34,"url":"http://patchwork.ozlabs.org/api/users/34/?format=json","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"]}