-
-static struct Qdisc *
-wme_classop_leaf(struct Qdisc *qd, unsigned long arg)
-{
- struct ieee80211_sched_data *q = qdisc_priv(qd);
- struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
- struct ieee80211_hw *hw = &local->hw;
- unsigned long queue = arg - 1;
-
- if (queue >= hw->queues)
- return NULL;
-
- return q->queues[queue];
-}
-
-
-static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid)
-{
- struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
- struct ieee80211_hw *hw = &local->hw;
- unsigned long queue = TC_H_MIN(classid);
-
- if (queue - 1 >= hw->queues)
- return 0;
-
- return queue;
-}
-
-
-static unsigned long wme_classop_bind(struct Qdisc *qd, unsigned long parent,
- u32 classid)
-{
- return wme_classop_get(qd, classid);
-}
-
-
-static void wme_classop_put(struct Qdisc *q, unsigned long cl)
-{
-}
-
-
-static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent,
- struct nlattr **tca, unsigned long *arg)
-{
- unsigned long cl = *arg;
- struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
- struct ieee80211_hw *hw = &local->hw;
-
- if (cl - 1 > hw->queues)
- return -ENOENT;
-
- /* TODO: put code to program hardware queue parameters here,
- * to allow programming from tc command line */
-
- return 0;
-}
-
-
-/* we don't support deleting hardware queues
- * when we add WMM-SA support - TSPECs may be deleted here */
-static int wme_classop_delete(struct Qdisc *qd, unsigned long cl)
-{
- struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
- struct ieee80211_hw *hw = &local->hw;
-
- if (cl - 1 > hw->queues)
- return -ENOENT;
- return 0;
-}
-
-
-static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl,
- struct sk_buff *skb, struct tcmsg *tcm)
-{
- struct ieee80211_sched_data *q = qdisc_priv(qd);
- struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
- struct ieee80211_hw *hw = &local->hw;
-
- if (cl - 1 > hw->queues)
- return -ENOENT;
- tcm->tcm_handle = TC_H_MIN(cl);
- tcm->tcm_parent = qd->handle;
- tcm->tcm_info = q->queues[cl-1]->handle; /* do we need this? */
- return 0;
-}
-
-
-static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg)
-{
- struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
- struct ieee80211_hw *hw = &local->hw;
- int queue;
-
- if (arg->stop)
- return;
-
- for (queue = 0; queue < hw->queues; queue++) {
- if (arg->count < arg->skip) {
- arg->count++;
- continue;
- }
- /* we should return classids for our internal queues here
- * as well as the external ones */
- if (arg->fn(qd, queue+1, arg) < 0) {
- arg->stop = 1;
- break;
- }
- arg->count++;
- }
-}
-
-
-static struct tcf_proto ** wme_classop_find_tcf(struct Qdisc *qd,
- unsigned long cl)
-{
- struct ieee80211_sched_data *q = qdisc_priv(qd);
-
- if (cl)
- return NULL;
-
- return &q->filter_list;
-}
-
-
-/* this qdisc is classful (i.e. has classes, some of which may have leaf qdiscs attached)
- * - these are the operations on the classes */
-static const struct Qdisc_class_ops class_ops =
-{
- .graft = wme_classop_graft,
- .leaf = wme_classop_leaf,
-
- .get = wme_classop_get,
- .put = wme_classop_put,
- .change = wme_classop_change,
- .delete = wme_classop_delete,
- .walk = wme_classop_walk,
-
- .tcf_chain = wme_classop_find_tcf,
- .bind_tcf = wme_classop_bind,
- .unbind_tcf = wme_classop_put,
-
- .dump = wme_classop_dump_class,
-};
-
-
-/* queueing discipline operations */
-static struct Qdisc_ops wme_qdisc_ops __read_mostly =
-{
- .next = NULL,
- .cl_ops = &class_ops,
- .id = "ieee80211",
- .priv_size = sizeof(struct ieee80211_sched_data),
-
- .enqueue = wme_qdiscop_enqueue,
- .dequeue = wme_qdiscop_dequeue,
- .requeue = wme_qdiscop_requeue,
- .drop = NULL, /* drop not needed since we are always the root qdisc */
-
- .init = wme_qdiscop_init,
- .reset = wme_qdiscop_reset,
- .destroy = wme_qdiscop_destroy,
- .change = wme_qdiscop_tune,
-
- .dump = wme_qdiscop_dump,
-};
-
-
-void ieee80211_install_qdisc(struct net_device *dev)
-{
- struct Qdisc *qdisc;
-
- qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT);
- if (!qdisc) {
- printk(KERN_ERR "%s: qdisc installation failed\n", dev->name);
- return;
- }
-
- /* same handle as would be allocated by qdisc_alloc_handle() */
- qdisc->handle = 0x80010000;
-
- qdisc_lock_tree(dev);
- list_add_tail(&qdisc->list, &dev->qdisc_list);
- dev->qdisc_sleeping = qdisc;
- qdisc_unlock_tree(dev);
-}
-
-
-int ieee80211_qdisc_installed(struct net_device *dev)
-{
- return dev->qdisc_sleeping->ops == &wme_qdisc_ops;
-}
-
-
-int ieee80211_wme_register(void)
-{
- return register_qdisc(&wme_qdisc_ops);
-}
-
-
-void ieee80211_wme_unregister(void)
-{
- unregister_qdisc(&wme_qdisc_ops);
-}
-
-int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
- struct sta_info *sta, u16 tid)
-{
- int i;
- struct ieee80211_sched_data *q =
- qdisc_priv(local->mdev->qdisc_sleeping);
- DECLARE_MAC_BUF(mac);
-
- /* prepare the filter and save it for the SW queue
- * matching the recieved HW queue */
-
- /* try to get a Qdisc from the pool */
- for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
- if (!test_and_set_bit(i, q->qdisc_pool)) {
- ieee80211_stop_queue(local_to_hw(local), i);
- sta->tid_to_tx_q[tid] = i;
-
- /* IF there are already pending packets
- * on this tid first we need to drain them
- * on the previous queue
- * since HT is strict in order */
-#ifdef CONFIG_MAC80211_HT_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "allocated aggregation queue"
- " %d tid %d addr %s pool=0x%lX",
- i, tid, print_mac(mac, sta->addr),
- q->qdisc_pool[0]);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
- return 0;
- }
-
- return -EAGAIN;
-}
-
-/**
- * the caller needs to hold local->mdev->queue_lock
- */
-void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
- struct sta_info *sta, u16 tid,
- u8 requeue)
-{
- struct ieee80211_sched_data *q =
- qdisc_priv(local->mdev->qdisc_sleeping);
- int agg_queue = sta->tid_to_tx_q[tid];
-
- /* return the qdisc to the pool */
- clear_bit(agg_queue, q->qdisc_pool);
- sta->tid_to_tx_q[tid] = local->hw.queues;
-
- if (requeue)
- ieee80211_requeue(local, agg_queue);
- else
- q->queues[agg_queue]->ops->reset(q->queues[agg_queue]);
-}
-
-void ieee80211_requeue(struct ieee80211_local *local, int queue)
-{
- struct Qdisc *root_qd = local->mdev->qdisc_sleeping;
- struct ieee80211_sched_data *q = qdisc_priv(root_qd);
- struct Qdisc *qdisc = q->queues[queue];
- struct sk_buff *skb = NULL;
- u32 len = qdisc->q.qlen;
-
- if (!qdisc || !qdisc->dequeue)
- return;
-
- printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen);
- for (len = qdisc->q.qlen; len > 0; len--) {
- skb = qdisc->dequeue(qdisc);
- root_qd->q.qlen--;
- /* packet will be classified again and */
- /* skb->packet_data->queue will be overridden if needed */
- if (skb)
- wme_qdiscop_enqueue(skb, root_qd);
- }