.llseek = default_llseek,
 };
 
-void ath_debug_airtime(struct ath_softc *sc,
-               struct ath_node *an,
-               u32 rx,
-               u32 tx)
-{
-       struct ath_airtime_stats *astats = &an->airtime_stats;
-
-       astats->rx_airtime += rx;
-       astats->tx_airtime += tx;
-}
-
-static ssize_t read_airtime(struct file *file, char __user *user_buf,
-                       size_t count, loff_t *ppos)
-{
-       struct ath_node *an = file->private_data;
-       struct ath_airtime_stats *astats;
-       static const char *qname[4] = {
-               "VO", "VI", "BE", "BK"
-       };
-       u32 len = 0, size = 256;
-       char *buf;
-       size_t retval;
-       int i;
-
-       buf = kzalloc(size, GFP_KERNEL);
-       if (buf == NULL)
-               return -ENOMEM;
-
-       astats = &an->airtime_stats;
-
-       len += scnprintf(buf + len, size - len, "RX: %u us\n", astats->rx_airtime);
-       len += scnprintf(buf + len, size - len, "TX: %u us\n", astats->tx_airtime);
-       len += scnprintf(buf + len, size - len, "Deficit: ");
-       for (i = 0; i < 4; i++)
-               len += scnprintf(buf+len, size - len, "%s: %lld us ", qname[i], an->airtime_deficit[i]);
-       if (len < size)
-               buf[len++] = '\n';
-
-       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-       kfree(buf);
-
-       return retval;
-}
-
-static ssize_t
-write_airtime_reset_stub(struct file *file, const char __user *ubuf,
-                  size_t count, loff_t *ppos)
-{
-       struct ath_node *an = file->private_data;
-       struct ath_airtime_stats *astats;
-       int i;
-
-       astats = &an->airtime_stats;
-       astats->rx_airtime = 0;
-       astats->tx_airtime = 0;
-       for (i = 0; i < 4; i++)
-               an->airtime_deficit[i] = ATH_AIRTIME_QUANTUM;
-       return count;
-}
-
-static const struct file_operations fops_airtime = {
-       .read = read_airtime,
-       .write = write_airtime_reset_stub,
-       .open = simple_open,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
-};
-
-
 void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
                           struct ieee80211_vif *vif,
                           struct ieee80211_sta *sta,
 
        debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr);
        debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv);
-       debugfs_create_file("airtime", 0644, dir, an, &fops_airtime);
 }
 
                ath_tx_status(hw, skb);
 }
 
-void __ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
-       struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
-       struct ath_chanctx *ctx = avp->chanctx;
-       struct ath_acq *acq;
-       struct list_head *tid_list;
-       u8 acno = TID_TO_WME_AC(tid->tidno);
-
-       if (!ctx || !list_empty(&tid->list))
-               return;
-
-
-       acq = &ctx->acq[acno];
-       if ((sc->airtime_flags & AIRTIME_USE_NEW_QUEUES) &&
-           tid->an->airtime_deficit[acno] > 0)
-               tid_list = &acq->acq_new;
-       else
-               tid_list = &acq->acq_old;
-
-       list_add_tail(&tid->list, tid_list);
-}
-
 void ath_tx_queue_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
-       struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv;
-       struct ath_chanctx *ctx = avp->chanctx;
-       struct ath_acq *acq;
+       struct ieee80211_txq *queue =
+               container_of((void *)tid, struct ieee80211_txq, drv_priv);
 
-       if (!ctx || !list_empty(&tid->list))
-               return;
-
-       acq = &ctx->acq[TID_TO_WME_AC(tid->tidno)];
-       spin_lock_bh(&acq->lock);
-       __ath_tx_queue_tid(sc, tid);
-       spin_unlock_bh(&acq->lock);
+       ieee80211_schedule_txq(sc->hw, queue);
 }
 
-
 void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
 {
        struct ath_softc *sc = hw->priv;
                tid->tidno);
 
        ath_txq_lock(sc, txq);
-
-       tid->has_queued = true;
-       ath_tx_queue_tid(sc, tid);
        ath_txq_schedule(sc, txq);
-
        ath_txq_unlock(sc, txq);
 }
 
        return ATH_AN_2_TID(an, tidno);
 }
 
