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