debugfs.c 10.1 KB
Newer Older
1

J
Jiri Benc 已提交
2 3 4 5
/*
 * mac80211 debugfs for wireless PHYs
 *
 * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
6
 * Copyright 2013-2014  Intel Mobile Communications GmbH
J
Jiri Benc 已提交
7 8 9 10 11 12 13 14
 *
 * GPLv2
 *
 */

#include <linux/debugfs.h>
#include <linux/rtnetlink.h>
#include "ieee80211_i.h"
15
#include "driver-ops.h"
J
Johannes Berg 已提交
16
#include "rate.h"
J
Jiri Benc 已提交
17 18
#include "debugfs.h"

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#define DEBUGFS_FORMAT_BUFFER_SIZE 100

int mac80211_format_buffer(char __user *userbuf, size_t count,
				  loff_t *ppos, char *fmt, ...)
{
	va_list args;
	char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
	int res;

	va_start(args, fmt);
	res = vscnprintf(buf, sizeof(buf), fmt, args);
	va_end(args);

	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}

B
Ben Greear 已提交
35
#define DEBUGFS_READONLY_FILE_FN(name, fmt, value...)			\
J
Jiri Benc 已提交
36 37 38 39 40
static ssize_t name## _read(struct file *file, char __user *userbuf,	\
			    size_t count, loff_t *ppos)			\
{									\
	struct ieee80211_local *local = file->private_data;		\
									\
41 42
	return mac80211_format_buffer(userbuf, count, ppos, 		\
				      fmt "\n", ##value);		\
B
Ben Greear 已提交
43 44 45
}

#define DEBUGFS_READONLY_FILE_OPS(name)			\
J
Jiri Benc 已提交
46 47
static const struct file_operations name## _ops = {			\
	.read = name## _read,						\
48
	.open = simple_open,						\
49
	.llseek = generic_file_llseek,					\
J
Jiri Benc 已提交
50 51
};

B
Ben Greear 已提交
52 53 54 55
#define DEBUGFS_READONLY_FILE(name, fmt, value...)		\
	DEBUGFS_READONLY_FILE_FN(name, fmt, value)		\
	DEBUGFS_READONLY_FILE_OPS(name)

J
Jiri Benc 已提交
56
#define DEBUGFS_ADD(name)						\
57
	debugfs_create_file(#name, 0400, phyd, local, &name## _ops);
J
Jiri Benc 已提交
58

59
#define DEBUGFS_ADD_MODE(name, mode)					\
60
	debugfs_create_file(#name, mode, phyd, local, &name## _ops);
J
Jiri Benc 已提交
61 62


B
Ben Greear 已提交
63 64 65 66
DEBUGFS_READONLY_FILE(user_power, "%d",
		      local->user_power_level);
DEBUGFS_READONLY_FILE(power, "%d",
		      local->hw.conf.power_level);
67
DEBUGFS_READONLY_FILE(total_ps_buffered, "%d",
J
Jiri Benc 已提交
68
		      local->total_ps_buffered);
69
DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
J
Jiri Benc 已提交
70
		      local->wep_iv & 0xffffff);
71
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
72
	local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
73

74
#ifdef CONFIG_PM
75 76 77 78 79 80
static ssize_t reset_write(struct file *file, const char __user *user_buf,
			   size_t count, loff_t *ppos)
{
	struct ieee80211_local *local = file->private_data;

	rtnl_lock();
81
	__ieee80211_suspend(&local->hw, NULL);
82 83 84 85 86 87 88 89
	__ieee80211_resume(&local->hw);
	rtnl_unlock();

	return count;
}

static const struct file_operations reset_ops = {
	.write = reset_write,
90
	.open = simple_open,
91
	.llseek = noop_llseek,
92
};
93
#endif
94

B
Ben Greear 已提交
95 96 97 98 99 100 101 102 103
static ssize_t hwflags_read(struct file *file, char __user *user_buf,
			    size_t count, loff_t *ppos)
{
	struct ieee80211_local *local = file->private_data;
	int mxln = 500;
	ssize_t rv;
	char *buf = kzalloc(mxln, GFP_KERNEL);
	int sf = 0; /* how many written so far */

104 105 106
	if (!buf)
		return 0;

E
Eliad Peller 已提交
107
	sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
B
Ben Greear 已提交
108
	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
E
Eliad Peller 已提交
109
		sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
B
Ben Greear 已提交
110
	if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
E
Eliad Peller 已提交
111
		sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
B
Ben Greear 已提交
112
	if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)
E
Eliad Peller 已提交
113 114
		sf += scnprintf(buf + sf, mxln - sf,
				"HOST_BCAST_PS_BUFFERING\n");
B
Ben Greear 已提交
115
	if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)
