cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rc80211_minstrel_ht_debugfs.c (9229B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
      4 */
      5#include <linux/netdevice.h>
      6#include <linux/types.h>
      7#include <linux/skbuff.h>
      8#include <linux/debugfs.h>
      9#include <linux/ieee80211.h>
     10#include <linux/export.h>
     11#include <net/mac80211.h>
     12#include "rc80211_minstrel_ht.h"
     13
     14struct minstrel_debugfs_info {
     15	size_t len;
     16	char buf[];
     17};
     18
     19static ssize_t
     20minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
     21{
     22	struct minstrel_debugfs_info *ms;
     23
     24	ms = file->private_data;
     25	return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len);
     26}
     27
     28static int
     29minstrel_stats_release(struct inode *inode, struct file *file)
     30{
     31	kfree(file->private_data);
     32	return 0;
     33}
     34
     35static bool
     36minstrel_ht_is_sample_rate(struct minstrel_ht_sta *mi, int idx)
     37{
     38	int type, i;
     39
     40	for (type = 0; type < ARRAY_SIZE(mi->sample); type++)
     41		for (i = 0; i < MINSTREL_SAMPLE_RATES; i++)
     42			if (mi->sample[type].cur_sample_rates[i] == idx)
     43				return true;
     44	return false;
     45}
     46
     47static char *
     48minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
     49{
     50	const struct mcs_group *mg;
     51	unsigned int j, tp_max, tp_avg, eprob, tx_time;
     52	char htmode = '2';
     53	char gimode = 'L';
     54	u32 gflags;
     55
     56	if (!mi->supported[i])
     57		return p;
     58
     59	mg = &minstrel_mcs_groups[i];
     60	gflags = mg->flags;
     61
     62	if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
     63		htmode = '4';
     64	else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
     65		htmode = '8';
     66	if (gflags & IEEE80211_TX_RC_SHORT_GI)
     67		gimode = 'S';
     68
     69	for (j = 0; j < MCS_GROUP_RATES; j++) {
     70		struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
     71		int idx = MI_RATE(i, j);
     72		unsigned int duration;
     73
     74		if (!(mi->supported[i] & BIT(j)))
     75			continue;
     76
     77		if (gflags & IEEE80211_TX_RC_MCS) {
     78			p += sprintf(p, "HT%c0  ", htmode);
     79			p += sprintf(p, "%cGI  ", gimode);
     80			p += sprintf(p, "%d  ", mg->streams);
     81		} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
     82			p += sprintf(p, "VHT%c0 ", htmode);
     83			p += sprintf(p, "%cGI ", gimode);
     84			p += sprintf(p, "%d  ", mg->streams);
     85		} else if (i == MINSTREL_OFDM_GROUP) {
     86			p += sprintf(p, "OFDM       ");
     87			p += sprintf(p, "1 ");
     88		} else {
     89			p += sprintf(p, "CCK    ");
     90			p += sprintf(p, "%cP  ", j < 4 ? 'L' : 'S');
     91			p += sprintf(p, "1 ");
     92		}
     93
     94		*(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' ';
     95		*(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' ';
     96		*(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' ';
     97		*(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' ';
     98		*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
     99		*(p++) = minstrel_ht_is_sample_rate(mi, idx) ? 'S' : ' ';
    100
    101		if (gflags & IEEE80211_TX_RC_MCS) {
    102			p += sprintf(p, "  MCS%-2u", (mg->streams - 1) * 8 + j);
    103		} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
    104			p += sprintf(p, "  MCS%-1u/%1u", j, mg->streams);
    105		} else {
    106			int r;
    107
    108			if (i == MINSTREL_OFDM_GROUP)
    109				r = minstrel_ofdm_bitrates[j % 8];
    110			else
    111				r = minstrel_cck_bitrates[j % 4];
    112
    113			p += sprintf(p, "   %2u.%1uM", r / 10, r % 10);
    114		}
    115
    116		p += sprintf(p, "  %3u  ", idx);
    117
    118		/* tx_time[rate(i)] in usec */
    119		duration = mg->duration[j];
    120		duration <<= mg->shift;
    121		tx_time = DIV_ROUND_CLOSEST(duration, 1000);
    122		p += sprintf(p, "%6u  ", tx_time);
    123
    124		tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
    125		tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg);
    126		eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
    127
    128		p += sprintf(p, "%4u.%1u    %4u.%1u     %3u.%1u"
    129				"     %3u   %3u %-3u   "
    130				"%9llu   %-9llu\n",
    131				tp_max / 10, tp_max % 10,
    132				tp_avg / 10, tp_avg % 10,
    133				eprob / 10, eprob % 10,
    134				mrs->retry_count,
    135				mrs->last_success,
    136				mrs->last_attempts,
    137				(unsigned long long)mrs->succ_hist,
    138				(unsigned long long)mrs->att_hist);
    139	}
    140
    141	return p;
    142}
    143
    144static int
    145minstrel_ht_stats_open(struct inode *inode, struct file *file)
    146{
    147	struct minstrel_ht_sta *mi = inode->i_private;
    148	struct minstrel_debugfs_info *ms;
    149	unsigned int i;
    150	char *p;
    151
    152	ms = kmalloc(32768, GFP_KERNEL);
    153	if (!ms)
    154		return -ENOMEM;
    155
    156	file->private_data = ms;
    157	p = ms->buf;
    158
    159	p += sprintf(p, "\n");
    160	p += sprintf(p,
    161		     "              best    ____________rate__________    ____statistics___    _____last____    ______sum-of________\n");
    162	p += sprintf(p,
    163		     "mode guard #  rate   [name   idx airtime  max_tp]  [avg(tp) avg(prob)]  [retry|suc|att]  [#success | #attempts]\n");
    164
    165	p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
    166	for (i = 0; i < MINSTREL_CCK_GROUP; i++)
    167		p = minstrel_ht_stats_dump(mi, i, p);
    168	for (i++; i < ARRAY_SIZE(mi->groups); i++)
    169		p = minstrel_ht_stats_dump(mi, i, p);
    170
    171	p += sprintf(p, "\nTotal packet count::    ideal %d      "
    172			"lookaround %d\n",
    173			max(0, (int) mi->total_packets - (int) mi->sample_packets),
    174			mi->sample_packets);
    175	if (mi->avg_ampdu_len)
    176		p += sprintf(p, "Average # of aggregated frames per A-MPDU: %d.%d\n",
    177			MINSTREL_TRUNC(mi->avg_ampdu_len),
    178			MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
    179	ms->len = p - ms->buf;
    180	WARN_ON(ms->len + sizeof(*ms) > 32768);
    181
    182	return nonseekable_open(inode, file);
    183}
    184
    185static const struct file_operations minstrel_ht_stat_fops = {
    186	.owner = THIS_MODULE,
    187	.open = minstrel_ht_stats_open,
    188	.read = minstrel_stats_read,
    189	.release = minstrel_stats_release,
    190	.llseek = no_llseek,
    191};
    192
    193static char *
    194minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
    195{
    196	const struct mcs_group *mg;
    197	unsigned int j, tp_max, tp_avg, eprob, tx_time;
    198	char htmode = '2';
    199	char gimode = 'L';
    200	u32 gflags;
    201
    202	if (!mi->supported[i])
    203		return p;
    204
    205	mg = &minstrel_mcs_groups[i];
    206	gflags = mg->flags;
    207
    208	if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
    209		htmode = '4';
    210	else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
    211		htmode = '8';
    212	if (gflags & IEEE80211_TX_RC_SHORT_GI)
    213		gimode = 'S';
    214
    215	for (j = 0; j < MCS_GROUP_RATES; j++) {
    216		struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
    217		int idx = MI_RATE(i, j);
    218		unsigned int duration;
    219
    220		if (!(mi->supported[i] & BIT(j)))
    221			continue;
    222
    223		if (gflags & IEEE80211_TX_RC_MCS) {
    224			p += sprintf(p, "HT%c0,", htmode);
    225			p += sprintf(p, "%cGI,", gimode);
    226			p += sprintf(p, "%d,", mg->streams);
    227		} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
    228			p += sprintf(p, "VHT%c0,", htmode);
    229			p += sprintf(p, "%cGI,", gimode);
    230			p += sprintf(p, "%d,", mg->streams);
    231		} else if (i == MINSTREL_OFDM_GROUP) {
    232			p += sprintf(p, "OFDM,,1,");
    233		} else {
    234			p += sprintf(p, "CCK,");
    235			p += sprintf(p, "%cP,", j < 4 ? 'L' : 'S');
    236			p += sprintf(p, "1,");
    237		}
    238
    239		p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[0]) ? "A" : ""));
    240		p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[1]) ? "B" : ""));
    241		p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : ""));
    242		p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : ""));
    243		p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : ""));
    244		p += sprintf(p, "%s", (minstrel_ht_is_sample_rate(mi, idx) ? "S" : ""));
    245
    246		if (gflags & IEEE80211_TX_RC_MCS) {
    247			p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j);
    248		} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
    249			p += sprintf(p, ",MCS%-1u/%1u,", j, mg->streams);
    250		} else {
    251			int r;
    252
    253			if (i == MINSTREL_OFDM_GROUP)
    254				r = minstrel_ofdm_bitrates[j % 8];
    255			else
    256				r = minstrel_cck_bitrates[j % 4];
    257
    258			p += sprintf(p, ",%2u.%1uM,", r / 10, r % 10);
    259		}
    260
    261		p += sprintf(p, "%u,", idx);
    262
    263		duration = mg->duration[j];
    264		duration <<= mg->shift;
    265		tx_time = DIV_ROUND_CLOSEST(duration, 1000);
    266		p += sprintf(p, "%u,", tx_time);
    267
    268		tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
    269		tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg);
    270		eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
    271
    272		p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,"
    273				"%u,%llu,%llu,",
    274				tp_max / 10, tp_max % 10,
    275				tp_avg / 10, tp_avg % 10,
    276				eprob / 10, eprob % 10,
    277				mrs->retry_count,
    278				mrs->last_success,
    279				mrs->last_attempts,
    280				(unsigned long long)mrs->succ_hist,
    281				(unsigned long long)mrs->att_hist);
    282		p += sprintf(p, "%d,%d,%d.%d\n",
    283				max(0, (int) mi->total_packets -
    284				(int) mi->sample_packets),
    285				mi->sample_packets,
    286				MINSTREL_TRUNC(mi->avg_ampdu_len),
    287				MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
    288	}
    289
    290	return p;
    291}
    292
    293static int
    294minstrel_ht_stats_csv_open(struct inode *inode, struct file *file)
    295{
    296	struct minstrel_ht_sta *mi = inode->i_private;
    297	struct minstrel_debugfs_info *ms;
    298	unsigned int i;
    299	char *p;
    300
    301	ms = kmalloc(32768, GFP_KERNEL);
    302	if (!ms)
    303		return -ENOMEM;
    304
    305	file->private_data = ms;
    306
    307	p = ms->buf;
    308
    309	p = minstrel_ht_stats_csv_dump(mi, MINSTREL_CCK_GROUP, p);
    310	for (i = 0; i < MINSTREL_CCK_GROUP; i++)
    311		p = minstrel_ht_stats_csv_dump(mi, i, p);
    312	for (i++; i < ARRAY_SIZE(mi->groups); i++)
    313		p = minstrel_ht_stats_csv_dump(mi, i, p);
    314
    315	ms->len = p - ms->buf;
    316	WARN_ON(ms->len + sizeof(*ms) > 32768);
    317
    318	return nonseekable_open(inode, file);
    319}
    320
    321static const struct file_operations minstrel_ht_stat_csv_fops = {
    322	.owner = THIS_MODULE,
    323	.open = minstrel_ht_stats_csv_open,
    324	.read = minstrel_stats_read,
    325	.release = minstrel_stats_release,
    326	.llseek = no_llseek,
    327};
    328
    329void
    330minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
    331{
    332	debugfs_create_file("rc_stats", 0444, dir, priv_sta,
    333			    &minstrel_ht_stat_fops);
    334	debugfs_create_file("rc_stats_csv", 0444, dir, priv_sta,
    335			    &minstrel_ht_stat_csv_fops);
    336}