DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
        local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
 
-struct aqm_info {
-       struct ieee80211_local *local;
-       size_t size;
-       size_t len;
-       unsigned char buf[0];
-};
-
-#define AQM_HDR_LEN 200
-#define AQM_HW_ENTRY_LEN 40
-#define AQM_TXQ_ENTRY_LEN 110
-
-static int aqm_open(struct inode *inode, struct file *file)
+static ssize_t aqm_read(struct file *file,
+                       char __user *user_buf,
+                       size_t count,
+                       loff_t *ppos)
 {
-       struct ieee80211_local *local = inode->i_private;
-       struct ieee80211_sub_if_data *sdata;
-       struct sta_info *sta;
-       struct txq_info *txqi;
+       struct ieee80211_local *local = file->private_data;
        struct fq *fq = &local->fq;
-       struct aqm_info *info = NULL;
+       char buf[200];
        int len = 0;
-       int i;
-
-       if (!local->ops->wake_tx_queue)
-               return -EOPNOTSUPP;
-
-       len += AQM_HDR_LEN;
-       len += 6 * AQM_HW_ENTRY_LEN;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               len += AQM_TXQ_ENTRY_LEN;
-       list_for_each_entry_rcu(sta, &local->sta_list, list)
-               len += AQM_TXQ_ENTRY_LEN * ARRAY_SIZE(sta->sta.txq);
-       rcu_read_unlock();
-
-       info = vmalloc(len);
-       if (!info)
-               return -ENOMEM;
 
        spin_lock_bh(&local->fq.lock);
        rcu_read_lock();
 
-       file->private_data = info;
-       info->local = local;
-       info->size = len;
-       len = 0;
-
-       len += scnprintf(info->buf + len, info->size - len,
-                        "* hw\n"
-                        "access name value\n"
-                        "R fq_flows_cnt %u\n"
-                        "R fq_backlog %u\n"
-                        "R fq_overlimit %u\n"
-                        "R fq_collisions %u\n"
-                        "RW fq_limit %u\n"
-                        "RW fq_quantum %u\n",
-                        fq->flows_cnt,
-                        fq->backlog,
-                        fq->overlimit,
-                        fq->collisions,
-                        fq->limit,
-                        fq->quantum);
-
-       len += scnprintf(info->buf + len,
-                        info->size - len,
-                        "* vif\n"
-                        "ifname addr ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
-
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               txqi = to_txq_info(sdata->vif.txq);
-               len += scnprintf(info->buf + len, info->size - len,
-                                "%s %pM %u %u %u %u %u %u %u %u\n",
-                                sdata->name,
-                                sdata->vif.addr,
-                                txqi->txq.ac,
-                                txqi->tin.backlog_bytes,
-                                txqi->tin.backlog_packets,
-                                txqi->tin.flows,
-                                txqi->tin.overlimit,
-                                txqi->tin.collisions,
-                                txqi->tin.tx_bytes,
-                                txqi->tin.tx_packets);
-       }
-
-       len += scnprintf(info->buf + len,
-                        info->size - len,
-                        "* sta\n"
-                        "ifname addr tid ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
-
-       list_for_each_entry_rcu(sta, &local->sta_list, list) {
-               sdata = sta->sdata;
-               for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-                       txqi = to_txq_info(sta->sta.txq[i]);
-                       len += scnprintf(info->buf + len, info->size - len,
-                                        "%s %pM %d %d %u %u %u %u %u %u %u\n",
-                                        sdata->name,
-                                        sta->sta.addr,
-                                        txqi->txq.tid,
-                                        txqi->txq.ac,
-                                        txqi->tin.backlog_bytes,
-                                        txqi->tin.backlog_packets,
-                                        txqi->tin.flows,
-                                        txqi->tin.overlimit,
-                                        txqi->tin.collisions,
-                                        txqi->tin.tx_bytes,
-                                        txqi->tin.tx_packets);
-               }
-       }
-
-       info->len = len;
+       len = scnprintf(buf, sizeof(buf),
+                       "access name value\n"
+                       "R fq_flows_cnt %u\n"
+                       "R fq_backlog %u\n"
+                       "R fq_overlimit %u\n"
+                       "R fq_collisions %u\n"
+                       "RW fq_limit %u\n"
+                       "RW fq_quantum %u\n",
+                       fq->flows_cnt,
+                       fq->backlog,
+                       fq->overlimit,
+                       fq->collisions,
+                       fq->limit,
+                       fq->quantum);
 
        rcu_read_unlock();
        spin_unlock_bh(&local->fq.lock);
 
-       return 0;
-}
-
-static int aqm_release(struct inode *inode, struct file *file)
-{
-       vfree(file->private_data);
-       return 0;
-}
-
-static ssize_t aqm_read(struct file *file,
-                       char __user *user_buf,
-                       size_t count,
-                       loff_t *ppos)
-{
-       struct aqm_info *info = file->private_data;
-
        return simple_read_from_buffer(user_buf, count, ppos,
-                                      info->buf, info->len);
+                                      buf, len);
 }
 
 static ssize_t aqm_write(struct file *file,
                         size_t count,
                         loff_t *ppos)
 {
-       struct aqm_info *info = file->private_data;
-       struct ieee80211_local *local = info->local;
+       struct ieee80211_local *local = file->private_data;
        char buf[100];
        size_t len;
 
 static const struct file_operations aqm_ops = {
        .write = aqm_write,
        .read = aqm_read,
-       .open = aqm_open,
-       .release = aqm_release,
+       .open = simple_open,
        .llseek = default_llseek,
 };
 
        DEBUGFS_ADD(hwflags);
        DEBUGFS_ADD(user_power);
        DEBUGFS_ADD(power);
-       DEBUGFS_ADD_MODE(aqm, 0600);
+
+       if (local->ops->wake_tx_queue)
+               DEBUGFS_ADD_MODE(aqm, 0600);
 
        statsd = debugfs_create_dir("statistics", phyd);
 
 
        size_t count, loff_t *ppos,
        ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
 {
-       char buf[70];
+       char buf[200];
        ssize_t ret = -EINVAL;
 
        read_lock(&dev_base_lock);
 }
 IEEE80211_IF_FILE_R(num_buffered_multicast);
 
+static ssize_t ieee80211_if_fmt_aqm(
+       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct txq_info *txqi = to_txq_info(sdata->vif.txq);
+       int len;
+
+       spin_lock_bh(&local->fq.lock);
+       rcu_read_lock();
+
+       len = scnprintf(buf,
+                       buflen,
+                       "ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
+                       "%u %u %u %u %u %u %u %u %u %u\n",
+                       txqi->txq.ac,
+                       txqi->tin.backlog_bytes,
+                       txqi->tin.backlog_packets,
+                       txqi->tin.flows,
+                       txqi->cstats.drop_count,
+                       txqi->cstats.ecn_mark,
+                       txqi->tin.overlimit,
+                       txqi->tin.collisions,
+                       txqi->tin.tx_bytes,
+                       txqi->tin.tx_packets);
+
+       rcu_read_unlock();
+       spin_unlock_bh(&local->fq.lock);
+
+       return len;
+}
+IEEE80211_IF_FILE_R(aqm);
+
 /* IBSS attributes */
 static ssize_t ieee80211_if_fmt_tsf(
        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
        DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
        DEBUGFS_ADD(hw_queues);
+
+       if (sdata->local->ops->wake_tx_queue)
+               DEBUGFS_ADD(aqm);
 }
 
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 
 }
 STA_OPS(last_seq_ctrl);
 
