iwl-debugfs.c revision fcf89d05404dafcde581d44dfa89bd8c8def27f9
1/****************************************************************************** 2 * 3 * GPL LICENSE SUMMARY 4 * 5 * Copyright(c) 2008 - 2009 Intel Corporation. All rights reserved. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of version 2 of the GNU General Public License as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 19 * USA 20 * 21 * The full GNU General Public License is included in this distribution 22 * in the file called LICENSE.GPL. 23 * 24 * Contact Information: 25 * Intel Linux Wireless <ilw@linux.intel.com> 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27 *****************************************************************************/ 28 29#include <linux/kernel.h> 30#include <linux/module.h> 31#include <linux/debugfs.h> 32 33#include <linux/ieee80211.h> 34#include <net/mac80211.h> 35 36 37#include "iwl-dev.h" 38#include "iwl-debug.h" 39#include "iwl-core.h" 40#include "iwl-io.h" 41 42 43/* create and remove of files */ 44#define DEBUGFS_ADD_DIR(name, parent) do { \ 45 dbgfs->dir_##name = debugfs_create_dir(#name, parent); \ 46 if (!(dbgfs->dir_##name)) \ 47 goto err; \ 48} while (0) 49 50#define DEBUGFS_ADD_FILE(name, parent) do { \ 51 dbgfs->dbgfs_##parent##_files.file_##name = \ 52 debugfs_create_file(#name, S_IWUSR | S_IRUSR, \ 53 dbgfs->dir_##parent, priv, \ 54 &iwl_dbgfs_##name##_ops); \ 55 if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \ 56 goto err; \ 57} while (0) 58 59#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ 60 dbgfs->dbgfs_##parent##_files.file_##name = \ 61 debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ 62 dbgfs->dir_##parent, ptr); \ 63 if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ 64 || !dbgfs->dbgfs_##parent##_files.file_##name) \ 65 goto err; \ 66} while (0) 67 68#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ 69 dbgfs->dbgfs_##parent##_files.file_##name = \ 70 debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \ 71 if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ 72 || !dbgfs->dbgfs_##parent##_files.file_##name) \ 73 goto err; \ 74} while (0) 75 76#define DEBUGFS_REMOVE(name) do { \ 77 debugfs_remove(name); \ 78 name = NULL; \ 79} while (0); 80 81/* file operation */ 82#define DEBUGFS_READ_FUNC(name) \ 83static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ 84 char __user *user_buf, \ 85 size_t count, loff_t *ppos); 86 87#define DEBUGFS_WRITE_FUNC(name) \ 88static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ 89 const char __user *user_buf, \ 90 size_t count, loff_t *ppos); 91 92 93static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) 94{ 95 file->private_data = inode->i_private; 96 return 0; 97} 98 99#define DEBUGFS_READ_FILE_OPS(name) \ 100 DEBUGFS_READ_FUNC(name); \ 101static const struct file_operations iwl_dbgfs_##name##_ops = { \ 102 .read = iwl_dbgfs_##name##_read, \ 103 .open = iwl_dbgfs_open_file_generic, \ 104}; 105 106#define DEBUGFS_WRITE_FILE_OPS(name) \ 107 DEBUGFS_WRITE_FUNC(name); \ 108static const struct file_operations iwl_dbgfs_##name##_ops = { \ 109 .write = iwl_dbgfs_##name##_write, \ 110 .open = iwl_dbgfs_open_file_generic, \ 111}; 112 113 114#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ 115 DEBUGFS_READ_FUNC(name); \ 116 DEBUGFS_WRITE_FUNC(name); \ 117static const struct file_operations iwl_dbgfs_##name##_ops = { \ 118 .write = iwl_dbgfs_##name##_write, \ 119 .read = iwl_dbgfs_##name##_read, \ 120 .open = iwl_dbgfs_open_file_generic, \ 121}; 122 123 124static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, 125 char __user *user_buf, 126 size_t count, loff_t *ppos) { 127 128 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 129 char buf[256]; 130 int pos = 0; 131 const size_t bufsz = sizeof(buf); 132 133 pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", 134 priv->tx_stats[0].cnt); 135 pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", 136 priv->tx_stats[1].cnt); 137 pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", 138 priv->tx_stats[2].cnt); 139 140 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 141} 142 143static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, 144 char __user *user_buf, 145 size_t count, loff_t *ppos) { 146 147 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 148 char buf[256]; 149 int pos = 0; 150 const size_t bufsz = sizeof(buf); 151 152 pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n", 153 priv->rx_stats[0].cnt); 154 pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n", 155 priv->rx_stats[1].cnt); 156 pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n", 157 priv->rx_stats[2].cnt); 158 159 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 160} 161 162#define BYTE1_MASK 0x000000ff; 163#define BYTE2_MASK 0x0000ffff; 164#define BYTE3_MASK 0x00ffffff; 165static ssize_t iwl_dbgfs_sram_read(struct file *file, 166 char __user *user_buf, 167 size_t count, loff_t *ppos) 168{ 169 u32 val; 170 char buf[1024]; 171 ssize_t ret; 172 int i; 173 int pos = 0; 174 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 175 const size_t bufsz = sizeof(buf); 176 177 for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { 178 val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ 179 priv->dbgfs->sram_len - i); 180 if (i < 4) { 181 switch (i) { 182 case 1: 183 val &= BYTE1_MASK; 184 break; 185 case 2: 186 val &= BYTE2_MASK; 187 break; 188 case 3: 189 val &= BYTE3_MASK; 190 break; 191 } 192 } 193 pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); 194 } 195 pos += scnprintf(buf + pos, bufsz - pos, "\n"); 196 197 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 198 return ret; 199} 200 201static ssize_t iwl_dbgfs_sram_write(struct file *file, 202 const char __user *user_buf, 203 size_t count, loff_t *ppos) 204{ 205 struct iwl_priv *priv = file->private_data; 206 char buf[64]; 207 int buf_size; 208 u32 offset, len; 209 210 memset(buf, 0, sizeof(buf)); 211 buf_size = min(count, sizeof(buf) - 1); 212 if (copy_from_user(buf, user_buf, buf_size)) 213 return -EFAULT; 214 215 if (sscanf(buf, "%x,%x", &offset, &len) == 2) { 216 priv->dbgfs->sram_offset = offset; 217 priv->dbgfs->sram_len = len; 218 } else { 219 priv->dbgfs->sram_offset = 0; 220 priv->dbgfs->sram_len = 0; 221 } 222 223 return count; 224} 225 226static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, 227 size_t count, loff_t *ppos) 228{ 229 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 230 struct iwl_station_entry *station; 231 int max_sta = priv->hw_params.max_stations; 232 char *buf; 233 int i, j, pos = 0; 234 ssize_t ret; 235 /* Add 30 for initial string */ 236 const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations); 237 238 buf = kmalloc(bufsz, GFP_KERNEL); 239 if (!buf) 240 return -ENOMEM; 241 242 pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n", 243 priv->num_stations); 244 245 for (i = 0; i < max_sta; i++) { 246 station = &priv->stations[i]; 247 if (station->used) { 248 pos += scnprintf(buf + pos, bufsz - pos, 249 "station %d:\ngeneral data:\n", i+1); 250 pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n", 251 station->sta.sta.sta_id); 252 pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n", 253 station->sta.mode); 254 pos += scnprintf(buf + pos, bufsz - pos, 255 "flags: 0x%x\n", 256 station->sta.station_flags_msk); 257 pos += scnprintf(buf + pos, bufsz - pos, 258 "ps_status: %u\n", station->ps_status); 259 pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n"); 260 pos += scnprintf(buf + pos, bufsz - pos, 261 "seq_num\t\ttxq_id"); 262 pos += scnprintf(buf + pos, bufsz - pos, 263 "\tframe_count\twait_for_ba\t"); 264 pos += scnprintf(buf + pos, bufsz - pos, 265 "start_idx\tbitmap0\t"); 266 pos += scnprintf(buf + pos, bufsz - pos, 267 "bitmap1\trate_n_flags"); 268 pos += scnprintf(buf + pos, bufsz - pos, "\n"); 269 270 for (j = 0; j < MAX_TID_COUNT; j++) { 271 pos += scnprintf(buf + pos, bufsz - pos, 272 "[%d]:\t\t%u", j, 273 station->tid[j].seq_number); 274 pos += scnprintf(buf + pos, bufsz - pos, 275 "\t%u\t\t%u\t\t%u\t\t", 276 station->tid[j].agg.txq_id, 277 station->tid[j].agg.frame_count, 278 station->tid[j].agg.wait_for_ba); 279 pos += scnprintf(buf + pos, bufsz - pos, 280 "%u\t%llu\t%u", 281 station->tid[j].agg.start_idx, 282 (unsigned long long)station->tid[j].agg.bitmap, 283 station->tid[j].agg.rate_n_flags); 284 pos += scnprintf(buf + pos, bufsz - pos, "\n"); 285 } 286 pos += scnprintf(buf + pos, bufsz - pos, "\n"); 287 } 288 } 289 290 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 291 kfree(buf); 292 return ret; 293} 294 295static ssize_t iwl_dbgfs_nvm_read(struct file *file, 296 char __user *user_buf, 297 size_t count, 298 loff_t *ppos) 299{ 300 ssize_t ret; 301 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 302 int pos = 0, ofs = 0, buf_size = 0; 303 const u8 *ptr; 304 char *buf; 305 size_t eeprom_len = priv->cfg->eeprom_size; 306 buf_size = 4 * eeprom_len + 256; 307 308 if (eeprom_len % 16) { 309 IWL_ERR(priv, "NVM size is not multiple of 16.\n"); 310 return -ENODATA; 311 } 312 313 /* 4 characters for byte 0xYY */ 314 buf = kzalloc(buf_size, GFP_KERNEL); 315 if (!buf) { 316 IWL_ERR(priv, "Can not allocate Buffer\n"); 317 return -ENOMEM; 318 } 319 320 ptr = priv->eeprom; 321 if (!ptr) { 322 IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); 323 return -ENOMEM; 324 } 325 pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", 326 (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) 327 ? "OTP" : "EEPROM"); 328 for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { 329 pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); 330 hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, 331 buf_size - pos, 0); 332 pos += strlen(buf); 333 if (buf_size - pos > 0) 334 buf[pos++] = '\n'; 335 } 336 337 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 338 kfree(buf); 339 return ret; 340} 341 342static ssize_t iwl_dbgfs_log_event_write(struct file *file, 343 const char __user *user_buf, 344 size_t count, loff_t *ppos) 345{ 346 struct iwl_priv *priv = file->private_data; 347 u32 event_log_flag; 348 char buf[8]; 349 int buf_size; 350 351 memset(buf, 0, sizeof(buf)); 352 buf_size = min(count, sizeof(buf) - 1); 353 if (copy_from_user(buf, user_buf, buf_size)) 354 return -EFAULT; 355 if (sscanf(buf, "%d", &event_log_flag) != 1) 356 return -EFAULT; 357 if (event_log_flag == 1) 358 iwl_dump_nic_event_log(priv); 359 360 return count; 361} 362 363 364 365static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, 366 size_t count, loff_t *ppos) 367{ 368 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 369 struct ieee80211_channel *channels = NULL; 370 const struct ieee80211_supported_band *supp_band = NULL; 371 int pos = 0, i, bufsz = PAGE_SIZE; 372 char *buf; 373 ssize_t ret; 374 375 if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) 376 return -EAGAIN; 377 378 buf = kzalloc(bufsz, GFP_KERNEL); 379 if (!buf) { 380 IWL_ERR(priv, "Can not allocate Buffer\n"); 381 return -ENOMEM; 382 } 383 384 supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); 385 if (supp_band) { 386 channels = supp_band->channels; 387 388 pos += scnprintf(buf + pos, bufsz - pos, 389 "Displaying %d channels in 2.4GHz band 802.11bg):\n", 390 supp_band->n_channels); 391 392 for (i = 0; i < supp_band->n_channels; i++) 393 pos += scnprintf(buf + pos, bufsz - pos, 394 "%d: %ddBm: BSS%s%s, %s.\n", 395 ieee80211_frequency_to_channel( 396 channels[i].center_freq), 397 channels[i].max_power, 398 channels[i].flags & IEEE80211_CHAN_RADAR ? 399 " (IEEE 802.11h required)" : "", 400 ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) 401 || (channels[i].flags & 402 IEEE80211_CHAN_RADAR)) ? "" : 403 ", IBSS", 404 channels[i].flags & 405 IEEE80211_CHAN_PASSIVE_SCAN ? 406 "passive only" : "active/passive"); 407 } 408 supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); 409 if (supp_band) { 410 channels = supp_band->channels; 411 412 pos += scnprintf(buf + pos, bufsz - pos, 413 "Displaying %d channels in 5.2GHz band (802.11a)\n", 414 supp_band->n_channels); 415 416 for (i = 0; i < supp_band->n_channels; i++) 417 pos += scnprintf(buf + pos, bufsz - pos, 418 "%d: %ddBm: BSS%s%s, %s.\n", 419 ieee80211_frequency_to_channel( 420 channels[i].center_freq), 421 channels[i].max_power, 422 channels[i].flags & IEEE80211_CHAN_RADAR ? 423 " (IEEE 802.11h required)" : "", 424 ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) 425 || (channels[i].flags & 426 IEEE80211_CHAN_RADAR)) ? "" : 427 ", IBSS", 428 channels[i].flags & 429 IEEE80211_CHAN_PASSIVE_SCAN ? 430 "passive only" : "active/passive"); 431 } 432 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 433 kfree(buf); 434 return ret; 435} 436 437static ssize_t iwl_dbgfs_status_read(struct file *file, 438 char __user *user_buf, 439 size_t count, loff_t *ppos) { 440 441 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 442 char buf[512]; 443 int pos = 0; 444 const size_t bufsz = sizeof(buf); 445 446 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n", 447 test_bit(STATUS_HCMD_ACTIVE, &priv->status)); 448 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n", 449 test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)); 450 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n", 451 test_bit(STATUS_INT_ENABLED, &priv->status)); 452 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", 453 test_bit(STATUS_RF_KILL_HW, &priv->status)); 454 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", 455 test_bit(STATUS_INIT, &priv->status)); 456 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", 457 test_bit(STATUS_ALIVE, &priv->status)); 458 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n", 459 test_bit(STATUS_READY, &priv->status)); 460 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n", 461 test_bit(STATUS_TEMPERATURE, &priv->status)); 462 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n", 463 test_bit(STATUS_GEO_CONFIGURED, &priv->status)); 464 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n", 465 test_bit(STATUS_EXIT_PENDING, &priv->status)); 466 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n", 467 test_bit(STATUS_STATISTICS, &priv->status)); 468 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n", 469 test_bit(STATUS_SCANNING, &priv->status)); 470 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n", 471 test_bit(STATUS_SCAN_ABORTING, &priv->status)); 472 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n", 473 test_bit(STATUS_SCAN_HW, &priv->status)); 474 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n", 475 test_bit(STATUS_POWER_PMI, &priv->status)); 476 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n", 477 test_bit(STATUS_FW_ERROR, &priv->status)); 478 pos += scnprintf(buf + pos, bufsz - pos, "STATUS_MODE_PENDING:\t %d\n", 479 test_bit(STATUS_MODE_PENDING, &priv->status)); 480 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 481} 482 483static ssize_t iwl_dbgfs_interrupt_read(struct file *file, 484 char __user *user_buf, 485 size_t count, loff_t *ppos) { 486 487 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 488 int pos = 0; 489 int cnt = 0; 490 char *buf; 491 int bufsz = 24 * 64; /* 24 items * 64 char per item */ 492 ssize_t ret; 493 494 buf = kzalloc(bufsz, GFP_KERNEL); 495 if (!buf) { 496 IWL_ERR(priv, "Can not allocate Buffer\n"); 497 return -ENOMEM; 498 } 499 500 pos += scnprintf(buf + pos, bufsz - pos, 501 "Interrupt Statistics Report:\n"); 502 503 pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n", 504 priv->isr_stats.hw); 505 pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n", 506 priv->isr_stats.sw); 507 if (priv->isr_stats.sw > 0) { 508 pos += scnprintf(buf + pos, bufsz - pos, 509 "\tLast Restarting Code: 0x%X\n", 510 priv->isr_stats.sw_err); 511 } 512#ifdef CONFIG_IWLWIFI_DEBUG 513 pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n", 514 priv->isr_stats.sch); 515 pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n", 516 priv->isr_stats.alive); 517#endif 518 pos += scnprintf(buf + pos, bufsz - pos, 519 "HW RF KILL switch toggled:\t %u\n", 520 priv->isr_stats.rfkill); 521 522 pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n", 523 priv->isr_stats.ctkill); 524 525 pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n", 526 priv->isr_stats.wakeup); 527 528 pos += scnprintf(buf + pos, bufsz - pos, 529 "Rx command responses:\t\t %u\n", 530 priv->isr_stats.rx); 531 for (cnt = 0; cnt < REPLY_MAX; cnt++) { 532 if (priv->isr_stats.rx_handlers[cnt] > 0) 533 pos += scnprintf(buf + pos, bufsz - pos, 534 "\tRx handler[%36s]:\t\t %u\n", 535 get_cmd_string(cnt), 536 priv->isr_stats.rx_handlers[cnt]); 537 } 538 539 pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n", 540 priv->isr_stats.tx); 541 542 pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n", 543 priv->isr_stats.unhandled); 544 545 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 546 kfree(buf); 547 return ret; 548} 549 550static ssize_t iwl_dbgfs_interrupt_write(struct file *file, 551 const char __user *user_buf, 552 size_t count, loff_t *ppos) 553{ 554 struct iwl_priv *priv = file->private_data; 555 char buf[8]; 556 int buf_size; 557 u32 reset_flag; 558 559 memset(buf, 0, sizeof(buf)); 560 buf_size = min(count, sizeof(buf) - 1); 561 if (copy_from_user(buf, user_buf, buf_size)) 562 return -EFAULT; 563 if (sscanf(buf, "%x", &reset_flag) != 1) 564 return -EFAULT; 565 if (reset_flag == 0) 566 iwl_clear_isr_stats(priv); 567 568 return count; 569} 570 571static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, 572 size_t count, loff_t *ppos) 573{ 574 struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 575 int pos = 0, i; 576 char buf[256]; 577 const size_t bufsz = sizeof(buf); 578 ssize_t ret; 579 580 for (i = 0; i < AC_NUM; i++) { 581 pos += scnprintf(buf + pos, bufsz - pos, 582 "\tcw_min\tcw_max\taifsn\ttxop\n"); 583 pos += scnprintf(buf + pos, bufsz - pos, 584 "AC[%d]\t%u\t%u\t%u\t%u\n", i, 585 priv->qos_data.def_qos_parm.ac[i].cw_min, 586 priv->qos_data.def_qos_parm.ac[i].cw_max, 587 priv->qos_data.def_qos_parm.ac[i].aifsn, 588 priv->qos_data.def_qos_parm.ac[i].edca_txop); 589 } 590 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 591 return ret; 592} 593 594DEBUGFS_READ_WRITE_FILE_OPS(sram); 595DEBUGFS_WRITE_FILE_OPS(log_event); 596DEBUGFS_READ_FILE_OPS(nvm); 597DEBUGFS_READ_FILE_OPS(stations); 598DEBUGFS_READ_FILE_OPS(rx_statistics); 599DEBUGFS_READ_FILE_OPS(tx_statistics); 600DEBUGFS_READ_FILE_OPS(channels); 601DEBUGFS_READ_FILE_OPS(status); 602DEBUGFS_READ_WRITE_FILE_OPS(interrupt); 603DEBUGFS_READ_FILE_OPS(qos); 604 605/* 606 * Create the debugfs files and directories 607 * 608 */ 609int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) 610{ 611 struct iwl_debugfs *dbgfs; 612 struct dentry *phyd = priv->hw->wiphy->debugfsdir; 613 int ret = 0; 614 615 dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL); 616 if (!dbgfs) { 617 ret = -ENOMEM; 618 goto err; 619 } 620 621 priv->dbgfs = dbgfs; 622 dbgfs->name = name; 623 dbgfs->dir_drv = debugfs_create_dir(name, phyd); 624 if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) { 625 ret = -ENOENT; 626 goto err; 627 } 628 629 DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); 630 DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); 631 DEBUGFS_ADD_FILE(nvm, data); 632 DEBUGFS_ADD_FILE(sram, data); 633 DEBUGFS_ADD_FILE(log_event, data); 634 DEBUGFS_ADD_FILE(stations, data); 635 DEBUGFS_ADD_FILE(rx_statistics, data); 636 DEBUGFS_ADD_FILE(tx_statistics, data); 637 DEBUGFS_ADD_FILE(channels, data); 638 DEBUGFS_ADD_FILE(status, data); 639 DEBUGFS_ADD_FILE(interrupt, data); 640 DEBUGFS_ADD_FILE(qos, data); 641 DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); 642 DEBUGFS_ADD_BOOL(disable_chain_noise, rf, 643 &priv->disable_chain_noise_cal); 644 if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || 645 ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) 646 DEBUGFS_ADD_BOOL(disable_tx_power, rf, 647 &priv->disable_tx_power_cal); 648 return 0; 649 650err: 651 IWL_ERR(priv, "Can't open the debugfs directory\n"); 652 iwl_dbgfs_unregister(priv); 653 return ret; 654} 655EXPORT_SYMBOL(iwl_dbgfs_register); 656 657/** 658 * Remove the debugfs files and directories 659 * 660 */ 661void iwl_dbgfs_unregister(struct iwl_priv *priv) 662{ 663 if (!priv->dbgfs) 664 return; 665 666 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); 667 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); 668 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); 669 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); 670 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); 671 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); 672 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); 673 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); 674 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt); 675 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos); 676 DEBUGFS_REMOVE(priv->dbgfs->dir_data); 677 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); 678 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); 679 if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) || 680 ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945)) 681 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power); 682 DEBUGFS_REMOVE(priv->dbgfs->dir_rf); 683 DEBUGFS_REMOVE(priv->dbgfs->dir_drv); 684 kfree(priv->dbgfs); 685 priv->dbgfs = NULL; 686} 687EXPORT_SYMBOL(iwl_dbgfs_unregister); 688 689 690 691