Introduce skb_blist and hard_start_xmit_batch API, handle driver's usage
of the new API, and add support routines.

Signed-off-by: Krishna Kumar <[EMAIL PROTECTED]>
---
 include/linux/netdevice.h |    8 +++
 net/core/dev.c            |   98 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)

diff -ruNp ORG/include/linux/netdevice.h NEW/include/linux/netdevice.h
--- ORG/include/linux/netdevice.h       2007-08-06 08:25:37.000000000 +0530
+++ NEW/include/linux/netdevice.h       2007-08-07 13:11:19.000000000 +0530
@@ -456,6 +456,9 @@ struct net_device
        /* Partially transmitted GSO packet. */
        struct sk_buff          *gso_skb;
 
+       /* List of batch skbs (optional, used if driver supports batching API */
+       struct sk_buff_head     *skb_blist;
+
        /* ingress path synchronizer */
        spinlock_t              ingress_lock;
        struct Qdisc            *qdisc_ingress;
@@ -472,6 +475,9 @@ struct net_device
        void                    *priv;  /* pointer to private data      */
        int                     (*hard_start_xmit) (struct sk_buff *skb,
                                                    struct net_device *dev);
+       int                     (*hard_start_xmit_batch) (struct net_device
+                                                         *dev);
+
        /* These may be needed for future network-power-down code. */
        unsigned long           trans_start;    /* Time (in jiffies) of last Tx 
*/
 
@@ -832,6 +838,8 @@ extern int          dev_set_mac_address(struct n
                                            struct sockaddr *);
 extern int             dev_hard_start_xmit(struct sk_buff *skb,
                                            struct net_device *dev);
+extern int             dev_add_skb_to_blist(struct sk_buff *skb,
+                                            struct net_device *dev);
 
 extern void            dev_init(void);
 
diff -ruNp ORG/net/core/dev.c NEW/net/core/dev.c
--- ORG/net/core/dev.c  2007-08-06 08:25:40.000000000 +0530
+++ NEW/net/core/dev.c  2007-08-07 13:11:19.000000000 +0530
@@ -897,6 +897,55 @@ void netdev_state_change(struct net_devi
        }
 }
 
+static void free_batching(struct net_device *dev)
+{
+       if (dev->skb_blist) {
+               if (!skb_queue_empty(dev->skb_blist))
+                       skb_queue_purge(dev->skb_blist);
+               kfree(dev->skb_blist);
+               dev->skb_blist = NULL;
+       }
+}
+
+int dev_change_tx_batch_skb(struct net_device *dev, unsigned long 
new_batch_skb)
+{
+       int ret = 0;
+       struct sk_buff_head *blist;
+
+       if (!dev->hard_start_xmit_batch) {
+               /* Driver doesn't support batching skb API */
+               ret = -ENOTSUPP;
+               goto out;
+       }
+
+       /* Handle invalid argument */
+       if (new_batch_skb < 0) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* Check if new value is same as the current */
+       if (!!dev->skb_blist == !!new_batch_skb)
+               goto out;
+
+       if (new_batch_skb &&
+           (blist = kmalloc(sizeof *blist, GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       spin_lock(&dev->queue_lock);
+       if (new_batch_skb) {
+               skb_queue_head_init(blist);
+               dev->skb_blist = blist;
+       } else
+               free_batching(dev);
+       spin_unlock(&dev->queue_lock);
+
+out:
+       return ret;
+}
+
 /**
  *     dev_load        - load a network module
  *     @name: name of interface
@@ -1459,6 +1508,45 @@ static int dev_gso_segment(struct sk_buf
        return 0;
 }
 
+/*
+ * Add skb (skbs in case segmentation is required) to dev->skb_blist. We are
+ * holding QDISC RUNNING bit, so no one else can add to this list. Also, skbs
+ * are dequeued from this list when we call the driver, so the list is safe
+ * from simultaneous deletes too.
+ *
+ * Returns count of successful skb(s) added to skb_blist.
+ */
+int dev_add_skb_to_blist(struct sk_buff *skb, struct net_device *dev)
+{
+       if (!list_empty(&ptype_all))
+               dev_queue_xmit_nit(skb, dev);
+
+       if (netif_needs_gso(dev, skb)) {
+               if (unlikely(dev_gso_segment(skb))) {
+                       kfree(skb);
+                       return 0;
+               }
+
+               if (skb->next) {
+                       int count = 0;
+
+                       do {
+                               struct sk_buff *nskb = skb->next;
+
+                               skb->next = nskb->next;
+                               __skb_queue_tail(dev->skb_blist, nskb);
+                               count++;
+                       } while (skb->next);
+
+                       skb->destructor = DEV_GSO_CB(skb)->destructor;
+                       kfree_skb(skb);
+                       return count;
+               }
+       }
+       __skb_queue_tail(dev->skb_blist, skb);
+       return 1;
+}
+
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        if (likely(!skb->next)) {
@@ -3446,6 +3535,13 @@ int register_netdevice(struct net_device
                }
        }
 
+       if (dev->hard_start_xmit_batch) {
+               /* Driver supports batching skb API */
+               dev->skb_blist = kmalloc(sizeof *dev->skb_blist, GFP_KERNEL);
+               if (dev->skb_blist)
+                       skb_queue_head_init(dev->skb_blist);
+       }
+
        /*
         *      nil rebuild_header routine,
         *      that should be never called and used as just bug trap.
@@ -3787,6 +3882,9 @@ void unregister_netdevice(struct net_dev
 
        synchronize_net();
 
+       /* Deallocate batching structure */
+       free_batching(dev);
+
        /* Shutdown queueing discipline. */
        dev_shutdown(dev);
 
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to