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 #define DEBUGFS_FORMAT_BUFFER_SIZE 100 19 20 #define TX_LATENCY_BIN_DELIMTER_C ',' 21 #define TX_LATENCY_BIN_DELIMTER_S "," 22 #define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n" 23 #define TX_LATENCY_DISABLED "disable\n" 24 25 26 /* 27 * Display if Tx latency statistics & bins are enabled/disabled 28 */ 29 static ssize_t sta_tx_latency_stat_read(struct file *file, 30 char __user *userbuf, 31 size_t count, loff_t *ppos) 32 { 33 struct ieee80211_local *local = file->private_data; 34 struct ieee80211_tx_latency_bin_ranges *tx_latency; 35 char *buf; 36 int bufsz, i, ret; 37 int pos = 0; 38 39 rcu_read_lock(); 40 41 tx_latency = rcu_dereference(local->tx_latency); 42 43 if (tx_latency && tx_latency->n_ranges) { 44 bufsz = tx_latency->n_ranges * 15; 45 buf = kzalloc(bufsz, GFP_ATOMIC); 46 if (!buf) 47 goto err; 48 49 for (i = 0; i < tx_latency->n_ranges; i++) 50 pos += scnprintf(buf + pos, bufsz - pos, "%d,", 51 tx_latency->ranges[i]); 52 pos += scnprintf(buf + pos, bufsz - pos, "\n"); 53 } else if (tx_latency) { 54 bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1; 55 buf = kzalloc(bufsz, GFP_ATOMIC); 56 if (!buf) 57 goto err; 58 59 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", 60 TX_LATENCY_BINS_DISABLED); 61 } else { 62 bufsz = sizeof(TX_LATENCY_DISABLED) + 1; 63 buf = kzalloc(bufsz, GFP_ATOMIC); 64 if (!buf) 65 goto err; 66 67 pos += scnprintf(buf + pos, bufsz - pos, "%s\n", 68 TX_LATENCY_DISABLED); 69 } 70 71 rcu_read_unlock(); 72 73 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 74 kfree(buf); 75 76 return ret; 77 err: 78 rcu_read_unlock(); 79 return -ENOMEM; 80 } 81 82 /* 83 * Receive input from user regarding Tx latency statistics 84 * The input should indicate if Tx latency statistics and bins are 85 * enabled/disabled. 86 * If bins are enabled input should indicate the amount of different bins and 87 * their ranges. Each bin will count how many Tx frames transmitted within the 88 * appropriate latency. 89 * Legal input is: 90 * a) "enable(bins disabled)" - to enable only general statistics 91 * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are 92 * numbers and a < b < c < d.. < z 93 * c) "disable" - disable all statistics 94 * NOTE: must configure Tx latency statistics bins before stations connected. 95 */ 96 97 static ssize_t sta_tx_latency_stat_write(struct file *file, 98 const char __user *userbuf, 99 size_t count, loff_t *ppos) 100 { 101 struct ieee80211_local *local = file->private_data; 102 char buf[128] = {}; 103 char *bins = buf; 104 char *token; 105 int buf_size, i, alloc_size; 106 int prev_bin = 0; 107 int n_ranges = 0; 108 int ret = count; 109 struct ieee80211_tx_latency_bin_ranges *tx_latency; 110 111 if (sizeof(buf) <= count) 112 return -EINVAL; 113 buf_size = count; 114 if (copy_from_user(buf, userbuf, buf_size)) 115 return -EFAULT; 116 117 mutex_lock(&local->sta_mtx); 118 119 /* cannot change config once we have stations */ 120 if (local->num_sta) 121 goto unlock; 122 123 tx_latency = 124 rcu_dereference_protected(local->tx_latency, 125 lockdep_is_held(&local->sta_mtx)); 126 127 /* disable Tx statistics */ 128 if (!strcmp(buf, TX_LATENCY_DISABLED)) { 129 if (!tx_latency) 130 goto unlock; 131 rcu_assign_pointer(local->tx_latency, NULL); 132 synchronize_rcu(); 133 kfree(tx_latency); 134 goto unlock; 135 } 136 137 /* Tx latency already enabled */ 138 if (tx_latency) 139 goto unlock; 140 141 if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) { 142 /* check how many bins and between what ranges user requested */ 143 token = buf; 144 while (*token != '\0') { 145 if (*token == TX_LATENCY_BIN_DELIMTER_C) 146 n_ranges++; 147 token++; 148 } 149 n_ranges++; 150 } 151 152 alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) + 153 n_ranges * sizeof(u32); 154 tx_latency = kzalloc(alloc_size, GFP_ATOMIC); 155 if (!tx_latency) { 156 ret = -ENOMEM; 157 goto unlock; 158 } 159 tx_latency->n_ranges = n_ranges; 160 for (i = 0; i < n_ranges; i++) { /* setting bin ranges */ 161 token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S); 162 sscanf(token, "%d", &tx_latency->ranges[i]); 163 /* bins values should be in ascending order */ 164 if (prev_bin >= tx_latency->ranges[i]) { 165 ret = -EINVAL; 166 kfree(tx_latency); 167 goto unlock; 168 } 169 prev_bin = tx_latency->ranges[i]; 170 } 171 rcu_assign_pointer(local->tx_latency, tx_latency); 172 173 unlock: 174 mutex_unlock(&local->sta_mtx); 175 176 return ret; 177 } 178 179 static const struct file_operations stats_tx_latency_ops = { 180 .write = sta_tx_latency_stat_write, 181 .read = sta_tx_latency_stat_read, 182 .open = simple_open, 183 .llseek = generic_file_llseek, 184 }; 185 186 int mac80211_format_buffer(char __user *userbuf, size_t count, 187 loff_t *ppos, char *fmt, ...) 188 { 189 va_list args; 190 char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; 191 int res; 192 193 va_start(args, fmt); 194 res = vscnprintf(buf, sizeof(buf), fmt, args); 195 va_end(args); 196 197 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 198 } 199 200 #define DEBUGFS_READONLY_FILE_FN(name, fmt, value...) \ 201 static ssize_t name## _read(struct file *file, char __user *userbuf, \ 202 size_t count, loff_t *ppos) \ 203 { \ 204 struct ieee80211_local *local = file->private_data; \ 205 \ 206 return mac80211_format_buffer(userbuf, count, ppos, \ 207 fmt "\n", ##value); \ 208 } 209 210 #define DEBUGFS_READONLY_FILE_OPS(name) \ 211 static const struct file_operations name## _ops = { \ 212 .read = name## _read, \ 213 .open = simple_open, \ 214 .llseek = generic_file_llseek, \ 215 }; 216 217 #define DEBUGFS_READONLY_FILE(name, fmt, value...) \ 218 DEBUGFS_READONLY_FILE_FN(name, fmt, value) \ 219 DEBUGFS_READONLY_FILE_OPS(name) 220 221 #define DEBUGFS_ADD(name) \ 222 debugfs_create_file(#name, 0400, phyd, local, &name## _ops); 223 224 #define DEBUGFS_ADD_MODE(name, mode) \ 225 debugfs_create_file(#name, mode, phyd, local, &name## _ops); 226 227 228 DEBUGFS_READONLY_FILE(user_power, "%d", 229 local->user_power_level); 230 DEBUGFS_READONLY_FILE(power, "%d", 231 local->hw.conf.power_level); 232 DEBUGFS_READONLY_FILE(total_ps_buffered, "%d", 233 local->total_ps_buffered); 234 DEBUGFS_READONLY_FILE(wep_iv, "%#08x", 235 local->wep_iv & 0xffffff); 236 DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", 237 local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); 238 239 #ifdef CONFIG_PM 240 static ssize_t reset_write(struct file *file, const char __user *user_buf, 241 size_t count, loff_t *ppos) 242 { 243 struct ieee80211_local *local = file->private_data; 244 245 rtnl_lock(); 246 __ieee80211_suspend(&local->hw, NULL); 247 __ieee80211_resume(&local->hw); 248 rtnl_unlock(); 249 250 return count; 251 } 252 253 static const struct file_operations reset_ops = { 254 .write = reset_write, 255 .open = simple_open, 256 .llseek = noop_llseek, 257 }; 258 #endif 259 260 static ssize_t hwflags_read(struct file *file, char __user *user_buf, 261 size_t count, loff_t *ppos) 262 { 263 struct ieee80211_local *local = file->private_data; 264 int mxln = 500; 265 ssize_t rv; 266 char *buf = kzalloc(mxln, GFP_KERNEL); 267 int sf = 0; /* how many written so far */ 268 269 if (!buf) 270 return 0; 271 272 sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags); 273 if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) 274 sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n"); 275 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) 276 sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n"); 277 if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) 278 sf += scnprintf(buf + sf, mxln - sf, 279 "HOST_BCAST_PS_BUFFERING\n"); 280 if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE) 281 sf += scnprintf(buf + sf, mxln - sf, 282 "2GHZ_SHORT_SLOT_INCAPABLE\n"); 283 if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE) 284 sf += scnprintf(buf + sf, mxln - sf, 285 "2GHZ_SHORT_PREAMBLE_INCAPABLE\n"); 286 if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) 287 sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n"); 288 if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) 289 sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n"); 290 if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC) 291 sf += scnprintf(buf + sf, mxln - sf, 292 "NEED_DTIM_BEFORE_ASSOC\n"); 293 if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT) 294 sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n"); 295 if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) 296 sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n"); 297 if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS) 298 sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n"); 299 if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) 300 sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n"); 301 if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) 302 sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n"); 303 if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE) 304 sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n"); 305 if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS) 306 sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n"); 307 if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) 308 sf += scnprintf(buf + sf, mxln - sf, 309 "SUPPORTS_DYNAMIC_SMPS\n"); 310 if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) 311 sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n"); 312 if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) 313 sf += scnprintf(buf + sf, mxln - sf, 314 "REPORTS_TX_ACK_STATUS\n"); 315 if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) 316 sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n"); 317 if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK) 318 sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n"); 319 if (local->hw.flags & IEEE80211_HW_AP_LINK_PS) 320 sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n"); 321 if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW) 322 sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n"); 323 324 rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 325 kfree(buf); 326 return rv; 327 } 328 329 static ssize_t queues_read(struct file *file, char __user *user_buf, 330 size_t count, loff_t *ppos) 331 { 332 struct ieee80211_local *local = file->private_data; 333 unsigned long flags; 334 char buf[IEEE80211_MAX_QUEUES * 20]; 335 int q, res = 0; 336 337 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 338 for (q = 0; q < local->hw.queues; q++) 339 res += sprintf(buf + res, "%02d: %#.8lx/%d\n", q, 340 local->queue_stop_reasons[q], 341 skb_queue_len(&local->pending[q])); 342 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 343 344 return simple_read_from_buffer(user_buf, count, ppos, buf, res); 345 } 346 347 DEBUGFS_READONLY_FILE_OPS(hwflags); 348 DEBUGFS_READONLY_FILE_OPS(queues); 349 350 /* statistics stuff */ 351 352 static ssize_t format_devstat_counter(struct ieee80211_local *local, 353 char __user *userbuf, 354 size_t count, loff_t *ppos, 355 int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf, 356 int buflen)) 357 { 358 struct ieee80211_low_level_stats stats; 359 char buf[20]; 360 int res; 361 362 rtnl_lock(); 363 res = drv_get_stats(local, &stats); 364 rtnl_unlock(); 365 if (res) 366 return res; 367 res = printvalue(&stats, buf, sizeof(buf)); 368 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 369 } 370 371 #define DEBUGFS_DEVSTATS_FILE(name) \ 372 static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\ 373 char *buf, int buflen) \ 374 { \ 375 return scnprintf(buf, buflen, "%u\n", stats->name); \ 376 } \ 377 static ssize_t stats_ ##name## _read(struct file *file, \ 378 char __user *userbuf, \ 379 size_t count, loff_t *ppos) \ 380 { \ 381 return format_devstat_counter(file->private_data, \ 382 userbuf, \ 383 count, \ 384 ppos, \ 385 print_devstats_##name); \ 386 } \ 387 \ 388 static const struct file_operations stats_ ##name## _ops = { \ 389 .read = stats_ ##name## _read, \ 390 .open = simple_open, \ 391 .llseek = generic_file_llseek, \ 392 }; 393 394 #define DEBUGFS_STATS_ADD(name, field) \ 395 debugfs_create_u32(#name, 0400, statsd, (u32 *) &field); 396 #define DEBUGFS_DEVSTATS_ADD(name) \ 397 debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops); 398 399 DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount); 400 DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount); 401 DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount); 402 DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount); 403 404 void debugfs_hw_add(struct ieee80211_local *local) 405 { 406 struct dentry *phyd = local->hw.wiphy->debugfsdir; 407 struct dentry *statsd; 408 409 if (!phyd) 410 return; 411 412 local->debugfs.keys = debugfs_create_dir("keys", phyd); 413 414 DEBUGFS_ADD(total_ps_buffered); 415 DEBUGFS_ADD(wep_iv); 416 DEBUGFS_ADD(queues); 417 #ifdef CONFIG_PM 418 DEBUGFS_ADD_MODE(reset, 0200); 419 #endif 420 DEBUGFS_ADD(hwflags); 421 DEBUGFS_ADD(user_power); 422 DEBUGFS_ADD(power); 423 424 statsd = debugfs_create_dir("statistics", phyd); 425 426 /* if the dir failed, don't put all the other things into the root! */ 427 if (!statsd) 428 return; 429 430 DEBUGFS_STATS_ADD(transmitted_fragment_count, 431 local->dot11TransmittedFragmentCount); 432 DEBUGFS_STATS_ADD(multicast_transmitted_frame_count, 433 local->dot11MulticastTransmittedFrameCount); 434 DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount); 435 DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount); 436 DEBUGFS_STATS_ADD(multiple_retry_count, 437 local->dot11MultipleRetryCount); 438 DEBUGFS_STATS_ADD(frame_duplicate_count, 439 local->dot11FrameDuplicateCount); 440 DEBUGFS_STATS_ADD(received_fragment_count, 441 local->dot11ReceivedFragmentCount); 442 DEBUGFS_STATS_ADD(multicast_received_frame_count, 443 local->dot11MulticastReceivedFrameCount); 444 DEBUGFS_STATS_ADD(transmitted_frame_count, 445 local->dot11TransmittedFrameCount); 446 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS 447 DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop); 448 DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued); 449 DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted, 450 local->tx_handlers_drop_unencrypted); 451 DEBUGFS_STATS_ADD(tx_handlers_drop_fragment, 452 local->tx_handlers_drop_fragment); 453 DEBUGFS_STATS_ADD(tx_handlers_drop_wep, 454 local->tx_handlers_drop_wep); 455 DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc, 456 local->tx_handlers_drop_not_assoc); 457 DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port, 458 local->tx_handlers_drop_unauth_port); 459 DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop); 460 DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued); 461 DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc, 462 local->rx_handlers_drop_nullfunc); 463 DEBUGFS_STATS_ADD(rx_handlers_drop_defrag, 464 local->rx_handlers_drop_defrag); 465 DEBUGFS_STATS_ADD(rx_handlers_drop_short, 466 local->rx_handlers_drop_short); 467 DEBUGFS_STATS_ADD(tx_expand_skb_head, 468 local->tx_expand_skb_head); 469 DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, 470 local->tx_expand_skb_head_cloned); 471 DEBUGFS_STATS_ADD(rx_expand_skb_head, 472 local->rx_expand_skb_head); 473 DEBUGFS_STATS_ADD(rx_expand_skb_head2, 474 local->rx_expand_skb_head2); 475 DEBUGFS_STATS_ADD(rx_handlers_fragments, 476 local->rx_handlers_fragments); 477 DEBUGFS_STATS_ADD(tx_status_drop, 478 local->tx_status_drop); 479 #endif 480 DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount); 481 DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount); 482 DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount); 483 DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount); 484 485 DEBUGFS_DEVSTATS_ADD(tx_latency); 486 } 487