+#define AQM_TXQ_ENTRY_LEN 130
+
+static ssize_t sta_aqm_read(struct file *file, char __user *userbuf,
+                       size_t count, loff_t *ppos)
+{
+       struct sta_info *sta = file->private_data;
+       struct ieee80211_local *local = sta->local;
+       size_t bufsz = AQM_TXQ_ENTRY_LEN*(IEEE80211_NUM_TIDS+1);
+       char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
+       struct txq_info *txqi;
+       ssize_t rv;
+       int i;
+
+       if (!buf)
+               return -ENOMEM;
+
+       spin_lock_bh(&local->fq.lock);
+       rcu_read_lock();
+
+       p += scnprintf(p,
+                      bufsz+buf-p,
+                      "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n");
+
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+               txqi = to_txq_info(sta->sta.txq[i]);
+               p += scnprintf(p, bufsz+buf-p,
+                              "%d %d %u %u %u %u %u %u %u %u %u\n",
+                              txqi->txq.tid,
+                              txqi->txq.ac,
+                              txqi->tin.backlog_bytes,
+                              txqi->tin.backlog_packets,
+                              txqi->tin.flows,
+                              txqi->cstats.drop_count,
+                              txqi->cstats.ecn_mark,
+                              txqi->tin.overlimit,
+                              txqi->tin.collisions,
+                              txqi->tin.tx_bytes,
+                              txqi->tin.tx_packets);
+       }
+
+       rcu_read_unlock();
+       spin_unlock_bh(&local->fq.lock);
+
+       rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+       kfree(buf);
+       return rv;
+}
+STA_OPS(aqm);
+
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
        DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments);
        DEBUGFS_ADD_COUNTER(tx_filtered, status_stats.filtered);
 
+       if (local->ops->wake_tx_queue)
+               DEBUGFS_ADD(aqm);
+
        if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
                debugfs_create_x32("driver_buffered_tids", 0400,
                                   sta->debugfs_dir,
 
        struct fq_tin tin;
        struct fq_flow def_flow;
        struct codel_vars def_cvars;
+       struct codel_stats cstats;
        unsigned long flags;
 
        /* keep last! */
        struct fq fq;
        struct codel_vars *cvars;
        struct codel_params cparams;
-       struct codel_stats cstats;
 
        const struct ieee80211_ops *ops;
 
 
        local = container_of(fq, struct ieee80211_local, fq);
        txqi = container_of(tin, struct txq_info, tin);
        cparams = &local->cparams;
-       cstats = &local->cstats;
+       cstats = &txqi->cstats;
 
        if (flow == &txqi->def_flow)
                cvars = &txqi->def_cvars;
        fq_tin_init(&txqi->tin);
        fq_flow_init(&txqi->def_flow);
        codel_vars_init(&txqi->def_cvars);
+       codel_stats_init(&txqi->cstats);
 
        txqi->txq.vif = &sdata->vif;
 
                return ret;
 
        codel_params_init(&local->cparams);
-       codel_stats_init(&local->cstats);
        local->cparams.interval = MS2TIME(100);
        local->cparams.target = MS2TIME(20);
        local->cparams.ecn = true;