xref: /linux/net/mac80211/debugfs.c (revision 963d0e8d08d97f9133b9fd00354ebc1a2467484b)
17f904d7eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e9f207f0SJiri Benc /*
3e9f207f0SJiri Benc  * mac80211 debugfs for wireless PHYs
4e9f207f0SJiri Benc  *
5e9f207f0SJiri Benc  * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
6d98ad83eSJohannes Berg  * Copyright 2013-2014  Intel Mobile Communications GmbH
7*963d0e8dSJohannes Berg  * Copyright (C) 2018 - 2019, 2021-2022 Intel Corporation
8e9f207f0SJiri Benc  */
9e9f207f0SJiri Benc 
10e9f207f0SJiri Benc #include <linux/debugfs.h>
11e9f207f0SJiri Benc #include <linux/rtnetlink.h>
129399b86cSMichal Kazior #include <linux/vmalloc.h>
13e9f207f0SJiri Benc #include "ieee80211_i.h"
1424487981SJohannes Berg #include "driver-ops.h"
152c8dccc7SJohannes Berg #include "rate.h"
16e9f207f0SJiri Benc #include "debugfs.h"
17e9f207f0SJiri Benc 
1807caf9d6SEliad Peller #define DEBUGFS_FORMAT_BUFFER_SIZE 100
1907caf9d6SEliad Peller 
2007caf9d6SEliad Peller int mac80211_format_buffer(char __user *userbuf, size_t count,
2107caf9d6SEliad Peller 				  loff_t *ppos, char *fmt, ...)
2207caf9d6SEliad Peller {
2307caf9d6SEliad Peller 	va_list args;
2407caf9d6SEliad Peller 	char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
2507caf9d6SEliad Peller 	int res;
2607caf9d6SEliad Peller 
2707caf9d6SEliad Peller 	va_start(args, fmt);
2807caf9d6SEliad Peller 	res = vscnprintf(buf, sizeof(buf), fmt, args);
2907caf9d6SEliad Peller 	va_end(args);
3007caf9d6SEliad Peller 
3107caf9d6SEliad Peller 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
3207caf9d6SEliad Peller }
3307caf9d6SEliad Peller 
34279daf64SBen Greear #define DEBUGFS_READONLY_FILE_FN(name, fmt, value...)			\
35e9f207f0SJiri Benc static ssize_t name## _read(struct file *file, char __user *userbuf,	\
36e9f207f0SJiri Benc 			    size_t count, loff_t *ppos)			\
37e9f207f0SJiri Benc {									\
38e9f207f0SJiri Benc 	struct ieee80211_local *local = file->private_data;		\
39e9f207f0SJiri Benc 									\
4007caf9d6SEliad Peller 	return mac80211_format_buffer(userbuf, count, ppos, 		\
4107caf9d6SEliad Peller 				      fmt "\n", ##value);		\
42279daf64SBen Greear }
43279daf64SBen Greear 
44279daf64SBen Greear #define DEBUGFS_READONLY_FILE_OPS(name)			\
45e9f207f0SJiri Benc static const struct file_operations name## _ops = {			\
46e9f207f0SJiri Benc 	.read = name## _read,						\
47234e3405SStephen Boyd 	.open = simple_open,						\
482b18ab36SArnd Bergmann 	.llseek = generic_file_llseek,					\
49e9f207f0SJiri Benc };
50e9f207f0SJiri Benc 
51279daf64SBen Greear #define DEBUGFS_READONLY_FILE(name, fmt, value...)		\
52279daf64SBen Greear 	DEBUGFS_READONLY_FILE_FN(name, fmt, value)		\
53279daf64SBen Greear 	DEBUGFS_READONLY_FILE_OPS(name)
54279daf64SBen Greear 
55e9f207f0SJiri Benc #define DEBUGFS_ADD(name)						\
5684674ef4STom Rix 	debugfs_create_file(#name, 0400, phyd, local, &name## _ops)
57e9f207f0SJiri Benc 
58827b1fb4SJohannes Berg #define DEBUGFS_ADD_MODE(name, mode)					\
597bcfaf2fSJohannes Berg 	debugfs_create_file(#name, mode, phyd, local, &name## _ops);
60e9f207f0SJiri Benc 
61e9f207f0SJiri Benc 
62c90142a5SThomas Pedersen DEBUGFS_READONLY_FILE(hw_conf, "%x",
63c90142a5SThomas Pedersen 		      local->hw.conf.flags);
6483bdf2a1SBen Greear DEBUGFS_READONLY_FILE(user_power, "%d",
6583bdf2a1SBen Greear 		      local->user_power_level);
6683bdf2a1SBen Greear DEBUGFS_READONLY_FILE(power, "%d",
6783bdf2a1SBen Greear 		      local->hw.conf.power_level);
6807caf9d6SEliad Peller DEBUGFS_READONLY_FILE(total_ps_buffered, "%d",
69e9f207f0SJiri Benc 		      local->total_ps_buffered);
7007caf9d6SEliad Peller DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
71e9f207f0SJiri Benc 		      local->wep_iv & 0xffffff);
7207caf9d6SEliad Peller DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
73af65cd96SJohannes Berg 	local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
743b5d665bSAlina Friedrichsen 
758d51dbb8SToke Høiland-Jørgensen static ssize_t aqm_read(struct file *file,
768d51dbb8SToke Høiland-Jørgensen 			char __user *user_buf,
778d51dbb8SToke Høiland-Jørgensen 			size_t count,
788d51dbb8SToke Høiland-Jørgensen 			loff_t *ppos)
799399b86cSMichal Kazior {
808d51dbb8SToke Høiland-Jørgensen 	struct ieee80211_local *local = file->private_data;
819399b86cSMichal Kazior 	struct fq *fq = &local->fq;
828d51dbb8SToke Høiland-Jørgensen 	char buf[200];
839399b86cSMichal Kazior 	int len = 0;
849399b86cSMichal Kazior 
859399b86cSMichal Kazior 	spin_lock_bh(&local->fq.lock);
869399b86cSMichal Kazior 	rcu_read_lock();
879399b86cSMichal Kazior 
888d51dbb8SToke Høiland-Jørgensen 	len = scnprintf(buf, sizeof(buf),
899399b86cSMichal Kazior 			"access name value\n"
909399b86cSMichal Kazior 			"R fq_flows_cnt %u\n"
919399b86cSMichal Kazior 			"R fq_backlog %u\n"
929399b86cSMichal Kazior 			"R fq_overlimit %u\n"
932a4e675dSToke Høiland-Jørgensen 			"R fq_overmemory %u\n"
949399b86cSMichal Kazior 			"R fq_collisions %u\n"
952a4e675dSToke Høiland-Jørgensen 			"R fq_memory_usage %u\n"
962a4e675dSToke Høiland-Jørgensen 			"RW fq_memory_limit %u\n"
979399b86cSMichal Kazior 			"RW fq_limit %u\n"
989399b86cSMichal Kazior 			"RW fq_quantum %u\n",
999399b86cSMichal Kazior 			fq->flows_cnt,
1009399b86cSMichal Kazior 			fq->backlog,
1012a4e675dSToke Høiland-Jørgensen 			fq->overmemory,
1029399b86cSMichal Kazior 			fq->overlimit,
1039399b86cSMichal Kazior 			fq->collisions,
1042a4e675dSToke Høiland-Jørgensen 			fq->memory_usage,
1052a4e675dSToke Høiland-Jørgensen 			fq->memory_limit,
1069399b86cSMichal Kazior 			fq->limit,
1079399b86cSMichal Kazior 			fq->quantum);
1089399b86cSMichal Kazior 
1099399b86cSMichal Kazior 	rcu_read_unlock();
1109399b86cSMichal Kazior 	spin_unlock_bh(&local->fq.lock);
1119399b86cSMichal Kazior 
1129399b86cSMichal Kazior 	return simple_read_from_buffer(user_buf, count, ppos,
1138d51dbb8SToke Høiland-Jørgensen 				       buf, len);
1149399b86cSMichal Kazior }
1159399b86cSMichal Kazior 
1169399b86cSMichal Kazior static ssize_t aqm_write(struct file *file,
1179399b86cSMichal Kazior 			 const char __user *user_buf,
1189399b86cSMichal Kazior 			 size_t count,
1199399b86cSMichal Kazior 			 loff_t *ppos)
1209399b86cSMichal Kazior {
1218d51dbb8SToke Høiland-Jørgensen 	struct ieee80211_local *local = file->private_data;
1229399b86cSMichal Kazior 	char buf[100];
1239399b86cSMichal Kazior 
1246020d534SShayne Chen 	if (count >= sizeof(buf))
1259399b86cSMichal Kazior 		return -EINVAL;
1269399b86cSMichal Kazior 
1279399b86cSMichal Kazior 	if (copy_from_user(buf, user_buf, count))
1289399b86cSMichal Kazior 		return -EFAULT;
1299399b86cSMichal Kazior 
1306020d534SShayne Chen 	if (count && buf[count - 1] == '\n')
1316020d534SShayne Chen 		buf[count - 1] = '\0';
1326020d534SShayne Chen 	else
1336020d534SShayne Chen 		buf[count] = '\0';
1349399b86cSMichal Kazior 
1359399b86cSMichal Kazior 	if (sscanf(buf, "fq_limit %u", &local->fq.limit) == 1)
1369399b86cSMichal Kazior 		return count;
1372a4e675dSToke Høiland-Jørgensen 	else if (sscanf(buf, "fq_memory_limit %u", &local->fq.memory_limit) == 1)
1382a4e675dSToke Høiland-Jørgensen 		return count;
1399399b86cSMichal Kazior 	else if (sscanf(buf, "fq_quantum %u", &local->fq.quantum) == 1)
1409399b86cSMichal Kazior 		return count;
1419399b86cSMichal Kazior 
1429399b86cSMichal Kazior 	return -EINVAL;
1439399b86cSMichal Kazior }
1449399b86cSMichal Kazior 
1459399b86cSMichal Kazior static const struct file_operations aqm_ops = {
1469399b86cSMichal Kazior 	.write = aqm_write,
1479399b86cSMichal Kazior 	.read = aqm_read,
1488d51dbb8SToke Høiland-Jørgensen 	.open = simple_open,
1499399b86cSMichal Kazior 	.llseek = default_llseek,
1509399b86cSMichal Kazior };
1519399b86cSMichal Kazior 
152e322c07fSLorenzo Bianconi static ssize_t airtime_flags_read(struct file *file,
153e322c07fSLorenzo Bianconi 				  char __user *user_buf,
154e322c07fSLorenzo Bianconi 				  size_t count, loff_t *ppos)
155e322c07fSLorenzo Bianconi {
156e322c07fSLorenzo Bianconi 	struct ieee80211_local *local = file->private_data;
157e322c07fSLorenzo Bianconi 	char buf[128] = {}, *pos, *end;
158e322c07fSLorenzo Bianconi 
159e322c07fSLorenzo Bianconi 	pos = buf;
160e322c07fSLorenzo Bianconi 	end = pos + sizeof(buf) - 1;
161e322c07fSLorenzo Bianconi 
162e322c07fSLorenzo Bianconi 	if (local->airtime_flags & AIRTIME_USE_TX)
163e322c07fSLorenzo Bianconi 		pos += scnprintf(pos, end - pos, "AIRTIME_TX\t(%lx)\n",
164e322c07fSLorenzo Bianconi 				 AIRTIME_USE_TX);
165e322c07fSLorenzo Bianconi 	if (local->airtime_flags & AIRTIME_USE_RX)
166e322c07fSLorenzo Bianconi 		pos += scnprintf(pos, end - pos, "AIRTIME_RX\t(%lx)\n",
167e322c07fSLorenzo Bianconi 				 AIRTIME_USE_RX);
168e322c07fSLorenzo Bianconi 
169e322c07fSLorenzo Bianconi 	return simple_read_from_buffer(user_buf, count, ppos, buf,
170e322c07fSLorenzo Bianconi 				       strlen(buf));
171e322c07fSLorenzo Bianconi }
172e322c07fSLorenzo Bianconi 
173e322c07fSLorenzo Bianconi static ssize_t airtime_flags_write(struct file *file,
174e322c07fSLorenzo Bianconi 				   const char __user *user_buf,
175e322c07fSLorenzo Bianconi 				   size_t count, loff_t *ppos)
176e322c07fSLorenzo Bianconi {
177e322c07fSLorenzo Bianconi 	struct ieee80211_local *local = file->private_data;
178e322c07fSLorenzo Bianconi 	char buf[16];
179e322c07fSLorenzo Bianconi 
1806020d534SShayne Chen 	if (count >= sizeof(buf))
181e322c07fSLorenzo Bianconi 		return -EINVAL;
182e322c07fSLorenzo Bianconi 
183e322c07fSLorenzo Bianconi 	if (copy_from_user(buf, user_buf, count))
184e322c07fSLorenzo Bianconi 		return -EFAULT;
185e322c07fSLorenzo Bianconi 
1866020d534SShayne Chen 	if (count && buf[count - 1] == '\n')
1876020d534SShayne Chen 		buf[count - 1] = '\0';
1886020d534SShayne Chen 	else
1896020d534SShayne Chen 		buf[count] = '\0';
190e322c07fSLorenzo Bianconi 
191e322c07fSLorenzo Bianconi 	if (kstrtou16(buf, 0, &local->airtime_flags))
192e322c07fSLorenzo Bianconi 		return -EINVAL;
193e322c07fSLorenzo Bianconi 
194e322c07fSLorenzo Bianconi 	return count;
195e322c07fSLorenzo Bianconi }
196e322c07fSLorenzo Bianconi 
197e322c07fSLorenzo Bianconi static const struct file_operations airtime_flags_ops = {
198e322c07fSLorenzo Bianconi 	.write = airtime_flags_write,
199e322c07fSLorenzo Bianconi 	.read = airtime_flags_read,
200e322c07fSLorenzo Bianconi 	.open = simple_open,
201e322c07fSLorenzo Bianconi 	.llseek = default_llseek,
202e322c07fSLorenzo Bianconi };
203e322c07fSLorenzo Bianconi 
2043db2c560SFelix Fietkau static ssize_t aql_pending_read(struct file *file,
2053db2c560SFelix Fietkau 				char __user *user_buf,
2063db2c560SFelix Fietkau 				size_t count, loff_t *ppos)
2073db2c560SFelix Fietkau {
2083db2c560SFelix Fietkau 	struct ieee80211_local *local = file->private_data;
2093db2c560SFelix Fietkau 	char buf[400];
2103db2c560SFelix Fietkau 	int len = 0;
2113db2c560SFelix Fietkau 
2123db2c560SFelix Fietkau 	len = scnprintf(buf, sizeof(buf),
2133db2c560SFelix Fietkau 			"AC     AQL pending\n"
2143db2c560SFelix Fietkau 			"VO     %u us\n"
2153db2c560SFelix Fietkau 			"VI     %u us\n"
2163db2c560SFelix Fietkau 			"BE     %u us\n"
2173db2c560SFelix Fietkau 			"BK     %u us\n"
2183db2c560SFelix Fietkau 			"total  %u us\n",
2193db2c560SFelix Fietkau 			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]),
2203db2c560SFelix Fietkau 			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]),
2213db2c560SFelix Fietkau 			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]),
2223db2c560SFelix Fietkau 			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]),
2233db2c560SFelix Fietkau 			atomic_read(&local->aql_total_pending_airtime));
2243db2c560SFelix Fietkau 	return simple_read_from_buffer(user_buf, count, ppos,
2253db2c560SFelix Fietkau 				       buf, len);
2263db2c560SFelix Fietkau }
2273db2c560SFelix Fietkau 
2283db2c560SFelix Fietkau static const struct file_operations aql_pending_ops = {
2293db2c560SFelix Fietkau 	.read = aql_pending_read,
2303db2c560SFelix Fietkau 	.open = simple_open,
2313db2c560SFelix Fietkau 	.llseek = default_llseek,
2323db2c560SFelix Fietkau };
2333db2c560SFelix Fietkau 
2343ace10f5SKan Yan static ssize_t aql_txq_limit_read(struct file *file,
2353ace10f5SKan Yan 				  char __user *user_buf,
2363ace10f5SKan Yan 				  size_t count,
2373ace10f5SKan Yan 				  loff_t *ppos)
2383ace10f5SKan Yan {
2393ace10f5SKan Yan 	struct ieee80211_local *local = file->private_data;
2403ace10f5SKan Yan 	char buf[400];
2413ace10f5SKan Yan 	int len = 0;
2423ace10f5SKan Yan 
2433ace10f5SKan Yan 	len = scnprintf(buf, sizeof(buf),
2443ace10f5SKan Yan 			"AC	AQL limit low	AQL limit high\n"
2453ace10f5SKan Yan 			"VO	%u		%u\n"
2463ace10f5SKan Yan 			"VI	%u		%u\n"
2473ace10f5SKan Yan 			"BE	%u		%u\n"
2483ace10f5SKan Yan 			"BK	%u		%u\n",
249942741daSFelix Fietkau 			local->aql_txq_limit_low[IEEE80211_AC_VO],
250942741daSFelix Fietkau 			local->aql_txq_limit_high[IEEE80211_AC_VO],
251942741daSFelix Fietkau 			local->aql_txq_limit_low[IEEE80211_AC_VI],
252942741daSFelix Fietkau 			local->aql_txq_limit_high[IEEE80211_AC_VI],
253942741daSFelix Fietkau 			local->aql_txq_limit_low[IEEE80211_AC_BE],
254942741daSFelix Fietkau 			local->aql_txq_limit_high[IEEE80211_AC_BE],
255942741daSFelix Fietkau 			local->aql_txq_limit_low[IEEE80211_AC_BK],
256942741daSFelix Fietkau 			local->aql_txq_limit_high[IEEE80211_AC_BK]);
2573ace10f5SKan Yan 	return simple_read_from_buffer(user_buf, count, ppos,
2583ace10f5SKan Yan 				       buf, len);
2593ace10f5SKan Yan }
2603ace10f5SKan Yan 
2613ace10f5SKan Yan static ssize_t aql_txq_limit_write(struct file *file,
2623ace10f5SKan Yan 				   const char __user *user_buf,
2633ace10f5SKan Yan 				   size_t count,
2643ace10f5SKan Yan 				   loff_t *ppos)
2653ace10f5SKan Yan {
2663ace10f5SKan Yan 	struct ieee80211_local *local = file->private_data;
2673ace10f5SKan Yan 	char buf[100];
2683ace10f5SKan Yan 	u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old;
2693ace10f5SKan Yan 	struct sta_info *sta;
2703ace10f5SKan Yan 
2716020d534SShayne Chen 	if (count >= sizeof(buf))
2723ace10f5SKan Yan 		return -EINVAL;
2733ace10f5SKan Yan 
2743ace10f5SKan Yan 	if (copy_from_user(buf, user_buf, count))
2753ace10f5SKan Yan 		return -EFAULT;
2763ace10f5SKan Yan 
2776020d534SShayne Chen 	if (count && buf[count - 1] == '\n')
2786020d534SShayne Chen 		buf[count - 1] = '\0';
2796020d534SShayne Chen 	else
2806020d534SShayne Chen 		buf[count] = '\0';
2813ace10f5SKan Yan 
2823ace10f5SKan Yan 	if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
2833ace10f5SKan Yan 		return -EINVAL;
2843ace10f5SKan Yan 
2853ace10f5SKan Yan 	if (ac >= IEEE80211_NUM_ACS)
2863ace10f5SKan Yan 		return -EINVAL;
2873ace10f5SKan Yan 
288942741daSFelix Fietkau 	q_limit_low_old = local->aql_txq_limit_low[ac];
289942741daSFelix Fietkau 	q_limit_high_old = local->aql_txq_limit_high[ac];
2903ace10f5SKan Yan 
291942741daSFelix Fietkau 	local->aql_txq_limit_low[ac] = q_limit_low;
292942741daSFelix Fietkau 	local->aql_txq_limit_high[ac] = q_limit_high;
2933ace10f5SKan Yan 
2943ace10f5SKan Yan 	mutex_lock(&local->sta_mtx);
2953ace10f5SKan Yan 	list_for_each_entry(sta, &local->sta_list, list) {
2963ace10f5SKan Yan 		/* If a sta has customized queue limits, keep it */
2973ace10f5SKan Yan 		if (sta->airtime[ac].aql_limit_low == q_limit_low_old &&
2983ace10f5SKan Yan 		    sta->airtime[ac].aql_limit_high == q_limit_high_old) {
2993ace10f5SKan Yan 			sta->airtime[ac].aql_limit_low = q_limit_low;
3003ace10f5SKan Yan 			sta->airtime[ac].aql_limit_high = q_limit_high;
3013ace10f5SKan Yan 		}
3023ace10f5SKan Yan 	}
3033ace10f5SKan Yan 	mutex_unlock(&local->sta_mtx);
3043ace10f5SKan Yan 	return count;
3053ace10f5SKan Yan }
3063ace10f5SKan Yan 
3073ace10f5SKan Yan static const struct file_operations aql_txq_limit_ops = {
3083ace10f5SKan Yan 	.write = aql_txq_limit_write,
3093ace10f5SKan Yan 	.read = aql_txq_limit_read,
3103ace10f5SKan Yan 	.open = simple_open,
3113ace10f5SKan Yan 	.llseek = default_llseek,
3123ace10f5SKan Yan };
3133ace10f5SKan Yan 
314e908435eSLorenzo Bianconi static ssize_t aql_enable_read(struct file *file, char __user *user_buf,
315e908435eSLorenzo Bianconi 			       size_t count, loff_t *ppos)
316e908435eSLorenzo Bianconi {
317e908435eSLorenzo Bianconi 	char buf[3];
318e908435eSLorenzo Bianconi 	int len;
319e908435eSLorenzo Bianconi 
320e908435eSLorenzo Bianconi 	len = scnprintf(buf, sizeof(buf), "%d\n",
321e908435eSLorenzo Bianconi 			!static_key_false(&aql_disable.key));
322e908435eSLorenzo Bianconi 
323e908435eSLorenzo Bianconi 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
324e908435eSLorenzo Bianconi }
325e908435eSLorenzo Bianconi 
326e908435eSLorenzo Bianconi static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
327e908435eSLorenzo Bianconi 				size_t count, loff_t *ppos)
328e908435eSLorenzo Bianconi {
329e908435eSLorenzo Bianconi 	bool aql_disabled = static_key_false(&aql_disable.key);
330e908435eSLorenzo Bianconi 	char buf[3];
331e908435eSLorenzo Bianconi 	size_t len;
332e908435eSLorenzo Bianconi 
333e908435eSLorenzo Bianconi 	if (count > sizeof(buf))
334e908435eSLorenzo Bianconi 		return -EINVAL;
335e908435eSLorenzo Bianconi 
336e908435eSLorenzo Bianconi 	if (copy_from_user(buf, user_buf, count))
337e908435eSLorenzo Bianconi 		return -EFAULT;
338e908435eSLorenzo Bianconi 
339e908435eSLorenzo Bianconi 	buf[sizeof(buf) - 1] = '\0';
340e908435eSLorenzo Bianconi 	len = strlen(buf);
341e908435eSLorenzo Bianconi 	if (len > 0 && buf[len - 1] == '\n')
342e908435eSLorenzo Bianconi 		buf[len - 1] = 0;
343e908435eSLorenzo Bianconi 
344e908435eSLorenzo Bianconi 	if (buf[0] == '0' && buf[1] == '\0') {
345e908435eSLorenzo Bianconi 		if (!aql_disabled)
346e908435eSLorenzo Bianconi 			static_branch_inc(&aql_disable);
347e908435eSLorenzo Bianconi 	} else if (buf[0] == '1' && buf[1] == '\0') {
348e908435eSLorenzo Bianconi 		if (aql_disabled)
349e908435eSLorenzo Bianconi 			static_branch_dec(&aql_disable);
350e908435eSLorenzo Bianconi 	} else {
351e908435eSLorenzo Bianconi 		return -EINVAL;
352e908435eSLorenzo Bianconi 	}
353e908435eSLorenzo Bianconi 
354e908435eSLorenzo Bianconi 	return count;
355e908435eSLorenzo Bianconi }
356e908435eSLorenzo Bianconi 
357e908435eSLorenzo Bianconi static const struct file_operations aql_enable_ops = {
358e908435eSLorenzo Bianconi 	.write = aql_enable_write,
359e908435eSLorenzo Bianconi 	.read = aql_enable_read,
360e908435eSLorenzo Bianconi 	.open = simple_open,
361e908435eSLorenzo Bianconi 	.llseek = default_llseek,
362e908435eSLorenzo Bianconi };
363e908435eSLorenzo Bianconi 
364276d9e82SJulius Niedworok static ssize_t force_tx_status_read(struct file *file,
365276d9e82SJulius Niedworok 				    char __user *user_buf,
366276d9e82SJulius Niedworok 				    size_t count,
367276d9e82SJulius Niedworok 				    loff_t *ppos)
368276d9e82SJulius Niedworok {
369276d9e82SJulius Niedworok 	struct ieee80211_local *local = file->private_data;
370276d9e82SJulius Niedworok 	char buf[3];
371276d9e82SJulius Niedworok 	int len = 0;
372276d9e82SJulius Niedworok 
373276d9e82SJulius Niedworok 	len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status);
374276d9e82SJulius Niedworok 
375276d9e82SJulius Niedworok 	return simple_read_from_buffer(user_buf, count, ppos,
376276d9e82SJulius Niedworok 				       buf, len);
377276d9e82SJulius Niedworok }
378276d9e82SJulius Niedworok 
379276d9e82SJulius Niedworok static ssize_t force_tx_status_write(struct file *file,
380276d9e82SJulius Niedworok 				     const char __user *user_buf,
381276d9e82SJulius Niedworok 				     size_t count,
382276d9e82SJulius Niedworok 				     loff_t *ppos)
383276d9e82SJulius Niedworok {
384276d9e82SJulius Niedworok 	struct ieee80211_local *local = file->private_data;
385276d9e82SJulius Niedworok 	char buf[3];
386276d9e82SJulius Niedworok 
3876020d534SShayne Chen 	if (count >= sizeof(buf))
388276d9e82SJulius Niedworok 		return -EINVAL;
389276d9e82SJulius Niedworok 
390276d9e82SJulius Niedworok 	if (copy_from_user(buf, user_buf, count))
391276d9e82SJulius Niedworok 		return -EFAULT;
392276d9e82SJulius Niedworok 
3936020d534SShayne Chen 	if (count && buf[count - 1] == '\n')
3946020d534SShayne Chen 		buf[count - 1] = '\0';
3956020d534SShayne Chen 	else
3966020d534SShayne Chen 		buf[count] = '\0';
397276d9e82SJulius Niedworok 
398276d9e82SJulius Niedworok 	if (buf[0] == '0' && buf[1] == '\0')
399276d9e82SJulius Niedworok 		local->force_tx_status = 0;
400276d9e82SJulius Niedworok 	else if (buf[0] == '1' && buf[1] == '\0')
401276d9e82SJulius Niedworok 		local->force_tx_status = 1;
402276d9e82SJulius Niedworok 	else
403276d9e82SJulius Niedworok 		return -EINVAL;
404276d9e82SJulius Niedworok 
405276d9e82SJulius Niedworok 	return count;
406276d9e82SJulius Niedworok }
407276d9e82SJulius Niedworok 
408276d9e82SJulius Niedworok static const struct file_operations force_tx_status_ops = {
409276d9e82SJulius Niedworok 	.write = force_tx_status_write,
410276d9e82SJulius Niedworok 	.read = force_tx_status_read,
411276d9e82SJulius Niedworok 	.open = simple_open,
412276d9e82SJulius Niedworok 	.llseek = default_llseek,
413276d9e82SJulius Niedworok };
414276d9e82SJulius Niedworok 
4152ad4814fSJohannes Berg #ifdef CONFIG_PM
416827b1fb4SJohannes Berg static ssize_t reset_write(struct file *file, const char __user *user_buf,
417827b1fb4SJohannes Berg 			   size_t count, loff_t *ppos)
418827b1fb4SJohannes Berg {
419827b1fb4SJohannes Berg 	struct ieee80211_local *local = file->private_data;
420f5baf287SJohannes Berg 	int ret;
421827b1fb4SJohannes Berg 
422827b1fb4SJohannes Berg 	rtnl_lock();
423adaed1b9SJohannes Berg 	wiphy_lock(local->hw.wiphy);
424eecc4800SJohannes Berg 	__ieee80211_suspend(&local->hw, NULL);
425f5baf287SJohannes Berg 	ret = __ieee80211_resume(&local->hw);
426adaed1b9SJohannes Berg 	wiphy_unlock(local->hw.wiphy);
427f5baf287SJohannes Berg 
428f5baf287SJohannes Berg 	if (ret)
429f5baf287SJohannes Berg 		cfg80211_shutdown_all_interfaces(local->hw.wiphy);
430f5baf287SJohannes Berg 
431827b1fb4SJohannes Berg 	rtnl_unlock();
432827b1fb4SJohannes Berg 
433827b1fb4SJohannes Berg 	return count;
434827b1fb4SJohannes Berg }
435827b1fb4SJohannes Berg 
436827b1fb4SJohannes Berg static const struct file_operations reset_ops = {
437827b1fb4SJohannes Berg 	.write = reset_write,
438234e3405SStephen Boyd 	.open = simple_open,
4396038f373SArnd Bergmann 	.llseek = noop_llseek,
440827b1fb4SJohannes Berg };
4412ad4814fSJohannes Berg #endif
442827b1fb4SJohannes Berg 
44368920c97SAndrey Ryabinin static const char *hw_flag_names[] = {
44430686bf7SJohannes Berg #define FLAG(F)	[IEEE80211_HW_##F] = #F
44530686bf7SJohannes Berg 	FLAG(HAS_RATE_CONTROL),
44630686bf7SJohannes Berg 	FLAG(RX_INCLUDES_FCS),
44730686bf7SJohannes Berg 	FLAG(HOST_BROADCAST_PS_BUFFERING),
44830686bf7SJohannes Berg 	FLAG(SIGNAL_UNSPEC),
44930686bf7SJohannes Berg 	FLAG(SIGNAL_DBM),
45030686bf7SJohannes Berg 	FLAG(NEED_DTIM_BEFORE_ASSOC),
45130686bf7SJohannes Berg 	FLAG(SPECTRUM_MGMT),
45230686bf7SJohannes Berg 	FLAG(AMPDU_AGGREGATION),
45330686bf7SJohannes Berg 	FLAG(SUPPORTS_PS),
45430686bf7SJohannes Berg 	FLAG(PS_NULLFUNC_STACK),
45530686bf7SJohannes Berg 	FLAG(SUPPORTS_DYNAMIC_PS),
45630686bf7SJohannes Berg 	FLAG(MFP_CAPABLE),
45730686bf7SJohannes Berg 	FLAG(WANT_MONITOR_VIF),
45830686bf7SJohannes Berg 	FLAG(NO_AUTO_VIF),
45930686bf7SJohannes Berg 	FLAG(SW_CRYPTO_CONTROL),
46030686bf7SJohannes Berg 	FLAG(SUPPORT_FAST_XMIT),
46130686bf7SJohannes Berg 	FLAG(REPORTS_TX_ACK_STATUS),
46230686bf7SJohannes Berg 	FLAG(CONNECTION_MONITOR),
46330686bf7SJohannes Berg 	FLAG(QUEUE_CONTROL),
46430686bf7SJohannes Berg 	FLAG(SUPPORTS_PER_STA_GTK),
46530686bf7SJohannes Berg 	FLAG(AP_LINK_PS),
46630686bf7SJohannes Berg 	FLAG(TX_AMPDU_SETUP_IN_HW),
46730686bf7SJohannes Berg 	FLAG(SUPPORTS_RC_TABLE),
46830686bf7SJohannes Berg 	FLAG(P2P_DEV_ADDR_FOR_INTF),
46930686bf7SJohannes Berg 	FLAG(TIMING_BEACON_ONLY),
47030686bf7SJohannes Berg 	FLAG(SUPPORTS_HT_CCK_RATES),
47130686bf7SJohannes Berg 	FLAG(CHANCTX_STA_CSA),
47230686bf7SJohannes Berg 	FLAG(SUPPORTS_CLONED_SKBS),
47330686bf7SJohannes Berg 	FLAG(SINGLE_SCAN_ON_ALL_BANDS),
474b98fb44fSArik Nemtsov 	FLAG(TDLS_WIDER_BW),
47599e7ca44SEmmanuel Grumbach 	FLAG(SUPPORTS_AMSDU_IN_AMPDU),
47635afa588SHelmut Schaa 	FLAG(BEACON_TX_STATUS),
47731104891SJohannes Berg 	FLAG(NEEDS_UNIQUE_STA_ADDR),
478412a6d80SSara Sharon 	FLAG(SUPPORTS_REORDERING_BUFFER),
479c9c5962bSJohannes Berg 	FLAG(USES_RSS),
4806e0456b5SFelix Fietkau 	FLAG(TX_AMSDU),
4816e0456b5SFelix Fietkau 	FLAG(TX_FRAG_LIST),
482e8a24cd4SRajkumar Manoharan 	FLAG(REPORTS_LOW_ACK),
483f3fe4e93SSara Sharon 	FLAG(SUPPORTS_TX_FRAG),
484e2fb1b83SYingying Tang 	FLAG(SUPPORTS_TDLS_BUFFER_STA),
48594ba9271SIlan Peer 	FLAG(DEAUTH_NEED_MGD_TX_PREP),
4867c181f4fSBen Caradoc-Davies 	FLAG(DOESNT_SUPPORT_QOS_NDP),
487adf8ed01SJohannes Berg 	FLAG(BUFF_MMPDU_TXQ),
48809b4a4faSJohannes Berg 	FLAG(SUPPORTS_VHT_EXT_NSS_BW),
4890eeb2b67SSara Sharon 	FLAG(STA_MMPDU_TXQ),
49077f7ffdcSFelix Fietkau 	FLAG(TX_STATUS_NO_AMPDU_LEN),
491caf56338SSara Sharon 	FLAG(SUPPORTS_MULTI_BSSID),
492caf56338SSara Sharon 	FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
493dc3998ecSAlexander Wetzel 	FLAG(AMPDU_KEYBORDER_SUPPORT),
4946aea26ceSFelix Fietkau 	FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
49580a915ecSFelix Fietkau 	FLAG(SUPPORTS_RX_DECAP_OFFLOAD),
49655f8205eSSriram R 	FLAG(SUPPORTS_CONC_MON_RX_DECAP),
4976d945a33SLorenzo Bianconi 	FLAG(DETECTS_COLOR_COLLISION),
498*963d0e8dSJohannes Berg 	FLAG(MLO_MCAST_MULTI_LINK_TX),
49930686bf7SJohannes Berg #undef FLAG
50030686bf7SJohannes Berg };
50130686bf7SJohannes Berg 
502279daf64SBen Greear static ssize_t hwflags_read(struct file *file, char __user *user_buf,
503279daf64SBen Greear 			    size_t count, loff_t *ppos)
504279daf64SBen Greear {
505279daf64SBen Greear 	struct ieee80211_local *local = file->private_data;
50630686bf7SJohannes Berg 	size_t bufsz = 30 * NUM_IEEE80211_HW_FLAGS;
50730686bf7SJohannes Berg 	char *buf = kzalloc(bufsz, GFP_KERNEL);
50830686bf7SJohannes Berg 	char *pos = buf, *end = buf + bufsz - 1;
509279daf64SBen Greear 	ssize_t rv;
51030686bf7SJohannes Berg 	int i;
511279daf64SBen Greear 
512d15b8459SJoe Perches 	if (!buf)
51330686bf7SJohannes Berg 		return -ENOMEM;
514d15b8459SJoe Perches 
51530686bf7SJohannes Berg 	/* fail compilation if somebody adds or removes
51630686bf7SJohannes Berg 	 * a flag without updating the name array above
51730686bf7SJohannes Berg 	 */
51868920c97SAndrey Ryabinin 	BUILD_BUG_ON(ARRAY_SIZE(hw_flag_names) != NUM_IEEE80211_HW_FLAGS);
51930686bf7SJohannes Berg 
52030686bf7SJohannes Berg 	for (i = 0; i < NUM_IEEE80211_HW_FLAGS; i++) {
52130686bf7SJohannes Berg 		if (test_bit(i, local->hw.flags))
5224633dfc3SMohammed Shafi Shajakhan 			pos += scnprintf(pos, end - pos, "%s\n",
52330686bf7SJohannes Berg 					 hw_flag_names[i]);
52430686bf7SJohannes Berg 	}
525279daf64SBen Greear 
526279daf64SBen Greear 	rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
527279daf64SBen Greear 	kfree(buf);
528279daf64SBen Greear 	return rv;
529279daf64SBen Greear }
530199d69f2SBenoit Papillault 
5314a5eccaaSBen Greear static ssize_t misc_read(struct file *file, char __user *user_buf,
5324a5eccaaSBen Greear 			 size_t count, loff_t *ppos)
5334a5eccaaSBen Greear {
5344a5eccaaSBen Greear 	struct ieee80211_local *local = file->private_data;
5354a5eccaaSBen Greear 	/* Max len of each line is 16 characters, plus 9 for 'pending:\n' */
5364a5eccaaSBen Greear 	size_t bufsz = IEEE80211_MAX_QUEUES * 16 + 9;
537b2347a32SDan Carpenter 	char *buf;
538b2347a32SDan Carpenter 	char *pos, *end;
5394a5eccaaSBen Greear 	ssize_t rv;
5404a5eccaaSBen Greear 	int i;
5414a5eccaaSBen Greear 	int ln;
5424a5eccaaSBen Greear 
543b2347a32SDan Carpenter 	buf = kzalloc(bufsz, GFP_KERNEL);
544b2347a32SDan Carpenter 	if (!buf)
545b2347a32SDan Carpenter 		return -ENOMEM;
546b2347a32SDan Carpenter 
547b2347a32SDan Carpenter 	pos = buf;
548b2347a32SDan Carpenter 	end = buf + bufsz - 1;
549b2347a32SDan Carpenter 
5504a5eccaaSBen Greear 	pos += scnprintf(pos, end - pos, "pending:\n");
5514a5eccaaSBen Greear 
5524a5eccaaSBen Greear 	for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
5534a5eccaaSBen Greear 		ln = skb_queue_len(&local->pending[i]);
5544a5eccaaSBen Greear 		pos += scnprintf(pos, end - pos, "[%i] %d\n",
5554a5eccaaSBen Greear 				 i, ln);
5564a5eccaaSBen Greear 	}
5574a5eccaaSBen Greear 
5584a5eccaaSBen Greear 	rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
5594a5eccaaSBen Greear 	kfree(buf);
5604a5eccaaSBen Greear 	return rv;
5614a5eccaaSBen Greear }
5624a5eccaaSBen Greear 
563db2e6bd4SJohannes Berg static ssize_t queues_read(struct file *file, char __user *user_buf,
564db2e6bd4SJohannes Berg 			   size_t count, loff_t *ppos)
565db2e6bd4SJohannes Berg {
566db2e6bd4SJohannes Berg 	struct ieee80211_local *local = file->private_data;
567db2e6bd4SJohannes Berg 	unsigned long flags;
568db2e6bd4SJohannes Berg 	char buf[IEEE80211_MAX_QUEUES * 20];
569db2e6bd4SJohannes Berg 	int q, res = 0;
570db2e6bd4SJohannes Berg 
571db2e6bd4SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
572db2e6bd4SJohannes Berg 	for (q = 0; q < local->hw.queues; q++)
573db2e6bd4SJohannes Berg 		res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
574db2e6bd4SJohannes Berg 				local->queue_stop_reasons[q],
5753b8d81e0SJohannes Berg 				skb_queue_len(&local->pending[q]));
576db2e6bd4SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
577db2e6bd4SJohannes Berg 
578db2e6bd4SJohannes Berg 	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
579db2e6bd4SJohannes Berg }
580db2e6bd4SJohannes Berg 
581279daf64SBen Greear DEBUGFS_READONLY_FILE_OPS(hwflags);
582279daf64SBen Greear DEBUGFS_READONLY_FILE_OPS(queues);
5834a5eccaaSBen Greear DEBUGFS_READONLY_FILE_OPS(misc);
584db2e6bd4SJohannes Berg 
585e9f207f0SJiri Benc /* statistics stuff */
586e9f207f0SJiri Benc 
587e9f207f0SJiri Benc static ssize_t format_devstat_counter(struct ieee80211_local *local,
588e9f207f0SJiri Benc 	char __user *userbuf,
589e9f207f0SJiri Benc 	size_t count, loff_t *ppos,
590e9f207f0SJiri Benc 	int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf,
591e9f207f0SJiri Benc 			  int buflen))
592e9f207f0SJiri Benc {
593e9f207f0SJiri Benc 	struct ieee80211_low_level_stats stats;
594e9f207f0SJiri Benc 	char buf[20];
595e9f207f0SJiri Benc 	int res;
596e9f207f0SJiri Benc 
59775636525SJohannes Berg 	rtnl_lock();
59824487981SJohannes Berg 	res = drv_get_stats(local, &stats);
599e9f207f0SJiri Benc 	rtnl_unlock();
60024487981SJohannes Berg 	if (res)
60124487981SJohannes Berg 		return res;
602e9f207f0SJiri Benc 	res = printvalue(&stats, buf, sizeof(buf));
603e9f207f0SJiri Benc 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
604e9f207f0SJiri Benc }
605e9f207f0SJiri Benc 
606e9f207f0SJiri Benc #define DEBUGFS_DEVSTATS_FILE(name)					\
607e9f207f0SJiri Benc static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
608e9f207f0SJiri Benc 				 char *buf, int buflen)			\
609e9f207f0SJiri Benc {									\
610e9f207f0SJiri Benc 	return scnprintf(buf, buflen, "%u\n", stats->name);		\
611e9f207f0SJiri Benc }									\
612e9f207f0SJiri Benc static ssize_t stats_ ##name## _read(struct file *file,			\
613e9f207f0SJiri Benc 				     char __user *userbuf,		\
614e9f207f0SJiri Benc 				     size_t count, loff_t *ppos)	\
615e9f207f0SJiri Benc {									\
616e9f207f0SJiri Benc 	return format_devstat_counter(file->private_data,		\
617e9f207f0SJiri Benc 				      userbuf,				\
618e9f207f0SJiri Benc 				      count,				\
619e9f207f0SJiri Benc 				      ppos,				\
620e9f207f0SJiri Benc 				      print_devstats_##name);		\
621e9f207f0SJiri Benc }									\
622e9f207f0SJiri Benc 									\
623e9f207f0SJiri Benc static const struct file_operations stats_ ##name## _ops = {		\
624e9f207f0SJiri Benc 	.read = stats_ ##name## _read,					\
625234e3405SStephen Boyd 	.open = simple_open,						\
6262b18ab36SArnd Bergmann 	.llseek = generic_file_llseek,					\
627e9f207f0SJiri Benc };
628e9f207f0SJiri Benc 
629453a2a82SJohannes Berg #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
630f1160434SJohannes Berg #define DEBUGFS_STATS_ADD(name)					\
631f1160434SJohannes Berg 	debugfs_create_u32(#name, 0400, statsd, &local->name);
632453a2a82SJohannes Berg #endif
6332826bcd8SFelix Fietkau #define DEBUGFS_DEVSTATS_ADD(name)					\
6347bcfaf2fSJohannes Berg 	debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
635e9f207f0SJiri Benc 
636e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
637e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
638e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
639e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
640e9f207f0SJiri Benc 
641e9f207f0SJiri Benc void debugfs_hw_add(struct ieee80211_local *local)
642e9f207f0SJiri Benc {
643e9f207f0SJiri Benc 	struct dentry *phyd = local->hw.wiphy->debugfsdir;
644e9f207f0SJiri Benc 	struct dentry *statsd;
645e9f207f0SJiri Benc 
646e9f207f0SJiri Benc 	if (!phyd)
647e9f207f0SJiri Benc 		return;
648e9f207f0SJiri Benc 
649e9f207f0SJiri Benc 	local->debugfs.keys = debugfs_create_dir("keys", phyd);
650e9f207f0SJiri Benc 
651e9f207f0SJiri Benc 	DEBUGFS_ADD(total_ps_buffered);
652e9f207f0SJiri Benc 	DEBUGFS_ADD(wep_iv);
653bddb2afcSJohannes Berg 	DEBUGFS_ADD(rate_ctrl_alg);
654db2e6bd4SJohannes Berg 	DEBUGFS_ADD(queues);
6554a5eccaaSBen Greear 	DEBUGFS_ADD(misc);
6562ad4814fSJohannes Berg #ifdef CONFIG_PM
657827b1fb4SJohannes Berg 	DEBUGFS_ADD_MODE(reset, 0200);
6582ad4814fSJohannes Berg #endif
659279daf64SBen Greear 	DEBUGFS_ADD(hwflags);
66083bdf2a1SBen Greear 	DEBUGFS_ADD(user_power);
66183bdf2a1SBen Greear 	DEBUGFS_ADD(power);
662c90142a5SThomas Pedersen 	DEBUGFS_ADD(hw_conf);
663276d9e82SJulius Niedworok 	DEBUGFS_ADD_MODE(force_tx_status, 0600);
664e908435eSLorenzo Bianconi 	DEBUGFS_ADD_MODE(aql_enable, 0600);
6653db2c560SFelix Fietkau 	DEBUGFS_ADD(aql_pending);
6668d51dbb8SToke Høiland-Jørgensen 
6678d51dbb8SToke Høiland-Jørgensen 	if (local->ops->wake_tx_queue)
6689399b86cSMichal Kazior 		DEBUGFS_ADD_MODE(aqm, 0600);
669e9f207f0SJiri Benc 
670e322c07fSLorenzo Bianconi 	DEBUGFS_ADD_MODE(airtime_flags, 0600);
671b4809e94SToke Høiland-Jørgensen 
6723ace10f5SKan Yan 	DEBUGFS_ADD(aql_txq_limit);
6733ace10f5SKan Yan 	debugfs_create_u32("aql_threshold", 0600,
6743ace10f5SKan Yan 			   phyd, &local->aql_threshold);
6753ace10f5SKan Yan 
676e9f207f0SJiri Benc 	statsd = debugfs_create_dir("statistics", phyd);
677e9f207f0SJiri Benc 
678e9f207f0SJiri Benc 	/* if the dir failed, don't put all the other things into the root! */
679e9f207f0SJiri Benc 	if (!statsd)
680e9f207f0SJiri Benc 		return;
681e9f207f0SJiri Benc 
682c206ca67SJohannes Berg #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
683f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount);
684f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount);
685f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11FailedCount);
686f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11RetryCount);
687f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11MultipleRetryCount);
688f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11FrameDuplicateCount);
689f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11ReceivedFragmentCount);
690f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11MulticastReceivedFrameCount);
691f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11TransmittedFrameCount);
692f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop);
693f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_queued);
694f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
695f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
696f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
697f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_drop);
698f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_queued);
699f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
700f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
701f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_expand_skb_head);
702f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
703f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag);
704f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_fragments);
705f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_status_drop);
706e9f207f0SJiri Benc #endif
7072826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
7082826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
7092826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
7102826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
711e9f207f0SJiri Benc }
712