A netdev_queue is an entity managed by a qdisc.
Currently there is one RX and one TX queue, and a netdev_queue merely
contains a backpointer to the net_device.
The Qdisc struct is augmented with a netdev_queue pointer as well.
Eventually the 'dev' Qdisc member will go away and we will have the
resulting hierarchy:
	net_device --> netdev_queue --> Qdisc
Also, qdisc_alloc() and qdisc_create_dflt() now take a netdev_queue
pointer argument.
Signed-off-by: David S. Miller <davem@davemloft.net>
 # define napi_synchronize(n)   barrier()
 #endif
 
+struct netdev_queue {
+       struct net_device       *dev;
+};
+
 /*
  *     The DEVICE structure.
  *     Actually, this whole structure is a big mistake.  It mixes I/O
 
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
 
+       struct netdev_queue     rx_queue;
+       struct netdev_queue     tx_queue;
+
        /* ingress path synchronizer */
        spinlock_t              ingress_lock;
        struct Qdisc            *qdisc_ingress;
 
        u32                     parent;
        atomic_t                refcnt;
        struct sk_buff_head     q;
+       struct netdev_queue     *dev_queue;
        struct net_device       *dev;
        struct list_head        list;
 
 extern void qdisc_reset(struct Qdisc *qdisc);
 extern void qdisc_destroy(struct Qdisc *qdisc);
 extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
-extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops);
+extern struct Qdisc *qdisc_alloc(struct net_device *dev,
+                                struct netdev_queue *dev_queue,
+                                struct Qdisc_ops *ops);
 extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
+                                      struct netdev_queue *dev_queue,
                                       struct Qdisc_ops *ops, u32 parentid);
 extern void tcf_destroy(struct tcf_proto *tp);
 extern void tcf_destroy_chain(struct tcf_proto **fl);
 
        return &dev->stats;
 }
 
