xref: /linux/net/mac80211/debugfs.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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
76f0107d1SJohannes Berg  * Copyright (C) 2018 - 2019, 2021-2024 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 
mac80211_format_buffer(char __user * userbuf,size_t count,loff_t * ppos,char * fmt,...)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 
aqm_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
aqm_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)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 
airtime_flags_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
airtime_flags_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)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 
aql_pending_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
aql_txq_limit_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
aql_txq_limit_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)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 
2914d3acf43SJohannes Berg 	wiphy_lock(local->hw.wiphy);
292942741daSFelix Fietkau 	local->aql_txq_limit_low[ac] = q_limit_low;
293942741daSFelix Fietkau 	local->aql_txq_limit_high[ac] = q_limit_high;
2943ace10f5SKan Yan 
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 	}
3034d3acf43SJohannes Berg 	wiphy_unlock(local->hw.wiphy);
3044d3acf43SJohannes Berg 
3053ace10f5SKan Yan 	return count;
3063ace10f5SKan Yan }
3073ace10f5SKan Yan 
3083ace10f5SKan Yan static const struct file_operations aql_txq_limit_ops = {
3093ace10f5SKan Yan 	.write = aql_txq_limit_write,
3103ace10f5SKan Yan 	.read = aql_txq_limit_read,
3113ace10f5SKan Yan 	.open = simple_open,
3123ace10f5SKan Yan 	.llseek = default_llseek,
3133ace10f5SKan Yan };
3143ace10f5SKan Yan 
aql_enable_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)315e908435eSLorenzo Bianconi static ssize_t aql_enable_read(struct file *file, char __user *user_buf,
316e908435eSLorenzo Bianconi 			       size_t count, loff_t *ppos)
317e908435eSLorenzo Bianconi {
318e908435eSLorenzo Bianconi 	char buf[3];
319e908435eSLorenzo Bianconi 	int len;
320e908435eSLorenzo Bianconi 
321e908435eSLorenzo Bianconi 	len = scnprintf(buf, sizeof(buf), "%d\n",
322e908435eSLorenzo Bianconi 			!static_key_false(&aql_disable.key));
323e908435eSLorenzo Bianconi 
324e908435eSLorenzo Bianconi 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
325e908435eSLorenzo Bianconi }
326e908435eSLorenzo Bianconi 
aql_enable_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)327e908435eSLorenzo Bianconi static ssize_t aql_enable_write(struct file *file, const char __user *user_buf,
328e908435eSLorenzo Bianconi 				size_t count, loff_t *ppos)
329e908435eSLorenzo Bianconi {
330e908435eSLorenzo Bianconi 	bool aql_disabled = static_key_false(&aql_disable.key);
331e908435eSLorenzo Bianconi 	char buf[3];
332e908435eSLorenzo Bianconi 	size_t len;
333e908435eSLorenzo Bianconi 
334e908435eSLorenzo Bianconi 	if (count > sizeof(buf))
335e908435eSLorenzo Bianconi 		return -EINVAL;
336e908435eSLorenzo Bianconi 
337e908435eSLorenzo Bianconi 	if (copy_from_user(buf, user_buf, count))
338e908435eSLorenzo Bianconi 		return -EFAULT;
339e908435eSLorenzo Bianconi 
340e908435eSLorenzo Bianconi 	buf[sizeof(buf) - 1] = '\0';
341e908435eSLorenzo Bianconi 	len = strlen(buf);
342e908435eSLorenzo Bianconi 	if (len > 0 && buf[len - 1] == '\n')
343e908435eSLorenzo Bianconi 		buf[len - 1] = 0;
344e908435eSLorenzo Bianconi 
345e908435eSLorenzo Bianconi 	if (buf[0] == '0' && buf[1] == '\0') {
346e908435eSLorenzo Bianconi 		if (!aql_disabled)
347e908435eSLorenzo Bianconi 			static_branch_inc(&aql_disable);
348e908435eSLorenzo Bianconi 	} else if (buf[0] == '1' && buf[1] == '\0') {
349e908435eSLorenzo Bianconi 		if (aql_disabled)
350e908435eSLorenzo Bianconi 			static_branch_dec(&aql_disable);
351e908435eSLorenzo Bianconi 	} else {
352e908435eSLorenzo Bianconi 		return -EINVAL;
353e908435eSLorenzo Bianconi 	}
354e908435eSLorenzo Bianconi 
355e908435eSLorenzo Bianconi 	return count;
356e908435eSLorenzo Bianconi }
357e908435eSLorenzo Bianconi 
358e908435eSLorenzo Bianconi static const struct file_operations aql_enable_ops = {
359e908435eSLorenzo Bianconi 	.write = aql_enable_write,
360e908435eSLorenzo Bianconi 	.read = aql_enable_read,
361e908435eSLorenzo Bianconi 	.open = simple_open,
362e908435eSLorenzo Bianconi 	.llseek = default_llseek,
363e908435eSLorenzo Bianconi };
364e908435eSLorenzo Bianconi 
force_tx_status_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)365276d9e82SJulius Niedworok static ssize_t force_tx_status_read(struct file *file,
366276d9e82SJulius Niedworok 				    char __user *user_buf,
367276d9e82SJulius Niedworok 				    size_t count,
368276d9e82SJulius Niedworok 				    loff_t *ppos)
369276d9e82SJulius Niedworok {
370276d9e82SJulius Niedworok 	struct ieee80211_local *local = file->private_data;
371276d9e82SJulius Niedworok 	char buf[3];
372276d9e82SJulius Niedworok 	int len = 0;
373276d9e82SJulius Niedworok 
374276d9e82SJulius Niedworok 	len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status);
375276d9e82SJulius Niedworok 
376276d9e82SJulius Niedworok 	return simple_read_from_buffer(user_buf, count, ppos,
377276d9e82SJulius Niedworok 				       buf, len);
378276d9e82SJulius Niedworok }
379276d9e82SJulius Niedworok 
force_tx_status_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)380276d9e82SJulius Niedworok static ssize_t force_tx_status_write(struct file *file,
381276d9e82SJulius Niedworok 				     const char __user *user_buf,
382276d9e82SJulius Niedworok 				     size_t count,
383276d9e82SJulius Niedworok 				     loff_t *ppos)
384276d9e82SJulius Niedworok {
385276d9e82SJulius Niedworok 	struct ieee80211_local *local = file->private_data;
386276d9e82SJulius Niedworok 	char buf[3];
387276d9e82SJulius Niedworok 
3886020d534SShayne Chen 	if (count >= sizeof(buf))
389276d9e82SJulius Niedworok 		return -EINVAL;
390276d9e82SJulius Niedworok 
391276d9e82SJulius Niedworok 	if (copy_from_user(buf, user_buf, count))
392276d9e82SJulius Niedworok 		return -EFAULT;
393276d9e82SJulius Niedworok 
3946020d534SShayne Chen 	if (count && buf[count - 1] == '\n')
3956020d534SShayne Chen 		buf[count - 1] = '\0';
3966020d534SShayne Chen 	else
3976020d534SShayne Chen 		buf[count] = '\0';
398276d9e82SJulius Niedworok 
399276d9e82SJulius Niedworok 	if (buf[0] == '0' && buf[1] == '\0')
400276d9e82SJulius Niedworok 		local->force_tx_status = 0;
401276d9e82SJulius Niedworok 	else if (buf[0] == '1' && buf[1] == '\0')
402276d9e82SJulius Niedworok 		local->force_tx_status = 1;
403276d9e82SJulius Niedworok 	else
404276d9e82SJulius Niedworok 		return -EINVAL;
405276d9e82SJulius Niedworok 
406276d9e82SJulius Niedworok 	return count;
407276d9e82SJulius Niedworok }
408276d9e82SJulius Niedworok 
409276d9e82SJulius Niedworok static const struct file_operations force_tx_status_ops = {
410276d9e82SJulius Niedworok 	.write = force_tx_status_write,
411276d9e82SJulius Niedworok 	.read = force_tx_status_read,
412276d9e82SJulius Niedworok 	.open = simple_open,
413276d9e82SJulius Niedworok 	.llseek = default_llseek,
414276d9e82SJulius Niedworok };
415276d9e82SJulius Niedworok 
4162ad4814fSJohannes Berg #ifdef CONFIG_PM
reset_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)417827b1fb4SJohannes Berg static ssize_t reset_write(struct file *file, const char __user *user_buf,
418827b1fb4SJohannes Berg 			   size_t count, loff_t *ppos)
419827b1fb4SJohannes Berg {
420827b1fb4SJohannes Berg 	struct ieee80211_local *local = file->private_data;
421f5baf287SJohannes Berg 	int ret;
422827b1fb4SJohannes Berg 
423827b1fb4SJohannes Berg 	rtnl_lock();
424adaed1b9SJohannes Berg 	wiphy_lock(local->hw.wiphy);
425eecc4800SJohannes Berg 	__ieee80211_suspend(&local->hw, NULL);
426f5baf287SJohannes Berg 	ret = __ieee80211_resume(&local->hw);
427adaed1b9SJohannes Berg 	wiphy_unlock(local->hw.wiphy);
428f5baf287SJohannes Berg 
429f5baf287SJohannes Berg 	if (ret)
430f5baf287SJohannes Berg 		cfg80211_shutdown_all_interfaces(local->hw.wiphy);
431f5baf287SJohannes Berg 
432827b1fb4SJohannes Berg 	rtnl_unlock();
433827b1fb4SJohannes Berg 
434827b1fb4SJohannes Berg 	return count;
435827b1fb4SJohannes Berg }
436827b1fb4SJohannes Berg 
437827b1fb4SJohannes Berg static const struct file_operations reset_ops = {
438827b1fb4SJohannes Berg 	.write = reset_write,
439234e3405SStephen Boyd 	.open = simple_open,
4406038f373SArnd Bergmann 	.llseek = noop_llseek,
441827b1fb4SJohannes Berg };
4422ad4814fSJohannes Berg #endif
443827b1fb4SJohannes Berg 
44468920c97SAndrey Ryabinin static const char *hw_flag_names[] = {
44530686bf7SJohannes Berg #define FLAG(F)	[IEEE80211_HW_##F] = #F
44630686bf7SJohannes Berg 	FLAG(HAS_RATE_CONTROL),
44730686bf7SJohannes Berg 	FLAG(RX_INCLUDES_FCS),
44830686bf7SJohannes Berg 	FLAG(HOST_BROADCAST_PS_BUFFERING),
44930686bf7SJohannes Berg 	FLAG(SIGNAL_UNSPEC),
45030686bf7SJohannes Berg 	FLAG(SIGNAL_DBM),
45130686bf7SJohannes Berg 	FLAG(NEED_DTIM_BEFORE_ASSOC),
45230686bf7SJohannes Berg 	FLAG(SPECTRUM_MGMT),
45330686bf7SJohannes Berg 	FLAG(AMPDU_AGGREGATION),
45430686bf7SJohannes Berg 	FLAG(SUPPORTS_PS),
45530686bf7SJohannes Berg 	FLAG(PS_NULLFUNC_STACK),
45630686bf7SJohannes Berg 	FLAG(SUPPORTS_DYNAMIC_PS),
45730686bf7SJohannes Berg 	FLAG(MFP_CAPABLE),
45830686bf7SJohannes Berg 	FLAG(WANT_MONITOR_VIF),
45930686bf7SJohannes Berg 	FLAG(NO_AUTO_VIF),
46030686bf7SJohannes Berg 	FLAG(SW_CRYPTO_CONTROL),
46130686bf7SJohannes Berg 	FLAG(SUPPORT_FAST_XMIT),
46230686bf7SJohannes Berg 	FLAG(REPORTS_TX_ACK_STATUS),
46330686bf7SJohannes Berg 	FLAG(CONNECTION_MONITOR),
46430686bf7SJohannes Berg 	FLAG(QUEUE_CONTROL),
46530686bf7SJohannes Berg 	FLAG(SUPPORTS_PER_STA_GTK),
46630686bf7SJohannes Berg 	FLAG(AP_LINK_PS),
46730686bf7SJohannes Berg 	FLAG(TX_AMPDU_SETUP_IN_HW),
46830686bf7SJohannes Berg 	FLAG(SUPPORTS_RC_TABLE),
46930686bf7SJohannes Berg 	FLAG(P2P_DEV_ADDR_FOR_INTF),
47030686bf7SJohannes Berg 	FLAG(TIMING_BEACON_ONLY),
47130686bf7SJohannes Berg 	FLAG(SUPPORTS_HT_CCK_RATES),
47230686bf7SJohannes Berg 	FLAG(CHANCTX_STA_CSA),
47330686bf7SJohannes Berg 	FLAG(SUPPORTS_CLONED_SKBS),
47430686bf7SJohannes Berg 	FLAG(SINGLE_SCAN_ON_ALL_BANDS),
475b98fb44fSArik Nemtsov 	FLAG(TDLS_WIDER_BW),
47699e7ca44SEmmanuel Grumbach 	FLAG(SUPPORTS_AMSDU_IN_AMPDU),
47735afa588SHelmut Schaa 	FLAG(BEACON_TX_STATUS),
47831104891SJohannes Berg 	FLAG(NEEDS_UNIQUE_STA_ADDR),
479412a6d80SSara Sharon 	FLAG(SUPPORTS_REORDERING_BUFFER),
480c9c5962bSJohannes Berg 	FLAG(USES_RSS),
4816e0456b5SFelix Fietkau 	FLAG(TX_AMSDU),
4826e0456b5SFelix Fietkau 	FLAG(TX_FRAG_LIST),
483e8a24cd4SRajkumar Manoharan 	FLAG(REPORTS_LOW_ACK),
484f3fe4e93SSara Sharon 	FLAG(SUPPORTS_TX_FRAG),
485e2fb1b83SYingying Tang 	FLAG(SUPPORTS_TDLS_BUFFER_STA),
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),
498963d0e8dSJohannes Berg 	FLAG(MLO_MCAST_MULTI_LINK_TX),
49942b941cdSJohannes Berg 	FLAG(DISALLOW_PUNCTURING),
500*6943e003SJohannes Berg 	FLAG(DISALLOW_PUNCTURING_5GHZ),
5016f0107d1SJohannes Berg 	FLAG(HANDLES_QUIET_CSA),
50230686bf7SJohannes Berg #undef FLAG
50330686bf7SJohannes Berg };
50430686bf7SJohannes Berg 
hwflags_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)505279daf64SBen Greear static ssize_t hwflags_read(struct file *file, char __user *user_buf,
506279daf64SBen Greear 			    size_t count, loff_t *ppos)
507279daf64SBen Greear {
508279daf64SBen Greear 	struct ieee80211_local *local = file->private_data;
50930686bf7SJohannes Berg 	size_t bufsz = 30 * NUM_IEEE80211_HW_FLAGS;
51030686bf7SJohannes Berg 	char *buf = kzalloc(bufsz, GFP_KERNEL);
51130686bf7SJohannes Berg 	char *pos = buf, *end = buf + bufsz - 1;
512279daf64SBen Greear 	ssize_t rv;
51330686bf7SJohannes Berg 	int i;
514279daf64SBen Greear 
515d15b8459SJoe Perches 	if (!buf)
51630686bf7SJohannes Berg 		return -ENOMEM;
517d15b8459SJoe Perches 
51830686bf7SJohannes Berg 	/* fail compilation if somebody adds or removes
51930686bf7SJohannes Berg 	 * a flag without updating the name array above
52030686bf7SJohannes Berg 	 */
52168920c97SAndrey Ryabinin 	BUILD_BUG_ON(ARRAY_SIZE(hw_flag_names) != NUM_IEEE80211_HW_FLAGS);
52230686bf7SJohannes Berg 
52330686bf7SJohannes Berg 	for (i = 0; i < NUM_IEEE80211_HW_FLAGS; i++) {
52430686bf7SJohannes Berg 		if (test_bit(i, local->hw.flags))
5254633dfc3SMohammed Shafi Shajakhan 			pos += scnprintf(pos, end - pos, "%s\n",
52630686bf7SJohannes Berg 					 hw_flag_names[i]);
52730686bf7SJohannes Berg 	}
528279daf64SBen Greear 
529279daf64SBen Greear 	rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
530279daf64SBen Greear 	kfree(buf);
531279daf64SBen Greear 	return rv;
532279daf64SBen Greear }
533199d69f2SBenoit Papillault 
misc_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)5344a5eccaaSBen Greear static ssize_t misc_read(struct file *file, char __user *user_buf,
5354a5eccaaSBen Greear 			 size_t count, loff_t *ppos)
5364a5eccaaSBen Greear {
5374a5eccaaSBen Greear 	struct ieee80211_local *local = file->private_data;
5384a5eccaaSBen Greear 	/* Max len of each line is 16 characters, plus 9 for 'pending:\n' */
5394a5eccaaSBen Greear 	size_t bufsz = IEEE80211_MAX_QUEUES * 16 + 9;
540b2347a32SDan Carpenter 	char *buf;
541b2347a32SDan Carpenter 	char *pos, *end;
5424a5eccaaSBen Greear 	ssize_t rv;
5434a5eccaaSBen Greear 	int i;
5444a5eccaaSBen Greear 	int ln;
5454a5eccaaSBen Greear 
546b2347a32SDan Carpenter 	buf = kzalloc(bufsz, GFP_KERNEL);
547b2347a32SDan Carpenter 	if (!buf)
548b2347a32SDan Carpenter 		return -ENOMEM;
549b2347a32SDan Carpenter 
550b2347a32SDan Carpenter 	pos = buf;
551b2347a32SDan Carpenter 	end = buf + bufsz - 1;
552b2347a32SDan Carpenter 
5534a5eccaaSBen Greear 	pos += scnprintf(pos, end - pos, "pending:\n");
5544a5eccaaSBen Greear 
5554a5eccaaSBen Greear 	for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
5564a5eccaaSBen Greear 		ln = skb_queue_len(&local->pending[i]);
5574a5eccaaSBen Greear 		pos += scnprintf(pos, end - pos, "[%i] %d\n",
5584a5eccaaSBen Greear 				 i, ln);
5594a5eccaaSBen Greear 	}
5604a5eccaaSBen Greear 
5614a5eccaaSBen Greear 	rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
5624a5eccaaSBen Greear 	kfree(buf);
5634a5eccaaSBen Greear 	return rv;
5644a5eccaaSBen Greear }
5654a5eccaaSBen Greear 
queues_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)566db2e6bd4SJohannes Berg static ssize_t queues_read(struct file *file, char __user *user_buf,
567db2e6bd4SJohannes Berg 			   size_t count, loff_t *ppos)
568db2e6bd4SJohannes Berg {
569db2e6bd4SJohannes Berg 	struct ieee80211_local *local = file->private_data;
570db2e6bd4SJohannes Berg 	unsigned long flags;
571db2e6bd4SJohannes Berg 	char buf[IEEE80211_MAX_QUEUES * 20];
572db2e6bd4SJohannes Berg 	int q, res = 0;
573db2e6bd4SJohannes Berg 
574db2e6bd4SJohannes Berg 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
575db2e6bd4SJohannes Berg 	for (q = 0; q < local->hw.queues; q++)
576db2e6bd4SJohannes Berg 		res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
577db2e6bd4SJohannes Berg 				local->queue_stop_reasons[q],
5783b8d81e0SJohannes Berg 				skb_queue_len(&local->pending[q]));
579db2e6bd4SJohannes Berg 	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
580db2e6bd4SJohannes Berg 
581db2e6bd4SJohannes Berg 	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
582db2e6bd4SJohannes Berg }
583db2e6bd4SJohannes Berg 
584279daf64SBen Greear DEBUGFS_READONLY_FILE_OPS(hwflags);
585279daf64SBen Greear DEBUGFS_READONLY_FILE_OPS(queues);
5864a5eccaaSBen Greear DEBUGFS_READONLY_FILE_OPS(misc);
587db2e6bd4SJohannes Berg 
588e9f207f0SJiri Benc /* statistics stuff */
589e9f207f0SJiri Benc 
format_devstat_counter(struct ieee80211_local * local,char __user * userbuf,size_t count,loff_t * ppos,int (* printvalue)(struct ieee80211_low_level_stats * stats,char * buf,int buflen))590e9f207f0SJiri Benc static ssize_t format_devstat_counter(struct ieee80211_local *local,
591e9f207f0SJiri Benc 	char __user *userbuf,
592e9f207f0SJiri Benc 	size_t count, loff_t *ppos,
593e9f207f0SJiri Benc 	int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf,
594e9f207f0SJiri Benc 			  int buflen))
595e9f207f0SJiri Benc {
596e9f207f0SJiri Benc 	struct ieee80211_low_level_stats stats;
597e9f207f0SJiri Benc 	char buf[20];
598e9f207f0SJiri Benc 	int res;
599e9f207f0SJiri Benc 
600629ebb85SJohannes Berg 	wiphy_lock(local->hw.wiphy);
60124487981SJohannes Berg 	res = drv_get_stats(local, &stats);
602629ebb85SJohannes Berg 	wiphy_unlock(local->hw.wiphy);
60324487981SJohannes Berg 	if (res)
60424487981SJohannes Berg 		return res;
605e9f207f0SJiri Benc 	res = printvalue(&stats, buf, sizeof(buf));
606e9f207f0SJiri Benc 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
607e9f207f0SJiri Benc }
608e9f207f0SJiri Benc 
609e9f207f0SJiri Benc #define DEBUGFS_DEVSTATS_FILE(name)					\
610e9f207f0SJiri Benc static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
611e9f207f0SJiri Benc 				 char *buf, int buflen)			\
612e9f207f0SJiri Benc {									\
613e9f207f0SJiri Benc 	return scnprintf(buf, buflen, "%u\n", stats->name);		\
614e9f207f0SJiri Benc }									\
615e9f207f0SJiri Benc static ssize_t stats_ ##name## _read(struct file *file,			\
616e9f207f0SJiri Benc 				     char __user *userbuf,		\
617e9f207f0SJiri Benc 				     size_t count, loff_t *ppos)	\
618e9f207f0SJiri Benc {									\
619e9f207f0SJiri Benc 	return format_devstat_counter(file->private_data,		\
620e9f207f0SJiri Benc 				      userbuf,				\
621e9f207f0SJiri Benc 				      count,				\
622e9f207f0SJiri Benc 				      ppos,				\
623e9f207f0SJiri Benc 				      print_devstats_##name);		\
624e9f207f0SJiri Benc }									\
625e9f207f0SJiri Benc 									\
626e9f207f0SJiri Benc static const struct file_operations stats_ ##name## _ops = {		\
627e9f207f0SJiri Benc 	.read = stats_ ##name## _read,					\
628234e3405SStephen Boyd 	.open = simple_open,						\
6292b18ab36SArnd Bergmann 	.llseek = generic_file_llseek,					\
630e9f207f0SJiri Benc };
631e9f207f0SJiri Benc 
632453a2a82SJohannes Berg #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
633f1160434SJohannes Berg #define DEBUGFS_STATS_ADD(name)					\
634f1160434SJohannes Berg 	debugfs_create_u32(#name, 0400, statsd, &local->name);
635453a2a82SJohannes Berg #endif
6362826bcd8SFelix Fietkau #define DEBUGFS_DEVSTATS_ADD(name)					\
6377bcfaf2fSJohannes Berg 	debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
638e9f207f0SJiri Benc 
639e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
640e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
641e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
642e9f207f0SJiri Benc DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
643e9f207f0SJiri Benc 
debugfs_hw_add(struct ieee80211_local * local)644e9f207f0SJiri Benc void debugfs_hw_add(struct ieee80211_local *local)
645e9f207f0SJiri Benc {
646e9f207f0SJiri Benc 	struct dentry *phyd = local->hw.wiphy->debugfsdir;
647e9f207f0SJiri Benc 	struct dentry *statsd;
648e9f207f0SJiri Benc 
649e9f207f0SJiri Benc 	if (!phyd)
650e9f207f0SJiri Benc 		return;
651e9f207f0SJiri Benc 
652e9f207f0SJiri Benc 	local->debugfs.keys = debugfs_create_dir("keys", phyd);
653e9f207f0SJiri Benc 
654e9f207f0SJiri Benc 	DEBUGFS_ADD(total_ps_buffered);
655e9f207f0SJiri Benc 	DEBUGFS_ADD(wep_iv);
656bddb2afcSJohannes Berg 	DEBUGFS_ADD(rate_ctrl_alg);
657db2e6bd4SJohannes Berg 	DEBUGFS_ADD(queues);
6584a5eccaaSBen Greear 	DEBUGFS_ADD(misc);
6592ad4814fSJohannes Berg #ifdef CONFIG_PM
660827b1fb4SJohannes Berg 	DEBUGFS_ADD_MODE(reset, 0200);
6612ad4814fSJohannes Berg #endif
662279daf64SBen Greear 	DEBUGFS_ADD(hwflags);
66383bdf2a1SBen Greear 	DEBUGFS_ADD(user_power);
66483bdf2a1SBen Greear 	DEBUGFS_ADD(power);
665c90142a5SThomas Pedersen 	DEBUGFS_ADD(hw_conf);
666276d9e82SJulius Niedworok 	DEBUGFS_ADD_MODE(force_tx_status, 0600);
667e908435eSLorenzo Bianconi 	DEBUGFS_ADD_MODE(aql_enable, 0600);
6683db2c560SFelix Fietkau 	DEBUGFS_ADD(aql_pending);
6699399b86cSMichal Kazior 	DEBUGFS_ADD_MODE(aqm, 0600);
670e9f207f0SJiri Benc 
671e322c07fSLorenzo Bianconi 	DEBUGFS_ADD_MODE(airtime_flags, 0600);
672b4809e94SToke Høiland-Jørgensen 
6733ace10f5SKan Yan 	DEBUGFS_ADD(aql_txq_limit);
6743ace10f5SKan Yan 	debugfs_create_u32("aql_threshold", 0600,
6753ace10f5SKan Yan 			   phyd, &local->aql_threshold);
6763ace10f5SKan Yan 
677e9f207f0SJiri Benc 	statsd = debugfs_create_dir("statistics", phyd);
678e9f207f0SJiri Benc 
679c206ca67SJohannes Berg #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
680f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount);
681f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount);
682f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11FailedCount);
683f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11RetryCount);
684f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11MultipleRetryCount);
685f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11FrameDuplicateCount);
686f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11ReceivedFragmentCount);
687f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11MulticastReceivedFrameCount);
688f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(dot11TransmittedFrameCount);
689f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop);
690f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_queued);
691f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
692f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
693f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
694f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_drop);
695f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_queued);
696f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
697f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
698f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_expand_skb_head);
699f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
700f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag);
701f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(rx_handlers_fragments);
702f1160434SJohannes Berg 	DEBUGFS_STATS_ADD(tx_status_drop);
703e9f207f0SJiri Benc #endif
7042826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
7052826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
7062826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
7072826bcd8SFelix Fietkau 	DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
708e9f207f0SJiri Benc }
709