Commit 9399b86c authored by Michal Kazior's avatar Michal Kazior Committed by Johannes Berg

mac80211: add debug knobs for fair queuing

This adds a debugfs entry to read and modify some fq parameters.

This makes it easy to debug, test and experiment.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
[remove module parameter for now]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent fa962b92
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/vmalloc.h>
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-ops.h" #include "driver-ops.h"
#include "rate.h" #include "rate.h"
...@@ -70,6 +71,177 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", ...@@ -70,6 +71,177 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); 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)
{
struct ieee80211_local *local = inode->i_private;
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct txq_info *txqi;
struct fq *fq = &local->fq;
struct aqm_info *info = NULL;
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;
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);
}
static ssize_t aqm_write(struct file *file,
const char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct aqm_info *info = file->private_data;
struct ieee80211_local *local = info->local;
char buf[100];
size_t len;
if (count > sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
buf[sizeof(buf) - 1] = '\0';
len = strlen(buf);
if (len > 0 && buf[len-1] == '\n')
buf[len-1] = 0;
if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1)
return count;
else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1)
return count;
return -EINVAL;
}
static const struct file_operations aqm_ops = {
.write = aqm_write,
.read = aqm_read,
.open = aqm_open,
.release = aqm_release,
.llseek = default_llseek,
};
#ifdef CONFIG_PM #ifdef CONFIG_PM
static ssize_t reset_write(struct file *file, const char __user *user_buf, static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
...@@ -256,6 +428,7 @@ void debugfs_hw_add(struct ieee80211_local *local) ...@@ -256,6 +428,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(hwflags); DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power); DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power); DEBUGFS_ADD(power);
DEBUGFS_ADD_MODE(aqm, 0600);
statsd = debugfs_create_dir("statistics", phyd); statsd = debugfs_create_dir("statistics", phyd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment