struct Qdisc *child;
        int queue;
 
+       if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) {
+               WARN_ONCE(1, "Trying to enqueue skb into the root of a taprio qdisc configured with full offload\n");
+               return qdisc_drop(skb, sch, to_free);
+       }
+
        queue = skb_get_queue_mapping(skb);
 
        child = q->qdiscs[queue];
 
 static struct sk_buff *taprio_peek_offload(struct Qdisc *sch)
 {
-       struct taprio_sched *q = qdisc_priv(sch);
-       struct net_device *dev = qdisc_dev(sch);
-       struct sk_buff *skb;
-       int i;
-
-       for (i = 0; i < dev->num_tx_queues; i++) {
-               struct Qdisc *child = q->qdiscs[i];
-
-               if (unlikely(!child))
-                       continue;
-
-               skb = child->ops->peek(child);
-               if (!skb)
-                       continue;
-
-               return skb;
-       }
+       WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n");
 
        return NULL;
 }
 
 static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch)
 {
-       struct taprio_sched *q = qdisc_priv(sch);
-       struct net_device *dev = qdisc_dev(sch);
-       struct sk_buff *skb;
-       int i;
-
-       for (i = 0; i < dev->num_tx_queues; i++) {
-               struct Qdisc *child = q->qdiscs[i];
-
-               if (unlikely(!child))
-                       continue;
-
-               skb = child->ops->dequeue(child);
-               if (unlikely(!skb))
-                       continue;
-
-               qdisc_bstats_update(sch, skb);
-               qdisc_qstats_backlog_dec(sch, skb);
-               sch->q.qlen--;
-
-               return skb;
-       }
+       WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n");
 
        return NULL;
 }
        return taprio_change(sch, opt, extack);
 }
 
+static void taprio_attach(struct Qdisc *sch)
+{
+       struct taprio_sched *q = qdisc_priv(sch);
+       struct net_device *dev = qdisc_dev(sch);
+       unsigned int ntx;
+
+       /* Attach underlying qdisc */
+       for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
+               struct Qdisc *qdisc = q->qdiscs[ntx];
+               struct Qdisc *old;
+
+               if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
+                       qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
+                       old = dev_graft_qdisc(qdisc->dev_queue, qdisc);
+                       if (ntx < dev->real_num_tx_queues)
+                               qdisc_hash_add(qdisc, false);
+               } else {
+                       old = dev_graft_qdisc(qdisc->dev_queue, sch);
+                       qdisc_refcount_inc(sch);
+               }
+               if (old)
+                       qdisc_put(old);
+       }
+
+       /* access to the child qdiscs is not needed in offload mode */
+       if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
+               kfree(q->qdiscs);
+               q->qdiscs = NULL;
+       }
+}
+
 static struct netdev_queue *taprio_queue_get(struct Qdisc *sch,
                                             unsigned long cl)
 {
        if (dev->flags & IFF_UP)
                dev_deactivate(dev);
 
-       *old = q->qdiscs[cl - 1];
-       q->qdiscs[cl - 1] = new;
+       if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
+               *old = dev_graft_qdisc(dev_queue, new);
+       } else {
+               *old = q->qdiscs[cl - 1];
+               q->qdiscs[cl - 1] = new;
+       }
 
        if (new)
                new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
        .change         = taprio_change,
        .destroy        = taprio_destroy,
        .reset          = taprio_reset,
+       .attach         = taprio_attach,
        .peek           = taprio_peek,
        .dequeue        = taprio_dequeue,
        .enqueue        = taprio_enqueue,