This adds a few debugfs entries and a module parameter to make it easier to test, debug and experiment. Signed-off-by: Michal Kazior <michal.kazior@xxxxxxxxx> --- net/mac80211/debugfs.c | 77 +++++++++++++++++++++++++++++++++++++++++++ net/mac80211/debugfs_netdev.c | 28 +++++++++++++++- net/mac80211/debugfs_sta.c | 45 +++++++++++++++++++++++++ net/mac80211/fq.h | 13 +++++++- net/mac80211/fq_i.h | 7 ++++ net/mac80211/tx.c | 8 ++++- 6 files changed, 175 insertions(+), 3 deletions(-) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 4ab5c522ceee..5cbaa5872e6b 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -31,6 +31,30 @@ int mac80211_format_buffer(char __user *userbuf, size_t count, return simple_read_from_buffer(userbuf, count, ppos, buf, res); } +static int mac80211_parse_buffer(const char __user *userbuf, + size_t count, + loff_t *ppos, + char *fmt, ...) +{ + va_list args; + char buf[DEBUGFS_FORMAT_BUFFER_SIZE] = {}; + int res; + + if (count > sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + + buf[sizeof(buf) - 1] = '\0'; + + va_start(args, fmt); + res = vsscanf(buf, fmt, args); + va_end(args); + + return count; +} + #define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -70,6 +94,52 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); +#define DEBUGFS_RW_FILE_FN(name, expr) \ +static ssize_t name## _write(struct file *file, \ + const char __user *userbuf, \ + size_t count, \ + loff_t *ppos) \ +{ \ + struct ieee80211_local *local = file->private_data; \ + return expr; \ +} + +#define DEBUGFS_RW_FILE(name, expr, fmt, value...) \ + DEBUGFS_READONLY_FILE_FN(name, fmt, value) \ + DEBUGFS_RW_FILE_FN(name, expr) \ + DEBUGFS_RW_FILE_OPS(name) + +#define DEBUGFS_RW_FILE_OPS(name) \ +static const struct file_operations name## _ops = { \ + .read = name## _read, \ + .write = name## _write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define DEBUGFS_RW_EXPR_FQ(args...) \ +({ \ + int res; \ + res = mac80211_parse_buffer(userbuf, count, ppos, args); \ + res; \ +}) + +DEBUGFS_READONLY_FILE(fq_flows_cnt, "%u", + local->fq.flows_cnt); +DEBUGFS_READONLY_FILE(fq_backlog, "%u", + local->fq.backlog); +DEBUGFS_READONLY_FILE(fq_overlimit, "%u", + local->fq.overlimit); +DEBUGFS_READONLY_FILE(fq_collisions, "%u", + local->fq.collisions); + +DEBUGFS_RW_FILE(fq_limit, + DEBUGFS_RW_EXPR_FQ("%u", &local->fq.limit), + "%u", local->fq.limit); +DEBUGFS_RW_FILE(fq_quantum, + DEBUGFS_RW_EXPR_FQ("%u", &local->fq.quantum), + "%u", local->fq.quantum); + #ifdef CONFIG_PM static ssize_t reset_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -254,6 +324,13 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(user_power); DEBUGFS_ADD(power); + DEBUGFS_ADD(fq_flows_cnt); + DEBUGFS_ADD(fq_backlog); + DEBUGFS_ADD(fq_overlimit); + DEBUGFS_ADD(fq_collisions); + DEBUGFS_ADD(fq_limit); + DEBUGFS_ADD(fq_quantum); + statsd = debugfs_create_dir("statistics", phyd); /* if the dir failed, don't put all the other things into the root! */ diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 37ea30e0754c..471cab40a25f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -30,7 +30,7 @@ static ssize_t ieee80211_if_read( 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); @@ -236,6 +236,31 @@ ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, } IEEE80211_IF_FILE_R(hw_queues); +static ssize_t +ieee80211_if_fmt_txq(const struct ieee80211_sub_if_data *sdata, + char *buf, int buflen) +{ + struct txq_info *txqi; + int len = 0; + + if (!sdata->vif.txq) + return 0; + + txqi = to_txq_info(sdata->vif.txq); + len += scnprintf(buf + len, buflen - len, + "CAB backlog %ub %up flows %u overlimit %u collisions %u tx %ub %up\n", + 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); + + return len; +} +IEEE80211_IF_FILE_R(txq); + /* STA attributes */ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); @@ -618,6 +643,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz); DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz); DEBUGFS_ADD(hw_queues); + DEBUGFS_ADD(txq); } static void add_sta_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index a39512f09f9e..b5eb4f402710 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -319,6 +319,50 @@ static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf, } STA_OPS(vht_capa); +static ssize_t sta_txqs_read(struct file *file, + char __user *userbuf, + size_t count, + loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct txq_info *txqi; + char *buf; + int buflen; + int len; + int res; + int i; + + len = 0; + buflen = 200 * IEEE80211_NUM_TIDS; + buf = kzalloc(buflen, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < IEEE80211_NUM_TIDS; i++) { + if (!sta->sta.txq[i]) + break; + + txqi = to_txq_info(sta->sta.txq[i]); + len += scnprintf(buf + len, buflen - len, + "TID %d AC %d backlog %ub %up flows %u overlimit %u collisions %u tx %ub %up\n", + i, + 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); + } + + res = simple_read_from_buffer(userbuf, count, ppos, buf, len); + kfree(buf); + + return res; +} +STA_OPS(txqs); + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ @@ -365,6 +409,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(agg_status); DEBUGFS_ADD(ht_capa); DEBUGFS_ADD(vht_capa); + DEBUGFS_ADD(txqs); DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates); DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments); diff --git a/net/mac80211/fq.h b/net/mac80211/fq.h index fa98576e1825..aa68363d6221 100644 --- a/net/mac80211/fq.h +++ b/net/mac80211/fq.h @@ -102,6 +102,8 @@ begin: } flow->deficit -= skb->len; + tin->tx_bytes += skb->len; + tin->tx_packets++; return skb; } @@ -120,8 +122,14 @@ static struct fq_flow *fq_flow_classify(struct fq *fq, idx = reciprocal_scale(hash, fq->flows_cnt); flow = &fq->flows[idx]; - if (flow->tin && flow->tin != tin) + if (flow->tin && flow->tin != tin) { flow = fq_flow_get_default_fn(fq, tin, idx, skb); + tin->collisions++; + fq->collisions++; + } + + if (!flow->tin) + tin->flows++; return flow; } @@ -174,6 +182,9 @@ static void fq_tin_enqueue(struct fq *fq, return; fq_skb_free_fn(fq, flow->tin, flow, skb); + + flow->tin->overlimit++; + fq->overlimit++; } } diff --git a/net/mac80211/fq_i.h b/net/mac80211/fq_i.h index 5d8423f22e8d..0e25dda4fce3 100644 --- a/net/mac80211/fq_i.h +++ b/net/mac80211/fq_i.h @@ -51,6 +51,11 @@ struct fq_tin { struct list_head old_flows; u32 backlog_bytes; u32 backlog_packets; + u32 overlimit; + u32 collisions; + u32 flows; + u32 tx_bytes; + u32 tx_packets; }; /** @@ -70,6 +75,8 @@ struct fq { u32 limit; u32 quantum; u32 backlog; + u32 overlimit; + u32 collisions; }; #endif diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d4e0c87ecec5..396d0d17edeb 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/etherdevice.h> +#include <linux/moduleparam.h> #include <linux/bitmap.h> #include <linux/rcupdate.h> #include <linux/export.h> @@ -36,6 +37,11 @@ #include "rate.h" #include "fq.h" +static unsigned int fq_flows_cnt = 4096; +module_param(fq_flows_cnt, uint, 0644); +MODULE_PARM_DESC(fq_flows_cnt, + "Maximum number of txq fair queuing flows. "); + /* misc utils */ static inline void ieee80211_tx_stats(struct net_device *dev, u32 len) @@ -1336,7 +1342,7 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local) if (!local->ops->wake_tx_queue) return 0; - ret = fq_init(fq, 4096); + ret = fq_init(fq, max_t(u32, fq_flows_cnt, 1)); if (ret) return ret; -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html