linux/net/mac80211/rc80211_minstrel_ht_debugfs.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8#include <linux/netdevice.h>
   9#include <linux/types.h>
  10#include <linux/skbuff.h>
  11#include <linux/debugfs.h>
  12#include <linux/ieee80211.h>
  13#include <linux/export.h>
  14#include <net/mac80211.h>
  15#include "rc80211_minstrel.h"
  16#include "rc80211_minstrel_ht.h"
  17
  18static char *
  19minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
  20{
  21        const struct mcs_group *mg;
  22        unsigned int j, tp, prob, eprob;
  23        char htmode = '2';
  24        char gimode = 'L';
  25        u32 gflags;
  26
  27        if (!mi->groups[i].supported)
  28                return p;
  29
  30        mg = &minstrel_mcs_groups[i];
  31        gflags = mg->flags;
  32
  33        if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
  34                htmode = '4';
  35        else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
  36                htmode = '8';
  37        if (gflags & IEEE80211_TX_RC_SHORT_GI)
  38                gimode = 'S';
  39
  40        for (j = 0; j < MCS_GROUP_RATES; j++) {
  41                struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
  42                static const int bitrates[4] = { 10, 20, 55, 110 };
  43                int idx = i * MCS_GROUP_RATES + j;
  44
  45                if (!(mi->groups[i].supported & BIT(j)))
  46                        continue;
  47
  48                if (gflags & IEEE80211_TX_RC_MCS)
  49                        p += sprintf(p, " HT%c0/%cGI ", htmode, gimode);
  50                else if (gflags & IEEE80211_TX_RC_VHT_MCS)
  51                        p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode);
  52                else
  53                        p += sprintf(p, " CCK/%cP   ", j < 4 ? 'L' : 'S');
  54
  55                *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' ';
  56                *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' ';
  57                *(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' ';
  58                *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' ';
  59                *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
  60
  61                if (gflags & IEEE80211_TX_RC_MCS) {
  62                        p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j);
  63                } else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
  64                        p += sprintf(p, " MCS%-1u/%1u", j, mg->streams);
  65                } else {
  66                        int r = bitrates[j % 4];
  67
  68                        p += sprintf(p, " %2u.%1uM ", r / 10, r % 10);
  69                }
  70
  71                tp = mr->cur_tp / 10;
  72                prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
  73                eprob = MINSTREL_TRUNC(mr->probability * 1000);
  74
  75                p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u "
  76                                "%3u %4u(%4u) %9llu(%9llu)\n",
  77                                tp / 10, tp % 10,
  78                                eprob / 10, eprob % 10,
  79                                prob / 10, prob % 10,
  80                                mr->retry_count,
  81                                mr->last_success,
  82                                mr->last_attempts,
  83                                (unsigned long long)mr->succ_hist,
  84                                (unsigned long long)mr->att_hist);
  85        }
  86
  87        return p;
  88}
  89
  90static int
  91minstrel_ht_stats_open(struct inode *inode, struct file *file)
  92{
  93        struct minstrel_ht_sta_priv *msp = inode->i_private;
  94        struct minstrel_ht_sta *mi = &msp->ht;
  95        struct minstrel_debugfs_info *ms;
  96        unsigned int i;
  97        char *p;
  98        int ret;
  99
 100        if (!msp->is_ht) {
 101                inode->i_private = &msp->legacy;
 102                ret = minstrel_stats_open(inode, file);
 103                inode->i_private = msp;
 104                return ret;
 105        }
 106
 107        ms = kmalloc(32768, GFP_KERNEL);
 108        if (!ms)
 109                return -ENOMEM;
 110
 111        file->private_data = ms;
 112        p = ms->buf;
 113        p += sprintf(p, " type           rate      tpt eprob *prob "
 114                        "ret  *ok(*cum)        ok(      cum)\n");
 115
 116        p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
 117        for (i = 0; i < MINSTREL_CCK_GROUP; i++)
 118                p = minstrel_ht_stats_dump(mi, i, p);
 119        for (i++; i < ARRAY_SIZE(mi->groups); i++)
 120                p = minstrel_ht_stats_dump(mi, i, p);
 121
 122        p += sprintf(p, "\nTotal packet count::    ideal %d      "
 123                        "lookaround %d\n",
 124                        max(0, (int) mi->total_packets - (int) mi->sample_packets),
 125                        mi->sample_packets);
 126        p += sprintf(p, "Average A-MPDU length: %d.%d\n",
 127                MINSTREL_TRUNC(mi->avg_ampdu_len),
 128                MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
 129        ms->len = p - ms->buf;
 130
 131        WARN_ON(ms->len + sizeof(*ms) > 32768);
 132
 133        return nonseekable_open(inode, file);
 134}
 135
 136static const struct file_operations minstrel_ht_stat_fops = {
 137        .owner = THIS_MODULE,
 138        .open = minstrel_ht_stats_open,
 139        .read = minstrel_stats_read,
 140        .release = minstrel_stats_release,
 141        .llseek = no_llseek,
 142};
 143
 144void
 145minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
 146{
 147        struct minstrel_ht_sta_priv *msp = priv_sta;
 148
 149        msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
 150                        &minstrel_ht_stat_fops);
 151}
 152
 153void
 154minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
 155{
 156        struct minstrel_ht_sta_priv *msp = priv_sta;
 157
 158        debugfs_remove(msp->dbg_stats);
 159}
 160