diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 1911 |
1 files changed, 1090 insertions, 821 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index c1c9c489edc9..683c0ba5fb39 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1,79 +1,24 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless <linuxwifi@intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2012-2014, 2018-2023, 2025 Intel Corporation + * Copyright (C) 2013-2015 Intel Mobile Communications GmbH + * Copyright (C) 2016-2017 Intel Deutschland GmbH + */ #include <linux/vmalloc.h> +#include <linux/err.h> #include <linux/ieee80211.h> #include <linux/netdevice.h> +#include <linux/dmi.h> #include "mvm.h" -#include "fw-dbg.h" #include "sta.h" #include "iwl-io.h" #include "debugfs.h" +#include "iwl-modparams.h" +#include "iwl-drv.h" +#include "iwl-utils.h" #include "fw/error-dump.h" +#include "fw/api/phy-ctxt.h" static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char __user *user_buf, @@ -83,8 +28,11 @@ static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char buf[16]; int pos, budget; + if (!iwl_mvm_is_ctdp_supported(mvm)) + return -EOPNOTSUPP; + if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -103,9 +51,22 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { int ret; + bool force; + + if (!kstrtobool(buf, &force)) + IWL_DEBUG_INFO(mvm, + "force start is %d [0=disabled, 1=enabled]\n", + force); + + /* we allow skipping cap support check and force stop ctdp + * statistics collection and with guerantee that it is + * safe to use. + */ + if (!force && !iwl_mvm_is_ctdp_supported(mvm)) + return -EOPNOTSUPP; if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -115,6 +76,48 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } +static ssize_t iwl_dbgfs_start_ctdp_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + int ret; + bool force; + + if (!kstrtobool(buf, &force)) + IWL_DEBUG_INFO(mvm, + "force start is %d [0=disabled, 1=enabled]\n", + force); + + /* we allow skipping cap support check and force enable ctdp + * for statistics collection and with guerantee that it is + * safe to use. + */ + if (!force && !iwl_mvm_is_ctdp_supported(mvm)) + return -EOPNOTSUPP; + + if (!iwl_mvm_firmware_running(mvm) || + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) + return -EIO; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, 0); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_force_ctkill_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + if (!iwl_mvm_firmware_running(mvm) || + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) + return -EIO; + + iwl_mvm_enter_ctkill(mvm); + + return count; +} + static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { @@ -122,7 +125,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, u32 flush_arg; if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; if (kstrtou32(buf, 0, &flush_arg)) @@ -133,7 +136,8 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, "FLUSHING all tids queues on sta_id = %d\n", flush_arg); mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count; + ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFFFF) + ? : count; mutex_unlock(&mvm->mutex); return ret; } @@ -142,38 +146,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, flush_arg); mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_tx_path(mvm, flush_arg, 0) ? : count; - mutex_unlock(&mvm->mutex); - - return ret; -} - -static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_sta *mvmsta; - int sta_id, drain, ret; - - if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) - return -EIO; - - if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) - return -EINVAL; - if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT) - return -EINVAL; - if (drain < 0 || drain > 1) - return -EINVAL; - - mutex_lock(&mvm->mutex); - - mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); - - if (!mvmsta) - ret = -ENOENT; - else - ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count; - + ret = iwl_mvm_flush_tx_path(mvm, flush_arg) ? : count; mutex_unlock(&mvm->mutex); return ret; @@ -192,7 +165,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, return -EINVAL; /* default is to dump the entire data segment */ - img = &mvm->fw->img[mvm->cur_ucode]; + img = &mvm->fw->img[mvm->fwrt.cur_fw_img]; ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; len = img->sec[IWL_UCODE_SECTION_DATA].len; @@ -224,7 +197,7 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, if (!iwl_mvm_firmware_running(mvm)) return -EINVAL; - img = &mvm->fw->img[mvm->cur_ucode]; + img = &mvm->fw->img[mvm->fwrt.cur_fw_img]; img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset; img_len = img->sec[IWL_UCODE_SECTION_DATA].len; @@ -254,9 +227,9 @@ static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file, int pos; if (!mvm->temperature_test) - pos = scnprintf(buf , sizeof(buf), "disabled\n"); + pos = scnprintf(buf, sizeof(buf), "disabled\n"); else - pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature); + pos = scnprintf(buf, sizeof(buf), "%d\n", mvm->temperature); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -301,7 +274,7 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm, mvm->temperature = temperature; } IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n", - mvm->temperature_test ? "En" : "Dis" , + mvm->temperature_test ? "En" : "Dis", mvm->temperature); /* handle the temperature change */ iwl_mvm_tt_handler(mvm); @@ -331,7 +304,7 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file, if (ret) return -EIO; - pos = scnprintf(buf , sizeof(buf), "%d\n", temp); + pos = scnprintf(buf, sizeof(buf), "%d\n", temp); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -346,7 +319,6 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, int pos = 0; int bufsz = sizeof(buf); int tbl_idx; - u8 *value; if (!iwl_mvm_firmware_running(mvm)) return -EIO; @@ -362,21 +334,41 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, pos = scnprintf(buf, bufsz, "SAR geographic profile disabled\n"); } else { - value = &mvm->geo_profiles[tbl_idx - 1].values[0]; - pos += scnprintf(buf + pos, bufsz - pos, "Use geographic profile %d\n", tbl_idx); pos += scnprintf(buf + pos, bufsz - pos, - "2.4GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n", - value[1], value[2], value[0]); + "2.4GHz:\n\tChain A offset: %u dBm\n\tChain B offset: %u dBm\n\tmax tx power: %u dBm\n", + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[0], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].chains[1], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[0].max); pos += scnprintf(buf + pos, bufsz - pos, - "5.2GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n", - value[4], value[5], value[3]); + "5.2GHz:\n\tChain A offset: %u dBm\n\tChain B offset: %u dBm\n\tmax tx power: %u dBm\n", + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[0], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].chains[1], + mvm->fwrt.geo_profiles[tbl_idx - 1].bands[1].max); } mutex_unlock(&mvm->mutex); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } + +static ssize_t iwl_dbgfs_wifi_6e_enable_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + int err, pos; + char buf[12]; + u32 value; + + err = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); + if (err) + return err; + + pos = sprintf(buf, "0x%08x\n", value); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} #endif static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, @@ -389,7 +381,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, mutex_lock(&mvm->mutex); - for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) { + for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) { pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i); sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], lockdep_is_held(&mvm->mutex)); @@ -408,6 +400,99 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_rs_data_read(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_lq_sta_rs_fw *lq_sta = &mvm_link_sta->lq_sta.rs_fw; + static const size_t bufsz = 2048; + char *buff; + int desc = 0; + ssize_t ret; + + buff = kmalloc(bufsz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + desc += scnprintf(buff + desc, bufsz - desc, "sta_id %d\n", + lq_sta->pers.sta_id); + desc += scnprintf(buff + desc, bufsz - desc, + "fixed rate 0x%X\n", + lq_sta->pers.dbg_fixed_rate); + desc += scnprintf(buff + desc, bufsz - desc, + "A-MPDU size limit %d\n", + lq_sta->pers.dbg_agg_frame_count_lim); + desc += scnprintf(buff + desc, bufsz - desc, + "valid_tx_ant %s%s\n", + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "", + (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : ""); + desc += scnprintf(buff + desc, bufsz - desc, + "last tx rate=0x%X ", + lq_sta->last_rate_n_flags); + + desc += rs_pretty_print_rate(buff + desc, bufsz - desc, + lq_sta->last_rate_n_flags); + if (desc < bufsz - 1) + buff[desc++] = '\n'; + + ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); + kfree(buff); + return ret; +} + +static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, + char *buf, size_t count, + loff_t *ppos) +{ + int i; + u16 amsdu_len; + + if (kstrtou16(buf, 0, &amsdu_len)) + return -EINVAL; + + /* only change from debug set <-> debug unset */ + if (amsdu_len && mvm_link_sta->orig_amsdu_len) + return -EBUSY; + + if (amsdu_len) { + mvm_link_sta->orig_amsdu_len = link_sta->agg.max_amsdu_len; + link_sta->agg.max_amsdu_len = amsdu_len; + for (i = 0; i < ARRAY_SIZE(link_sta->agg.max_tid_amsdu_len); i++) + link_sta->agg.max_tid_amsdu_len[i] = amsdu_len; + } else { + link_sta->agg.max_amsdu_len = mvm_link_sta->orig_amsdu_len; + mvm_link_sta->orig_amsdu_len = 0; + } + + ieee80211_sta_recalc_aggregates(link_sta->sta); + + return count; +} + +static ssize_t iwl_dbgfs_amsdu_len_read(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[32]; + int pos; + + pos = scnprintf(buf, sizeof(buf), "current %d ", + link_sta->agg.max_amsdu_len); + pos += scnprintf(buf + pos, sizeof(buf) - pos, "stored %d\n", + mvm_link_sta->orig_amsdu_len); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -452,205 +537,215 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } -#define BT_MBOX_MSG(_notif, _num, _field) \ - ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ - >> BT_MBOX##_num##_##_field##_POS) - - -#define BT_MBOX_PRINT(_num, _field, _end) \ - pos += scnprintf(buf + pos, bufsz - pos, \ - "\t%s: %d%s", \ - #_field, \ - BT_MBOX_MSG(notif, _num, _field), \ - true ? "\n" : ", "); - -static -int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, - int pos, int bufsz) -{ - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); - - BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); - BT_MBOX_PRINT(0, LE_PROF1, false); - BT_MBOX_PRINT(0, LE_PROF2, false); - BT_MBOX_PRINT(0, LE_PROF_OTHER, false); - BT_MBOX_PRINT(0, CHL_SEQ_N, false); - BT_MBOX_PRINT(0, INBAND_S, false); - BT_MBOX_PRINT(0, LE_MIN_RSSI, false); - BT_MBOX_PRINT(0, LE_SCAN, false); - BT_MBOX_PRINT(0, LE_ADV, false); - BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false); - BT_MBOX_PRINT(0, OPEN_CON_1, true); - - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n"); - - BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false); - BT_MBOX_PRINT(1, IP_SR, false); - BT_MBOX_PRINT(1, LE_MSTR, false); - BT_MBOX_PRINT(1, AGGR_TRFC_LD, false); - BT_MBOX_PRINT(1, MSG_TYPE, false); - BT_MBOX_PRINT(1, SSN, true); - - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n"); - - BT_MBOX_PRINT(2, SNIFF_ACT, false); - BT_MBOX_PRINT(2, PAG, false); - BT_MBOX_PRINT(2, INQUIRY, false); - BT_MBOX_PRINT(2, CONN, false); - BT_MBOX_PRINT(2, SNIFF_INTERVAL, false); - BT_MBOX_PRINT(2, DISC, false); - BT_MBOX_PRINT(2, SCO_TX_ACT, false); - BT_MBOX_PRINT(2, SCO_RX_ACT, false); - BT_MBOX_PRINT(2, ESCO_RE_TX, false); - BT_MBOX_PRINT(2, SCO_DURATION, true); - - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n"); - - BT_MBOX_PRINT(3, SCO_STATE, false); - BT_MBOX_PRINT(3, SNIFF_STATE, false); - BT_MBOX_PRINT(3, A2DP_STATE, false); - BT_MBOX_PRINT(3, ACL_STATE, false); - BT_MBOX_PRINT(3, MSTR_STATE, false); - BT_MBOX_PRINT(3, OBX_STATE, false); - BT_MBOX_PRINT(3, OPEN_CON_2, false); - BT_MBOX_PRINT(3, TRAFFIC_LOAD, false); - BT_MBOX_PRINT(3, CHL_SEQN_LSB, false); - BT_MBOX_PRINT(3, INBAND_P, false); - BT_MBOX_PRINT(3, MSG_TYPE_2, false); - BT_MBOX_PRINT(3, SSN_2, false); - BT_MBOX_PRINT(3, UPDATE_REQUEST, true); - - return pos; -} - -static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; - char *buf; - int ret, pos = 0, bufsz = sizeof(char) * 1024; - - buf = kmalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - mutex_lock(&mvm->mutex); - - pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz); - - pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n", - notif->bt_ci_compliance); - pos += scnprintf(buf + pos, bufsz - pos, "primary_ch_lut = %d\n", - le32_to_cpu(notif->primary_ch_lut)); - pos += scnprintf(buf + pos, bufsz - pos, "secondary_ch_lut = %d\n", - le32_to_cpu(notif->secondary_ch_lut)); - pos += scnprintf(buf + pos, - bufsz - pos, "bt_activity_grading = %d\n", - le32_to_cpu(notif->bt_activity_grading)); - pos += scnprintf(buf + pos, bufsz - pos, - "antenna isolation = %d CORUN LUT index = %d\n", - mvm->last_ant_isol, mvm->last_corun_lut); - pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n", - (notif->ttc_rrc_status >> 4) & 0xF); - pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n", - notif->ttc_rrc_status & 0xF); - - pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n", - IWL_MVM_BT_COEX_SYNC2SCO); - pos += scnprintf(buf + pos, bufsz - pos, "mplut = %d\n", - IWL_MVM_BT_COEX_MPLUT); - pos += scnprintf(buf + pos, bufsz - pos, "corunning = %d\n", - IWL_MVM_BT_COEX_CORUNNING); - - mutex_unlock(&mvm->mutex); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); + struct iwl_tas_status_resp *rsp = NULL; + static const size_t bufsz = 1024; + char *buff, *pos, *endpos; + const char * const tas_dis_reason[TAS_DISABLED_REASON_MAX] = { + [TAS_DISABLED_DUE_TO_BIOS] = + "Due To BIOS", + [TAS_DISABLED_DUE_TO_SAR_6DBM] = + "Due To SAR Limit Less Than 6 dBm", + [TAS_DISABLED_REASON_INVALID] = + "N/A", + [TAS_DISABLED_DUE_TO_TABLE_SOURCE_INVALID] = + "Due to table source invalid", + }; + const char * const tas_current_status[TAS_DYNA_STATUS_MAX] = { + [TAS_DYNA_INACTIVE] = "INACTIVE", + [TAS_DYNA_INACTIVE_MVM_MODE] = + "inactive due to mvm mode", + [TAS_DYNA_INACTIVE_TRIGGER_MODE] = + "inactive due to trigger mode", + [TAS_DYNA_INACTIVE_BLOCK_LISTED] = + "inactive due to block listed", + [TAS_DYNA_INACTIVE_UHB_NON_US] = + "inactive due to uhb non US", + [TAS_DYNA_ACTIVE] = "ACTIVE", + }; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(DEBUG_GROUP, GET_TAS_STATUS), + .flags = CMD_WANT_SKB, + .len = { 0, }, + .data = { NULL, }, + }; + int ret, i, tmp; + bool tas_enabled = false; + unsigned long dyn_status; - return ret; -} -#undef BT_MBOX_PRINT + if (!iwl_mvm_firmware_running(mvm)) + return -ENODEV; -static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; - char buf[256]; - int bufsz = sizeof(buf); - int pos = 0; + if (iwl_fw_lookup_notif_ver(mvm->fw, DEBUG_GROUP, GET_TAS_STATUS, + 0) != 3) + return -EOPNOTSUPP; mutex_lock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, "Channel inhibition CMD\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\tPrimary Channel Bitmap 0x%016llx\n", - le64_to_cpu(cmd->bt_primary_ci)); - pos += scnprintf(buf + pos, bufsz - pos, - "\tSecondary Channel Bitmap 0x%016llx\n", - le64_to_cpu(cmd->bt_secondary_ci)); - + ret = iwl_mvm_send_cmd(mvm, &hcmd); mutex_unlock(&mvm->mutex); + if (ret < 0) + return ret; - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} + buff = kzalloc(bufsz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + pos = buff; + endpos = pos + bufsz; -static ssize_t -iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - u32 bt_tx_prio; + rsp = (void *)hcmd.resp_pkt->data; - if (sscanf(buf, "%u", &bt_tx_prio) != 1) - return -EINVAL; - if (bt_tx_prio > 4) - return -EINVAL; + pos += scnprintf(pos, endpos - pos, "TAS Conclusion:\n"); + for (i = 0; i < rsp->in_dual_radio + 1; i++) { + if (rsp->tas_status_mac[i].dynamic_status & + BIT(TAS_DYNA_ACTIVE)) { + pos += scnprintf(pos, endpos - pos, "\tON for "); + switch (rsp->tas_status_mac[i].band) { + case PHY_BAND_5: + pos += scnprintf(pos, endpos - pos, "HB\n"); + break; + case PHY_BAND_24: + pos += scnprintf(pos, endpos - pos, "LB\n"); + break; + case PHY_BAND_6: + pos += scnprintf(pos, endpos - pos, "UHB\n"); + break; + default: + pos += scnprintf(pos, endpos - pos, + "Unsupported band (%d)\n", + rsp->tas_status_mac[i].band); + goto out; + } + tas_enabled = true; + } + } + if (!tas_enabled) + pos += scnprintf(pos, endpos - pos, "\tOFF\n"); + + pos += scnprintf(pos, endpos - pos, "TAS Report\n"); + pos += scnprintf(pos, endpos - pos, "TAS FW version: %d\n", + rsp->tas_fw_version); + pos += scnprintf(pos, endpos - pos, "Is UHB enabled for USA?: %s\n", + rsp->is_uhb_for_usa_enable ? "True" : "False"); + + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT)) + pos += scnprintf(pos, endpos - pos, + "Is UHB enabled for CANADA?: %s\n", + rsp->uhb_allowed_flags & + TAS_UHB_ALLOWED_CANADA ? "True" : "False"); + + pos += scnprintf(pos, endpos - pos, "Current MCC: 0x%x\n", + le16_to_cpu(rsp->curr_mcc)); + + pos += scnprintf(pos, endpos - pos, "Block list entries:"); + for (i = 0; i < IWL_WTAS_BLACK_LIST_MAX; i++) + pos += scnprintf(pos, endpos - pos, " 0x%x", + le16_to_cpu(rsp->block_list[i])); + + pos += scnprintf(pos, endpos - pos, "\nOEM name: %s\n", + dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); + pos += scnprintf(pos, endpos - pos, "\tVendor In Approved List: %s\n", + iwl_is_tas_approved() ? "YES" : "NO"); + pos += scnprintf(pos, endpos - pos, + "\tDo TAS Support Dual Radio?: %s\n", + rsp->in_dual_radio ? "TRUE" : "FALSE"); + + for (i = 0; i < rsp->in_dual_radio + 1; i++) { + if (rsp->tas_status_mac[i].static_status == 0) { + pos += scnprintf(pos, endpos - pos, + "Static status: disabled\n"); + pos += scnprintf(pos, endpos - pos, + "Static disabled reason: %s (0)\n", + tas_dis_reason[0]); + goto out; + } - mvm->bt_tx_prio = bt_tx_prio; + pos += scnprintf(pos, endpos - pos, "TAS status for "); + switch (rsp->tas_status_mac[i].band) { + case PHY_BAND_5: + pos += scnprintf(pos, endpos - pos, "High band\n"); + break; + case PHY_BAND_24: + pos += scnprintf(pos, endpos - pos, "Low band\n"); + break; + case PHY_BAND_6: + pos += scnprintf(pos, endpos - pos, + "Ultra high band\n"); + break; + default: + pos += scnprintf(pos, endpos - pos, + "Unsupported band (%d)\n", + rsp->tas_status_mac[i].band); + goto out; + } + pos += scnprintf(pos, endpos - pos, "Static status: %sabled\n", + rsp->tas_status_mac[i].static_status ? + "En" : "Dis"); + pos += scnprintf(pos, endpos - pos, + "\tStatic Disabled Reason: "); + if (rsp->tas_status_mac[i].static_dis_reason < TAS_DISABLED_REASON_MAX) + pos += scnprintf(pos, endpos - pos, "%s (%d)\n", + tas_dis_reason[rsp->tas_status_mac[i].static_dis_reason], + rsp->tas_status_mac[i].static_dis_reason); + else + pos += scnprintf(pos, endpos - pos, + "unsupported value (%d)\n", + rsp->tas_status_mac[i].static_dis_reason); + + pos += scnprintf(pos, endpos - pos, "Dynamic status:\n"); + dyn_status = (rsp->tas_status_mac[i].dynamic_status); + for_each_set_bit(tmp, &dyn_status, TAS_DYNA_STATUS_MAX) { + pos += scnprintf(pos, endpos - pos, "\t%s (%d)\n", + tas_current_status[tmp], tmp); + } - return count; + pos += scnprintf(pos, endpos - pos, + "Is near disconnection?: %s\n", + rsp->tas_status_mac[i].near_disconnection ? + "True" : "False"); + tmp = le16_to_cpu(rsp->tas_status_mac[i].max_reg_pwr_limit); + pos += scnprintf(pos, endpos - pos, + "Max. regulatory pwr limit (dBm): %d.%03d\n", + tmp / 8, 125 * (tmp % 8)); + tmp = le16_to_cpu(rsp->tas_status_mac[i].sar_limit); + pos += scnprintf(pos, endpos - pos, + "SAR limit (dBm): %d.%03d\n", + tmp / 8, 125 * (tmp % 8)); + } + +out: + ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); + kfree(buff); + iwl_free_resp(&hcmd); + return ret; } -static ssize_t -iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_phy_integration_ver_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - static const char * const modes_str[BT_FORCE_ANT_MAX] = { - [BT_FORCE_ANT_DIS] = "dis", - [BT_FORCE_ANT_AUTO] = "auto", - [BT_FORCE_ANT_BT] = "bt", - [BT_FORCE_ANT_WIFI] = "wifi", - }; - int ret, bt_force_ant_mode; - - for (bt_force_ant_mode = 0; - bt_force_ant_mode < ARRAY_SIZE(modes_str); - bt_force_ant_mode++) { - if (!strcmp(buf, modes_str[bt_force_ant_mode])) - break; - } - - if (bt_force_ant_mode >= ARRAY_SIZE(modes_str)) - return -EINVAL; + struct iwl_mvm *mvm = file->private_data; + char *buf; + size_t bufsz; + int pos; + ssize_t ret; - ret = 0; - mutex_lock(&mvm->mutex); - if (mvm->bt_force_ant_mode == bt_force_ant_mode) - goto out; + bufsz = mvm->fw->phy_integration_ver_len + 2; + buf = kmalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; - mvm->bt_force_ant_mode = bt_force_ant_mode; - IWL_DEBUG_COEX(mvm, "Force mode: %s\n", - modes_str[mvm->bt_force_ant_mode]); + pos = scnprintf(buf, bufsz, "%.*s\n", mvm->fw->phy_integration_ver_len, + mvm->fw->phy_integration_ver); - if (iwl_mvm_firmware_running(mvm)) - ret = iwl_mvm_send_bt_init_conf(mvm); - else - ret = 0; + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); -out: - mutex_unlock(&mvm->mutex); - return ret ?: count; + kfree(buf); + return ret; } #define PRINT_STATS_LE32(_struct, _memb) \ @@ -669,6 +764,13 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, char *buf; int ret; size_t bufsz; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(SYSTEM_GROUP, + SYSTEM_STATISTICS_CMD), + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver != IWL_FW_CMD_VER_UNKNOWN) + return -EOPNOTSUPP; if (iwl_mvm_has_new_rx_stats_api(mvm)) bufsz = ((sizeof(struct mvm_statistics_rx) / @@ -684,6 +786,9 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, mutex_lock(&mvm->mutex); + if (iwl_mvm_firmware_running(mvm)) + iwl_mvm_request_statistics(mvm, false); + pos += scnprintf(buf + pos, bufsz - pos, fmt_header, "Statistics_Rx - OFDM"); if (!iwl_mvm_has_new_rx_stats_api(mvm)) { @@ -845,6 +950,101 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, } #undef PRINT_STAT_LE32 +static ssize_t iwl_dbgfs_fw_system_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + char *buff, *pos, *endpos; + int ret; + size_t bufsz; + int i; + struct iwl_mvm_vif *mvmvif; + struct ieee80211_vif *vif; + struct iwl_mvm *mvm = file->private_data; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(SYSTEM_GROUP, + SYSTEM_STATISTICS_CMD), + IWL_FW_CMD_VER_UNKNOWN); + + /* in case of a wrong cmd version, allocate buffer only for error msg */ + bufsz = (cmd_ver == 1) ? 4096 : 64; + + buff = kzalloc(bufsz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + pos = buff; + endpos = pos + bufsz; + + if (cmd_ver != 1) { + pos += scnprintf(pos, endpos - pos, + "System stats not supported:%d\n", cmd_ver); + goto send_out; + } + + mutex_lock(&mvm->mutex); + if (iwl_mvm_firmware_running(mvm)) + iwl_mvm_request_statistics(mvm, false); + + for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) { + vif = iwl_mvm_rcu_dereference_vif_id(mvm, i, false); + if (!vif) + continue; + + if (vif->type == NL80211_IFTYPE_STATION) + break; + } + + if (i == NUM_MAC_INDEX_DRIVER || !vif) { + pos += scnprintf(pos, endpos - pos, "vif is NULL\n"); + goto release_send_out; + } + + mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (!mvmvif) { + pos += scnprintf(pos, endpos - pos, "mvmvif is NULL\n"); + goto release_send_out; + } + + for_each_mvm_vif_valid_link(mvmvif, i) { + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[i]; + + pos += scnprintf(pos, endpos - pos, + "link_id %d", i); + pos += scnprintf(pos, endpos - pos, + " num_beacons %d", + link_info->beacon_stats.num_beacons); + pos += scnprintf(pos, endpos - pos, + " accu_num_beacons %d", + link_info->beacon_stats.accu_num_beacons); + pos += scnprintf(pos, endpos - pos, + " avg_signal %d\n", + link_info->beacon_stats.avg_signal); + } + + pos += scnprintf(pos, endpos - pos, + "radio_stats.rx_time %lld\n", + mvm->radio_stats.rx_time); + pos += scnprintf(pos, endpos - pos, + "radio_stats.tx_time %lld\n", + mvm->radio_stats.tx_time); + pos += scnprintf(pos, endpos - pos, + "accu_radio_stats.rx_time %lld\n", + mvm->accu_radio_stats.rx_time); + pos += scnprintf(pos, endpos - pos, + "accu_radio_stats.tx_time %lld\n", + mvm->accu_radio_stats.tx_time); + +release_send_out: + mutex_unlock(&mvm->mutex); + +send_out: + ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); + kfree(buff); + + return ret; +} + static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, char __user *user_buf, size_t count, loff_t *ppos, @@ -899,7 +1099,10 @@ static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, continue; pos += scnprintf(pos, endpos - pos, "Rate[%d]: ", (int)(ARRAY_SIZE(stats->last_rates) - i)); - pos += rs_pretty_print_rate(pos, stats->last_rates[idx]); + pos += rs_pretty_print_rate_v1(pos, endpos - pos, + stats->last_rates[idx]); + if (pos < endpos - 1) + *pos++ = '\n'; } spin_unlock_bh(&mvm->drv_stats_lock); @@ -929,12 +1132,15 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, mutex_lock(&mvm->mutex); - /* allow one more restart that we're provoking here */ - if (mvm->fw_restart >= 0) - mvm->fw_restart++; + if (count == 6 && !strcmp(buf, "nolog\n")) { + set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); + mvm->trans->suppress_cmd_error_once = true; + } /* take the return value to make compiler happy - it will fail anyway */ - ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(LONG_GROUP, REPLY_ERROR), + 0, 0, NULL); mutex_unlock(&mvm->mutex); @@ -944,18 +1150,15 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret; - if (!iwl_mvm_firmware_running(mvm)) return -EIO; - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI); - if (ret) - return ret; + IWL_ERR(mvm, "Triggering an NMI from debugfs\n"); - iwl_force_nmi(mvm->trans); + if (count == 6 && !strcmp(buf, "nolog\n")) + set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); - iwl_mvm_unref(mvm, IWL_MVM_REF_NMI); + iwl_force_nmi(mvm->trans); return count; } @@ -976,9 +1179,7 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "A"); if (mvm->scan_rx_ant & ANT_B) pos += scnprintf(buf + pos, bufsz - pos, "B"); - if (mvm->scan_rx_ant & ANT_C) - pos += scnprintf(buf + pos, bufsz - pos, "C"); - pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant); + pos += scnprintf(buf + pos, bufsz - pos, " (%x)\n", mvm->scan_rx_ant); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1060,22 +1261,24 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { + struct iwl_op_mode *opmode = container_of((void *)mvm, + struct iwl_op_mode, + op_mode_specific); struct iwl_rx_cmd_buffer rxb = { ._rx_page_order = 0, .truesize = 0, /* not used */ ._offset = 0, }; struct iwl_rx_packet *pkt; - struct iwl_rx_mpdu_desc *desc; int bin_len = count / 2; int ret = -EINVAL; if (!iwl_mvm_firmware_running(mvm)) return -EIO; - /* supporting only 9000 descriptor */ - if (!mvm->trans->cfg->mq_rx_supported) - return -ENOTSUPP; + /* supporting only MQ RX */ + if (!mvm->trans->mac_cfg->mq_rx_supported) + return -EOPNOTSUPP; rxb._page = alloc_pages(GFP_ATOMIC, 0); if (!rxb._page) @@ -1086,23 +1289,13 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, if (ret) goto out; - /* avoid invalid memory access */ - if (bin_len < sizeof(*pkt) + sizeof(*desc)) - goto out; - - /* check this is RX packet */ - if (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd) != - WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)) - goto out; - - /* check the length in metadata matches actual received length */ - desc = (void *)pkt->data; - if (le16_to_cpu(desc->mpdu_len) != - (bin_len - sizeof(*desc) - sizeof(*pkt))) + /* avoid invalid memory access and malformed packet */ + if (bin_len < sizeof(*pkt) || + bin_len != sizeof(*pkt) + iwl_rx_packet_payload_len(pkt)) goto out; local_bh_disable(); - iwl_mvm_rx_mpdu_mq(mvm, NULL, &rxb, 0); + iwl_mvm_rx_mq(opmode, NULL, &rxb); local_bh_enable(); ret = 0; @@ -1112,64 +1305,139 @@ out: return ret ?: count; } -static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len) { - struct iwl_mvm *mvm = file->private_data; - int conf; - char buf[8]; - const size_t bufsz = sizeof(buf); - int pos = 0; + struct ieee80211_vif *vif; + struct iwl_mvm_vif *mvmvif; + struct sk_buff *beacon; + struct ieee80211_tx_info *info; + struct iwl_mac_beacon_cmd beacon_cmd = {}; + unsigned int link_id; + u8 rate; + int i; + + len /= 2; + + /* Element len should be represented by u8 */ + if (len >= U8_MAX) + return -EINVAL; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + if (!iwl_mvm_has_new_tx_api(mvm) && + !fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE)) + return -EINVAL; mutex_lock(&mvm->mutex); - conf = mvm->fw_dbg_conf; + + for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) { + vif = iwl_mvm_rcu_dereference_vif_id(mvm, i, false); + if (!vif) + continue; + + if (vif->type == NL80211_IFTYPE_AP) + break; + } + + if (i == NUM_MAC_INDEX_DRIVER || !vif) + goto out_err; + + mvm->hw->extra_beacon_tailroom = len; + + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL, 0); + if (!beacon) + goto out_err; + + if (len && hex2bin(skb_put_zero(beacon, len), bin, len)) { + dev_kfree_skb(beacon); + goto out_err; + } + + mvm->beacon_inject_active = true; + + mvmvif = iwl_mvm_vif_from_mac80211(vif); + info = IEEE80211_SKB_CB(beacon); + rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif); + + for_each_mvm_vif_valid_link(mvmvif, link_id) { + beacon_cmd.flags = + cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, + rate)); + beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len); + if (iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 12) + beacon_cmd.link_id = + cpu_to_le32(mvmvif->link[link_id]->fw_link_id); + else + beacon_cmd.link_id = cpu_to_le32((u32)mvmvif->id); + + iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx, + &beacon_cmd.tim_size, + beacon->data, beacon->len); + + if (iwl_fw_lookup_cmd_ver(mvm->fw, + BEACON_TEMPLATE_CMD, 0) >= 14) { + u32 offset = iwl_find_ie_offset(beacon->data, + WLAN_EID_S1G_TWT, + beacon->len); + + beacon_cmd.btwt_offset = cpu_to_le32(offset); + } + + iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd, + sizeof(beacon_cmd)); + } mutex_unlock(&mvm->mutex); - pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); + dev_kfree_skb(beacon); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return 0; + +out_err: + mutex_unlock(&mvm->mutex); + return -EINVAL; } -/* - * Enable / Disable continuous recording. - * Cause the FW to start continuous recording, by sending the relevant hcmd. - * Enable: input of every integer larger than 0, ENABLE_CONT_RECORDING. - * Disable: for 0 as input, DISABLE_CONT_RECORDING. - */ -static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm, - char *buf, size_t count, - loff_t *ppos) +static ssize_t iwl_dbgfs_inject_beacon_ie_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) { - struct iwl_trans *trans = mvm->trans; - const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv; - struct iwl_continuous_record_cmd cont_rec = {}; - int ret, rec_mode; + int ret = _iwl_dbgfs_inject_beacon_ie(mvm, buf, count); - if (!iwl_mvm_firmware_running(mvm)) - return -EIO; - - if (!dest) - return -EOPNOTSUPP; + mvm->hw->extra_beacon_tailroom = 0; + return ret ?: count; +} - if (dest->monitor_mode != SMEM_MODE || - trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) - return -EOPNOTSUPP; +static ssize_t iwl_dbgfs_inject_beacon_ie_restore_write(struct iwl_mvm *mvm, + char *buf, + size_t count, + loff_t *ppos) +{ + int ret = _iwl_dbgfs_inject_beacon_ie(mvm, NULL, 0); - ret = kstrtoint(buf, 0, &rec_mode); - if (ret) - return ret; + mvm->hw->extra_beacon_tailroom = 0; + mvm->beacon_inject_active = false; + return ret ?: count; +} - cont_rec.record_mode.enable_recording = rec_mode ? - cpu_to_le16(ENABLE_CONT_RECORDING) : - cpu_to_le16(DISABLE_CONT_RECORDING); +static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + int conf; + char buf[8]; + const size_t bufsz = sizeof(buf); + int pos = 0; mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, LDBG_CONFIG_CMD, 0, - sizeof(cont_rec), &cont_rec); + conf = mvm->fwrt.dump.conf; mutex_unlock(&mvm->mutex); - return ret ?: count; + pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, @@ -1190,451 +1458,452 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, return -EINVAL; mutex_lock(&mvm->mutex); - ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id); + ret = iwl_fw_start_dbg_conf(&mvm->fwrt, conf_id); mutex_unlock(&mvm->mutex); return ret ?: count; } -static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, - char *buf, size_t count, - loff_t *ppos) +static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) { - int ret; + if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_9000) + return -EOPNOTSUPP; + /* + * If the firmware is not running, silently succeed since there is + * no data to clear. + */ if (!iwl_mvm_firmware_running(mvm)) - return -EIO; - - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); - if (ret) - return ret; - if (count == 0) - return 0; - - iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf, - (count - 1), NULL); + return count; - iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); + mutex_lock(&mvm->mutex); + iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt); + mutex_unlock(&mvm->mutex); return count; } -static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm, - char *buf, size_t count, - loff_t *ppos) +static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) { - unsigned int max_amsdu_len; - int ret; + u32 timepoint; - ret = kstrtouint(buf, 0, &max_amsdu_len); - if (ret) - return ret; + if (kstrtou32(buf, 0, &timepoint)) + return -EINVAL; - if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454) + if (timepoint == IWL_FW_INI_TIME_POINT_INVALID || + timepoint >= IWL_FW_INI_TIME_POINT_NUM) return -EINVAL; - mvm->max_amsdu_len = max_amsdu_len; + + iwl_dbg_tlv_time_point(&mvm->fwrt, timepoint, NULL); return count; } -#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__) -#ifdef CONFIG_IWLWIFI_BCAST_FILTERING -static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) +#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) +#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ + debugfs_create_file(alias, mode, parent, mvm, \ + &iwl_dbgfs_##name##_ops); \ + } while (0) +#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ + MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) + +static ssize_t +_iwl_dbgfs_link_sta_wrap_write(ssize_t (*real)(struct ieee80211_link_sta *, + struct iwl_mvm_sta *, + struct iwl_mvm *, + struct iwl_mvm_link_sta *, + char *, + size_t, loff_t *), + struct file *file, + char *buf, size_t buf_size, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - struct iwl_bcast_filter_cmd cmd; - const struct iwl_fw_bcast_filter *filter; - char *buf; - int bufsz = 1024; - int i, j, pos = 0; + struct ieee80211_link_sta *link_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta); + struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm; + struct iwl_mvm_link_sta *mvm_link_sta; ssize_t ret; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - mutex_lock(&mvm->mutex); - if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { - ADD_TEXT("None\n"); + + mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id], + lockdep_is_held(&mvm->mutex)); + if (WARN_ON(!mvm_link_sta)) { mutex_unlock(&mvm->mutex); - goto out; + return -ENODEV; } - mutex_unlock(&mvm->mutex); - for (i = 0; cmd.filters[i].attrs[0].mask; i++) { - filter = &cmd.filters[i]; + ret = real(link_sta, mvmsta, mvm, mvm_link_sta, buf, buf_size, ppos); - ADD_TEXT("Filter [%d]:\n", i); - ADD_TEXT("\tDiscard=%d\n", filter->discard); - ADD_TEXT("\tFrame Type: %s\n", - filter->frame_type ? "IPv4" : "Generic"); - - for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) { - const struct iwl_fw_bcast_filter_attr *attr; - - attr = &filter->attrs[j]; - if (!attr->mask) - break; + mutex_unlock(&mvm->mutex); - ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n", - j, attr->offset, - attr->offset_type ? "IP End" : - "Payload Start", - be32_to_cpu(attr->mask), - be32_to_cpu(attr->val), - le16_to_cpu(attr->reserved1)); - } - } -out: - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); return ret; } -static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) +static ssize_t +_iwl_dbgfs_link_sta_wrap_read(ssize_t (*real)(struct ieee80211_link_sta *, + struct iwl_mvm_sta *, + struct iwl_mvm *, + struct iwl_mvm_link_sta *, + char __user *, + size_t, loff_t *), + struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) { - int pos, next_pos; - struct iwl_fw_bcast_filter filter = {}; - struct iwl_bcast_filter_cmd cmd; - u32 filter_id, attr_id, mask, value; - int err = 0; - - if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard, - &filter.frame_type, &pos) != 3) - return -EINVAL; + struct ieee80211_link_sta *link_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta); + struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm; + struct iwl_mvm_link_sta *mvm_link_sta; + ssize_t ret; - if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) || - filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4) - return -EINVAL; + mutex_lock(&mvm->mutex); - for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs); - attr_id++) { - struct iwl_fw_bcast_filter_attr *attr = - &filter.attrs[attr_id]; + mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id], + lockdep_is_held(&mvm->mutex)); + if (WARN_ON(!mvm_link_sta)) { + mutex_unlock(&mvm->mutex); + return -ENODEV; + } - if (pos >= count) - break; + ret = real(link_sta, mvmsta, mvm, mvm_link_sta, user_buf, count, ppos); - if (sscanf(&buf[pos], "%hhi %hhi %i %i %n", - &attr->offset, &attr->offset_type, - &mask, &value, &next_pos) != 4) - return -EINVAL; + mutex_unlock(&mvm->mutex); - attr->mask = cpu_to_be32(mask); - attr->val = cpu_to_be32(value); - if (mask) - filter.num_attrs++; + return ret; +} - pos += next_pos; - } +#define MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, buflen) \ +static ssize_t _iwl_dbgfs_link_sta_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + char buf[buflen] = {}; \ + size_t buf_size = min(count, sizeof(buf) - 1); \ + \ + if (copy_from_user(buf, user_buf, buf_size)) \ + return -EFAULT; \ + \ + return _iwl_dbgfs_link_sta_wrap_write(iwl_dbgfs_##name##_write, \ + file, \ + buf, buf_size, ppos); \ +} \ + +#define MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +static ssize_t _iwl_dbgfs_link_sta_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + return _iwl_dbgfs_link_sta_wrap_read(iwl_dbgfs_##name##_read, \ + file, \ + user_buf, count, ppos); \ +} \ + +#define MVM_DEBUGFS_WRITE_LINK_STA_FILE_OPS(name, bufsz) \ +MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .write = _iwl_dbgfs_link_sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} - mutex_lock(&mvm->mutex); - memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id], - &filter, sizeof(filter)); - - /* send updated bcast filtering configuration */ - if (iwl_mvm_firmware_running(mvm) && - mvm->dbgfs_bcast_filtering.override && - iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) - err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, - sizeof(cmd), &cmd); - mutex_unlock(&mvm->mutex); +#define MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(name) \ +MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .read = _iwl_dbgfs_link_sta_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} - return err ?: count; +#define MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(name, bufsz) \ +MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .read = _iwl_dbgfs_link_sta_##name##_read, \ + .write = _iwl_dbgfs_link_sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ } -static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +#define MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(alias, name, parent, mode) \ + debugfs_create_file(alias, mode, parent, link_sta, \ + &iwl_dbgfs_link_sta_##name##_ops) +#define MVM_DEBUGFS_ADD_LINK_STA_FILE(name, parent, mode) \ + MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(#name, name, parent, mode) + +static ssize_t +iwl_dbgfs_prph_reg_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - struct iwl_bcast_filter_cmd cmd; - char *buf; - int bufsz = 1024; - int i, pos = 0; - ssize_t ret; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; + int pos = 0; + char buf[32]; + const size_t bufsz = sizeof(buf); - mutex_lock(&mvm->mutex); - if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) { - ADD_TEXT("None\n"); - mutex_unlock(&mvm->mutex); - goto out; - } - mutex_unlock(&mvm->mutex); + if (!mvm->dbgfs_prph_reg_addr) + return -EINVAL; - for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) { - const struct iwl_fw_bcast_mac *mac = &cmd.macs[i]; + pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", + mvm->dbgfs_prph_reg_addr, + iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); - ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n", - i, mac->default_discard, mac->attached_filters); - } -out: - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm, - char *buf, size_t count, - loff_t *ppos) +static ssize_t +iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) { - struct iwl_bcast_filter_cmd cmd; - struct iwl_fw_bcast_mac mac = {}; - u32 mac_id, attached_filters; - int err = 0; + u8 args; + u32 value; - if (!mvm->bcast_filters) - return -ENOENT; + args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); + /* if we only want to set the reg address - nothing more to do */ + if (args == 1) + goto out; - if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard, - &attached_filters) != 3) + /* otherwise, make sure we have both address and value */ + if (args != 2) return -EINVAL; - if (mac_id >= ARRAY_SIZE(cmd.macs) || - mac.default_discard > 1 || - attached_filters >= BIT(ARRAY_SIZE(cmd.filters))) - return -EINVAL; + iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); - mac.attached_filters = cpu_to_le16(attached_filters); +out: + return count; +} + +static ssize_t +iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + int ret; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; mutex_lock(&mvm->mutex); - memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id], - &mac, sizeof(mac)); - - /* send updated bcast filtering configuration */ - if (iwl_mvm_firmware_running(mvm) && - mvm->dbgfs_bcast_filtering.override && - iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) - err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0, - sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL); mutex_unlock(&mvm->mutex); - return err ?: count; + return ret ?: count; } -#endif -#ifdef CONFIG_PM_SLEEP -static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - int store; +struct iwl_mvm_sniffer_apply { + struct iwl_mvm *mvm; + u8 *bssid; + u16 aid; +}; - if (sscanf(buf, "%d", &store) != 1) - return -EINVAL; +static bool iwl_mvm_sniffer_apply(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt, void *data) +{ + struct iwl_mvm_sniffer_apply *apply = data; - mvm->store_d3_resume_sram = store; + apply->mvm->cur_aid = cpu_to_le16(apply->aid); + memcpy(apply->mvm->cur_bssid, apply->bssid, + sizeof(apply->mvm->cur_bssid)); - return count; + return true; } -static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t +iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - const struct fw_img *img; - int ofs, len, pos = 0; - size_t bufsz, ret; - char *buf; - u8 *ptr = mvm->d3_resume_sram; + struct iwl_notification_wait wait; + struct iwl_he_monitor_cmd he_mon_cmd = {}; + struct iwl_mvm_sniffer_apply apply = { + .mvm = mvm, + }; + u16 wait_cmds[] = { + WIDE_ID(DATA_PATH_GROUP, HE_AIR_SNIFFER_CONFIG_CMD), + }; + u32 aid; + int ret; - img = &mvm->fw->img[IWL_UCODE_WOWLAN]; - len = img->sec[IWL_UCODE_SECTION_DATA].len; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; - bufsz = len * 4 + 256; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; + ret = sscanf(buf, "%x %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &aid, + &he_mon_cmd.bssid[0], &he_mon_cmd.bssid[1], + &he_mon_cmd.bssid[2], &he_mon_cmd.bssid[3], + &he_mon_cmd.bssid[4], &he_mon_cmd.bssid[5]); + if (ret != 7) + return -EINVAL; - pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n", - mvm->store_d3_resume_sram ? "en" : "dis"); + he_mon_cmd.aid = cpu_to_le16(aid); - if (ptr) { - for (ofs = 0; ofs < len; ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, - "0x%.4x %16ph\n", ofs, ptr + ofs); - } - } else { - pos += scnprintf(buf + pos, bufsz - pos, - "(no data captured)\n"); - } + apply.aid = aid; + apply.bssid = (void *)he_mon_cmd.bssid; - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + mutex_lock(&mvm->mutex); - kfree(buf); + /* + * Use the notification waiter to get our function triggered + * in sequence with other RX. This ensures that frames we get + * on the RX queue _before_ the new configuration is applied + * still have mvm->cur_aid pointing to the old AID, and that + * frames on the RX queue _after_ the firmware processed the + * new configuration (and sent the response, synchronously) + * get mvm->cur_aid correctly set to the new AID. + */ + iwl_init_notification_wait(&mvm->notif_wait, &wait, + wait_cmds, ARRAY_SIZE(wait_cmds), + iwl_mvm_sniffer_apply, &apply); - return ret; -} -#endif + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(DATA_PATH_GROUP, HE_AIR_SNIFFER_CONFIG_CMD), + 0, + sizeof(he_mon_cmd), &he_mon_cmd); -#define PRINT_MVM_REF(ref) do { \ - if (mvm->refs[ref]) \ - pos += scnprintf(buf + pos, bufsz - pos, \ - "\t(0x%lx): %d %s\n", \ - BIT(ref), mvm->refs[ref], #ref); \ -} while (0) + /* no need to really wait, we already did anyway */ + iwl_remove_notification(&mvm->notif_wait, &wait); -static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t +iwl_dbgfs_he_sniffer_params_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; - int i, pos = 0; - char buf[256]; - const size_t bufsz = sizeof(buf); - u32 refs = 0; - - for (i = 0; i < IWL_MVM_REF_COUNT; i++) - if (mvm->refs[i]) - refs |= BIT(i); - - pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n", - refs); - - PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN); - PRINT_MVM_REF(IWL_MVM_REF_SCAN); - PRINT_MVM_REF(IWL_MVM_REF_ROC); - PRINT_MVM_REF(IWL_MVM_REF_ROC_AUX); - PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT); - PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS); - PRINT_MVM_REF(IWL_MVM_REF_USER); - PRINT_MVM_REF(IWL_MVM_REF_TX); - PRINT_MVM_REF(IWL_MVM_REF_TX_AGG); - PRINT_MVM_REF(IWL_MVM_REF_ADD_IF); - PRINT_MVM_REF(IWL_MVM_REF_START_AP); - PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED); - PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX); - PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS); - PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL); - PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ); - PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE); - PRINT_MVM_REF(IWL_MVM_REF_NMI); - PRINT_MVM_REF(IWL_MVM_REF_TM_CMD); - PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK); - PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA); - PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT); - PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE); - PRINT_MVM_REF(IWL_MVM_REF_SENDING_CMD); - PRINT_MVM_REF(IWL_MVM_REF_RX); + u8 buf[32]; + int len; - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + len = scnprintf(buf, sizeof(buf), + "%d %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", + le16_to_cpu(mvm->cur_aid), mvm->cur_bssid[0], + mvm->cur_bssid[1], mvm->cur_bssid[2], mvm->cur_bssid[3], + mvm->cur_bssid[4], mvm->cur_bssid[5]); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) +static ssize_t +iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { - unsigned long value; - int ret; - bool taken; - - ret = kstrtoul(buf, 10, &value); - if (ret < 0) - return ret; + struct iwl_mvm *mvm = file->private_data; + u8 buf[IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM * ETH_ALEN * 3 + 1]; + unsigned int pos = 0; + size_t bufsz = sizeof(buf); + int i; mutex_lock(&mvm->mutex); - taken = mvm->refs[IWL_MVM_REF_USER]; - if (value == 1 && !taken) - iwl_mvm_ref(mvm, IWL_MVM_REF_USER); - else if (value == 0 && taken) - iwl_mvm_unref(mvm, IWL_MVM_REF_USER); - else - ret = -EINVAL; + for (i = 0; i < IWL_MVM_UAPSD_NOAGG_LIST_LEN; i++) + pos += scnprintf(buf + pos, bufsz - pos, "%pM\n", + mvm->uapsd_noagg_bssids[i].addr); mutex_unlock(&mvm->mutex); - if (ret < 0) - return ret; - return count; + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ - _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) -#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ - _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm) -#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ - if (!debugfs_create_file(alias, mode, parent, mvm, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ - } while (0) -#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ - MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) - static ssize_t -iwl_dbgfs_prph_reg_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +iwl_dbgfs_ltr_config_write(struct iwl_mvm *mvm, + char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm *mvm = file->private_data; - int pos = 0; - char buf[32]; - const size_t bufsz = sizeof(buf); int ret; + struct iwl_ltr_config_cmd ltr_config = {0}; - if (!mvm->dbgfs_prph_reg_addr) - return -EINVAL; + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ); - if (ret) - return ret; + if (sscanf(buf, "%x,%x,%x,%x,%x,%x,%x", + <r_config.flags, + <r_config.static_long, + <r_config.static_short, + <r_config.ltr_cfg_values[0], + <r_config.ltr_cfg_values[1], + <r_config.ltr_cfg_values[2], + <r_config.ltr_cfg_values[3]) != 7) { + return -EINVAL; + } - pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", - mvm->dbgfs_prph_reg_addr, - iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); + mutex_lock(&mvm->mutex); + ret = iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, sizeof(ltr_config), + <r_config); + mutex_unlock(&mvm->mutex); - iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ); + if (ret) + IWL_ERR(mvm, "failed to send ltr configuration cmd\n"); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + return ret ?: count; } -static ssize_t -iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_rfi_freq_table_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) { - u8 args; - u32 value; - int ret; - - args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); - /* if we only want to set the reg address - nothing more to do */ - if (args == 1) - goto out; + int ret = 0; + u16 op_id; - /* otherwise, make sure we have both address and value */ - if (args != 2) + if (kstrtou16(buf, 10, &op_id)) return -EINVAL; - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE); - if (ret) - return ret; - - iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); + /* value zero triggers re-sending the default table to the device */ + if (!op_id) { + mutex_lock(&mvm->mutex); + ret = iwl_rfi_send_config_cmd(mvm, NULL); + mutex_unlock(&mvm->mutex); + } else { + ret = -EOPNOTSUPP; /* in the future a new table will be added */ + } - iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); -out: - return count; + return ret ?: count; } -static ssize_t -iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) +/* The size computation is as follows: + * each number needs at most 3 characters, number of rows is the size of + * the table; So, need 5 chars for the "freq: " part and each tuple afterwards + * needs 6 characters for numbers and 5 for the punctuation around. + */ +#define IWL_RFI_BUF_SIZE (IWL_RFI_LUT_INSTALLED_SIZE *\ + (5 + IWL_RFI_LUT_ENTRY_CHANNELS_NUM * (6 + 5))) + +static ssize_t iwl_dbgfs_rfi_freq_table_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { - int ret; + struct iwl_mvm *mvm = file->private_data; + struct iwl_rfi_freq_table_resp_cmd *resp; + u32 status; + char buf[IWL_RFI_BUF_SIZE]; + int i, j, pos = 0; - if (!iwl_mvm_firmware_running(mvm)) - return -EIO; + resp = iwl_rfi_get_freq_table(mvm); + if (IS_ERR(resp)) + return PTR_ERR(resp); - mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL); - mutex_unlock(&mvm->mutex); + status = le32_to_cpu(resp->status); + if (status != RFI_FREQ_TABLE_OK) { + scnprintf(buf, IWL_RFI_BUF_SIZE, "status = %d\n", status); + goto out; + } - return ret ?: count; + for (i = 0; i < ARRAY_SIZE(resp->table); i++) { + pos += scnprintf(buf + pos, IWL_RFI_BUF_SIZE - pos, "%d: ", + resp->table[i].freq); + + for (j = 0; j < ARRAY_SIZE(resp->table[i].channels); j++) + pos += scnprintf(buf + pos, IWL_RFI_BUF_SIZE - pos, + "(%d, %d) ", + resp->table[i].channels[j], + resp->table[i].bands[j]); + pos += scnprintf(buf + pos, IWL_RFI_BUF_SIZE - pos, "\n"); + } + +out: + kfree(resp); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); @@ -1642,44 +1911,47 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget); MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(start_ctdp, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(force_ctkill, 8); MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); -MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); MVM_DEBUGFS_READ_FILE_OPS(nic_temp); MVM_DEBUGFS_READ_FILE_OPS(stations); -MVM_DEBUGFS_READ_FILE_OPS(bt_notif); -MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); +MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(rs_data); MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); +MVM_DEBUGFS_READ_FILE_OPS(fw_system_stats); +MVM_DEBUGFS_READ_FILE_OPS(phy_integration_ver); +MVM_DEBUGFS_READ_FILE_OPS(tas_get_status); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); -MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); -MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); -MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_clear, 64); +MVM_DEBUGFS_WRITE_FILE_OPS(dbg_time_point, 64); MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512); +MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie, 512); +MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512); -#ifdef CONFIG_IWLWIFI_BCAST_FILTERING -MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); -#endif +MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids); -#ifdef CONFIG_PM_SLEEP -MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); -#endif #ifdef CONFIG_ACPI MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); +MVM_DEBUGFS_READ_FILE_OPS(wifi_6e_enable); #endif +MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(amsdu_len, 16); + +MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32); + +MVM_DEBUGFS_WRITE_FILE_OPS(ltr_config, 512); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(rfi_freq_table, 16); + static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1697,8 +1969,7 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, if (!iwl_mvm_firmware_running(mvm)) return -EIO; - hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR, - DEBUG_GROUP, 0); + hcmd.id = WIDE_ID(DEBUG_GROUP, *ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR); cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ); /* Take care of alignment of both the position and the length */ @@ -1714,6 +1985,11 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, if (ret < 0) return ret; + if (iwl_rx_packet_payload_len(hcmd.resp_pkt) < sizeof(*rsp)) { + ret = -EIO; + goto out; + } + rsp = (void *)hcmd.resp_pkt->data; if (le32_to_cpu(rsp->status) != DEBUG_MEM_STATUS_SUCCESS) { ret = -ENXIO; @@ -1728,7 +2004,7 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, goto out; } - ret = len - copy_to_user(user_buf, (void *)rsp->data + delta, len); + ret = len - copy_to_user(user_buf, (u8 *)rsp->data + delta, len); *ppos += ret; out: @@ -1752,8 +2028,7 @@ static ssize_t iwl_dbgfs_mem_write(struct file *file, if (!iwl_mvm_firmware_running(mvm)) return -EIO; - hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR, - DEBUG_GROUP, 0); + hcmd.id = WIDE_ID(DEBUG_GROUP, *ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR); if (*ppos & 0x3 || count < 4) { op = DEBUG_MEM_OP_WRITE_BYTES; @@ -1791,6 +2066,11 @@ static ssize_t iwl_dbgfs_mem_write(struct file *file, if (ret < 0) return ret; + if (iwl_rx_packet_payload_len(hcmd.resp_pkt) < sizeof(*rsp)) { + ret = -EIO; + goto out; + } + rsp = (void *)hcmd.resp_pkt->data; if (rsp->status != DEBUG_MEM_STATUS_SUCCESS) { ret = -ENXIO; @@ -1812,120 +2092,109 @@ static const struct file_operations iwl_dbgfs_mem_ops = { .llseek = default_llseek, }; -int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) +void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct dentry *dir) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + if (iwl_mvm_has_tlc_offload(mvm)) { + MVM_DEBUGFS_ADD_LINK_STA_FILE(rs_data, dir, 0400); + } + + MVM_DEBUGFS_ADD_LINK_STA_FILE(amsdu_len, dir, 0600); +} + +void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) { struct dentry *bcast_dir __maybe_unused; - char buf[100]; spin_lock_init(&mvm->drv_stats_lock); - mvm->debugfs_dir = dbgfs_dir; - - MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, - S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, - S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, - S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(nic_temp, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(ctdp_budget, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(stop_ctdp, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(start_ctdp, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(force_ctkill, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(stations, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(fw_system_stats, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(fw_dbg_clear, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(dbg_time_point, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(inject_beacon_ie, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(rfi_freq_table, mvm->debugfs_dir, 0600); + + if (mvm->fw->phy_integration_ver) + MVM_DEBUGFS_ADD_FILE(phy_integration_ver, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(tas_get_status, mvm->debugfs_dir, 0400); #ifdef CONFIG_ACPI - MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(sar_geo_profile, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(wifi_6e_enable, mvm->debugfs_dir, 0400); #endif + MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0600); - if (!debugfs_create_bool("enable_scan_iteration_notif", - S_IRUSR | S_IWUSR, - mvm->debugfs_dir, - &mvm->scan_iter_notif_enabled)) - goto err; - if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR, - mvm->debugfs_dir, &mvm->drop_bcn_ap_mode)) - goto err; - -#ifdef CONFIG_IWLWIFI_BCAST_FILTERING - if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) { - bcast_dir = debugfs_create_dir("bcast_filtering", - mvm->debugfs_dir); - if (!bcast_dir) - goto err; - - if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR, - bcast_dir, - &mvm->dbgfs_bcast_filtering.override)) - goto err; - - MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters, - bcast_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs, - bcast_dir, S_IWUSR | S_IRUSR); - } -#endif + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_LTR_GEN2)) + MVM_DEBUGFS_ADD_FILE(ltr_config, mvm->debugfs_dir, 0200); + + debugfs_create_bool("enable_scan_iteration_notif", 0600, + mvm->debugfs_dir, &mvm->scan_iter_notif_enabled); + debugfs_create_bool("drop_bcn_ap_mode", 0600, mvm->debugfs_dir, + &mvm->drop_bcn_ap_mode); + + MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR); #ifdef CONFIG_PM_SLEEP - MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); - if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, - mvm->debugfs_dir, &mvm->d3_wake_sysassert)) - goto err; - if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR, - mvm->debugfs_dir, &mvm->last_netdetect_scans)) - goto err; + debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir, + &mvm->d3_wake_sysassert); + debugfs_create_u32("last_netdetect_scans", 0400, mvm->debugfs_dir, + &mvm->last_netdetect_scans); #endif - if (!debugfs_create_u8("ps_disabled", S_IRUSR, - mvm->debugfs_dir, &mvm->ps_disabled)) - goto err; - if (!debugfs_create_blob("nvm_hw", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_hw_blob)) - goto err; - if (!debugfs_create_blob("nvm_sw", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_sw_blob)) - goto err; - if (!debugfs_create_blob("nvm_calib", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_calib_blob)) - goto err; - if (!debugfs_create_blob("nvm_prod", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_prod_blob)) - goto err; - if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_phy_sku_blob)) - goto err; - - debugfs_create_file("mem", S_IRUSR | S_IWUSR, dbgfs_dir, mvm, + debugfs_create_u8("ps_disabled", 0400, mvm->debugfs_dir, + &mvm->ps_disabled); + debugfs_create_blob("nvm_hw", 0400, mvm->debugfs_dir, + &mvm->nvm_hw_blob); + debugfs_create_blob("nvm_sw", 0400, mvm->debugfs_dir, + &mvm->nvm_sw_blob); + debugfs_create_blob("nvm_calib", 0400, mvm->debugfs_dir, + &mvm->nvm_calib_blob); + debugfs_create_blob("nvm_prod", 0400, mvm->debugfs_dir, + &mvm->nvm_prod_blob); + debugfs_create_blob("nvm_phy_sku", 0400, mvm->debugfs_dir, + &mvm->nvm_phy_sku_blob); + debugfs_create_blob("nvm_reg", S_IRUSR, + mvm->debugfs_dir, &mvm->nvm_reg_blob); + + debugfs_create_file("mem", 0600, mvm->debugfs_dir, mvm, &iwl_dbgfs_mem_ops); + debugfs_create_bool("rx_ts_ptp", 0600, mvm->debugfs_dir, + &mvm->rx_ts_ptp); + /* * Create a symlink with mac80211. It will be removed when mac80211 * exists (before the opmode exists which removes the target.) */ - snprintf(buf, 100, "../../%pd2", dbgfs_dir->d_parent); - if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf)) - goto err; + if (!IS_ERR(mvm->debugfs_dir)) { + char buf[100]; - return 0; -err: - IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); - return -ENOMEM; + snprintf(buf, 100, "../../%pd2", mvm->debugfs_dir->d_parent); + debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, + buf); + } } |
