]> xenbits.xensource.com Git - xen.git/commitdiff
[NET] front: Transmit TSO packets if supported
authorkfraser@dhcp93.uk.xensource.com <kfraser@dhcp93.uk.xensource.com>
Thu, 29 Jun 2006 18:34:16 +0000 (19:34 +0100)
committerkfraser@dhcp93.uk.xensource.com <kfraser@dhcp93.uk.xensource.com>
Thu, 29 Jun 2006 18:34:16 +0000 (19:34 +0100)
This patch adds TSO transmission support to the frontend.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c

index 4a70fa448439d25f2af89b0a80637ea24dc09180..8ebcf841d4824bc290574a2a93e7e9f0e5ba5e8c 100644 (file)
@@ -463,7 +463,7 @@ static int network_open(struct net_device *dev)
 
 static inline int netfront_tx_slot_available(struct netfront_info *np)
 {
-       return RING_FREE_REQUESTS(&np->tx) >= MAX_SKB_FRAGS + 1;
+       return RING_FREE_REQUESTS(&np->tx) >= MAX_SKB_FRAGS + 2;
 }
 
 static inline void network_maybe_wake_tx(struct net_device *dev)
@@ -491,7 +491,13 @@ static void network_tx_buf_gc(struct net_device *dev)
                rmb(); /* Ensure we see responses up to 'rp'. */
 
                for (cons = np->tx.rsp_cons; cons != prod; cons++) {
-                       id  = RING_GET_RESPONSE(&np->tx, cons)->id;
+                       struct netif_tx_response *txrsp;
+
+                       txrsp = RING_GET_RESPONSE(&np->tx, cons);
+                       if (txrsp->status == NETIF_RSP_NULL)
+                               continue;
+
+                       id  = txrsp->id;
                        skb = np->tx_skbs[id];
                        if (unlikely(gnttab_query_foreign_access(
                                np->grant_tx_ref[id]) != 0)) {
@@ -719,6 +725,7 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned short id;
        struct netfront_info *np = netdev_priv(dev);
        struct netif_tx_request *tx;
+       struct netif_extra_info *extra;
        char *data = skb->data;
        RING_IDX i;
        grant_ref_t ref;
@@ -739,7 +746,8 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_lock_irq(&np->tx_lock);
 
        if (unlikely(!netif_carrier_ok(dev) ||
-                    (frags > 1 && !xennet_can_sg(dev)))) {
+                    (frags > 1 && !xennet_can_sg(dev)) ||
+                    netif_needs_gso(dev, skb))) {
                spin_unlock_irq(&np->tx_lock);
                goto drop;
        }
@@ -762,11 +770,31 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx->size = len;
 
        tx->flags = 0;
+       extra = NULL;
+
        if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
                tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
        if (skb->proto_data_valid) /* remote but checksummed? */
                tx->flags |= NETTXF_data_validated;
 
+       if (skb_shinfo(skb)->gso_size) {
+               struct netif_extra_info *gso = (struct netif_extra_info *)
+                       RING_GET_REQUEST(&np->tx, ++i);
+
+               if (extra)
+                       extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+               else
+                       tx->flags |= NETTXF_extra_info;
+
+               gso->u.gso.size = skb_shinfo(skb)->gso_size;
+               gso->u.gso.segs = skb_shinfo(skb)->gso_segs;
+               gso->u.gso.type = XEN_NETIF_GSO_TCPV4;
+
+               gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+               gso->flags = 0;
+               extra = gso;
+       }
+
        np->tx.req_prod_pvt = i + 1;
 
        xennet_make_frags(skb, dev, tx);
@@ -1065,9 +1093,28 @@ static int xennet_set_sg(struct net_device *dev, u32 data)
        return ethtool_op_set_sg(dev, data);
 }
 
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+       if (data) {
+               struct netfront_info *np = netdev_priv(dev);
+               int val;
+
+               if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-tso",
+                                "%d", &val) < 0)
+                       val = 0;
+#if 0 /* KAF: After the protocol is finalised. */
+               if (!val)
+#endif
+                       return -ENOSYS;
+       }
+
+       return ethtool_op_set_tso(dev, data);
+}
+
 static void xennet_set_features(struct net_device *dev)
 {
-       xennet_set_sg(dev, 1);
+       if (!xennet_set_sg(dev, 1))
+               xennet_set_tso(dev, 1);
 }
 
 static void network_connect(struct net_device *dev)
@@ -1148,6 +1195,8 @@ static struct ethtool_ops network_ethtool_ops =
        .set_tx_csum = ethtool_op_set_tx_csum,
        .get_sg = ethtool_op_get_sg,
        .set_sg = xennet_set_sg,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = xennet_set_tso,
 };
 
 #ifdef CONFIG_SYSFS