18c2ecf20Sopenharmony_ci/****************************************************************************** 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 98c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 108c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 138c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 148c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 198c2ecf20Sopenharmony_ci * General Public License for more details. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 228c2ecf20Sopenharmony_ci * in the file called COPYING. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Contact Information: 258c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 268c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * BSD LICENSE 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 318c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 328c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 338c2ecf20Sopenharmony_ci * All rights reserved. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 368c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 378c2ecf20Sopenharmony_ci * are met: 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 408c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 418c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 428c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 438c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 448c2ecf20Sopenharmony_ci * distribution. 458c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 468c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 478c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 508c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 518c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 528c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 538c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 548c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 558c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 568c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 578c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 588c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 598c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci *****************************************************************************/ 628c2ecf20Sopenharmony_ci#include "mvm.h" 638c2ecf20Sopenharmony_ci#include "debugfs.h" 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, 668c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 678c2ecf20Sopenharmony_ci enum iwl_dbgfs_pm_mask param, int val) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 708c2ecf20Sopenharmony_ci struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci dbgfs_pm->mask |= param; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci switch (param) { 758c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_KEEP_ALIVE: { 768c2ecf20Sopenharmony_ci int dtimper = vif->bss_conf.dtim_period ?: 1; 778c2ecf20Sopenharmony_ci int dtimper_msec = dtimper * vif->bss_conf.beacon_int; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); 808c2ecf20Sopenharmony_ci if (val * MSEC_PER_SEC < 3 * dtimper_msec) 818c2ecf20Sopenharmony_ci IWL_WARN(mvm, 828c2ecf20Sopenharmony_ci "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n", 838c2ecf20Sopenharmony_ci val * MSEC_PER_SEC, 3 * dtimper_msec); 848c2ecf20Sopenharmony_ci dbgfs_pm->keep_alive_seconds = val; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_SKIP_OVER_DTIM: 888c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n", 898c2ecf20Sopenharmony_ci val ? "enabled" : "disabled"); 908c2ecf20Sopenharmony_ci dbgfs_pm->skip_over_dtim = val; 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS: 938c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val); 948c2ecf20Sopenharmony_ci dbgfs_pm->skip_dtim_periods = val; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT: 978c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val); 988c2ecf20Sopenharmony_ci dbgfs_pm->rx_data_timeout = val; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT: 1018c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val); 1028c2ecf20Sopenharmony_ci dbgfs_pm->tx_data_timeout = val; 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_LPRX_ENA: 1058c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled"); 1068c2ecf20Sopenharmony_ci dbgfs_pm->lprx_ena = val; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD: 1098c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); 1108c2ecf20Sopenharmony_ci dbgfs_pm->lprx_rssi_threshold = val; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_SNOOZE_ENABLE: 1138c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val); 1148c2ecf20Sopenharmony_ci dbgfs_pm->snooze_ena = val; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING: 1178c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val); 1188c2ecf20Sopenharmony_ci dbgfs_pm->uapsd_misbehaving = val; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case MVM_DEBUGFS_PM_USE_PS_POLL: 1218c2ecf20Sopenharmony_ci IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val); 1228c2ecf20Sopenharmony_ci dbgfs_pm->use_ps_poll = val; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, 1288c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1318c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 1328c2ecf20Sopenharmony_ci enum iwl_dbgfs_pm_mask param; 1338c2ecf20Sopenharmony_ci int val, ret; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!strncmp("keep_alive=", buf, 11)) { 1368c2ecf20Sopenharmony_ci if (sscanf(buf + 11, "%d", &val) != 1) 1378c2ecf20Sopenharmony_ci return -EINVAL; 1388c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_KEEP_ALIVE; 1398c2ecf20Sopenharmony_ci } else if (!strncmp("skip_over_dtim=", buf, 15)) { 1408c2ecf20Sopenharmony_ci if (sscanf(buf + 15, "%d", &val) != 1) 1418c2ecf20Sopenharmony_ci return -EINVAL; 1428c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM; 1438c2ecf20Sopenharmony_ci } else if (!strncmp("skip_dtim_periods=", buf, 18)) { 1448c2ecf20Sopenharmony_ci if (sscanf(buf + 18, "%d", &val) != 1) 1458c2ecf20Sopenharmony_ci return -EINVAL; 1468c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS; 1478c2ecf20Sopenharmony_ci } else if (!strncmp("rx_data_timeout=", buf, 16)) { 1488c2ecf20Sopenharmony_ci if (sscanf(buf + 16, "%d", &val) != 1) 1498c2ecf20Sopenharmony_ci return -EINVAL; 1508c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT; 1518c2ecf20Sopenharmony_ci } else if (!strncmp("tx_data_timeout=", buf, 16)) { 1528c2ecf20Sopenharmony_ci if (sscanf(buf + 16, "%d", &val) != 1) 1538c2ecf20Sopenharmony_ci return -EINVAL; 1548c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; 1558c2ecf20Sopenharmony_ci } else if (!strncmp("lprx=", buf, 5)) { 1568c2ecf20Sopenharmony_ci if (sscanf(buf + 5, "%d", &val) != 1) 1578c2ecf20Sopenharmony_ci return -EINVAL; 1588c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_LPRX_ENA; 1598c2ecf20Sopenharmony_ci } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) { 1608c2ecf20Sopenharmony_ci if (sscanf(buf + 20, "%d", &val) != 1) 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val < 1638c2ecf20Sopenharmony_ci POWER_LPRX_RSSI_THRESHOLD_MIN) 1648c2ecf20Sopenharmony_ci return -EINVAL; 1658c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; 1668c2ecf20Sopenharmony_ci } else if (!strncmp("snooze_enable=", buf, 14)) { 1678c2ecf20Sopenharmony_ci if (sscanf(buf + 14, "%d", &val) != 1) 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_SNOOZE_ENABLE; 1708c2ecf20Sopenharmony_ci } else if (!strncmp("uapsd_misbehaving=", buf, 18)) { 1718c2ecf20Sopenharmony_ci if (sscanf(buf + 18, "%d", &val) != 1) 1728c2ecf20Sopenharmony_ci return -EINVAL; 1738c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING; 1748c2ecf20Sopenharmony_ci } else if (!strncmp("use_ps_poll=", buf, 12)) { 1758c2ecf20Sopenharmony_ci if (sscanf(buf + 12, "%d", &val) != 1) 1768c2ecf20Sopenharmony_ci return -EINVAL; 1778c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_PM_USE_PS_POLL; 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci return -EINVAL; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 1838c2ecf20Sopenharmony_ci iwl_dbgfs_update_pm(mvm, vif, param, val); 1848c2ecf20Sopenharmony_ci ret = iwl_mvm_power_update_mac(mvm); 1858c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return ret ?: count; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file, 1918c2ecf20Sopenharmony_ci char __user *user_buf, 1928c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 1958c2ecf20Sopenharmony_ci char buf[64]; 1968c2ecf20Sopenharmony_ci int bufsz = sizeof(buf); 1978c2ecf20Sopenharmony_ci int pos; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci pos = scnprintf(buf, bufsz, "bss limit = %d\n", 2008c2ecf20Sopenharmony_ci vif->bss_conf.txpower); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_pm_params_read(struct file *file, 2068c2ecf20Sopenharmony_ci char __user *user_buf, 2078c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 2108c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2118c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 2128c2ecf20Sopenharmony_ci char buf[512]; 2138c2ecf20Sopenharmony_ci int bufsz = sizeof(buf); 2148c2ecf20Sopenharmony_ci int pos; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_mac_params_read(struct file *file, 2228c2ecf20Sopenharmony_ci char __user *user_buf, 2238c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 2268c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2278c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 2288c2ecf20Sopenharmony_ci u8 ap_sta_id; 2298c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 2308c2ecf20Sopenharmony_ci char buf[512]; 2318c2ecf20Sopenharmony_ci int bufsz = sizeof(buf); 2328c2ecf20Sopenharmony_ci int pos = 0; 2338c2ecf20Sopenharmony_ci int i; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ap_sta_id = mvmvif->ap_sta_id; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci switch (ieee80211_vif_type_p2p(vif)) { 2408c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 2418c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n"); 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 2448c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n"); 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 2478c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n"); 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 2508c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n"); 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 2538c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n"); 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 2568c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n"); 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci default: 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", 2638c2ecf20Sopenharmony_ci mvmvif->id, mvmvif->color); 2648c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", 2658c2ecf20Sopenharmony_ci vif->bss_conf.bssid); 2668c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n", 2678c2ecf20Sopenharmony_ci mvm->tcm.result.load[mvmvif->id]); 2688c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); 2698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) 2708c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, 2718c2ecf20Sopenharmony_ci "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", 2728c2ecf20Sopenharmony_ci i, mvmvif->queue_params[i].txop, 2738c2ecf20Sopenharmony_ci mvmvif->queue_params[i].cw_min, 2748c2ecf20Sopenharmony_ci mvmvif->queue_params[i].cw_max, 2758c2ecf20Sopenharmony_ci mvmvif->queue_params[i].aifs, 2768c2ecf20Sopenharmony_ci mvmvif->queue_params[i].uapsd); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && 2798c2ecf20Sopenharmony_ci ap_sta_id != IWL_MVM_INVALID_STA) { 2808c2ecf20Sopenharmony_ci struct iwl_mvm_sta *mvm_sta; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); 2838c2ecf20Sopenharmony_ci if (mvm_sta) { 2848c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, 2858c2ecf20Sopenharmony_ci "ap_sta_id %d - reduced Tx power %d\n", 2868c2ecf20Sopenharmony_ci ap_sta_id, 2878c2ecf20Sopenharmony_ci mvm_sta->bt_reduced_txpower); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci rcu_read_lock(); 2928c2ecf20Sopenharmony_ci chanctx_conf = rcu_dereference(vif->chanctx_conf); 2938c2ecf20Sopenharmony_ci if (chanctx_conf) 2948c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, 2958c2ecf20Sopenharmony_ci "idle rx chains %d, active rx chains: %d\n", 2968c2ecf20Sopenharmony_ci chanctx_conf->rx_chains_static, 2978c2ecf20Sopenharmony_ci chanctx_conf->rx_chains_dynamic); 2988c2ecf20Sopenharmony_ci rcu_read_unlock(); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, 3068c2ecf20Sopenharmony_ci enum iwl_dbgfs_bf_mask param, int value) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 3098c2ecf20Sopenharmony_ci struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci dbgfs_bf->mask |= param; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci switch (param) { 3148c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_ENERGY_DELTA: 3158c2ecf20Sopenharmony_ci dbgfs_bf->bf_energy_delta = value; 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA: 3188c2ecf20Sopenharmony_ci dbgfs_bf->bf_roaming_energy_delta = value; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_ROAMING_STATE: 3218c2ecf20Sopenharmony_ci dbgfs_bf->bf_roaming_state = value; 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_TEMP_THRESHOLD: 3248c2ecf20Sopenharmony_ci dbgfs_bf->bf_temp_threshold = value; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_TEMP_FAST_FILTER: 3278c2ecf20Sopenharmony_ci dbgfs_bf->bf_temp_fast_filter = value; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER: 3308c2ecf20Sopenharmony_ci dbgfs_bf->bf_temp_slow_filter = value; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: 3338c2ecf20Sopenharmony_ci dbgfs_bf->bf_enable_beacon_filter = value; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_DEBUG_FLAG: 3368c2ecf20Sopenharmony_ci dbgfs_bf->bf_debug_flag = value; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BF_ESCAPE_TIMER: 3398c2ecf20Sopenharmony_ci dbgfs_bf->bf_escape_timer = value; 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT: 3428c2ecf20Sopenharmony_ci dbgfs_bf->ba_enable_beacon_abort = value; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci case MVM_DEBUGFS_BA_ESCAPE_TIMER: 3458c2ecf20Sopenharmony_ci dbgfs_bf->ba_escape_timer = value; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf, 3518c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 3548c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 3558c2ecf20Sopenharmony_ci enum iwl_dbgfs_bf_mask param; 3568c2ecf20Sopenharmony_ci int value, ret = 0; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!strncmp("bf_energy_delta=", buf, 16)) { 3598c2ecf20Sopenharmony_ci if (sscanf(buf+16, "%d", &value) != 1) 3608c2ecf20Sopenharmony_ci return -EINVAL; 3618c2ecf20Sopenharmony_ci if (value < IWL_BF_ENERGY_DELTA_MIN || 3628c2ecf20Sopenharmony_ci value > IWL_BF_ENERGY_DELTA_MAX) 3638c2ecf20Sopenharmony_ci return -EINVAL; 3648c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_ENERGY_DELTA; 3658c2ecf20Sopenharmony_ci } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) { 3668c2ecf20Sopenharmony_ci if (sscanf(buf+24, "%d", &value) != 1) 3678c2ecf20Sopenharmony_ci return -EINVAL; 3688c2ecf20Sopenharmony_ci if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN || 3698c2ecf20Sopenharmony_ci value > IWL_BF_ROAMING_ENERGY_DELTA_MAX) 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA; 3728c2ecf20Sopenharmony_ci } else if (!strncmp("bf_roaming_state=", buf, 17)) { 3738c2ecf20Sopenharmony_ci if (sscanf(buf+17, "%d", &value) != 1) 3748c2ecf20Sopenharmony_ci return -EINVAL; 3758c2ecf20Sopenharmony_ci if (value < IWL_BF_ROAMING_STATE_MIN || 3768c2ecf20Sopenharmony_ci value > IWL_BF_ROAMING_STATE_MAX) 3778c2ecf20Sopenharmony_ci return -EINVAL; 3788c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_ROAMING_STATE; 3798c2ecf20Sopenharmony_ci } else if (!strncmp("bf_temp_threshold=", buf, 18)) { 3808c2ecf20Sopenharmony_ci if (sscanf(buf+18, "%d", &value) != 1) 3818c2ecf20Sopenharmony_ci return -EINVAL; 3828c2ecf20Sopenharmony_ci if (value < IWL_BF_TEMP_THRESHOLD_MIN || 3838c2ecf20Sopenharmony_ci value > IWL_BF_TEMP_THRESHOLD_MAX) 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_TEMP_THRESHOLD; 3868c2ecf20Sopenharmony_ci } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) { 3878c2ecf20Sopenharmony_ci if (sscanf(buf+20, "%d", &value) != 1) 3888c2ecf20Sopenharmony_ci return -EINVAL; 3898c2ecf20Sopenharmony_ci if (value < IWL_BF_TEMP_FAST_FILTER_MIN || 3908c2ecf20Sopenharmony_ci value > IWL_BF_TEMP_FAST_FILTER_MAX) 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER; 3938c2ecf20Sopenharmony_ci } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) { 3948c2ecf20Sopenharmony_ci if (sscanf(buf+20, "%d", &value) != 1) 3958c2ecf20Sopenharmony_ci return -EINVAL; 3968c2ecf20Sopenharmony_ci if (value < IWL_BF_TEMP_SLOW_FILTER_MIN || 3978c2ecf20Sopenharmony_ci value > IWL_BF_TEMP_SLOW_FILTER_MAX) 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER; 4008c2ecf20Sopenharmony_ci } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { 4018c2ecf20Sopenharmony_ci if (sscanf(buf+24, "%d", &value) != 1) 4028c2ecf20Sopenharmony_ci return -EINVAL; 4038c2ecf20Sopenharmony_ci if (value < 0 || value > 1) 4048c2ecf20Sopenharmony_ci return -EINVAL; 4058c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER; 4068c2ecf20Sopenharmony_ci } else if (!strncmp("bf_debug_flag=", buf, 14)) { 4078c2ecf20Sopenharmony_ci if (sscanf(buf+14, "%d", &value) != 1) 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci if (value < 0 || value > 1) 4108c2ecf20Sopenharmony_ci return -EINVAL; 4118c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_DEBUG_FLAG; 4128c2ecf20Sopenharmony_ci } else if (!strncmp("bf_escape_timer=", buf, 16)) { 4138c2ecf20Sopenharmony_ci if (sscanf(buf+16, "%d", &value) != 1) 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci if (value < IWL_BF_ESCAPE_TIMER_MIN || 4168c2ecf20Sopenharmony_ci value > IWL_BF_ESCAPE_TIMER_MAX) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BF_ESCAPE_TIMER; 4198c2ecf20Sopenharmony_ci } else if (!strncmp("ba_escape_timer=", buf, 16)) { 4208c2ecf20Sopenharmony_ci if (sscanf(buf+16, "%d", &value) != 1) 4218c2ecf20Sopenharmony_ci return -EINVAL; 4228c2ecf20Sopenharmony_ci if (value < IWL_BA_ESCAPE_TIMER_MIN || 4238c2ecf20Sopenharmony_ci value > IWL_BA_ESCAPE_TIMER_MAX) 4248c2ecf20Sopenharmony_ci return -EINVAL; 4258c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BA_ESCAPE_TIMER; 4268c2ecf20Sopenharmony_ci } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) { 4278c2ecf20Sopenharmony_ci if (sscanf(buf+23, "%d", &value) != 1) 4288c2ecf20Sopenharmony_ci return -EINVAL; 4298c2ecf20Sopenharmony_ci if (value < 0 || value > 1) 4308c2ecf20Sopenharmony_ci return -EINVAL; 4318c2ecf20Sopenharmony_ci param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT; 4328c2ecf20Sopenharmony_ci } else { 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 4378c2ecf20Sopenharmony_ci iwl_dbgfs_update_bf(vif, param, value); 4388c2ecf20Sopenharmony_ci if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) 4398c2ecf20Sopenharmony_ci ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); 4408c2ecf20Sopenharmony_ci else 4418c2ecf20Sopenharmony_ci ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); 4428c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return ret ?: count; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_bf_params_read(struct file *file, 4488c2ecf20Sopenharmony_ci char __user *user_buf, 4498c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 4528c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 4538c2ecf20Sopenharmony_ci char buf[256]; 4548c2ecf20Sopenharmony_ci int pos = 0; 4558c2ecf20Sopenharmony_ci const size_t bufsz = sizeof(buf); 4568c2ecf20Sopenharmony_ci struct iwl_beacon_filter_cmd cmd = { 4578c2ecf20Sopenharmony_ci IWL_BF_CMD_CONFIG_DEFAULTS, 4588c2ecf20Sopenharmony_ci .bf_enable_beacon_filter = 4598c2ecf20Sopenharmony_ci cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT), 4608c2ecf20Sopenharmony_ci .ba_enable_beacon_abort = 4618c2ecf20Sopenharmony_ci cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT), 4628c2ecf20Sopenharmony_ci }; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 4658c2ecf20Sopenharmony_ci if (mvmvif->bf_data.bf_enabled) 4668c2ecf20Sopenharmony_ci cmd.bf_enable_beacon_filter = cpu_to_le32(1); 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci cmd.bf_enable_beacon_filter = 0; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", 4718c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_energy_delta)); 4728c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", 4738c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_roaming_energy_delta)); 4748c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", 4758c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_roaming_state)); 4768c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n", 4778c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_temp_threshold)); 4788c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n", 4798c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_temp_fast_filter)); 4808c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n", 4818c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_temp_slow_filter)); 4828c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", 4838c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_enable_beacon_filter)); 4848c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", 4858c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_debug_flag)); 4868c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", 4878c2ecf20Sopenharmony_ci le32_to_cpu(cmd.bf_escape_timer)); 4888c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", 4898c2ecf20Sopenharmony_ci le32_to_cpu(cmd.ba_escape_timer)); 4908c2ecf20Sopenharmony_ci pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", 4918c2ecf20Sopenharmony_ci le32_to_cpu(cmd.ba_enable_beacon_abort)); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic inline char *iwl_dbgfs_is_match(char *name, char *buf) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci int len = strlen(name); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return !strncmp(name, buf, len) ? buf + len : NULL; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, 5048c2ecf20Sopenharmony_ci char __user *user_buf, 5058c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 5088c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 5098c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 5108c2ecf20Sopenharmony_ci u32 curr_gp2; 5118c2ecf20Sopenharmony_ci u64 curr_os; 5128c2ecf20Sopenharmony_ci s64 diff; 5138c2ecf20Sopenharmony_ci char buf[64]; 5148c2ecf20Sopenharmony_ci const size_t bufsz = sizeof(buf); 5158c2ecf20Sopenharmony_ci int pos = 0; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 5188c2ecf20Sopenharmony_ci iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os); 5198c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci do_div(curr_os, NSEC_PER_USEC); 5228c2ecf20Sopenharmony_ci diff = curr_os - curr_gp2; 5238c2ecf20Sopenharmony_ci pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, 5298c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 5328c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 5338c2ecf20Sopenharmony_ci u8 value; 5348c2ecf20Sopenharmony_ci int ret; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci ret = kstrtou8(buf, 0, &value); 5378c2ecf20Sopenharmony_ci if (ret) 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci if (value > 1) 5408c2ecf20Sopenharmony_ci return -EINVAL; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 5438c2ecf20Sopenharmony_ci iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS); 5448c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci return count; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic ssize_t 5508c2ecf20Sopenharmony_ciiwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, 5518c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 5548c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 5558c2ecf20Sopenharmony_ci u8 value; 5568c2ecf20Sopenharmony_ci int ret; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = kstrtou8(buf, 0, &value); 5598c2ecf20Sopenharmony_ci if (ret) 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (value > NUM_LOW_LATENCY_FORCE) 5638c2ecf20Sopenharmony_ci return -EINVAL; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 5668c2ecf20Sopenharmony_ci if (value == LOW_LATENCY_FORCE_UNSET) { 5678c2ecf20Sopenharmony_ci iwl_mvm_update_low_latency(mvm, vif, false, 5688c2ecf20Sopenharmony_ci LOW_LATENCY_DEBUGFS_FORCE); 5698c2ecf20Sopenharmony_ci iwl_mvm_update_low_latency(mvm, vif, false, 5708c2ecf20Sopenharmony_ci LOW_LATENCY_DEBUGFS_FORCE_ENABLE); 5718c2ecf20Sopenharmony_ci } else { 5728c2ecf20Sopenharmony_ci iwl_mvm_update_low_latency(mvm, vif, 5738c2ecf20Sopenharmony_ci value == LOW_LATENCY_FORCE_ON, 5748c2ecf20Sopenharmony_ci LOW_LATENCY_DEBUGFS_FORCE); 5758c2ecf20Sopenharmony_ci iwl_mvm_update_low_latency(mvm, vif, true, 5768c2ecf20Sopenharmony_ci LOW_LATENCY_DEBUGFS_FORCE_ENABLE); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 5798c2ecf20Sopenharmony_ci return count; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_low_latency_read(struct file *file, 5838c2ecf20Sopenharmony_ci char __user *user_buf, 5848c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 5878c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 5888c2ecf20Sopenharmony_ci char format[] = "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n" 5898c2ecf20Sopenharmony_ci "dbgfs_force_enable=%d\ndbgfs_force=%d\nactual=%d\n"; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* 5928c2ecf20Sopenharmony_ci * all values in format are boolean so the size of format is enough 5938c2ecf20Sopenharmony_ci * for holding the result string 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci char buf[sizeof(format) + 1] = {}; 5968c2ecf20Sopenharmony_ci int len; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf) - 1, format, 5998c2ecf20Sopenharmony_ci !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC), 6008c2ecf20Sopenharmony_ci !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS), 6018c2ecf20Sopenharmony_ci !!(mvmvif->low_latency & LOW_LATENCY_VCMD), 6028c2ecf20Sopenharmony_ci !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE), 6038c2ecf20Sopenharmony_ci !!(mvmvif->low_latency & 6048c2ecf20Sopenharmony_ci LOW_LATENCY_DEBUGFS_FORCE_ENABLE), 6058c2ecf20Sopenharmony_ci !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE), 6068c2ecf20Sopenharmony_ci !!(mvmvif->low_latency_actual)); 6078c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, 6118c2ecf20Sopenharmony_ci char __user *user_buf, 6128c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 6158c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 6168c2ecf20Sopenharmony_ci char buf[20]; 6178c2ecf20Sopenharmony_ci int len; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); 6208c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, 6248c2ecf20Sopenharmony_ci char *buf, size_t count, 6258c2ecf20Sopenharmony_ci loff_t *ppos) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 6288c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 6298c2ecf20Sopenharmony_ci bool ret; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 6328c2ecf20Sopenharmony_ci ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); 6338c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return ret ? count : -EINVAL; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, 6398c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 6428c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 6438c2ecf20Sopenharmony_ci struct ieee80211_chanctx_conf *chanctx_conf; 6448c2ecf20Sopenharmony_ci struct iwl_mvm_phy_ctxt *phy_ctxt; 6458c2ecf20Sopenharmony_ci u16 value; 6468c2ecf20Sopenharmony_ci int ret; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ret = kstrtou16(buf, 0, &value); 6498c2ecf20Sopenharmony_ci if (ret) 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 6538c2ecf20Sopenharmony_ci rcu_read_lock(); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci chanctx_conf = rcu_dereference(vif->chanctx_conf); 6568c2ecf20Sopenharmony_ci /* make sure the channel context is assigned */ 6578c2ecf20Sopenharmony_ci if (!chanctx_conf) { 6588c2ecf20Sopenharmony_ci rcu_read_unlock(); 6598c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 6608c2ecf20Sopenharmony_ci return -EINVAL; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; 6648c2ecf20Sopenharmony_ci rcu_read_unlock(); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci mvm->dbgfs_rx_phyinfo = value; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, 6698c2ecf20Sopenharmony_ci chanctx_conf->rx_chains_static, 6708c2ecf20Sopenharmony_ci chanctx_conf->rx_chains_dynamic); 6718c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return ret ?: count; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, 6778c2ecf20Sopenharmony_ci char __user *user_buf, 6788c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 6818c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 6828c2ecf20Sopenharmony_ci char buf[8]; 6838c2ecf20Sopenharmony_ci int len; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "0x%04x\n", 6868c2ecf20Sopenharmony_ci mvmvif->mvm->dbgfs_rx_phyinfo); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic void iwl_dbgfs_quota_check(void *data, u8 *mac, 6928c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 6958c2ecf20Sopenharmony_ci int *ret = data; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (mvmvif->dbgfs_quota_min) 6988c2ecf20Sopenharmony_ci *ret = -EINVAL; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf, 7028c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 7058c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = mvmvif->mvm; 7068c2ecf20Sopenharmony_ci u16 value; 7078c2ecf20Sopenharmony_ci int ret; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci ret = kstrtou16(buf, 0, &value); 7108c2ecf20Sopenharmony_ci if (ret) 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (value > 95) 7148c2ecf20Sopenharmony_ci return -EINVAL; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci mutex_lock(&mvm->mutex); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci mvmvif->dbgfs_quota_min = 0; 7198c2ecf20Sopenharmony_ci ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 7208c2ecf20Sopenharmony_ci iwl_dbgfs_quota_check, &ret); 7218c2ecf20Sopenharmony_ci if (ret == 0) { 7228c2ecf20Sopenharmony_ci mvmvif->dbgfs_quota_min = value; 7238c2ecf20Sopenharmony_ci iwl_mvm_update_quotas(mvm, false, NULL); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci mutex_unlock(&mvm->mutex); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return ret ?: count; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic ssize_t iwl_dbgfs_quota_min_read(struct file *file, 7318c2ecf20Sopenharmony_ci char __user *user_buf, 7328c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct ieee80211_vif *vif = file->private_data; 7358c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 7368c2ecf20Sopenharmony_ci char buf[10]; 7378c2ecf20Sopenharmony_ci int len; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, count, ppos, buf, len); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 7458c2ecf20Sopenharmony_ci _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 7468c2ecf20Sopenharmony_ci#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ 7478c2ecf20Sopenharmony_ci _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 7488c2ecf20Sopenharmony_ci#define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ 7498c2ecf20Sopenharmony_ci debugfs_create_file(#name, mode, parent, vif, \ 7508c2ecf20Sopenharmony_ci &iwl_dbgfs_##name##_ops); \ 7518c2ecf20Sopenharmony_ci } while (0) 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_FILE_OPS(mac_params); 7548c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); 7558c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); 7568c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); 7578c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); 7588c2ecf20Sopenharmony_ciMVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10); 7598c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); 7608c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); 7618c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); 7628c2ecf20Sopenharmony_ciMVM_DEBUGFS_READ_FILE_OPS(os_device_timediff); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_civoid iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct dentry *dbgfs_dir = vif->debugfs_dir; 7688c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 7698c2ecf20Sopenharmony_ci char buf[100]; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* 7728c2ecf20Sopenharmony_ci * Check if debugfs directory already exist before creating it. 7738c2ecf20Sopenharmony_ci * This may happen when, for example, resetting hw or suspend-resume 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci if (!dbgfs_dir || mvmvif->dbgfs_dir) 7768c2ecf20Sopenharmony_ci return; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); 7798c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) { 7808c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n", 7818c2ecf20Sopenharmony_ci dbgfs_dir); 7828c2ecf20Sopenharmony_ci return; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && 7868c2ecf20Sopenharmony_ci ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || 7878c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_STATION && vif->p2p))) 7888c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400); 7918c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400); 7928c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600); 7938c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600); 7948c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600); 7958c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600); 7968c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600); 7978c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && 8008c2ecf20Sopenharmony_ci mvmvif == mvm->bf_allowed_vif) 8018c2ecf20Sopenharmony_ci MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* 8048c2ecf20Sopenharmony_ci * Create symlink for convenience pointing to interface specific 8058c2ecf20Sopenharmony_ci * debugfs entries for the driver. For example, under 8068c2ecf20Sopenharmony_ci * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ 8078c2ecf20Sopenharmony_ci * find 8088c2ecf20Sopenharmony_ci * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_ci snprintf(buf, 100, "../../../%pd3/%pd", 8118c2ecf20Sopenharmony_ci dbgfs_dir, 8128c2ecf20Sopenharmony_ci mvmvif->dbgfs_dir); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, 8158c2ecf20Sopenharmony_ci mvm->debugfs_dir, buf); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_civoid iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci debugfs_remove(mvmvif->dbgfs_slink); 8238c2ecf20Sopenharmony_ci mvmvif->dbgfs_slink = NULL; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci debugfs_remove_recursive(mvmvif->dbgfs_dir); 8268c2ecf20Sopenharmony_ci mvmvif->dbgfs_dir = NULL; 8278c2ecf20Sopenharmony_ci} 828