E
Eliad Peller 已提交
116 117
		sf += scnprintf(buf + sf, mxln - sf,
				"2GHZ_SHORT_SLOT_INCAPABLE\n");
B
Ben Greear 已提交
118
	if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)
E
Eliad Peller 已提交
119 120
		sf += scnprintf(buf + sf, mxln - sf,
				"2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
B
Ben Greear 已提交
121
	if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
E
Eliad Peller 已提交
122
		sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
B
Ben Greear 已提交
123
	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
E
Eliad Peller 已提交
124
		sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
125
	if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC)
E
Eliad Peller 已提交
126 127
		sf += scnprintf(buf + sf, mxln - sf,
				"NEED_DTIM_BEFORE_ASSOC\n");
B
Ben Greear 已提交
128
	if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)
E
Eliad Peller 已提交
129
		sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
B
Ben Greear 已提交
130
	if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
E
Eliad Peller 已提交
131
		sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
B
Ben Greear 已提交
132
	if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)
E
Eliad Peller 已提交
133
		sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
B
Ben Greear 已提交
134
	if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
E
Eliad Peller 已提交
135
		sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
B
Ben Greear 已提交
136
	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
E
Eliad Peller 已提交
137
		sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
B
Ben Greear 已提交
138
	if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
E
Eliad Peller 已提交
139
		sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
B
Ben Greear 已提交
140
	if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
E
Eliad Peller 已提交
141 142
		sf += scnprintf(buf + sf, mxln - sf,
				"REPORTS_TX_ACK_STATUS\n");
B
Ben Greear 已提交
143
	if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
E
Eliad Peller 已提交
144
		sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
B
Ben Greear 已提交
145
	if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)
E
Eliad Peller 已提交
146
		sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
B
Ben Greear 已提交
147
	if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
E
Eliad Peller 已提交
148
		sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
149
	if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)
E
Eliad Peller 已提交
150
		sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
B
Ben Greear 已提交
151 152 153 154 155

	rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
	kfree(buf);
	return rv;
}
156

J
Johannes Berg 已提交
157 158 159 160 161 162 163 164 165 166 167 168
static ssize_t queues_read(struct file *file, char __user *user_buf,
			   size_t count, loff_t *ppos)
{
	struct ieee80211_local *local = file->private_data;
	unsigned long flags;
	char buf[IEEE80211_MAX_QUEUES * 20];
	int q, res = 0;

	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
	for (q = 0; q < local->hw.queues; q++)
		res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q,
				local->queue_stop_reasons[q],
J
Johannes Berg 已提交
169
				skb_queue_len(&local->pending[q]));
J
Johannes Berg 已提交
170 171 172 173 174
	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);

	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
}

B
Ben Greear 已提交
175 176
DEBUGFS_READONLY_FILE_OPS(hwflags);
DEBUGFS_READONLY_FILE_OPS(queues);
J
Johannes Berg 已提交
177

J
Jiri Benc 已提交
178 179 180 181 182 183 184 185 186 187 188 189
/* statistics stuff */

static ssize_t 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))
{
	struct ieee80211_low_level_stats stats;
	char buf[20];
	int res;

190
	rtnl_lock();
191
	res = drv_get_stats(local, &stats);
J
Jiri Benc 已提交
192
	rtnl_unlock();
193 194 195
	if (res)
		return res;
	res = printvalue(&stats, buf, sizeof(buf));
J
Jiri Benc 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}