+static void netdev_init_queues(struct net_device *dev)
+{
+       dev->rx_queue.dev = dev;
+       dev->tx_queue.dev = dev;
+}
+
 /**
  *     alloc_netdev_mq - allocate network device
  *     @sizeof_priv:   size of private data to allocate space for
        dev->egress_subqueue_count = queue_count;
        dev->gso_max_size = GSO_MAX_SIZE;
 
+       netdev_init_queues(dev);
+
        dev->get_stats = internal_stats;
        netpoll_netdev_init(dev);
        setup(dev);
 
        /* create child queues */
        for (i = 0; i < QD_NUM(hw); i++) {
                skb_queue_head_init(&q->requeued[i]);
-               q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
+               q->queues[i] = qdisc_create_dflt(qd->dev, qd->dev_queue,
+                                                &pfifo_qdisc_ops,
                                                 qd->handle);
                if (!q->queues[i]) {
                        q->queues[i] = &noop_qdisc;
 {
        struct Qdisc *qdisc;
 
-       qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT);
+       qdisc = qdisc_create_dflt(dev, &dev->tx_queue,
+                                 &wme_qdisc_ops, TC_H_ROOT);
        if (!qdisc) {
                printk(KERN_ERR "%s: qdisc installation failed\n", dev->name);
                return;
 
  */
 
 static struct Qdisc *
-qdisc_create(struct net_device *dev, u32 parent, u32 handle,
-          struct nlattr **tca, int *errp)
+qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
+            u32 parent, u32 handle, struct nlattr **tca, int *errp)
 {
        int err;
        struct nlattr *kind = tca[TCA_KIND];
        if (ops == NULL)
                goto err_out;
 
-       sch = qdisc_alloc(dev, ops);
+       sch = qdisc_alloc(dev, dev_queue, ops);
        if (IS_ERR(sch)) {
                err = PTR_ERR(sch);
                goto err_out2;
        if (!(n->nlmsg_flags&NLM_F_CREATE))
                return -ENOENT;
        if (clid == TC_H_INGRESS)
-               q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_parent,
+               q = qdisc_create(dev, &dev->rx_queue,
+                                tcm->tcm_parent, tcm->tcm_parent,
                                 tca, &err);
        else
-               q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_handle,
+               q = qdisc_create(dev, &dev->tx_queue,
+                                tcm->tcm_parent, tcm->tcm_handle,
                                 tca, &err);
        if (q == NULL) {
                if (err == -EAGAIN)
 
                goto err_out;
        }
        flow->filter_list = NULL;
-       flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+       flow->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                   &pfifo_qdisc_ops, classid);
        if (!flow->q)
                flow->q = &noop_qdisc;
        pr_debug("atm_tc_change: qdisc %p\n", flow->q);
 
        pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
        p->flows = &p->link;
-       p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
+       p->link.q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                     &pfifo_qdisc_ops, sch->handle);
        if (!p->link.q)
                p->link.q = &noop_qdisc;
        pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
 
        q->link.sibling = &q->link;
        q->link.common.classid = sch->handle;
        q->link.qdisc = sch;
-       if (!(q->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+       if (!(q->link.q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                           &pfifo_qdisc_ops,
                                            sch->handle)))
                q->link.q = &noop_qdisc;
 
 
        if (cl) {
                if (new == NULL) {
-                       new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                       new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                               &pfifo_qdisc_ops,
                                                cl->common.classid);
                        if (new == NULL)
                                return -ENOBUFS;
        cl->R_tab = rtab;
        rtab = NULL;
        cl->refcnt = 1;
-       if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
+       if (!(cl->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                       &pfifo_qdisc_ops, classid)))
                cl->q = &noop_qdisc;
        cl->common.classid = classid;
        cl->tparent = parent;
 
                sch, p, new, old);
 
        if (new == NULL) {
-               new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+               new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                       &pfifo_qdisc_ops,
                                        sch->handle);
                if (new == NULL)
                        new = &noop_qdisc;
        p->default_index = default_index;
        p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
 
-       p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
+       p->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                &pfifo_qdisc_ops, sch->handle);
        if (p->q == NULL)
                p->q = &noop_qdisc;
 
 
        struct Qdisc *q;
        int err = -ENOMEM;
 
-       q = qdisc_create_dflt(sch->dev, ops, TC_H_MAKE(sch->handle, 1));
+       q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                             ops, TC_H_MAKE(sch->handle, 1));
        if (q) {
                err = fifo_set_limit(q, limit);
                if (err < 0) {
 
        .owner          =       THIS_MODULE,
 };
 
-struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
+struct Qdisc *qdisc_alloc(struct net_device *dev,
+                         struct netdev_queue *dev_queue,
+                         struct Qdisc_ops *ops)
 {
        void *p;
        struct Qdisc *sch;
        sch->ops = ops;
        sch->enqueue = ops->enqueue;
        sch->dequeue = ops->dequeue;
+       sch->dev_queue = dev_queue;
        sch->dev = dev;
        dev_hold(dev);
        atomic_set(&sch->refcnt, 1);
        return ERR_PTR(err);
 }
 
-struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops,
+struct Qdisc * qdisc_create_dflt(struct net_device *dev,
+                                struct netdev_queue *dev_queue,
+                                struct Qdisc_ops *ops,
                                 unsigned int parentid)
 {
        struct Qdisc *sch;
 
-       sch = qdisc_alloc(dev, ops);
+       sch = qdisc_alloc(dev, dev_queue, ops);
        if (IS_ERR(sch))
                goto errout;
        sch->stats_lock = &dev->queue_lock;
        if (dev->qdisc_sleeping == &noop_qdisc) {
                struct Qdisc *qdisc;
                if (dev->tx_queue_len) {
-                       qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops,
+                       qdisc = qdisc_create_dflt(dev, &dev->tx_queue,
+                                                 &pfifo_fast_ops,
                                                  TC_H_ROOT);
                        if (qdisc == NULL) {
                                printk(KERN_INFO "%s: activation failed\n", dev->name);
 
        cl->refcnt    = 1;
        cl->sched     = q;
        cl->cl_parent = parent;
-       cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+       cl->qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                     &pfifo_qdisc_ops, classid);
        if (cl->qdisc == NULL)
                cl->qdisc = &noop_qdisc;
        INIT_LIST_HEAD(&cl->children);
        if (cl->level > 0)
                return -EINVAL;
        if (new == NULL) {
-               new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+               new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                       &pfifo_qdisc_ops,
                                        cl->cl_common.classid);
                if (new == NULL)
                        new = &noop_qdisc;
        q->root.cl_common.classid = sch->handle;
        q->root.refcnt  = 1;
        q->root.sched   = q;
-       q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+       q->root.qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                         &pfifo_qdisc_ops,
                                          sch->handle);
        if (q->root.qdisc == NULL)
                q->root.qdisc = &noop_qdisc;
 
 
        if (cl && !cl->level) {
                if (new == NULL &&
-                   (new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                   (new = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                            &pfifo_qdisc_ops,
                                             cl->common.classid))
                    == NULL)
                        return -ENOBUFS;
                return -EBUSY;
 
        if (!cl->level && htb_parent_last_child(cl)) {
-               new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
-                                               cl->parent->common.classid);
+               new_q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                         &pfifo_qdisc_ops,
+                                         cl->parent->common.classid);
                last_child = 1;
        }
 
                /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
                   so that can't be used inside of sch_tree_lock
                   -- thanks to Karlis Peisenieks */
-               new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+               new_q = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                         &pfifo_qdisc_ops, classid);
                sch_tree_lock(sch);
                if (parent && !parent->level) {
                        unsigned int qlen = parent->un.leaf.q->q.qlen;
 
 
        qdisc_watchdog_init(&q->watchdog, sch);
 
-       q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops,
+       q->qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                    &tfifo_qdisc_ops,
                                     TC_H_MAKE(sch->handle, 1));
        if (!q->qdisc) {
                pr_debug("netem: qdisc create failed\n");
 
        for (i=0; i<q->bands; i++) {
                if (q->queues[i] == &noop_qdisc) {
                        struct Qdisc *child;
-                       child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+                       child = qdisc_create_dflt(sch->dev, sch->dev_queue,
+                                                 &pfifo_qdisc_ops,
                                                  TC_H_MAKE(sch->handle, i + 1));
                        if (child) {
                                sch_tree_lock(sch);