1/****************************************************************************** 2 * 3 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * redistributing this file, you may do so under either license. 5 * 6 * GPL LICENSE SUMMARY 7 * 8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 23 * USA 24 * 25 * The full GNU General Public License is included in this distribution 26 * in the file called COPYING. 27 * 28 * Contact Information: 29 * Intel Linux Wireless <ilw@linux.intel.com> 30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 31 * 32 * BSD LICENSE 33 * 34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 35 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 42 * * Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * * Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in 46 * the documentation and/or other materials provided with the 47 * distribution. 48 * * Neither the name Intel Corporation nor the names of its 49 * contributors may be used to endorse or promote products derived 50 * from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 * 64 *****************************************************************************/ 65#include <linux/vmalloc.h> 66 67#include "mvm.h" 68#include "sta.h" 69#include "iwl-io.h" 70#include "debugfs.h" 71#include "iwl-fw-error-dump.h" 72 73static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, 74 size_t count, loff_t *ppos) 75{ 76 int ret; 77 u32 scd_q_msk; 78 79 if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) 80 return -EIO; 81 82 if (sscanf(buf, "%x", &scd_q_msk) != 1) 83 return -EINVAL; 84 85 IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk); 86 87 mutex_lock(&mvm->mutex); 88 ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count; 89 mutex_unlock(&mvm->mutex); 90 91 return ret; 92} 93 94static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, 95 size_t count, loff_t *ppos) 96{ 97 struct iwl_mvm_sta *mvmsta; 98 int sta_id, drain, ret; 99 100 if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR) 101 return -EIO; 102 103 if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) 104 return -EINVAL; 105 if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT) 106 return -EINVAL; 107 if (drain < 0 || drain > 1) 108 return -EINVAL; 109 110 mutex_lock(&mvm->mutex); 111 112 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); 113 114 if (!mvmsta) 115 ret = -ENOENT; 116 else 117 ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count; 118 119 mutex_unlock(&mvm->mutex); 120 121 return ret; 122} 123 124static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file) 125{ 126 struct iwl_mvm *mvm = inode->i_private; 127 int ret; 128 129 if (!mvm) 130 return -EINVAL; 131 132 mutex_lock(&mvm->mutex); 133 if (!mvm->fw_error_dump) { 134 ret = -ENODATA; 135 goto out; 136 } 137 138 file->private_data = mvm->fw_error_dump; 139 mvm->fw_error_dump = NULL; 140 ret = 0; 141 142out: 143 mutex_unlock(&mvm->mutex); 144 return ret; 145} 146 147static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file, 148 char __user *user_buf, 149 size_t count, loff_t *ppos) 150{ 151 struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; 152 ssize_t bytes_read = 0; 153 ssize_t bytes_read_trans = 0; 154 155 if (*ppos < dump_ptrs->op_mode_len) 156 bytes_read += 157 simple_read_from_buffer(user_buf, count, ppos, 158 dump_ptrs->op_mode_ptr, 159 dump_ptrs->op_mode_len); 160 161 if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len) 162 return bytes_read; 163 164 if (dump_ptrs->trans_ptr) { 165 *ppos -= dump_ptrs->op_mode_len; 166 bytes_read_trans = 167 simple_read_from_buffer(user_buf + bytes_read, 168 count - bytes_read, ppos, 169 dump_ptrs->trans_ptr->data, 170 dump_ptrs->trans_ptr->len); 171 *ppos += dump_ptrs->op_mode_len; 172 173 if (bytes_read_trans >= 0) 174 bytes_read += bytes_read_trans; 175 else if (!bytes_read) 176 /* propagate the failure */ 177 return bytes_read_trans; 178 } 179 180 return bytes_read; 181 182} 183 184static int iwl_dbgfs_fw_error_dump_release(struct inode *inode, 185 struct file *file) 186{ 187 struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data; 188 189 vfree(dump_ptrs->op_mode_ptr); 190 vfree(dump_ptrs->trans_ptr); 191 kfree(dump_ptrs); 192 193 return 0; 194} 195 196static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, 197 size_t count, loff_t *ppos) 198{ 199 struct iwl_mvm *mvm = file->private_data; 200 const struct fw_img *img; 201 unsigned int ofs, len; 202 size_t ret; 203 u8 *ptr; 204 205 if (!mvm->ucode_loaded) 206 return -EINVAL; 207 208 /* default is to dump the entire data segment */ 209 img = &mvm->fw->img[mvm->cur_ucode]; 210 ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; 211 len = img->sec[IWL_UCODE_SECTION_DATA].len; 212 213 if (mvm->dbgfs_sram_len) { 214 ofs = mvm->dbgfs_sram_offset; 215 len = mvm->dbgfs_sram_len; 216 } 217 218 ptr = kzalloc(len, GFP_KERNEL); 219 if (!ptr) 220 return -ENOMEM; 221 222 iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len); 223 224 ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len); 225 226 kfree(ptr); 227 228 return ret; 229} 230 231static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, 232 size_t count, loff_t *ppos) 233{ 234 const struct fw_img *img; 235 u32 offset, len; 236 u32 img_offset, img_len; 237 238 if (!mvm->ucode_loaded) 239 return -EINVAL; 240 241 img = &mvm->fw->img[mvm->cur_ucode]; 242 img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset; 243 img_len = img->sec[IWL_UCODE_SECTION_DATA].len; 244 245 if (sscanf(buf, "%x,%x", &offset, &len) == 2) { 246 if ((offset & 0x3) || (len & 0x3)) 247 return -EINVAL; 248 249 if (offset + len > img_offset + img_len) 250 return -EINVAL; 251 252 mvm->dbgfs_sram_offset = offset; 253 mvm->dbgfs_sram_len = len; 254 } else { 255 mvm->dbgfs_sram_offset = 0; 256 mvm->dbgfs_sram_len = 0; 257 } 258 259 return count; 260} 261 262static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file, 263 char __user *user_buf, 264 size_t count, loff_t *ppos) 265{ 266 struct iwl_mvm *mvm = file->private_data; 267 char buf[16]; 268 int pos; 269 270 if (!mvm->temperature_test) 271 pos = scnprintf(buf , sizeof(buf), "disabled\n"); 272 else 273 pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature); 274 275 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 276} 277 278/* 279 * Set NIC Temperature 280 * Cause the driver to ignore the actual NIC temperature reported by the FW 281 * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN - 282 * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 283 * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE 284 */ 285static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, 286 char *buf, size_t count, 287 loff_t *ppos) 288{ 289 int temperature; 290 291 if (!mvm->ucode_loaded && !mvm->temperature_test) 292 return -EIO; 293 294 if (kstrtoint(buf, 10, &temperature)) 295 return -EINVAL; 296 /* not a legal temperature */ 297 if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX && 298 temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) || 299 temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN) 300 return -EINVAL; 301 302 mutex_lock(&mvm->mutex); 303 if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) { 304 if (!mvm->temperature_test) 305 goto out; 306 307 mvm->temperature_test = false; 308 /* Since we can't read the temp while awake, just set 309 * it to zero until we get the next RX stats from the 310 * firmware. 311 */ 312 mvm->temperature = 0; 313 } else { 314 mvm->temperature_test = true; 315 mvm->temperature = temperature; 316 } 317 IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n", 318 mvm->temperature_test ? "En" : "Dis" , 319 mvm->temperature); 320 /* handle the temperature change */ 321 iwl_mvm_tt_handler(mvm); 322 323out: 324 mutex_unlock(&mvm->mutex); 325 326 return count; 327} 328 329static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, 330 char __user *user_buf, 331 size_t count, loff_t *ppos) 332{ 333 struct iwl_mvm *mvm = file->private_data; 334 char buf[16]; 335 int pos, temp; 336 337 if (!mvm->ucode_loaded) 338 return -EIO; 339 340 mutex_lock(&mvm->mutex); 341 temp = iwl_mvm_get_temp(mvm); 342 mutex_unlock(&mvm->mutex); 343 344 if (temp < 0) 345 return temp; 346 347 pos = scnprintf(buf , sizeof(buf), "%d\n", temp); 348 349 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 350} 351 352static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, 353 size_t count, loff_t *ppos) 354{ 355 struct iwl_mvm *mvm = file->private_data; 356 struct ieee80211_sta *sta; 357 char buf[400]; 358 int i, pos = 0, bufsz = sizeof(buf); 359 360 mutex_lock(&mvm->mutex); 361 362 for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { 363 pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i); 364 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], 365 lockdep_is_held(&mvm->mutex)); 366 if (!sta) 367 pos += scnprintf(buf + pos, bufsz - pos, "N/A\n"); 368 else if (IS_ERR(sta)) 369 pos += scnprintf(buf + pos, bufsz - pos, "%ld\n", 370 PTR_ERR(sta)); 371 else 372 pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", 373 sta->addr); 374 } 375 376 mutex_unlock(&mvm->mutex); 377 378 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 379} 380 381static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file, 382 char __user *user_buf, 383 size_t count, loff_t *ppos) 384{ 385 struct iwl_mvm *mvm = file->private_data; 386 char buf[64]; 387 int bufsz = sizeof(buf); 388 int pos = 0; 389 390 pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n", 391 mvm->disable_power_off); 392 pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n", 393 mvm->disable_power_off_d3); 394 395 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 396} 397 398static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, 399 size_t count, loff_t *ppos) 400{ 401 int ret, val; 402 403 if (!mvm->ucode_loaded) 404 return -EIO; 405 406 if (!strncmp("disable_power_off_d0=", buf, 21)) { 407 if (sscanf(buf + 21, "%d", &val) != 1) 408 return -EINVAL; 409 mvm->disable_power_off = val; 410 } else if (!strncmp("disable_power_off_d3=", buf, 21)) { 411 if (sscanf(buf + 21, "%d", &val) != 1) 412 return -EINVAL; 413 mvm->disable_power_off_d3 = val; 414 } else { 415 return -EINVAL; 416 } 417 418 mutex_lock(&mvm->mutex); 419 ret = iwl_mvm_power_update_device(mvm); 420 mutex_unlock(&mvm->mutex); 421 422 return ret ?: count; 423} 424 425#define BT_MBOX_MSG(_notif, _num, _field) \ 426 ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ 427 >> BT_MBOX##_num##_##_field##_POS) 428 429 430#define BT_MBOX_PRINT(_num, _field, _end) \ 431 pos += scnprintf(buf + pos, bufsz - pos, \ 432 "\t%s: %d%s", \ 433 #_field, \ 434 BT_MBOX_MSG(notif, _num, _field), \ 435 true ? "\n" : ", "); 436 437static 438int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, 439 int pos, int bufsz) 440{ 441 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); 442 443 BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); 444 BT_MBOX_PRINT(0, LE_PROF1, false); 445 BT_MBOX_PRINT(0, LE_PROF2, false); 446 BT_MBOX_PRINT(0, LE_PROF_OTHER, false); 447 BT_MBOX_PRINT(0, CHL_SEQ_N, false); 448 BT_MBOX_PRINT(0, INBAND_S, false); 449 BT_MBOX_PRINT(0, LE_MIN_RSSI, false); 450 BT_MBOX_PRINT(0, LE_SCAN, false); 451 BT_MBOX_PRINT(0, LE_ADV, false); 452 BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false); 453 BT_MBOX_PRINT(0, OPEN_CON_1, true); 454 455 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n"); 456 457 BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false); 458 BT_MBOX_PRINT(1, IP_SR, false); 459 BT_MBOX_PRINT(1, LE_MSTR, false); 460 BT_MBOX_PRINT(1, AGGR_TRFC_LD, false); 461 BT_MBOX_PRINT(1, MSG_TYPE, false); 462 BT_MBOX_PRINT(1, SSN, true); 463 464 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n"); 465 466 BT_MBOX_PRINT(2, SNIFF_ACT, false); 467 BT_MBOX_PRINT(2, PAG, false); 468 BT_MBOX_PRINT(2, INQUIRY, false); 469 BT_MBOX_PRINT(2, CONN, false); 470 BT_MBOX_PRINT(2, SNIFF_INTERVAL, false); 471 BT_MBOX_PRINT(2, DISC, false); 472 BT_MBOX_PRINT(2, SCO_TX_ACT, false); 473 BT_MBOX_PRINT(2, SCO_RX_ACT, false); 474 BT_MBOX_PRINT(2, ESCO_RE_TX, false); 475 BT_MBOX_PRINT(2, SCO_DURATION, true); 476 477 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n"); 478 479 BT_MBOX_PRINT(3, SCO_STATE, false); 480 BT_MBOX_PRINT(3, SNIFF_STATE, false); 481 BT_MBOX_PRINT(3, A2DP_STATE, false); 482 BT_MBOX_PRINT(3, ACL_STATE, false); 483 BT_MBOX_PRINT(3, MSTR_STATE, false); 484 BT_MBOX_PRINT(3, OBX_STATE, false); 485 BT_MBOX_PRINT(3, OPEN_CON_2, false); 486 BT_MBOX_PRINT(3, TRAFFIC_LOAD, false); 487 BT_MBOX_PRINT(3, CHL_SEQN_LSB, false); 488 BT_MBOX_PRINT(3, INBAND_P, false); 489 BT_MBOX_PRINT(3, MSG_TYPE_2, false); 490 BT_MBOX_PRINT(3, SSN_2, false); 491 BT_MBOX_PRINT(3, UPDATE_REQUEST, true); 492 493 return pos; 494} 495 496static 497int iwl_mvm_coex_dump_mbox_old(struct iwl_bt_coex_profile_notif_old *notif, 498 char *buf, int pos, int bufsz) 499{ 500 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); 501 502 BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); 503 BT_MBOX_PRINT(0, LE_PROF1, false); 504 BT_MBOX_PRINT(0, LE_PROF2, false); 505 BT_MBOX_PRINT(0, LE_PROF_OTHER, false); 506 BT_MBOX_PRINT(0, CHL_SEQ_N, false); 507 BT_MBOX_PRINT(0, INBAND_S, false); 508 BT_MBOX_PRINT(0, LE_MIN_RSSI, false); 509 BT_MBOX_PRINT(0, LE_SCAN, false); 510 BT_MBOX_PRINT(0, LE_ADV, false); 511 BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false); 512 BT_MBOX_PRINT(0, OPEN_CON_1, true); 513 514 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n"); 515 516 BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false); 517 BT_MBOX_PRINT(1, IP_SR, false); 518 BT_MBOX_PRINT(1, LE_MSTR, false); 519 BT_MBOX_PRINT(1, AGGR_TRFC_LD, false); 520 BT_MBOX_PRINT(1, MSG_TYPE, false); 521 BT_MBOX_PRINT(1, SSN, true); 522 523 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n"); 524 525 BT_MBOX_PRINT(2, SNIFF_ACT, false); 526 BT_MBOX_PRINT(2, PAG, false); 527 BT_MBOX_PRINT(2, INQUIRY, false); 528 BT_MBOX_PRINT(2, CONN, false); 529 BT_MBOX_PRINT(2, SNIFF_INTERVAL, false); 530 BT_MBOX_PRINT(2, DISC, false); 531 BT_MBOX_PRINT(2, SCO_TX_ACT, false); 532 BT_MBOX_PRINT(2, SCO_RX_ACT, false); 533 BT_MBOX_PRINT(2, ESCO_RE_TX, false); 534 BT_MBOX_PRINT(2, SCO_DURATION, true); 535 536 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n"); 537 538 BT_MBOX_PRINT(3, SCO_STATE, false); 539 BT_MBOX_PRINT(3, SNIFF_STATE, false); 540 BT_MBOX_PRINT(3, A2DP_STATE, false); 541 BT_MBOX_PRINT(3, ACL_STATE, false); 542 BT_MBOX_PRINT(3, MSTR_STATE, false); 543 BT_MBOX_PRINT(3, OBX_STATE, false); 544 BT_MBOX_PRINT(3, OPEN_CON_2, false); 545 BT_MBOX_PRINT(3, TRAFFIC_LOAD, false); 546 BT_MBOX_PRINT(3, CHL_SEQN_LSB, false); 547 BT_MBOX_PRINT(3, INBAND_P, false); 548 BT_MBOX_PRINT(3, MSG_TYPE_2, false); 549 BT_MBOX_PRINT(3, SSN_2, false); 550 BT_MBOX_PRINT(3, UPDATE_REQUEST, true); 551 552 return pos; 553} 554 555static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, 556 size_t count, loff_t *ppos) 557{ 558 struct iwl_mvm *mvm = file->private_data; 559 char *buf; 560 int ret, pos = 0, bufsz = sizeof(char) * 1024; 561 562 buf = kmalloc(bufsz, GFP_KERNEL); 563 if (!buf) 564 return -ENOMEM; 565 566 mutex_lock(&mvm->mutex); 567 568 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { 569 struct iwl_bt_coex_profile_notif_old *notif = 570 &mvm->last_bt_notif_old; 571 572 pos += iwl_mvm_coex_dump_mbox_old(notif, buf, pos, bufsz); 573 574 pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", 575 notif->bt_ci_compliance); 576 pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", 577 le32_to_cpu(notif->primary_ch_lut)); 578 pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n", 579 le32_to_cpu(notif->secondary_ch_lut)); 580 pos += scnprintf(buf+pos, 581 bufsz-pos, "bt_activity_grading = %d\n", 582 le32_to_cpu(notif->bt_activity_grading)); 583 pos += scnprintf(buf+pos, bufsz-pos, 584 "antenna isolation = %d CORUN LUT index = %d\n", 585 mvm->last_ant_isol, mvm->last_corun_lut); 586 } else { 587 struct iwl_bt_coex_profile_notif *notif = 588 &mvm->last_bt_notif; 589 590 pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz); 591 592 pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n", 593 notif->bt_ci_compliance); 594 pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n", 595 le32_to_cpu(notif->primary_ch_lut)); 596 pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n", 597 le32_to_cpu(notif->secondary_ch_lut)); 598 pos += scnprintf(buf+pos, 599 bufsz-pos, "bt_activity_grading = %d\n", 600 le32_to_cpu(notif->bt_activity_grading)); 601 pos += scnprintf(buf+pos, bufsz-pos, 602 "antenna isolation = %d CORUN LUT index = %d\n", 603 mvm->last_ant_isol, mvm->last_corun_lut); 604 } 605 606 mutex_unlock(&mvm->mutex); 607 608 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 609 kfree(buf); 610 611 return ret; 612} 613#undef BT_MBOX_PRINT 614 615static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, 616 size_t count, loff_t *ppos) 617{ 618 struct iwl_mvm *mvm = file->private_data; 619 char buf[256]; 620 int bufsz = sizeof(buf); 621 int pos = 0; 622 623 mutex_lock(&mvm->mutex); 624 625 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { 626 struct iwl_bt_coex_ci_cmd_old *cmd = &mvm->last_bt_ci_cmd_old; 627 628 pos += scnprintf(buf+pos, bufsz-pos, 629 "Channel inhibition CMD\n"); 630 pos += scnprintf(buf+pos, bufsz-pos, 631 "\tPrimary Channel Bitmap 0x%016llx\n", 632 le64_to_cpu(cmd->bt_primary_ci)); 633 pos += scnprintf(buf+pos, bufsz-pos, 634 "\tSecondary Channel Bitmap 0x%016llx\n", 635 le64_to_cpu(cmd->bt_secondary_ci)); 636 637 pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); 638 pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", 639 iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); 640 pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", 641 iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); 642 643 } else { 644 struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; 645 646 pos += scnprintf(buf+pos, bufsz-pos, 647 "Channel inhibition CMD\n"); 648 pos += scnprintf(buf+pos, bufsz-pos, 649 "\tPrimary Channel Bitmap 0x%016llx\n", 650 le64_to_cpu(cmd->bt_primary_ci)); 651 pos += scnprintf(buf+pos, bufsz-pos, 652 "\tSecondary Channel Bitmap 0x%016llx\n", 653 le64_to_cpu(cmd->bt_secondary_ci)); 654 655 pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); 656 pos += scnprintf(buf+pos, bufsz-pos, 657 "\tPrimary: ACK Kill Mask 0x%08x\n", 658 iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); 659 pos += scnprintf(buf+pos, bufsz-pos, 660 "\tPrimary: CTS Kill Mask 0x%08x\n", 661 iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); 662 pos += scnprintf(buf+pos, bufsz-pos, 663 "\tSecondary: ACK Kill Mask 0x%08x\n", 664 iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]); 665 pos += scnprintf(buf+pos, bufsz-pos, 666 "\tSecondary: CTS Kill Mask 0x%08x\n", 667 iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]); 668 669 } 670 671 mutex_unlock(&mvm->mutex); 672 673 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 674} 675 676static ssize_t 677iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, 678 size_t count, loff_t *ppos) 679{ 680 u32 bt_tx_prio; 681 682 if (sscanf(buf, "%u", &bt_tx_prio) != 1) 683 return -EINVAL; 684 if (bt_tx_prio > 4) 685 return -EINVAL; 686 687 mvm->bt_tx_prio = bt_tx_prio; 688 689 return count; 690} 691 692static ssize_t 693iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, 694 size_t count, loff_t *ppos) 695{ 696 static const char * const modes_str[BT_FORCE_ANT_MAX] = { 697 [BT_FORCE_ANT_DIS] = "dis", 698 [BT_FORCE_ANT_AUTO] = "auto", 699 [BT_FORCE_ANT_BT] = "bt", 700 [BT_FORCE_ANT_WIFI] = "wifi", 701 }; 702 int ret, bt_force_ant_mode; 703 704 for (bt_force_ant_mode = 0; 705 bt_force_ant_mode < ARRAY_SIZE(modes_str); 706 bt_force_ant_mode++) { 707 if (!strcmp(buf, modes_str[bt_force_ant_mode])) 708 break; 709 } 710 711 if (bt_force_ant_mode >= ARRAY_SIZE(modes_str)) 712 return -EINVAL; 713 714 ret = 0; 715 mutex_lock(&mvm->mutex); 716 if (mvm->bt_force_ant_mode == bt_force_ant_mode) 717 goto out; 718 719 mvm->bt_force_ant_mode = bt_force_ant_mode; 720 IWL_DEBUG_COEX(mvm, "Force mode: %s\n", 721 modes_str[mvm->bt_force_ant_mode]); 722 ret = iwl_send_bt_init_conf(mvm); 723 724out: 725 mutex_unlock(&mvm->mutex); 726 return ret ?: count; 727} 728 729#define PRINT_STATS_LE32(_str, _val) \ 730 pos += scnprintf(buf + pos, bufsz - pos, \ 731 fmt_table, _str, \ 732 le32_to_cpu(_val)) 733 734static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, 735 char __user *user_buf, size_t count, 736 loff_t *ppos) 737{ 738 struct iwl_mvm *mvm = file->private_data; 739 static const char *fmt_table = "\t%-30s %10u\n"; 740 static const char *fmt_header = "%-32s\n"; 741 int pos = 0; 742 char *buf; 743 int ret; 744 /* 43 is the size of each data line, 33 is the size of each header */ 745 size_t bufsz = 746 ((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) + 747 (4 * 33) + 1; 748 749 struct mvm_statistics_rx_phy *ofdm; 750 struct mvm_statistics_rx_phy *cck; 751 struct mvm_statistics_rx_non_phy *general; 752 struct mvm_statistics_rx_ht_phy *ht; 753 754 buf = kzalloc(bufsz, GFP_KERNEL); 755 if (!buf) 756 return -ENOMEM; 757 758 mutex_lock(&mvm->mutex); 759 760 ofdm = &mvm->rx_stats.ofdm; 761 cck = &mvm->rx_stats.cck; 762 general = &mvm->rx_stats.general; 763 ht = &mvm->rx_stats.ofdm_ht; 764 765 pos += scnprintf(buf + pos, bufsz - pos, fmt_header, 766 "Statistics_Rx - OFDM"); 767 PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt); 768 PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt); 769 PRINT_STATS_LE32("plcp_err", ofdm->plcp_err); 770 PRINT_STATS_LE32("crc32_err", ofdm->crc32_err); 771 PRINT_STATS_LE32("overrun_err", ofdm->overrun_err); 772 PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err); 773 PRINT_STATS_LE32("crc32_good", ofdm->crc32_good); 774 PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt); 775 PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt); 776 PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout); 777 PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout); 778 PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts); 779 PRINT_STATS_LE32("rxe_frame_lmt_overrun", 780 ofdm->rxe_frame_limit_overrun); 781 PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt); 782 PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt); 783 PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt); 784 PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill); 785 PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err); 786 PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum); 787 PRINT_STATS_LE32("reserved", ofdm->reserved); 788 789 pos += scnprintf(buf + pos, bufsz - pos, fmt_header, 790 "Statistics_Rx - CCK"); 791 PRINT_STATS_LE32("ina_cnt", cck->ina_cnt); 792 PRINT_STATS_LE32("fina_cnt", cck->fina_cnt); 793 PRINT_STATS_LE32("plcp_err", cck->plcp_err); 794 PRINT_STATS_LE32("crc32_err", cck->crc32_err); 795 PRINT_STATS_LE32("overrun_err", cck->overrun_err); 796 PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err); 797 PRINT_STATS_LE32("crc32_good", cck->crc32_good); 798 PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt); 799 PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt); 800 PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout); 801 PRINT_STATS_LE32("fina_timeout", cck->fina_timeout); 802 PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts); 803 PRINT_STATS_LE32("rxe_frame_lmt_overrun", 804 cck->rxe_frame_limit_overrun); 805 PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt); 806 PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt); 807 PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt); 808 PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill); 809 PRINT_STATS_LE32("mh_format_err", cck->mh_format_err); 810 PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum); 811 PRINT_STATS_LE32("reserved", cck->reserved); 812 813 pos += scnprintf(buf + pos, bufsz - pos, fmt_header, 814 "Statistics_Rx - GENERAL"); 815 PRINT_STATS_LE32("bogus_cts", general->bogus_cts); 816 PRINT_STATS_LE32("bogus_ack", general->bogus_ack); 817 PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames); 818 PRINT_STATS_LE32("filtered_frames", general->filtered_frames); 819 PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons); 820 PRINT_STATS_LE32("channel_beacons", general->channel_beacons); 821 PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon); 822 PRINT_STATS_LE32("adc_rx_saturation_time", 823 general->adc_rx_saturation_time); 824 PRINT_STATS_LE32("ina_detection_search_time", 825 general->ina_detection_search_time); 826 PRINT_STATS_LE32("beacon_silence_rssi_a", 827 general->beacon_silence_rssi_a); 828 PRINT_STATS_LE32("beacon_silence_rssi_b", 829 general->beacon_silence_rssi_b); 830 PRINT_STATS_LE32("beacon_silence_rssi_c", 831 general->beacon_silence_rssi_c); 832 PRINT_STATS_LE32("interference_data_flag", 833 general->interference_data_flag); 834 PRINT_STATS_LE32("channel_load", general->channel_load); 835 PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms); 836 PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a); 837 PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b); 838 PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c); 839 PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a); 840 PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b); 841 PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c); 842 PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills); 843 PRINT_STATS_LE32("mac_id", general->mac_id); 844 PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu); 845 846 pos += scnprintf(buf + pos, bufsz - pos, fmt_header, 847 "Statistics_Rx - HT"); 848 PRINT_STATS_LE32("plcp_err", ht->plcp_err); 849 PRINT_STATS_LE32("overrun_err", ht->overrun_err); 850 PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err); 851 PRINT_STATS_LE32("crc32_good", ht->crc32_good); 852 PRINT_STATS_LE32("crc32_err", ht->crc32_err); 853 PRINT_STATS_LE32("mh_format_err", ht->mh_format_err); 854 PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good); 855 PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt); 856 PRINT_STATS_LE32("agg_cnt", ht->agg_cnt); 857 PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs); 858 859 mutex_unlock(&mvm->mutex); 860 861 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 862 kfree(buf); 863 864 return ret; 865} 866#undef PRINT_STAT_LE32 867 868static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, 869 char __user *user_buf, size_t count, 870 loff_t *ppos, 871 struct iwl_mvm_frame_stats *stats) 872{ 873 char *buff, *pos, *endpos; 874 int idx, i; 875 int ret; 876 static const size_t bufsz = 1024; 877 878 buff = kmalloc(bufsz, GFP_KERNEL); 879 if (!buff) 880 return -ENOMEM; 881 882 spin_lock_bh(&mvm->drv_stats_lock); 883 884 pos = buff; 885 endpos = pos + bufsz; 886 887 pos += scnprintf(pos, endpos - pos, 888 "Legacy/HT/VHT\t:\t%d/%d/%d\n", 889 stats->legacy_frames, 890 stats->ht_frames, 891 stats->vht_frames); 892 pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n", 893 stats->bw_20_frames, 894 stats->bw_40_frames, 895 stats->bw_80_frames); 896 pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n", 897 stats->ngi_frames, 898 stats->sgi_frames); 899 pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n", 900 stats->siso_frames, 901 stats->mimo2_frames); 902 pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n", 903 stats->fail_frames, 904 stats->success_frames); 905 pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n", 906 stats->agg_frames); 907 pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n", 908 stats->ampdu_count); 909 pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n", 910 stats->ampdu_count > 0 ? 911 (stats->agg_frames / stats->ampdu_count) : 0); 912 913 pos += scnprintf(pos, endpos - pos, "Last Rates\n"); 914 915 idx = stats->last_frame_idx - 1; 916 for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) { 917 idx = (idx + 1) % ARRAY_SIZE(stats->last_rates); 918 if (stats->last_rates[idx] == 0) 919 continue; 920 pos += scnprintf(pos, endpos - pos, "Rate[%d]: ", 921 (int)(ARRAY_SIZE(stats->last_rates) - i)); 922 pos += rs_pretty_print_rate(pos, stats->last_rates[idx]); 923 } 924 spin_unlock_bh(&mvm->drv_stats_lock); 925 926 ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); 927 kfree(buff); 928 929 return ret; 930} 931 932static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file, 933 char __user *user_buf, size_t count, 934 loff_t *ppos) 935{ 936 struct iwl_mvm *mvm = file->private_data; 937 938 return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos, 939 &mvm->drv_rx_stats); 940} 941 942static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, 943 size_t count, loff_t *ppos) 944{ 945 int ret; 946 947 mutex_lock(&mvm->mutex); 948 949 /* allow one more restart that we're provoking here */ 950 if (mvm->restart_fw >= 0) 951 mvm->restart_fw++; 952 953 /* take the return value to make compiler happy - it will fail anyway */ 954 ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); 955 956 mutex_unlock(&mvm->mutex); 957 958 return count; 959} 960 961static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, 962 size_t count, loff_t *ppos) 963{ 964 int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); 965 if (ret) 966 return ret; 967 968 iwl_force_nmi(mvm->trans); 969 970 iwl_mvm_unref(mvm, IWL_MVM_REF_NMI); 971 972 return count; 973} 974 975static ssize_t 976iwl_dbgfs_scan_ant_rxchain_read(struct file *file, 977 char __user *user_buf, 978 size_t count, loff_t *ppos) 979{ 980 struct iwl_mvm *mvm = file->private_data; 981 int pos = 0; 982 char buf[32]; 983 const size_t bufsz = sizeof(buf); 984 985 /* print which antennas were set for the scan command by the user */ 986 pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: "); 987 if (mvm->scan_rx_ant & ANT_A) 988 pos += scnprintf(buf + pos, bufsz - pos, "A"); 989 if (mvm->scan_rx_ant & ANT_B) 990 pos += scnprintf(buf + pos, bufsz - pos, "B"); 991 if (mvm->scan_rx_ant & ANT_C) 992 pos += scnprintf(buf + pos, bufsz - pos, "C"); 993 pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant); 994 995 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 996} 997 998static ssize_t 999iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, 1000 size_t count, loff_t *ppos) 1001{ 1002 u8 scan_rx_ant; 1003 1004 if (sscanf(buf, "%hhx", &scan_rx_ant) != 1) 1005 return -EINVAL; 1006 if (scan_rx_ant > ANT_ABC) 1007 return -EINVAL; 1008 if (scan_rx_ant & ~mvm->fw->valid_rx_ant) 1009 return -EINVAL; 1010 1011 mvm->scan_rx_ant = scan_rx_ant; 1012 1013 return count; 1014} 1015 1016#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) 1017#ifdef CONFIG_IWLWIFI_BCAST_FILTERING 1018static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, 1019 char __user *user_buf, 1020 size_t count, loff_t *ppos) 1021{ 1022 struct iwl_mvm *mvm = file->private_data; 1023 struct iwl_bcast_filter_cmd cmd; 1024 const struct iwl_fw_bcast_filter *filter; 1025 char *buf; 1026 int bufsz = 1024; 1027 int i, j, pos = 0; 1028 ssize_t ret; 1029 1030 buf = kzalloc(bufsz, GFP_KERNEL); 1031 if (!buf) 1032 return -ENOMEM; 1033 1034 mutex_lock(&mvm->mutex); 1035 if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { 1036 ADD_TEXT("None\n"); 1037 mutex_unlock(&mvm->mutex); 1038 goto out; 1039 } 1040 mutex_unlock(&mvm->mutex); 1041 1042 for (i = 0; cmd.filters[i].attrs[0].mask; i++) { 1043 filter = &cmd.filters[i]; 1044 1045 ADD_TEXT("Filter [%d]:\n", i); 1046 ADD_TEXT("\tDiscard=%d\n", filter->discard); 1047 ADD_TEXT("\tFrame Type: %s\n", 1048 filter->frame_type ? "IPv4" : "Generic"); 1049 1050 for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) { 1051 const struct iwl_fw_bcast_filter_attr *attr; 1052 1053 attr = &filter->attrs[j]; 1054 if (!attr->mask) 1055 break; 1056 1057 ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n", 1058 j, attr->offset, 1059 attr->offset_type ? "IP End" : 1060 "Payload Start", 1061 be32_to_cpu(attr->mask), 1062 be32_to_cpu(attr->val), 1063 le16_to_cpu(attr->reserved1)); 1064 } 1065 } 1066out: 1067 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1068 kfree(buf); 1069 return ret; 1070} 1071 1072static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, 1073 size_t count, loff_t *ppos) 1074{ 1075 int pos, next_pos; 1076 struct iwl_fw_bcast_filter filter = {}; 1077 struct iwl_bcast_filter_cmd cmd; 1078 u32 filter_id, attr_id, mask, value; 1079 int err = 0; 1080 1081 if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard, 1082 &filter.frame_type, &pos) != 3) 1083 return -EINVAL; 1084 1085 if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) || 1086 filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4) 1087 return -EINVAL; 1088 1089 for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs); 1090 attr_id++) { 1091 struct iwl_fw_bcast_filter_attr *attr = 1092 &filter.attrs[attr_id]; 1093 1094 if (pos >= count) 1095 break; 1096 1097 if (sscanf(&buf[pos], "%hhi %hhi %i %i %n", 1098 &attr->offset, &attr->offset_type, 1099 &mask, &value, &next_pos) != 4) 1100 return -EINVAL; 1101 1102 attr->mask = cpu_to_be32(mask); 1103 attr->val = cpu_to_be32(value); 1104 if (mask) 1105 filter.num_attrs++; 1106 1107 pos += next_pos; 1108 } 1109 1110 mutex_lock(&mvm->mutex); 1111 memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id], 1112 &filter, sizeof(filter)); 1113 1114 /* send updated bcast filtering configuration */ 1115 if (mvm->dbgfs_bcast_filtering.override && 1116 iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) 1117 err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, 1118 sizeof(cmd), &cmd); 1119 mutex_unlock(&mvm->mutex); 1120 1121 return err ?: count; 1122} 1123 1124static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file, 1125 char __user *user_buf, 1126 size_t count, loff_t *ppos) 1127{ 1128 struct iwl_mvm *mvm = file->private_data; 1129 struct iwl_bcast_filter_cmd cmd; 1130 char *buf; 1131 int bufsz = 1024; 1132 int i, pos = 0; 1133 ssize_t ret; 1134 1135 buf = kzalloc(bufsz, GFP_KERNEL); 1136 if (!buf) 1137 return -ENOMEM; 1138 1139 mutex_lock(&mvm->mutex); 1140 if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { 1141 ADD_TEXT("None\n"); 1142 mutex_unlock(&mvm->mutex); 1143 goto out; 1144 } 1145 mutex_unlock(&mvm->mutex); 1146 1147 for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) { 1148 const struct iwl_fw_bcast_mac *mac = &cmd.macs[i]; 1149 1150 ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n", 1151 i, mac->default_discard, mac->attached_filters); 1152 } 1153out: 1154 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1155 kfree(buf); 1156 return ret; 1157} 1158 1159static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, 1160 char *buf, size_t count, 1161 loff_t *ppos) 1162{ 1163 struct iwl_bcast_filter_cmd cmd; 1164 struct iwl_fw_bcast_mac mac = {}; 1165 u32 mac_id, attached_filters; 1166 int err = 0; 1167 1168 if (!mvm->bcast_filters) 1169 return -ENOENT; 1170 1171 if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard, 1172 &attached_filters) != 3) 1173 return -EINVAL; 1174 1175 if (mac_id >= ARRAY_SIZE(cmd.macs) || 1176 mac.default_discard > 1 || 1177 attached_filters >= BIT(ARRAY_SIZE(cmd.filters))) 1178 return -EINVAL; 1179 1180 mac.attached_filters = cpu_to_le16(attached_filters); 1181 1182 mutex_lock(&mvm->mutex); 1183 memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id], 1184 &mac, sizeof(mac)); 1185 1186 /* send updated bcast filtering configuration */ 1187 if (mvm->dbgfs_bcast_filtering.override && 1188 iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) 1189 err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, 1190 sizeof(cmd), &cmd); 1191 mutex_unlock(&mvm->mutex); 1192 1193 return err ?: count; 1194} 1195#endif 1196 1197#ifdef CONFIG_PM_SLEEP 1198static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, 1199 size_t count, loff_t *ppos) 1200{ 1201 int store; 1202 1203 if (sscanf(buf, "%d", &store) != 1) 1204 return -EINVAL; 1205 1206 mvm->store_d3_resume_sram = store; 1207 1208 return count; 1209} 1210 1211static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, 1212 size_t count, loff_t *ppos) 1213{ 1214 struct iwl_mvm *mvm = file->private_data; 1215 const struct fw_img *img; 1216 int ofs, len, pos = 0; 1217 size_t bufsz, ret; 1218 char *buf; 1219 u8 *ptr = mvm->d3_resume_sram; 1220 1221 img = &mvm->fw->img[IWL_UCODE_WOWLAN]; 1222 len = img->sec[IWL_UCODE_SECTION_DATA].len; 1223 1224 bufsz = len * 4 + 256; 1225 buf = kzalloc(bufsz, GFP_KERNEL); 1226 if (!buf) 1227 return -ENOMEM; 1228 1229 pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n", 1230 mvm->store_d3_resume_sram ? "en" : "dis"); 1231 1232 if (ptr) { 1233 for (ofs = 0; ofs < len; ofs += 16) { 1234 pos += scnprintf(buf + pos, bufsz - pos, 1235 "0x%.4x ", ofs); 1236 hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, 1237 bufsz - pos, false); 1238 pos += strlen(buf + pos); 1239 if (bufsz - pos > 0) 1240 buf[pos++] = '\n'; 1241 } 1242 } else { 1243 pos += scnprintf(buf + pos, bufsz - pos, 1244 "(no data captured)\n"); 1245 } 1246 1247 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1248 1249 kfree(buf); 1250 1251 return ret; 1252} 1253#endif 1254 1255#define PRINT_MVM_REF(ref) do { \ 1256 if (mvm->refs[ref]) \ 1257 pos += scnprintf(buf + pos, bufsz - pos, \ 1258 "\t(0x%lx): %d %s\n", \ 1259 BIT(ref), mvm->refs[ref], #ref); \ 1260} while (0) 1261 1262static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, 1263 char __user *user_buf, 1264 size_t count, loff_t *ppos) 1265{ 1266 struct iwl_mvm *mvm = file->private_data; 1267 int i, pos = 0; 1268 char buf[256]; 1269 const size_t bufsz = sizeof(buf); 1270 u32 refs = 0; 1271 1272 for (i = 0; i < IWL_MVM_REF_COUNT; i++) 1273 if (mvm->refs[i]) 1274 refs |= BIT(i); 1275 1276 pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n", 1277 refs); 1278 1279 PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); 1280 PRINT_MVM_REF(IWL_MVM_REF_SCAN); 1281 PRINT_MVM_REF(IWL_MVM_REF_ROC); 1282 PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); 1283 PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); 1284 PRINT_MVM_REF(IWL_MVM_REF_USER); 1285 PRINT_MVM_REF(IWL_MVM_REF_TX); 1286 PRINT_MVM_REF(IWL_MVM_REF_TX_AGG); 1287 PRINT_MVM_REF(IWL_MVM_REF_ADD_IF); 1288 PRINT_MVM_REF(IWL_MVM_REF_START_AP); 1289 PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED); 1290 PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX); 1291 PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS); 1292 PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL); 1293 PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ); 1294 PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE); 1295 PRINT_MVM_REF(IWL_MVM_REF_NMI); 1296 PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); 1297 PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); 1298 1299 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1300} 1301 1302static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, 1303 size_t count, loff_t *ppos) 1304{ 1305 unsigned long value; 1306 int ret; 1307 bool taken; 1308 1309 ret = kstrtoul(buf, 10, &value); 1310 if (ret < 0) 1311 return ret; 1312 1313 mutex_lock(&mvm->mutex); 1314 1315 taken = mvm->refs[IWL_MVM_REF_USER]; 1316 if (value == 1 && !taken) 1317 iwl_mvm_ref(mvm, IWL_MVM_REF_USER); 1318 else if (value == 0 && taken) 1319 iwl_mvm_unref(mvm, IWL_MVM_REF_USER); 1320 else 1321 ret = -EINVAL; 1322 1323 mutex_unlock(&mvm->mutex); 1324 1325 if (ret < 0) 1326 return ret; 1327 return count; 1328} 1329 1330#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 1331 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) 1332#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ 1333 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) 1334#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ 1335 if (!debugfs_create_file(alias, mode, parent, mvm, \ 1336 &iwl_dbgfs_##name##_ops)) \ 1337 goto err; \ 1338 } while (0) 1339#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ 1340 MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) 1341 1342static ssize_t 1343iwl_dbgfs_prph_reg_read(struct file *file, 1344 char __user *user_buf, 1345 size_t count, loff_t *ppos) 1346{ 1347 struct iwl_mvm *mvm = file->private_data; 1348 int pos = 0; 1349 char buf[32]; 1350 const size_t bufsz = sizeof(buf); 1351 int ret; 1352 1353 if (!mvm->dbgfs_prph_reg_addr) 1354 return -EINVAL; 1355 1356 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ); 1357 if (ret) 1358 return ret; 1359 1360 pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", 1361 mvm->dbgfs_prph_reg_addr, 1362 iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); 1363 1364 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ); 1365 1366 return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 1367} 1368 1369static ssize_t 1370iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, 1371 size_t count, loff_t *ppos) 1372{ 1373 u8 args; 1374 u32 value; 1375 int ret; 1376 1377 args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); 1378 /* if we only want to set the reg address - nothing more to do */ 1379 if (args == 1) 1380 goto out; 1381 1382 /* otherwise, make sure we have both address and value */ 1383 if (args != 2) 1384 return -EINVAL; 1385 1386 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); 1387 if (ret) 1388 return ret; 1389 1390 iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); 1391 1392 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); 1393out: 1394 return count; 1395} 1396 1397MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); 1398 1399/* Device wide debugfs entries */ 1400MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); 1401MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); 1402MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); 1403MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); 1404MVM_DEBUGFS_READ_FILE_OPS(nic_temp); 1405MVM_DEBUGFS_READ_FILE_OPS(stations); 1406MVM_DEBUGFS_READ_FILE_OPS(bt_notif); 1407MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); 1408MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); 1409MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); 1410MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); 1411MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); 1412MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); 1413MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); 1414MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); 1415MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); 1416MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); 1417 1418static const struct file_operations iwl_dbgfs_fw_error_dump_ops = { 1419 .open = iwl_dbgfs_fw_error_dump_open, 1420 .read = iwl_dbgfs_fw_error_dump_read, 1421 .release = iwl_dbgfs_fw_error_dump_release, 1422}; 1423 1424#ifdef CONFIG_IWLWIFI_BCAST_FILTERING 1425MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); 1426MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); 1427#endif 1428 1429#ifdef CONFIG_PM_SLEEP 1430MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); 1431#endif 1432 1433int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) 1434{ 1435 struct dentry *bcast_dir __maybe_unused; 1436 char buf[100]; 1437 1438 spin_lock_init(&mvm->drv_stats_lock); 1439 1440 mvm->debugfs_dir = dbgfs_dir; 1441 1442 MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); 1443 MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); 1444 MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); 1445 MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, 1446 S_IWUSR | S_IRUSR); 1447 MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); 1448 MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); 1449 MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR); 1450 MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); 1451 MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); 1452 MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, 1453 S_IRUSR | S_IWUSR); 1454 MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); 1455 MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); 1456 MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); 1457 MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); 1458 MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); 1459 MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR); 1460 MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, 1461 S_IWUSR | S_IRUSR); 1462 MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); 1463 MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); 1464 1465#ifdef CONFIG_IWLWIFI_BCAST_FILTERING 1466 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { 1467 bcast_dir = debugfs_create_dir("bcast_filtering", 1468 mvm->debugfs_dir); 1469 if (!bcast_dir) 1470 goto err; 1471 1472 if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR, 1473 bcast_dir, 1474 &mvm->dbgfs_bcast_filtering.override)) 1475 goto err; 1476 1477 MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters, 1478 bcast_dir, S_IWUSR | S_IRUSR); 1479 MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs, 1480 bcast_dir, S_IWUSR | S_IRUSR); 1481 } 1482#endif 1483 1484#ifdef CONFIG_PM_SLEEP 1485 MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); 1486 MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); 1487 if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, 1488 mvm->debugfs_dir, &mvm->d3_wake_sysassert)) 1489 goto err; 1490#endif 1491 1492 if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR, 1493 mvm->debugfs_dir, 1494 &mvm->low_latency_agg_frame_limit)) 1495 goto err; 1496 if (!debugfs_create_u8("ps_disabled", S_IRUSR, 1497 mvm->debugfs_dir, &mvm->ps_disabled)) 1498 goto err; 1499 if (!debugfs_create_blob("nvm_hw", S_IRUSR, 1500 mvm->debugfs_dir, &mvm->nvm_hw_blob)) 1501 goto err; 1502 if (!debugfs_create_blob("nvm_sw", S_IRUSR, 1503 mvm->debugfs_dir, &mvm->nvm_sw_blob)) 1504 goto err; 1505 if (!debugfs_create_blob("nvm_calib", S_IRUSR, 1506 mvm->debugfs_dir, &mvm->nvm_calib_blob)) 1507 goto err; 1508 if (!debugfs_create_blob("nvm_prod", S_IRUSR, 1509 mvm->debugfs_dir, &mvm->nvm_prod_blob)) 1510 goto err; 1511 1512 /* 1513 * Create a symlink with mac80211. It will be removed when mac80211 1514 * exists (before the opmode exists which removes the target.) 1515 */ 1516 snprintf(buf, 100, "../../%s/%s", 1517 dbgfs_dir->d_parent->d_parent->d_name.name, 1518 dbgfs_dir->d_parent->d_name.name); 1519 if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf)) 1520 goto err; 1521 1522 return 0; 1523err: 1524 IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); 1525 return -ENOMEM; 1526} 1527