struct net_device       *dev;
        struct sk_buff          *gro_list;
        struct sk_buff          *skb;
+       struct hrtimer          timer;
        struct list_head        dev_list;
        struct hlist_node       napi_hash_node;
        unsigned int            napi_id;
        return false;
 }
 
+void __napi_complete(struct napi_struct *n);
+void napi_complete_done(struct napi_struct *n, int work_done);
 /**
  *     napi_complete - NAPI processing complete
  *     @n: napi context
  *
  * Mark NAPI processing as complete.
+ * Consider using napi_complete_done() instead.
  */
-void __napi_complete(struct napi_struct *n);
-void napi_complete(struct napi_struct *n);
+static inline void napi_complete(struct napi_struct *n)
+{
+       return napi_complete_done(n, 0);
+}
 
 /**
  *     napi_by_id - lookup a NAPI by napi_id
  * Stop NAPI from being scheduled on this context.
  * Waits till any outstanding processing completes.
  */
-static inline void napi_disable(struct napi_struct *n)
-{
-       might_sleep();
-       set_bit(NAPI_STATE_DISABLE, &n->state);
-       while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
-               msleep(1);
-       clear_bit(NAPI_STATE_DISABLE, &n->state);
-}
+void napi_disable(struct napi_struct *n);
 
 /**
  *     napi_enable - enable NAPI scheduling
 
 #endif
 
+       unsigned long           gro_flush_timeout;
        rx_handler_func_t __rcu *rx_handler;
        void __rcu              *rx_handler_data;
 
 
 #include <linux/vmalloc.h>
 #include <linux/if_macvlan.h>
 #include <linux/errqueue.h>
+#include <linux/hrtimer.h>
 
 #include "net-sysfs.h"
 
 void __napi_complete(struct napi_struct *n)
 {
        BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
-       BUG_ON(n->gro_list);
 
        list_del_init(&n->poll_list);
        smp_mb__before_atomic();
 }
 EXPORT_SYMBOL(__napi_complete);
 
-void napi_complete(struct napi_struct *n)
+void napi_complete_done(struct napi_struct *n, int work_done)
 {
        unsigned long flags;
 
        if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state)))
                return;
 
-       napi_gro_flush(n, false);
+       if (n->gro_list) {
+               unsigned long timeout = 0;
 
+               if (work_done)
+                       timeout = n->dev->gro_flush_timeout;
+
+               if (timeout)
+                       hrtimer_start(&n->timer, ns_to_ktime(timeout),
+                                     HRTIMER_MODE_REL_PINNED);
+               else
+                       napi_gro_flush(n, false);
+       }
        if (likely(list_empty(&n->poll_list))) {
                WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state));
        } else {
                local_irq_restore(flags);
        }
 }
-EXPORT_SYMBOL(napi_complete);
+EXPORT_SYMBOL(napi_complete_done);
 
 /* must be called under rcu_read_lock(), as we dont take a reference */
 struct napi_struct *napi_by_id(unsigned int napi_id)
 }
 EXPORT_SYMBOL_GPL(napi_hash_del);
 
+static enum hrtimer_restart napi_watchdog(struct hrtimer *timer)
+{
+       struct napi_struct *napi;
+
+       napi = container_of(timer, struct napi_struct, timer);
+       if (napi->gro_list)
+               napi_schedule(napi);
+
+       return HRTIMER_NORESTART;
+}
+
 void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
                    int (*poll)(struct napi_struct *, int), int weight)
 {
        INIT_LIST_HEAD(&napi->poll_list);
+       hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+       napi->timer.function = napi_watchdog;
        napi->gro_count = 0;
        napi->gro_list = NULL;
        napi->skb = NULL;
 }
 EXPORT_SYMBOL(netif_napi_add);
 
+void napi_disable(struct napi_struct *n)
+{
+       might_sleep();
+       set_bit(NAPI_STATE_DISABLE, &n->state);
+
+       while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
+               msleep(1);
+
+       hrtimer_cancel(&n->timer);
+
+       clear_bit(NAPI_STATE_DISABLE, &n->state);
+}
+EXPORT_SYMBOL(napi_disable);
+
 void netif_napi_del(struct napi_struct *napi)
 {
        list_del_init(&napi->dev_list);
 
 }
 NETDEVICE_SHOW_RW(tx_queue_len, fmt_ulong);
 
+static int change_gro_flush_timeout(struct net_device *dev, unsigned long val)
+{
+       dev->gro_flush_timeout = val;
+       return 0;
+}
+
+static ssize_t gro_flush_timeout_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       return netdev_store(dev, attr, buf, len, change_gro_flush_timeout);
+}
+NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong);
+
 static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t len)
 {
        &dev_attr_mtu.attr,
        &dev_attr_flags.attr,
        &dev_attr_tx_queue_len.attr,
+       &dev_attr_gro_flush_timeout.attr,
        &dev_attr_phys_port_id.attr,
        NULL,
 };