-static struct sk_buff *
-ath_tid_pull(struct ath_atx_tid *tid)
+static int
+ath_tid_pull(struct ath_atx_tid *tid, struct sk_buff **skbuf)
 {
        struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv);
        struct ath_softc *sc = tid->an->sc;
        };
        struct sk_buff *skb;
        struct ath_frame_info *fi;
-       int q;
-
-       if (!tid->has_queued)
-               return NULL;
+       int q, ret;
 
        skb = ieee80211_tx_dequeue(hw, txq);
-       if (!skb) {
-               tid->has_queued = false;
-               return NULL;
-       }
+       if (!skb)
+               return -ENOENT;
 
-       if (ath_tx_prepare(hw, skb, &txctl)) {
+       ret = ath_tx_prepare(hw, skb, &txctl);
+       if (ret) {
                ieee80211_free_txskb(hw, skb);
-               return NULL;
+               return ret;
        }
 
        q = skb_get_queue_mapping(skb);
                ++tid->txq->pending_frames;
        }
 
-       return skb;
-}
-
-
-static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
-{
-       return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
+       *skbuf = skb;
+       return 0;
 }
 
-static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
+static int ath_tid_dequeue(struct ath_atx_tid *tid,
+                          struct sk_buff **skb)
 {
-       struct sk_buff *skb;
-
-       skb = __skb_dequeue(&tid->retry_q);
-       if (!skb)
-               skb = ath_tid_pull(tid);
+       int ret = 0;
+       *skb = __skb_dequeue(&tid->retry_q);
+       if (!*skb)
+               ret = ath_tid_pull(tid, skb);
 
-       return skb;
+       return ret;
 }
 
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
        struct list_head bf_head;
        struct ath_tx_status ts;
        struct ath_frame_info *fi;
+       int ret;
 
        memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
-       while ((skb = ath_tid_dequeue(tid))) {
+       while ((ret = ath_tid_dequeue(tid, &skb)) == 0) {
                fi = get_frame_info(skb);
                bf = fi->bf;
 
                skb_queue_splice_tail(&bf_pending, &tid->retry_q);
                if (!an->sleeping) {
                        ath_tx_queue_tid(sc, tid);
-
                        if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
                                tid->clear_ps_filter = true;
                }
     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
 }
 
-static void ath_tx_count_airtime(struct ath_softc *sc, struct ath_node *an,
-                                struct ath_atx_tid *tid, struct ath_buf *bf,
+static void ath_tx_count_airtime(struct ath_softc *sc,
+                                struct ieee80211_sta *sta,
+                                struct ath_buf *bf,
                                 struct ath_tx_status *ts)
 {
-       struct ath_txq *txq = tid->txq;
        u32 airtime = 0;
        int i;
 
                airtime += rate_dur * bf->rates[i].count;
        }
 
-       if (sc->airtime_flags & AIRTIME_USE_TX) {
-               int q = txq->mac80211_qnum;
-               struct ath_acq *acq = &sc->cur_chan->acq[q];
-
-               spin_lock_bh(&acq->lock);
-               an->airtime_deficit[q] -= airtime;
-               if (an->airtime_deficit[q] <= 0)
-                       __ath_tx_queue_tid(sc, tid);
-               spin_unlock_bh(&acq->lock);
-       }
-       ath_debug_airtime(sc, an, 0, airtime);
+       ieee80211_sta_register_airtime(sta, ts->tid, airtime, 0);
 }
 
 static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
        if (sta) {
                struct ath_node *an = (struct ath_node *)sta->drv_priv;
                tid = ath_get_skb_tid(sc, an, bf->bf_mpdu);
-               ath_tx_count_airtime(sc, an, tid, bf, ts);
+               ath_tx_count_airtime(sc, sta, bf, ts);
                if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY))
                        tid->clear_ps_filter = true;
        }
        return ndelim;
 }
 
-static struct ath_buf *
+static int
 ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