#define DEBUGFS_DEVSTATS_FILE(name)					\
static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
				 char *buf, int buflen)			\
{									\
	return scnprintf(buf, buflen, "%u\n", stats->name);		\
}									\
static ssize_t stats_ ##name## _read(struct file *file,			\
				     char __user *userbuf,		\
				     size_t count, loff_t *ppos)	\
{									\
	return format_devstat_counter(file->private_data,		\
				      userbuf,				\
				      count,				\
				      ppos,				\
				      print_devstats_##name);		\
}									\
									\
static const struct file_operations stats_ ##name## _ops = {		\
	.read = stats_ ##name## _read,					\
218
	.open = simple_open,						\
219
	.llseek = generic_file_llseek,					\
J
Jiri Benc 已提交
220 221
};

222 223 224
#define DEBUGFS_STATS_ADD(name, field)					\
	debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
#define DEBUGFS_DEVSTATS_ADD(name)					\
225
	debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
J
Jiri Benc 已提交
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243

DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);

void debugfs_hw_add(struct ieee80211_local *local)
{
	struct dentry *phyd = local->hw.wiphy->debugfsdir;
	struct dentry *statsd;

	if (!phyd)
		return;

	local->debugfs.keys = debugfs_create_dir("keys", phyd);

	DEBUGFS_ADD(total_ps_buffered);
	DEBUGFS_ADD(wep_iv);
J
Johannes Berg 已提交
244
	DEBUGFS_ADD(queues);
245
#ifdef CONFIG_PM
246
	DEBUGFS_ADD_MODE(reset, 0200);
247
#endif
B
Ben Greear 已提交
248
	DEBUGFS_ADD(hwflags);
B
Ben Greear 已提交
249 250
	DEBUGFS_ADD(user_power);
	DEBUGFS_ADD(power);
J
Jiri Benc 已提交
251 252 253 254 255 256 257

	statsd = debugfs_create_dir("statistics", phyd);

	/* if the dir failed, don't put all the other things into the root! */
	if (!statsd)
		return;

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
	DEBUGFS_STATS_ADD(transmitted_fragment_count,
		local->dot11TransmittedFragmentCount);
	DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
		local->dot11MulticastTransmittedFrameCount);
	DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
	DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
	DEBUGFS_STATS_ADD(multiple_retry_count,
		local->dot11MultipleRetryCount);
	DEBUGFS_STATS_ADD(frame_duplicate_count,
		local->dot11FrameDuplicateCount);
	DEBUGFS_STATS_ADD(received_fragment_count,
		local->dot11ReceivedFragmentCount);
	DEBUGFS_STATS_ADD(multicast_received_frame_count,
		local->dot11MulticastReceivedFrameCount);
	DEBUGFS_STATS_ADD(transmitted_frame_count,
		local->dot11TransmittedFrameCount);
J
Jiri Benc 已提交
274
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
	DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
	DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
	DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
		local->tx_handlers_drop_unencrypted);
	DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
		local->tx_handlers_drop_fragment);
	DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
		local->tx_handlers_drop_wep);
	DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
		local->tx_handlers_drop_not_assoc);
	DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
		local->tx_handlers_drop_unauth_port);
	DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
	DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
	DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
		local->rx_handlers_drop_nullfunc);
	DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
		local->rx_handlers_drop_defrag);
	DEBUGFS_STATS_ADD(rx_handlers_drop_short,
		local->rx_handlers_drop_short);
	DEBUGFS_STATS_ADD(tx_expand_skb_head,
		local->tx_expand_skb_head);
	DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
		local->tx_expand_skb_head_cloned);
	DEBUGFS_STATS_ADD(rx_expand_skb_head,
		local->rx_expand_skb_head);
	DEBUGFS_STATS_ADD(rx_expand_skb_head2,
		local->rx_expand_skb_head2);
	DEBUGFS_STATS_ADD(rx_handlers_fragments,
		local->rx_handlers_fragments);
	DEBUGFS_STATS_ADD(tx_status_drop,
		local->tx_status_drop);
J
Jiri Benc 已提交
307
#endif
308 309 310 311
	DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
	DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
	DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
	DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
J
Jiri Benc 已提交
312
}