Root/
1 | |
2 | /* |
3 | * mac80211 debugfs for wireless PHYs |
4 | * |
5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
6 | * |
7 | * GPLv2 |
8 | * |
9 | */ |
10 | |
11 | #include <linux/debugfs.h> |
12 | #include <linux/rtnetlink.h> |
13 | #include "ieee80211_i.h" |
14 | #include "driver-ops.h" |
15 | #include "rate.h" |
16 | #include "debugfs.h" |
17 | |
18 | int mac80211_open_file_generic(struct inode *inode, struct file *file) |
19 | { |
20 | file->private_data = inode->i_private; |
21 | return 0; |
22 | } |
23 | |
24 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ |
25 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ |
26 | size_t count, loff_t *ppos) \ |
27 | { \ |
28 | struct ieee80211_local *local = file->private_data; \ |
29 | char buf[buflen]; \ |
30 | int res; \ |
31 | \ |
32 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ |
33 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ |
34 | } \ |
35 | \ |
36 | static const struct file_operations name## _ops = { \ |
37 | .read = name## _read, \ |
38 | .open = mac80211_open_file_generic, \ |
39 | }; |
40 | |
41 | #define DEBUGFS_ADD(name) \ |
42 | debugfs_create_file(#name, 0400, phyd, local, &name## _ops); |
43 | |
44 | #define DEBUGFS_ADD_MODE(name, mode) \ |
45 | debugfs_create_file(#name, mode, phyd, local, &name## _ops); |
46 | |
47 | |
48 | DEBUGFS_READONLY_FILE(frequency, 20, "%d", |
49 | local->hw.conf.channel->center_freq); |
50 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", |
51 | local->total_ps_buffered); |
52 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", |
53 | local->wep_iv & 0xffffff); |
54 | DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", |
55 | local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); |
56 | |
57 | static ssize_t tsf_read(struct file *file, char __user *user_buf, |
58 | size_t count, loff_t *ppos) |
59 | { |
60 | struct ieee80211_local *local = file->private_data; |
61 | u64 tsf; |
62 | char buf[100]; |
63 | |
64 | tsf = drv_get_tsf(local); |
65 | |
66 | snprintf(buf, sizeof(buf), "0x%016llx\n", (unsigned long long) tsf); |
67 | |
68 | return simple_read_from_buffer(user_buf, count, ppos, buf, 19); |
69 | } |
70 | |
71 | static ssize_t tsf_write(struct file *file, |
72 | const char __user *user_buf, |
73 | size_t count, loff_t *ppos) |
74 | { |
75 | struct ieee80211_local *local = file->private_data; |
76 | unsigned long long tsf; |
77 | char buf[100]; |
78 | size_t len; |
79 | |
80 | len = min(count, sizeof(buf) - 1); |
81 | if (copy_from_user(buf, user_buf, len)) |
82 | return -EFAULT; |
83 | buf[len] = '\0'; |
84 | |
85 | if (strncmp(buf, "reset", 5) == 0) { |
86 | if (local->ops->reset_tsf) { |
87 | drv_reset_tsf(local); |
88 | printk(KERN_INFO "%s: debugfs reset TSF\n", wiphy_name(local->hw.wiphy)); |
89 | } |
90 | } else { |
91 | tsf = simple_strtoul(buf, NULL, 0); |
92 | if (local->ops->set_tsf) { |
93 | drv_set_tsf(local, tsf); |
94 | printk(KERN_INFO "%s: debugfs set TSF to %#018llx\n", wiphy_name(local->hw.wiphy), tsf); |
95 | } |
96 | } |
97 | |
98 | return count; |
99 | } |
100 | |
101 | static const struct file_operations tsf_ops = { |
102 | .read = tsf_read, |
103 | .write = tsf_write, |
104 | .open = mac80211_open_file_generic |
105 | }; |
106 | |
107 | static ssize_t reset_write(struct file *file, const char __user *user_buf, |
108 | size_t count, loff_t *ppos) |
109 | { |
110 | struct ieee80211_local *local = file->private_data; |
111 | |
112 | rtnl_lock(); |
113 | __ieee80211_suspend(&local->hw); |
114 | __ieee80211_resume(&local->hw); |
115 | rtnl_unlock(); |
116 | |
117 | return count; |
118 | } |
119 | |
120 | static const struct file_operations reset_ops = { |
121 | .write = reset_write, |
122 | .open = mac80211_open_file_generic, |
123 | }; |
124 | |
125 | static ssize_t noack_read(struct file *file, char __user *user_buf, |
126 | size_t count, loff_t *ppos) |
127 | { |
128 | struct ieee80211_local *local = file->private_data; |
129 | int res; |
130 | char buf[10]; |
131 | |
132 | res = scnprintf(buf, sizeof(buf), "%d\n", local->wifi_wme_noack_test); |
133 | |
134 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); |
135 | } |
136 | |
137 | static ssize_t noack_write(struct file *file, |
138 | const char __user *user_buf, |
139 | size_t count, loff_t *ppos) |
140 | { |
141 | struct ieee80211_local *local = file->private_data; |
142 | char buf[10]; |
143 | size_t len; |
144 | |
145 | len = min(count, sizeof(buf) - 1); |
146 | if (copy_from_user(buf, user_buf, len)) |
147 | return -EFAULT; |
148 | buf[len] = '\0'; |
149 | |
150 | local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0); |
151 | |
152 | return count; |
153 | } |
154 | |
155 | static const struct file_operations noack_ops = { |
156 | .read = noack_read, |
157 | .write = noack_write, |
158 | .open = mac80211_open_file_generic |
159 | }; |
160 | |
161 | static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, |
162 | size_t count, loff_t *ppos) |
163 | { |
164 | struct ieee80211_local *local = file->private_data; |
165 | int res; |
166 | char buf[10]; |
167 | |
168 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); |
169 | |
170 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); |
171 | } |
172 | |
173 | static ssize_t uapsd_queues_write(struct file *file, |
174 | const char __user *user_buf, |
175 | size_t count, loff_t *ppos) |
176 | { |
177 | struct ieee80211_local *local = file->private_data; |
178 | unsigned long val; |
179 | char buf[10]; |
180 | size_t len; |
181 | int ret; |
182 | |
183 | len = min(count, sizeof(buf) - 1); |
184 | if (copy_from_user(buf, user_buf, len)) |
185 | return -EFAULT; |
186 | buf[len] = '\0'; |
187 | |
188 | ret = strict_strtoul(buf, 0, &val); |
189 | |
190 | if (ret) |
191 | return -EINVAL; |
192 | |
193 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) |
194 | return -ERANGE; |
195 | |
196 | local->uapsd_queues = val; |
197 | |
198 | return count; |
199 | } |
200 | |
201 | static const struct file_operations uapsd_queues_ops = { |
202 | .read = uapsd_queues_read, |
203 | .write = uapsd_queues_write, |
204 | .open = mac80211_open_file_generic |
205 | }; |
206 | |
207 | static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, |
208 | size_t count, loff_t *ppos) |
209 | { |
210 | struct ieee80211_local *local = file->private_data; |
211 | int res; |
212 | char buf[10]; |
213 | |
214 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); |
215 | |
216 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); |
217 | } |
218 | |
219 | static ssize_t uapsd_max_sp_len_write(struct file *file, |
220 | const char __user *user_buf, |
221 | size_t count, loff_t *ppos) |
222 | { |
223 | struct ieee80211_local *local = file->private_data; |
224 | unsigned long val; |
225 | char buf[10]; |
226 | size_t len; |
227 | int ret; |
228 | |
229 | len = min(count, sizeof(buf) - 1); |
230 | if (copy_from_user(buf, user_buf, len)) |
231 | return -EFAULT; |
232 | buf[len] = '\0'; |
233 | |
234 | ret = strict_strtoul(buf, 0, &val); |
235 | |
236 | if (ret) |
237 | return -EINVAL; |
238 | |
239 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) |
240 | return -ERANGE; |
241 | |
242 | local->uapsd_max_sp_len = val; |
243 | |
244 | return count; |
245 | } |
246 | |
247 | static const struct file_operations uapsd_max_sp_len_ops = { |
248 | .read = uapsd_max_sp_len_read, |
249 | .write = uapsd_max_sp_len_write, |
250 | .open = mac80211_open_file_generic |
251 | }; |
252 | |
253 | static ssize_t channel_type_read(struct file *file, char __user *user_buf, |
254 | size_t count, loff_t *ppos) |
255 | { |
256 | struct ieee80211_local *local = file->private_data; |
257 | const char *buf; |
258 | |
259 | switch (local->hw.conf.channel_type) { |
260 | case NL80211_CHAN_NO_HT: |
261 | buf = "no ht\n"; |
262 | break; |
263 | case NL80211_CHAN_HT20: |
264 | buf = "ht20\n"; |
265 | break; |
266 | case NL80211_CHAN_HT40MINUS: |
267 | buf = "ht40-\n"; |
268 | break; |
269 | case NL80211_CHAN_HT40PLUS: |
270 | buf = "ht40+\n"; |
271 | break; |
272 | default: |
273 | buf = "???"; |
274 | break; |
275 | } |
276 | |
277 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); |
278 | } |
279 | |
280 | static const struct file_operations channel_type_ops = { |
281 | .read = channel_type_read, |
282 | .open = mac80211_open_file_generic |
283 | }; |
284 | |
285 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
286 | size_t count, loff_t *ppos) |
287 | { |
288 | struct ieee80211_local *local = file->private_data; |
289 | unsigned long flags; |
290 | char buf[IEEE80211_MAX_QUEUES * 20]; |
291 | int q, res = 0; |
292 | |
293 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
294 | for (q = 0; q < local->hw.queues; q++) |
295 | res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q, |
296 | local->queue_stop_reasons[q], |
297 | skb_queue_len(&local->pending[q])); |
298 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
299 | |
300 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); |
301 | } |
302 | |
303 | static const struct file_operations queues_ops = { |
304 | .read = queues_read, |
305 | .open = mac80211_open_file_generic |
306 | }; |
307 | |
308 | /* statistics stuff */ |
309 | |
310 | static ssize_t format_devstat_counter(struct ieee80211_local *local, |
311 | char __user *userbuf, |
312 | size_t count, loff_t *ppos, |
313 | int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf, |
314 | int buflen)) |
315 | { |
316 | struct ieee80211_low_level_stats stats; |
317 | char buf[20]; |
318 | int res; |
319 | |
320 | rtnl_lock(); |
321 | res = drv_get_stats(local, &stats); |
322 | rtnl_unlock(); |
323 | if (res) |
324 | return res; |
325 | res = printvalue(&stats, buf, sizeof(buf)); |
326 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
327 | } |
328 | |
329 | #define DEBUGFS_DEVSTATS_FILE(name) \ |
330 | static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\ |
331 | char *buf, int buflen) \ |
332 | { \ |
333 | return scnprintf(buf, buflen, "%u\n", stats->name); \ |
334 | } \ |
335 | static ssize_t stats_ ##name## _read(struct file *file, \ |
336 | char __user *userbuf, \ |
337 | size_t count, loff_t *ppos) \ |
338 | { \ |
339 | return format_devstat_counter(file->private_data, \ |
340 | userbuf, \ |
341 | count, \ |
342 | ppos, \ |
343 | print_devstats_##name); \ |
344 | } \ |
345 | \ |
346 | static const struct file_operations stats_ ##name## _ops = { \ |
347 | .read = stats_ ##name## _read, \ |
348 | .open = mac80211_open_file_generic, \ |
349 | }; |
350 | |
351 | #define DEBUGFS_STATS_ADD(name, field) \ |
352 | debugfs_create_u32(#name, 0400, statsd, (u32 *) &field); |
353 | #define DEBUGFS_DEVSTATS_ADD(name) \ |
354 | debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops); |
355 | |
356 | DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); |
357 | DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount); |
358 | DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount); |
359 | DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount); |
360 | |
361 | void debugfs_hw_add(struct ieee80211_local *local) |
362 | { |
363 | struct dentry *phyd = local->hw.wiphy->debugfsdir; |
364 | struct dentry *statsd; |
365 | |
366 | if (!phyd) |
367 | return; |
368 | |
369 | local->debugfs.stations = debugfs_create_dir("stations", phyd); |
370 | local->debugfs.keys = debugfs_create_dir("keys", phyd); |
371 | |
372 | DEBUGFS_ADD(frequency); |
373 | DEBUGFS_ADD(total_ps_buffered); |
374 | DEBUGFS_ADD(wep_iv); |
375 | DEBUGFS_ADD(tsf); |
376 | DEBUGFS_ADD(queues); |
377 | DEBUGFS_ADD_MODE(reset, 0200); |
378 | DEBUGFS_ADD(noack); |
379 | DEBUGFS_ADD(uapsd_queues); |
380 | DEBUGFS_ADD(uapsd_max_sp_len); |
381 | DEBUGFS_ADD(channel_type); |
382 | |
383 | statsd = debugfs_create_dir("statistics", phyd); |
384 | |
385 | /* if the dir failed, don't put all the other things into the root! */ |
386 | if (!statsd) |
387 | return; |
388 | |
389 | DEBUGFS_STATS_ADD(transmitted_fragment_count, |
390 | local->dot11TransmittedFragmentCount); |
391 | DEBUGFS_STATS_ADD(multicast_transmitted_frame_count, |
392 | local->dot11MulticastTransmittedFrameCount); |
393 | DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount); |
394 | DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount); |
395 | DEBUGFS_STATS_ADD(multiple_retry_count, |
396 | local->dot11MultipleRetryCount); |
397 | DEBUGFS_STATS_ADD(frame_duplicate_count, |
398 | local->dot11FrameDuplicateCount); |
399 | DEBUGFS_STATS_ADD(received_fragment_count, |
400 | local->dot11ReceivedFragmentCount); |
401 | DEBUGFS_STATS_ADD(multicast_received_frame_count, |
402 | local->dot11MulticastReceivedFrameCount); |
403 | DEBUGFS_STATS_ADD(transmitted_frame_count, |
404 | local->dot11TransmittedFrameCount); |
405 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
406 | DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop); |
407 | DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued); |
408 | DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted, |
409 | local->tx_handlers_drop_unencrypted); |
410 | DEBUGFS_STATS_ADD(tx_handlers_drop_fragment, |
411 | local->tx_handlers_drop_fragment); |
412 | DEBUGFS_STATS_ADD(tx_handlers_drop_wep, |
413 | local->tx_handlers_drop_wep); |
414 | DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc, |
415 | local->tx_handlers_drop_not_assoc); |
416 | DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port, |
417 | local->tx_handlers_drop_unauth_port); |
418 | DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop); |
419 | DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued); |
420 | DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc, |
421 | local->rx_handlers_drop_nullfunc); |
422 | DEBUGFS_STATS_ADD(rx_handlers_drop_defrag, |
423 | local->rx_handlers_drop_defrag); |
424 | DEBUGFS_STATS_ADD(rx_handlers_drop_short, |
425 | local->rx_handlers_drop_short); |
426 | DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan, |
427 | local->rx_handlers_drop_passive_scan); |
428 | DEBUGFS_STATS_ADD(tx_expand_skb_head, |
429 | local->tx_expand_skb_head); |
430 | DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, |
431 | local->tx_expand_skb_head_cloned); |
432 | DEBUGFS_STATS_ADD(rx_expand_skb_head, |
433 | local->rx_expand_skb_head); |
434 | DEBUGFS_STATS_ADD(rx_expand_skb_head2, |
435 | local->rx_expand_skb_head2); |
436 | DEBUGFS_STATS_ADD(rx_handlers_fragments, |
437 | local->rx_handlers_fragments); |
438 | DEBUGFS_STATS_ADD(tx_status_drop, |
439 | local->tx_status_drop); |
440 | #endif |
441 | DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount); |
442 | DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); |
443 | DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); |
444 | DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); |
445 | } |
446 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9