#include <linux/pkt_sched.h>
 #include <linux/pkt_cls.h>
 #include <linux/percpu.h>
+#include <linux/dynamic_queue_limits.h>
 #include <net/gen_stats.h>
 #include <net/rtnetlink.h>
 
        qdisc->__state &= ~__QDISC___STATE_RUNNING;
 }
 
+static inline bool qdisc_may_bulk(const struct Qdisc *qdisc)
+{
+       return qdisc->flags & TCQ_F_ONETXQUEUE;
+}
+
+static inline int qdisc_avail_bulklimit(const struct netdev_queue *txq)
+{
+#ifdef CONFIG_BQL
+       /* Non-BQL migrated drivers will return 0, too. */
+       return dql_avail(&txq->dql);
+#else
+       return 0;
+#endif
+}
+
 static inline bool qdisc_is_throttled(const struct Qdisc *qdisc)
 {
        return test_bit(__QDISC_STATE_THROTTLED, &qdisc->state) ? true : false;
 
        return 0;
 }
 
+static struct sk_buff *try_bulk_dequeue_skb(struct Qdisc *q,
+                                           struct sk_buff *head_skb,
+                                           int bytelimit)
+{
+       struct sk_buff *skb, *tail_skb = head_skb;
+
+       while (bytelimit > 0) {
+               /* For now, don't bulk dequeue GSO (or GSO segmented) pkts */
+               if (tail_skb->next || skb_is_gso(tail_skb))
+                       break;
+
+               skb = q->dequeue(q);
+               if (!skb)
+                       break;
+
+               bytelimit -= skb->len; /* covers GSO len */
+               skb = validate_xmit_skb(skb, qdisc_dev(q));
+               if (!skb)
+                       break;
+
+               /* "skb" can be a skb list after validate call above
+                * (GSO segmented), but it is okay to append it to
+                * current tail_skb->next, because next round will exit
+                * in-case "tail_skb->next" is a skb list.
+                */
+               tail_skb->next = skb;
+               tail_skb = skb;
+       }
+
+       return head_skb;
+}
+
+/* Note that dequeue_skb can possibly return a SKB list (via skb->next).
+ * A requeued skb (via q->gso_skb) can also be a SKB list.
+ */
 static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
 {
        struct sk_buff *skb = q->gso_skb;
                } else
                        skb = NULL;
        } else {
-               if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq)) {
+               if (!(q->flags & TCQ_F_ONETXQUEUE) ||
+                   !netif_xmit_frozen_or_stopped(txq)) {
+                       int bytelimit = qdisc_avail_bulklimit(txq);
+
                        skb = q->dequeue(q);
-                       if (skb)
+                       if (skb) {
+                               bytelimit -= skb->len;
                                skb = validate_xmit_skb(skb, qdisc_dev(q));
+                       }
+                       if (skb && qdisc_may_bulk(q))
+                               skb = try_bulk_dequeue_skb(q, skb, bytelimit);
                }
        }