-                       struct ath_atx_tid *tid)
+                       struct ath_atx_tid *tid, struct ath_buf **buf)
 {
        struct ieee80211_tx_info *tx_info;
        struct ath_frame_info *fi;
-       struct sk_buff *skb, *first_skb = NULL;
        struct ath_buf *bf;
+       struct sk_buff *skb, *first_skb = NULL;
        u16 seqno;
+       int ret;
 
        while (1) {
-               skb = ath_tid_dequeue(tid);
-               if (!skb)
-                       break;
+               ret = ath_tid_dequeue(tid, &skb);
+               if (ret < 0)
+                       return ret;
 
                fi = get_frame_info(skb);
                bf = fi->bf;
 
                if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
                        bf->bf_state.bf_type = 0;
-                       return bf;
+                       break;
                }
 
                bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR;
                                        first_skb = skb;
                                continue;
                        }
-                       break;
+                       return -EINPROGRESS;
                }
 
                if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
                if (bf_isampdu(bf))
                        ath_tx_addto_baw(sc, tid, bf);
 
-               return bf;
+               break;
        }
 
-       return NULL;
+       *buf = bf;
+       return 0;
 }
 
 static int
 {
 #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
        struct ath_buf *bf = bf_first, *bf_prev = NULL;
-       int nframes = 0, ndelim;
+       int nframes = 0, ndelim, ret;
        u16 aggr_limit = 0, al = 0, bpad = 0,
            al_delta, h_baw = tid->baw_size / 2;
        struct ieee80211_tx_info *tx_info;
 
                bf_prev = bf;
 
-               bf = ath_tx_get_tid_subframe(sc, txq, tid);
+               ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf);
+               if (ret < 0)
+                       break;
        }
        goto finish;
 stop:
                  struct ath_buf *bf_first)
 {
        struct ath_buf *bf = bf_first, *bf_prev = NULL;
-       int nframes = 0;
+       int nframes = 0, ret;
 
        do {
                struct ieee80211_tx_info *tx_info;
                if (nframes >= 2)
                        break;
 
-               bf = ath_tx_get_tid_subframe(sc, txq, tid);
-               if (!bf)
+               ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf);
+               if (ret < 0)
                        break;
 
                tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
        } while (1);
 }
 
-static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
-                             struct ath_atx_tid *tid)
+static int ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
+                            struct ath_atx_tid *tid)
 {
-       struct ath_buf *bf;
+       struct ath_buf *bf = NULL;
        struct ieee80211_tx_info *tx_info;
        struct list_head bf_q;
-       int aggr_len = 0;
+       int aggr_len = 0, ret;
        bool aggr;
 
-       if (!ath_tid_has_buffered(tid))
-               return false;
-
        INIT_LIST_HEAD(&bf_q);
 
-       bf = ath_tx_get_tid_subframe(sc, txq, tid);
-       if (!bf)
-               return false;
+       ret = ath_tx_get_tid_subframe(sc, txq, tid, &bf);
+       if (ret < 0)
+               return ret;
 
        tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
        aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
        if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
            (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
                __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
-               return false;
+               return -EBUSY;
        }
 
        ath_set_rates(tid->an->vif, tid->an->sta, bf);
                ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
 
        if (list_empty(&bf_q))
-               return false;
+               return -EAGAIN;
 
        if (tid->clear_ps_filter || tid->an->no_ps_filter) {
                tid->clear_ps_filter = false;
 
        ath_tx_fill_desc(sc, bf, txq, aggr_len);
        ath_tx_txqaddbuf(sc, txq, &bf_q, false);
-       return true;
+       return 0;
 }
 
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_atx_tid *tid;
-       struct ath_txq *txq;
        int tidno;
 
        ath_dbg(common, XMIT, "%s called\n", __func__);
 
        for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
                tid = ath_node_to_tid(an, tidno);
-               txq = tid->txq;
-
-               ath_txq_lock(sc, txq);
-
-               if (list_empty(&tid->list)) {
-                       ath_txq_unlock(sc, txq);
-                       continue;
-               }
 
                if (!skb_queue_empty(&tid->retry_q))
                        ieee80211_sta_set_buffered(sta, tid->tidno, true);
 
-               list_del_init(&tid->list);
-
-               ath_txq_unlock(sc, txq);
        }
 }
 
 
                ath_txq_lock(sc, txq);
                tid->clear_ps_filter = true;
-               if (ath_tid_has_buffered(tid)) {
+               if (!skb_queue_empty(&tid->retry_q)) {
                        ath_tx_queue_tid(sc, tid);
                        ath_txq_schedule(sc, txq);
                }
                ath_txq_unlock_complete(sc, txq);
+
        }
 }
 
        struct ath_txq *txq = sc->tx.uapsdq;
        struct ieee80211_tx_info *info;
        struct list_head bf_q;
-       struct ath_buf *bf_tail = NULL, *bf;
+       struct ath_buf *bf_tail = NULL, *bf = NULL;
        int sent = 0;
-       int i;
+       int i, ret;
 
        INIT_LIST_HEAD(&bf_q);
        for (i = 0; tids && nframes; i++, tids >>= 1) {
 
                ath_txq_lock(sc, tid->txq);
                while (nframes > 0) {
-                       bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
-                       if (!bf)
+                       ret = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq,
+                                                     tid, &bf);
+                       if (ret < 0)
                                break;
 
                        ath9k_set_moredata(sc, bf, true);
  */
 void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
 {
+       struct ieee80211_hw *hw = sc->hw;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_txq *queue;
        struct ath_atx_tid *tid;
-       struct list_head *tid_list;
-       struct ath_acq *acq;
-       bool active = AIRTIME_ACTIVE(sc->airtime_flags);
+       int ret;
 
        if (txq->mac80211_qnum < 0)
                return;
        if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
                return;
 
+       ieee80211_txq_schedule_start(hw, txq->mac80211_qnum);
        spin_lock_bh(&sc->chan_lock);
        rcu_read_lock();
-       acq = &sc->cur_chan->acq[txq->mac80211_qnum];
 
        if (sc->cur_chan->stopped)
                goto out;
 
-begin:
-       tid_list = &acq->acq_new;
-       if (list_empty(tid_list)) {
-               tid_list = &acq->acq_old;
-               if (list_empty(tid_list))
-                       goto out;
-       }
-       tid = list_first_entry(tid_list, struct ath_atx_tid, list);
-
-       if (active && tid->an->airtime_deficit[txq->mac80211_qnum] <= 0) {
-               spin_lock_bh(&acq->lock);
-               tid->an->airtime_deficit[txq->mac80211_qnum] += ATH_AIRTIME_QUANTUM;
-               list_move_tail(&tid->list, &acq->acq_old);
-               spin_unlock_bh(&acq->lock);
-               goto begin;
-       }
-
-       if (!ath_tid_has_buffered(tid)) {
-               spin_lock_bh(&acq->lock);
-               if ((tid_list == &acq->acq_new) && !list_empty(&acq->acq_old))
-                       list_move_tail(&tid->list, &acq->acq_old);
-               else {
-                       list_del_init(&tid->list);
-               }
-               spin_unlock_bh(&acq->lock);
-               goto begin;
-       }
+       while ((queue = ieee80211_next_txq(hw, txq->mac80211_qnum))) {
+               tid = (struct ath_atx_tid *)queue->drv_priv;
 
+               ret = ath_tx_sched_aggr(sc, txq, tid);
+               ath_dbg(common, QUEUE, "ath_tx_sched_aggr returned %d\n", ret);
 
-       /*
-        * If we succeed in scheduling something, immediately restart to make
-        * sure we keep the HW busy.
-        */
-       if(ath_tx_sched_aggr(sc, txq, tid)) {
-               if (!active) {
-                       spin_lock_bh(&acq->lock);
-                       list_move_tail(&tid->list, &acq->acq_old);
-                       spin_unlock_bh(&acq->lock);
-               }
-               goto begin;
+               ieee80211_return_txq(hw, queue);
        }
 
 out:
        rcu_read_unlock();
        spin_unlock_bh(&sc->chan_lock);
+       ieee80211_txq_schedule_end(hw, txq->mac80211_qnum);
 }
 
 void ath_txq_schedule_all(struct ath_softc *sc)
        struct ath_atx_tid *tid;
        int tidno, acno;
 
-       for (acno = 0; acno < IEEE80211_NUM_ACS; acno++)
-               an->airtime_deficit[acno] = ATH_AIRTIME_QUANTUM;
-
        for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
                tid = ath_node_to_tid(an, tidno);
                tid->an        = an;
                tid->baw_head  = tid->baw_tail = 0;
                tid->active        = false;
                tid->clear_ps_filter = true;
-               tid->has_queued  = false;
                __skb_queue_head_init(&tid->retry_q);
                INIT_LIST_HEAD(&tid->list);
                acno = TID_TO_WME_AC(tidno);