192daf3a6SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 292daf3a6SBjoern A. Zeeb /* 392daf3a6SBjoern A. Zeeb * Copyright (C) 2012-2014, 2018-2021 Intel Corporation 492daf3a6SBjoern A. Zeeb * Copyright (C) 2013-2015 Intel Mobile Communications GmbH 592daf3a6SBjoern A. Zeeb * Copyright (C) 2016-2017 Intel Deutschland GmbH 692daf3a6SBjoern A. Zeeb */ 792daf3a6SBjoern A. Zeeb #include "mvm.h" 892daf3a6SBjoern A. Zeeb #include "debugfs.h" 992daf3a6SBjoern A. Zeeb #if defined(__FreeBSD__) 1092daf3a6SBjoern A. Zeeb #include <linux/math64.h> 1192daf3a6SBjoern A. Zeeb #endif 1292daf3a6SBjoern A. Zeeb 1392daf3a6SBjoern A. Zeeb static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, 1492daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif, 1592daf3a6SBjoern A. Zeeb enum iwl_dbgfs_pm_mask param, int val) 1692daf3a6SBjoern A. Zeeb { 1792daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1892daf3a6SBjoern A. Zeeb struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm; 1992daf3a6SBjoern A. Zeeb 2092daf3a6SBjoern A. Zeeb dbgfs_pm->mask |= param; 2192daf3a6SBjoern A. Zeeb 2292daf3a6SBjoern A. Zeeb switch (param) { 2392daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_KEEP_ALIVE: { 2492daf3a6SBjoern A. Zeeb int dtimper = vif->bss_conf.dtim_period ?: 1; 2592daf3a6SBjoern A. Zeeb int dtimper_msec = dtimper * vif->bss_conf.beacon_int; 2692daf3a6SBjoern A. Zeeb 2792daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); 2892daf3a6SBjoern A. Zeeb if (val * MSEC_PER_SEC < 3 * dtimper_msec) 2992daf3a6SBjoern A. Zeeb IWL_WARN(mvm, 3092daf3a6SBjoern A. Zeeb "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n", 3192daf3a6SBjoern A. Zeeb val * MSEC_PER_SEC, 3 * dtimper_msec); 3292daf3a6SBjoern A. Zeeb dbgfs_pm->keep_alive_seconds = val; 3392daf3a6SBjoern A. Zeeb break; 3492daf3a6SBjoern A. Zeeb } 3592daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_SKIP_OVER_DTIM: 3692daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n", 3792daf3a6SBjoern A. Zeeb val ? "enabled" : "disabled"); 3892daf3a6SBjoern A. Zeeb dbgfs_pm->skip_over_dtim = val; 3992daf3a6SBjoern A. Zeeb break; 4092daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS: 4192daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val); 4292daf3a6SBjoern A. Zeeb dbgfs_pm->skip_dtim_periods = val; 4392daf3a6SBjoern A. Zeeb break; 4492daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT: 4592daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val); 4692daf3a6SBjoern A. Zeeb dbgfs_pm->rx_data_timeout = val; 4792daf3a6SBjoern A. Zeeb break; 4892daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT: 4992daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val); 5092daf3a6SBjoern A. Zeeb dbgfs_pm->tx_data_timeout = val; 5192daf3a6SBjoern A. Zeeb break; 5292daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_LPRX_ENA: 5392daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled"); 5492daf3a6SBjoern A. Zeeb dbgfs_pm->lprx_ena = val; 5592daf3a6SBjoern A. Zeeb break; 5692daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD: 5792daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val); 5892daf3a6SBjoern A. Zeeb dbgfs_pm->lprx_rssi_threshold = val; 5992daf3a6SBjoern A. Zeeb break; 6092daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_SNOOZE_ENABLE: 6192daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val); 6292daf3a6SBjoern A. Zeeb dbgfs_pm->snooze_ena = val; 6392daf3a6SBjoern A. Zeeb break; 6492daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING: 6592daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val); 6692daf3a6SBjoern A. Zeeb dbgfs_pm->uapsd_misbehaving = val; 6792daf3a6SBjoern A. Zeeb break; 6892daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_PM_USE_PS_POLL: 6992daf3a6SBjoern A. Zeeb IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val); 7092daf3a6SBjoern A. Zeeb dbgfs_pm->use_ps_poll = val; 7192daf3a6SBjoern A. Zeeb break; 7292daf3a6SBjoern A. Zeeb } 7392daf3a6SBjoern A. Zeeb } 7492daf3a6SBjoern A. Zeeb 7592daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf, 7692daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 7792daf3a6SBjoern A. Zeeb { 7892daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 7992daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 8092daf3a6SBjoern A. Zeeb enum iwl_dbgfs_pm_mask param; 8192daf3a6SBjoern A. Zeeb int val, ret; 8292daf3a6SBjoern A. Zeeb 8392daf3a6SBjoern A. Zeeb if (!strncmp("keep_alive=", buf, 11)) { 8492daf3a6SBjoern A. Zeeb if (sscanf(buf + 11, "%d", &val) != 1) 8592daf3a6SBjoern A. Zeeb return -EINVAL; 8692daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_KEEP_ALIVE; 8792daf3a6SBjoern A. Zeeb } else if (!strncmp("skip_over_dtim=", buf, 15)) { 8892daf3a6SBjoern A. Zeeb if (sscanf(buf + 15, "%d", &val) != 1) 8992daf3a6SBjoern A. Zeeb return -EINVAL; 9092daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM; 9192daf3a6SBjoern A. Zeeb } else if (!strncmp("skip_dtim_periods=", buf, 18)) { 9292daf3a6SBjoern A. Zeeb if (sscanf(buf + 18, "%d", &val) != 1) 9392daf3a6SBjoern A. Zeeb return -EINVAL; 9492daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS; 9592daf3a6SBjoern A. Zeeb } else if (!strncmp("rx_data_timeout=", buf, 16)) { 9692daf3a6SBjoern A. Zeeb if (sscanf(buf + 16, "%d", &val) != 1) 9792daf3a6SBjoern A. Zeeb return -EINVAL; 9892daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT; 9992daf3a6SBjoern A. Zeeb } else if (!strncmp("tx_data_timeout=", buf, 16)) { 10092daf3a6SBjoern A. Zeeb if (sscanf(buf + 16, "%d", &val) != 1) 10192daf3a6SBjoern A. Zeeb return -EINVAL; 10292daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; 10392daf3a6SBjoern A. Zeeb } else if (!strncmp("lprx=", buf, 5)) { 10492daf3a6SBjoern A. Zeeb if (sscanf(buf + 5, "%d", &val) != 1) 10592daf3a6SBjoern A. Zeeb return -EINVAL; 10692daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_LPRX_ENA; 10792daf3a6SBjoern A. Zeeb } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) { 10892daf3a6SBjoern A. Zeeb if (sscanf(buf + 20, "%d", &val) != 1) 10992daf3a6SBjoern A. Zeeb return -EINVAL; 11092daf3a6SBjoern A. Zeeb if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val < 11192daf3a6SBjoern A. Zeeb POWER_LPRX_RSSI_THRESHOLD_MIN) 11292daf3a6SBjoern A. Zeeb return -EINVAL; 11392daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD; 11492daf3a6SBjoern A. Zeeb } else if (!strncmp("snooze_enable=", buf, 14)) { 11592daf3a6SBjoern A. Zeeb if (sscanf(buf + 14, "%d", &val) != 1) 11692daf3a6SBjoern A. Zeeb return -EINVAL; 11792daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_SNOOZE_ENABLE; 11892daf3a6SBjoern A. Zeeb } else if (!strncmp("uapsd_misbehaving=", buf, 18)) { 11992daf3a6SBjoern A. Zeeb if (sscanf(buf + 18, "%d", &val) != 1) 12092daf3a6SBjoern A. Zeeb return -EINVAL; 12192daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING; 12292daf3a6SBjoern A. Zeeb } else if (!strncmp("use_ps_poll=", buf, 12)) { 12392daf3a6SBjoern A. Zeeb if (sscanf(buf + 12, "%d", &val) != 1) 12492daf3a6SBjoern A. Zeeb return -EINVAL; 12592daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_PM_USE_PS_POLL; 12692daf3a6SBjoern A. Zeeb } else { 12792daf3a6SBjoern A. Zeeb return -EINVAL; 12892daf3a6SBjoern A. Zeeb } 12992daf3a6SBjoern A. Zeeb 13092daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 13192daf3a6SBjoern A. Zeeb iwl_dbgfs_update_pm(mvm, vif, param, val); 13292daf3a6SBjoern A. Zeeb ret = iwl_mvm_power_update_mac(mvm); 13392daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 13492daf3a6SBjoern A. Zeeb 13592daf3a6SBjoern A. Zeeb return ret ?: count; 13692daf3a6SBjoern A. Zeeb } 13792daf3a6SBjoern A. Zeeb 13892daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file, 13992daf3a6SBjoern A. Zeeb char __user *user_buf, 14092daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 14192daf3a6SBjoern A. Zeeb { 14292daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 14392daf3a6SBjoern A. Zeeb char buf[64]; 14492daf3a6SBjoern A. Zeeb int bufsz = sizeof(buf); 14592daf3a6SBjoern A. Zeeb int pos; 14692daf3a6SBjoern A. Zeeb 14792daf3a6SBjoern A. Zeeb pos = scnprintf(buf, bufsz, "bss limit = %d\n", 14892daf3a6SBjoern A. Zeeb vif->bss_conf.txpower); 14992daf3a6SBjoern A. Zeeb 15092daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 15192daf3a6SBjoern A. Zeeb } 15292daf3a6SBjoern A. Zeeb 15392daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_pm_params_read(struct file *file, 15492daf3a6SBjoern A. Zeeb char __user *user_buf, 15592daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 15692daf3a6SBjoern A. Zeeb { 15792daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 15892daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 15992daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 16092daf3a6SBjoern A. Zeeb char buf[512]; 16192daf3a6SBjoern A. Zeeb int bufsz = sizeof(buf); 16292daf3a6SBjoern A. Zeeb int pos; 16392daf3a6SBjoern A. Zeeb 16492daf3a6SBjoern A. Zeeb pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz); 16592daf3a6SBjoern A. Zeeb 16692daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 16792daf3a6SBjoern A. Zeeb } 16892daf3a6SBjoern A. Zeeb 16992daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_mac_params_read(struct file *file, 17092daf3a6SBjoern A. Zeeb char __user *user_buf, 17192daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 17292daf3a6SBjoern A. Zeeb { 17392daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 17492daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 17592daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 17692daf3a6SBjoern A. Zeeb u8 ap_sta_id; 17792daf3a6SBjoern A. Zeeb struct ieee80211_chanctx_conf *chanctx_conf; 17892daf3a6SBjoern A. Zeeb char buf[512]; 17992daf3a6SBjoern A. Zeeb int bufsz = sizeof(buf); 18092daf3a6SBjoern A. Zeeb int pos = 0; 18192daf3a6SBjoern A. Zeeb int i; 18292daf3a6SBjoern A. Zeeb 18392daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 18492daf3a6SBjoern A. Zeeb 18592daf3a6SBjoern A. Zeeb ap_sta_id = mvmvif->ap_sta_id; 18692daf3a6SBjoern A. Zeeb 18792daf3a6SBjoern A. Zeeb switch (ieee80211_vif_type_p2p(vif)) { 18892daf3a6SBjoern A. Zeeb case NL80211_IFTYPE_ADHOC: 18992daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n"); 19092daf3a6SBjoern A. Zeeb break; 19192daf3a6SBjoern A. Zeeb case NL80211_IFTYPE_STATION: 19292daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n"); 19392daf3a6SBjoern A. Zeeb break; 19492daf3a6SBjoern A. Zeeb case NL80211_IFTYPE_AP: 19592daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n"); 19692daf3a6SBjoern A. Zeeb break; 19792daf3a6SBjoern A. Zeeb case NL80211_IFTYPE_P2P_CLIENT: 19892daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n"); 19992daf3a6SBjoern A. Zeeb break; 20092daf3a6SBjoern A. Zeeb case NL80211_IFTYPE_P2P_GO: 20192daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n"); 20292daf3a6SBjoern A. Zeeb break; 20392daf3a6SBjoern A. Zeeb case NL80211_IFTYPE_P2P_DEVICE: 20492daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n"); 20592daf3a6SBjoern A. Zeeb break; 20692daf3a6SBjoern A. Zeeb default: 20792daf3a6SBjoern A. Zeeb break; 20892daf3a6SBjoern A. Zeeb } 20992daf3a6SBjoern A. Zeeb 21092daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n", 21192daf3a6SBjoern A. Zeeb mvmvif->id, mvmvif->color); 21292daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n", 21392daf3a6SBjoern A. Zeeb vif->bss_conf.bssid); 21492daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n", 21592daf3a6SBjoern A. Zeeb mvm->tcm.result.load[mvmvif->id]); 21692daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n"); 21792daf3a6SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) 21892daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, 21992daf3a6SBjoern A. Zeeb "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n", 22092daf3a6SBjoern A. Zeeb i, mvmvif->queue_params[i].txop, 22192daf3a6SBjoern A. Zeeb mvmvif->queue_params[i].cw_min, 22292daf3a6SBjoern A. Zeeb mvmvif->queue_params[i].cw_max, 22392daf3a6SBjoern A. Zeeb mvmvif->queue_params[i].aifs, 22492daf3a6SBjoern A. Zeeb mvmvif->queue_params[i].uapsd); 22592daf3a6SBjoern A. Zeeb 22692daf3a6SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && 22792daf3a6SBjoern A. Zeeb ap_sta_id != IWL_MVM_INVALID_STA) { 22892daf3a6SBjoern A. Zeeb struct iwl_mvm_sta *mvm_sta; 22992daf3a6SBjoern A. Zeeb 23092daf3a6SBjoern A. Zeeb mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); 23192daf3a6SBjoern A. Zeeb if (mvm_sta) { 23292daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, 23392daf3a6SBjoern A. Zeeb "ap_sta_id %d - reduced Tx power %d\n", 23492daf3a6SBjoern A. Zeeb ap_sta_id, 23592daf3a6SBjoern A. Zeeb mvm_sta->bt_reduced_txpower); 23692daf3a6SBjoern A. Zeeb } 23792daf3a6SBjoern A. Zeeb } 23892daf3a6SBjoern A. Zeeb 23992daf3a6SBjoern A. Zeeb rcu_read_lock(); 24092daf3a6SBjoern A. Zeeb chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); 24192daf3a6SBjoern A. Zeeb if (chanctx_conf) 24292daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, 24392daf3a6SBjoern A. Zeeb "idle rx chains %d, active rx chains: %d\n", 24492daf3a6SBjoern A. Zeeb chanctx_conf->rx_chains_static, 24592daf3a6SBjoern A. Zeeb chanctx_conf->rx_chains_dynamic); 24692daf3a6SBjoern A. Zeeb rcu_read_unlock(); 24792daf3a6SBjoern A. Zeeb 24892daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 24992daf3a6SBjoern A. Zeeb 25092daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 25192daf3a6SBjoern A. Zeeb } 25292daf3a6SBjoern A. Zeeb 25392daf3a6SBjoern A. Zeeb static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, 25492daf3a6SBjoern A. Zeeb enum iwl_dbgfs_bf_mask param, int value) 25592daf3a6SBjoern A. Zeeb { 25692daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 25792daf3a6SBjoern A. Zeeb struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; 25892daf3a6SBjoern A. Zeeb 25992daf3a6SBjoern A. Zeeb dbgfs_bf->mask |= param; 26092daf3a6SBjoern A. Zeeb 26192daf3a6SBjoern A. Zeeb switch (param) { 26292daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_ENERGY_DELTA: 26392daf3a6SBjoern A. Zeeb dbgfs_bf->bf_energy_delta = value; 26492daf3a6SBjoern A. Zeeb break; 26592daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA: 26692daf3a6SBjoern A. Zeeb dbgfs_bf->bf_roaming_energy_delta = value; 26792daf3a6SBjoern A. Zeeb break; 26892daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_ROAMING_STATE: 26992daf3a6SBjoern A. Zeeb dbgfs_bf->bf_roaming_state = value; 27092daf3a6SBjoern A. Zeeb break; 27192daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_TEMP_THRESHOLD: 27292daf3a6SBjoern A. Zeeb dbgfs_bf->bf_temp_threshold = value; 27392daf3a6SBjoern A. Zeeb break; 27492daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_TEMP_FAST_FILTER: 27592daf3a6SBjoern A. Zeeb dbgfs_bf->bf_temp_fast_filter = value; 27692daf3a6SBjoern A. Zeeb break; 27792daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER: 27892daf3a6SBjoern A. Zeeb dbgfs_bf->bf_temp_slow_filter = value; 27992daf3a6SBjoern A. Zeeb break; 28092daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: 28192daf3a6SBjoern A. Zeeb dbgfs_bf->bf_enable_beacon_filter = value; 28292daf3a6SBjoern A. Zeeb break; 28392daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_DEBUG_FLAG: 28492daf3a6SBjoern A. Zeeb dbgfs_bf->bf_debug_flag = value; 28592daf3a6SBjoern A. Zeeb break; 28692daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BF_ESCAPE_TIMER: 28792daf3a6SBjoern A. Zeeb dbgfs_bf->bf_escape_timer = value; 28892daf3a6SBjoern A. Zeeb break; 28992daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT: 29092daf3a6SBjoern A. Zeeb dbgfs_bf->ba_enable_beacon_abort = value; 29192daf3a6SBjoern A. Zeeb break; 29292daf3a6SBjoern A. Zeeb case MVM_DEBUGFS_BA_ESCAPE_TIMER: 29392daf3a6SBjoern A. Zeeb dbgfs_bf->ba_escape_timer = value; 29492daf3a6SBjoern A. Zeeb break; 29592daf3a6SBjoern A. Zeeb } 29692daf3a6SBjoern A. Zeeb } 29792daf3a6SBjoern A. Zeeb 29892daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf, 29992daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 30092daf3a6SBjoern A. Zeeb { 30192daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 30292daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 30392daf3a6SBjoern A. Zeeb enum iwl_dbgfs_bf_mask param; 30492daf3a6SBjoern A. Zeeb int value, ret = 0; 30592daf3a6SBjoern A. Zeeb 30692daf3a6SBjoern A. Zeeb if (!strncmp("bf_energy_delta=", buf, 16)) { 30792daf3a6SBjoern A. Zeeb if (sscanf(buf+16, "%d", &value) != 1) 30892daf3a6SBjoern A. Zeeb return -EINVAL; 30992daf3a6SBjoern A. Zeeb if (value < IWL_BF_ENERGY_DELTA_MIN || 31092daf3a6SBjoern A. Zeeb value > IWL_BF_ENERGY_DELTA_MAX) 31192daf3a6SBjoern A. Zeeb return -EINVAL; 31292daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_ENERGY_DELTA; 31392daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) { 31492daf3a6SBjoern A. Zeeb if (sscanf(buf+24, "%d", &value) != 1) 31592daf3a6SBjoern A. Zeeb return -EINVAL; 31692daf3a6SBjoern A. Zeeb if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN || 31792daf3a6SBjoern A. Zeeb value > IWL_BF_ROAMING_ENERGY_DELTA_MAX) 31892daf3a6SBjoern A. Zeeb return -EINVAL; 31992daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA; 32092daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_roaming_state=", buf, 17)) { 32192daf3a6SBjoern A. Zeeb if (sscanf(buf+17, "%d", &value) != 1) 32292daf3a6SBjoern A. Zeeb return -EINVAL; 32392daf3a6SBjoern A. Zeeb if (value < IWL_BF_ROAMING_STATE_MIN || 32492daf3a6SBjoern A. Zeeb value > IWL_BF_ROAMING_STATE_MAX) 32592daf3a6SBjoern A. Zeeb return -EINVAL; 32692daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_ROAMING_STATE; 32792daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_temp_threshold=", buf, 18)) { 32892daf3a6SBjoern A. Zeeb if (sscanf(buf+18, "%d", &value) != 1) 32992daf3a6SBjoern A. Zeeb return -EINVAL; 33092daf3a6SBjoern A. Zeeb if (value < IWL_BF_TEMP_THRESHOLD_MIN || 33192daf3a6SBjoern A. Zeeb value > IWL_BF_TEMP_THRESHOLD_MAX) 33292daf3a6SBjoern A. Zeeb return -EINVAL; 33392daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_TEMP_THRESHOLD; 33492daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) { 33592daf3a6SBjoern A. Zeeb if (sscanf(buf+20, "%d", &value) != 1) 33692daf3a6SBjoern A. Zeeb return -EINVAL; 33792daf3a6SBjoern A. Zeeb if (value < IWL_BF_TEMP_FAST_FILTER_MIN || 33892daf3a6SBjoern A. Zeeb value > IWL_BF_TEMP_FAST_FILTER_MAX) 33992daf3a6SBjoern A. Zeeb return -EINVAL; 34092daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER; 34192daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) { 34292daf3a6SBjoern A. Zeeb if (sscanf(buf+20, "%d", &value) != 1) 34392daf3a6SBjoern A. Zeeb return -EINVAL; 34492daf3a6SBjoern A. Zeeb if (value < IWL_BF_TEMP_SLOW_FILTER_MIN || 34592daf3a6SBjoern A. Zeeb value > IWL_BF_TEMP_SLOW_FILTER_MAX) 34692daf3a6SBjoern A. Zeeb return -EINVAL; 34792daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER; 34892daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { 34992daf3a6SBjoern A. Zeeb if (sscanf(buf+24, "%d", &value) != 1) 35092daf3a6SBjoern A. Zeeb return -EINVAL; 35192daf3a6SBjoern A. Zeeb if (value < 0 || value > 1) 35292daf3a6SBjoern A. Zeeb return -EINVAL; 35392daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER; 35492daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_debug_flag=", buf, 14)) { 35592daf3a6SBjoern A. Zeeb if (sscanf(buf+14, "%d", &value) != 1) 35692daf3a6SBjoern A. Zeeb return -EINVAL; 35792daf3a6SBjoern A. Zeeb if (value < 0 || value > 1) 35892daf3a6SBjoern A. Zeeb return -EINVAL; 35992daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_DEBUG_FLAG; 36092daf3a6SBjoern A. Zeeb } else if (!strncmp("bf_escape_timer=", buf, 16)) { 36192daf3a6SBjoern A. Zeeb if (sscanf(buf+16, "%d", &value) != 1) 36292daf3a6SBjoern A. Zeeb return -EINVAL; 36392daf3a6SBjoern A. Zeeb if (value < IWL_BF_ESCAPE_TIMER_MIN || 36492daf3a6SBjoern A. Zeeb value > IWL_BF_ESCAPE_TIMER_MAX) 36592daf3a6SBjoern A. Zeeb return -EINVAL; 36692daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BF_ESCAPE_TIMER; 36792daf3a6SBjoern A. Zeeb } else if (!strncmp("ba_escape_timer=", buf, 16)) { 36892daf3a6SBjoern A. Zeeb if (sscanf(buf+16, "%d", &value) != 1) 36992daf3a6SBjoern A. Zeeb return -EINVAL; 37092daf3a6SBjoern A. Zeeb if (value < IWL_BA_ESCAPE_TIMER_MIN || 37192daf3a6SBjoern A. Zeeb value > IWL_BA_ESCAPE_TIMER_MAX) 37292daf3a6SBjoern A. Zeeb return -EINVAL; 37392daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BA_ESCAPE_TIMER; 37492daf3a6SBjoern A. Zeeb } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) { 37592daf3a6SBjoern A. Zeeb if (sscanf(buf+23, "%d", &value) != 1) 37692daf3a6SBjoern A. Zeeb return -EINVAL; 37792daf3a6SBjoern A. Zeeb if (value < 0 || value > 1) 37892daf3a6SBjoern A. Zeeb return -EINVAL; 37992daf3a6SBjoern A. Zeeb param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT; 38092daf3a6SBjoern A. Zeeb } else { 38192daf3a6SBjoern A. Zeeb return -EINVAL; 38292daf3a6SBjoern A. Zeeb } 38392daf3a6SBjoern A. Zeeb 38492daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 38592daf3a6SBjoern A. Zeeb iwl_dbgfs_update_bf(vif, param, value); 38692daf3a6SBjoern A. Zeeb if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) 38792daf3a6SBjoern A. Zeeb ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); 38892daf3a6SBjoern A. Zeeb else 38992daf3a6SBjoern A. Zeeb ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); 39092daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 39192daf3a6SBjoern A. Zeeb 39292daf3a6SBjoern A. Zeeb return ret ?: count; 39392daf3a6SBjoern A. Zeeb } 39492daf3a6SBjoern A. Zeeb 39592daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_bf_params_read(struct file *file, 39692daf3a6SBjoern A. Zeeb char __user *user_buf, 39792daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 39892daf3a6SBjoern A. Zeeb { 39992daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 40092daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 40192daf3a6SBjoern A. Zeeb char buf[256]; 40292daf3a6SBjoern A. Zeeb int pos = 0; 40392daf3a6SBjoern A. Zeeb const size_t bufsz = sizeof(buf); 40492daf3a6SBjoern A. Zeeb struct iwl_beacon_filter_cmd cmd = { 40592daf3a6SBjoern A. Zeeb IWL_BF_CMD_CONFIG_DEFAULTS, 40692daf3a6SBjoern A. Zeeb .bf_enable_beacon_filter = 40792daf3a6SBjoern A. Zeeb cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT), 40892daf3a6SBjoern A. Zeeb .ba_enable_beacon_abort = 40992daf3a6SBjoern A. Zeeb cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT), 41092daf3a6SBjoern A. Zeeb }; 41192daf3a6SBjoern A. Zeeb 41292daf3a6SBjoern A. Zeeb iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 41392daf3a6SBjoern A. Zeeb if (mvmvif->bf_data.bf_enabled) 41492daf3a6SBjoern A. Zeeb cmd.bf_enable_beacon_filter = cpu_to_le32(1); 41592daf3a6SBjoern A. Zeeb else 41692daf3a6SBjoern A. Zeeb cmd.bf_enable_beacon_filter = 0; 41792daf3a6SBjoern A. Zeeb 41892daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", 41992daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_energy_delta)); 42092daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", 42192daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_roaming_energy_delta)); 42292daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", 42392daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_roaming_state)); 42492daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n", 42592daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_temp_threshold)); 42692daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n", 42792daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_temp_fast_filter)); 42892daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n", 42992daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_temp_slow_filter)); 43092daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", 43192daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_enable_beacon_filter)); 43292daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", 43392daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_debug_flag)); 43492daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", 43592daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.bf_escape_timer)); 43692daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", 43792daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.ba_escape_timer)); 43892daf3a6SBjoern A. Zeeb pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", 43992daf3a6SBjoern A. Zeeb le32_to_cpu(cmd.ba_enable_beacon_abort)); 44092daf3a6SBjoern A. Zeeb 44192daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 44292daf3a6SBjoern A. Zeeb } 44392daf3a6SBjoern A. Zeeb 44492daf3a6SBjoern A. Zeeb #if defined(__linux__) 44592daf3a6SBjoern A. Zeeb static inline char *iwl_dbgfs_is_match(char *name, char *buf) 44692daf3a6SBjoern A. Zeeb { 44792daf3a6SBjoern A. Zeeb int len = strlen(name); 44892daf3a6SBjoern A. Zeeb 44992daf3a6SBjoern A. Zeeb return !strncmp(name, buf, len) ? buf + len : NULL; 45092daf3a6SBjoern A. Zeeb } 45192daf3a6SBjoern A. Zeeb #endif 45292daf3a6SBjoern A. Zeeb 45392daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, 45492daf3a6SBjoern A. Zeeb char __user *user_buf, 45592daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 45692daf3a6SBjoern A. Zeeb { 45792daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 45892daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 45992daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 46092daf3a6SBjoern A. Zeeb u32 curr_gp2; 46192daf3a6SBjoern A. Zeeb u64 curr_os; 46292daf3a6SBjoern A. Zeeb s64 diff; 46392daf3a6SBjoern A. Zeeb char buf[64]; 46492daf3a6SBjoern A. Zeeb const size_t bufsz = sizeof(buf); 46592daf3a6SBjoern A. Zeeb int pos = 0; 46692daf3a6SBjoern A. Zeeb 46792daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 46892daf3a6SBjoern A. Zeeb iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, &curr_os, NULL); 46992daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 47092daf3a6SBjoern A. Zeeb 47192daf3a6SBjoern A. Zeeb do_div(curr_os, NSEC_PER_USEC); 47292daf3a6SBjoern A. Zeeb diff = curr_os - curr_gp2; 47392daf3a6SBjoern A. Zeeb pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff); 47492daf3a6SBjoern A. Zeeb 47592daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, pos); 47692daf3a6SBjoern A. Zeeb } 47792daf3a6SBjoern A. Zeeb 47892daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, 47992daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 48092daf3a6SBjoern A. Zeeb { 48192daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 48292daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 48392daf3a6SBjoern A. Zeeb u8 value; 48492daf3a6SBjoern A. Zeeb int ret; 48592daf3a6SBjoern A. Zeeb 48692daf3a6SBjoern A. Zeeb ret = kstrtou8(buf, 0, &value); 48792daf3a6SBjoern A. Zeeb if (ret) 48892daf3a6SBjoern A. Zeeb return ret; 48992daf3a6SBjoern A. Zeeb if (value > 1) 49092daf3a6SBjoern A. Zeeb return -EINVAL; 49192daf3a6SBjoern A. Zeeb 49292daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 49392daf3a6SBjoern A. Zeeb iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS); 49492daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 49592daf3a6SBjoern A. Zeeb 49692daf3a6SBjoern A. Zeeb return count; 49792daf3a6SBjoern A. Zeeb } 49892daf3a6SBjoern A. Zeeb 49992daf3a6SBjoern A. Zeeb static ssize_t 50092daf3a6SBjoern A. Zeeb iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, 50192daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 50292daf3a6SBjoern A. Zeeb { 50392daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 50492daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 50592daf3a6SBjoern A. Zeeb u8 value; 50692daf3a6SBjoern A. Zeeb int ret; 50792daf3a6SBjoern A. Zeeb 50892daf3a6SBjoern A. Zeeb ret = kstrtou8(buf, 0, &value); 50992daf3a6SBjoern A. Zeeb if (ret) 51092daf3a6SBjoern A. Zeeb return ret; 51192daf3a6SBjoern A. Zeeb 51292daf3a6SBjoern A. Zeeb if (value > NUM_LOW_LATENCY_FORCE) 51392daf3a6SBjoern A. Zeeb return -EINVAL; 51492daf3a6SBjoern A. Zeeb 51592daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 51692daf3a6SBjoern A. Zeeb if (value == LOW_LATENCY_FORCE_UNSET) { 51792daf3a6SBjoern A. Zeeb iwl_mvm_update_low_latency(mvm, vif, false, 51892daf3a6SBjoern A. Zeeb LOW_LATENCY_DEBUGFS_FORCE); 51992daf3a6SBjoern A. Zeeb iwl_mvm_update_low_latency(mvm, vif, false, 52092daf3a6SBjoern A. Zeeb LOW_LATENCY_DEBUGFS_FORCE_ENABLE); 52192daf3a6SBjoern A. Zeeb } else { 52292daf3a6SBjoern A. Zeeb iwl_mvm_update_low_latency(mvm, vif, 52392daf3a6SBjoern A. Zeeb value == LOW_LATENCY_FORCE_ON, 52492daf3a6SBjoern A. Zeeb LOW_LATENCY_DEBUGFS_FORCE); 52592daf3a6SBjoern A. Zeeb iwl_mvm_update_low_latency(mvm, vif, true, 52692daf3a6SBjoern A. Zeeb LOW_LATENCY_DEBUGFS_FORCE_ENABLE); 52792daf3a6SBjoern A. Zeeb } 52892daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 52992daf3a6SBjoern A. Zeeb return count; 53092daf3a6SBjoern A. Zeeb } 53192daf3a6SBjoern A. Zeeb 53292daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_low_latency_read(struct file *file, 53392daf3a6SBjoern A. Zeeb char __user *user_buf, 53492daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 53592daf3a6SBjoern A. Zeeb { 53692daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 53792daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 53892daf3a6SBjoern A. Zeeb char format[] = "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n" 53992daf3a6SBjoern A. Zeeb "dbgfs_force_enable=%d\ndbgfs_force=%d\nactual=%d\n"; 54092daf3a6SBjoern A. Zeeb 54192daf3a6SBjoern A. Zeeb /* 54292daf3a6SBjoern A. Zeeb * all values in format are boolean so the size of format is enough 54392daf3a6SBjoern A. Zeeb * for holding the result string 54492daf3a6SBjoern A. Zeeb */ 54592daf3a6SBjoern A. Zeeb char buf[sizeof(format) + 1] = {}; 54692daf3a6SBjoern A. Zeeb int len; 54792daf3a6SBjoern A. Zeeb 54892daf3a6SBjoern A. Zeeb len = scnprintf(buf, sizeof(buf) - 1, format, 54992daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC), 55092daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS), 55192daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency & LOW_LATENCY_VCMD), 55292daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE), 55392daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency & 55492daf3a6SBjoern A. Zeeb LOW_LATENCY_DEBUGFS_FORCE_ENABLE), 55592daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE), 55692daf3a6SBjoern A. Zeeb !!(mvmvif->low_latency_actual)); 55792daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 55892daf3a6SBjoern A. Zeeb } 55992daf3a6SBjoern A. Zeeb 56092daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, 56192daf3a6SBjoern A. Zeeb char __user *user_buf, 56292daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 56392daf3a6SBjoern A. Zeeb { 56492daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 56592daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 56692daf3a6SBjoern A. Zeeb char buf[20]; 56792daf3a6SBjoern A. Zeeb int len; 56892daf3a6SBjoern A. Zeeb 56992daf3a6SBjoern A. Zeeb #if defined(__linux__) 57092daf3a6SBjoern A. Zeeb len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); 57192daf3a6SBjoern A. Zeeb #elif defined(__FreeBSD__) 57292daf3a6SBjoern A. Zeeb len = sprintf(buf, "%6D\n", mvmvif->uapsd_misbehaving_bssid, ":"); 57392daf3a6SBjoern A. Zeeb #endif 57492daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 57592daf3a6SBjoern A. Zeeb } 57692daf3a6SBjoern A. Zeeb 57792daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, 57892daf3a6SBjoern A. Zeeb char *buf, size_t count, 57992daf3a6SBjoern A. Zeeb loff_t *ppos) 58092daf3a6SBjoern A. Zeeb { 58192daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 58292daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 58392daf3a6SBjoern A. Zeeb bool ret; 58492daf3a6SBjoern A. Zeeb 58592daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 58692daf3a6SBjoern A. Zeeb ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); 58792daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 58892daf3a6SBjoern A. Zeeb 58992daf3a6SBjoern A. Zeeb return ret ? count : -EINVAL; 59092daf3a6SBjoern A. Zeeb } 59192daf3a6SBjoern A. Zeeb 59292daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, 59392daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 59492daf3a6SBjoern A. Zeeb { 59592daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 59692daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 59792daf3a6SBjoern A. Zeeb struct ieee80211_chanctx_conf *chanctx_conf; 59892daf3a6SBjoern A. Zeeb struct iwl_mvm_phy_ctxt *phy_ctxt; 59992daf3a6SBjoern A. Zeeb u16 value; 60092daf3a6SBjoern A. Zeeb int ret; 60192daf3a6SBjoern A. Zeeb 60292daf3a6SBjoern A. Zeeb ret = kstrtou16(buf, 0, &value); 60392daf3a6SBjoern A. Zeeb if (ret) 60492daf3a6SBjoern A. Zeeb return ret; 60592daf3a6SBjoern A. Zeeb 60692daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 60792daf3a6SBjoern A. Zeeb rcu_read_lock(); 60892daf3a6SBjoern A. Zeeb 60992daf3a6SBjoern A. Zeeb chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); 61092daf3a6SBjoern A. Zeeb /* make sure the channel context is assigned */ 61192daf3a6SBjoern A. Zeeb if (!chanctx_conf) { 61292daf3a6SBjoern A. Zeeb rcu_read_unlock(); 61392daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 61492daf3a6SBjoern A. Zeeb return -EINVAL; 61592daf3a6SBjoern A. Zeeb } 61692daf3a6SBjoern A. Zeeb 61792daf3a6SBjoern A. Zeeb phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; 61892daf3a6SBjoern A. Zeeb rcu_read_unlock(); 61992daf3a6SBjoern A. Zeeb 62092daf3a6SBjoern A. Zeeb mvm->dbgfs_rx_phyinfo = value; 62192daf3a6SBjoern A. Zeeb 62292daf3a6SBjoern A. Zeeb ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, 62392daf3a6SBjoern A. Zeeb chanctx_conf->rx_chains_static, 62492daf3a6SBjoern A. Zeeb chanctx_conf->rx_chains_dynamic); 62592daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 62692daf3a6SBjoern A. Zeeb 62792daf3a6SBjoern A. Zeeb return ret ?: count; 62892daf3a6SBjoern A. Zeeb } 62992daf3a6SBjoern A. Zeeb 63092daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file, 63192daf3a6SBjoern A. Zeeb char __user *user_buf, 63292daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 63392daf3a6SBjoern A. Zeeb { 63492daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 63592daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 63692daf3a6SBjoern A. Zeeb char buf[8]; 63792daf3a6SBjoern A. Zeeb int len; 63892daf3a6SBjoern A. Zeeb 63992daf3a6SBjoern A. Zeeb len = scnprintf(buf, sizeof(buf), "0x%04x\n", 64092daf3a6SBjoern A. Zeeb mvmvif->mvm->dbgfs_rx_phyinfo); 64192daf3a6SBjoern A. Zeeb 64292daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 64392daf3a6SBjoern A. Zeeb } 64492daf3a6SBjoern A. Zeeb 64592daf3a6SBjoern A. Zeeb static void iwl_dbgfs_quota_check(void *data, u8 *mac, 64692daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif) 64792daf3a6SBjoern A. Zeeb { 64892daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 64992daf3a6SBjoern A. Zeeb int *ret = data; 65092daf3a6SBjoern A. Zeeb 65192daf3a6SBjoern A. Zeeb if (mvmvif->dbgfs_quota_min) 65292daf3a6SBjoern A. Zeeb *ret = -EINVAL; 65392daf3a6SBjoern A. Zeeb } 65492daf3a6SBjoern A. Zeeb 65592daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf, 65692daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 65792daf3a6SBjoern A. Zeeb { 65892daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 65992daf3a6SBjoern A. Zeeb struct iwl_mvm *mvm = mvmvif->mvm; 66092daf3a6SBjoern A. Zeeb u16 value; 66192daf3a6SBjoern A. Zeeb int ret; 66292daf3a6SBjoern A. Zeeb 66392daf3a6SBjoern A. Zeeb ret = kstrtou16(buf, 0, &value); 66492daf3a6SBjoern A. Zeeb if (ret) 66592daf3a6SBjoern A. Zeeb return ret; 66692daf3a6SBjoern A. Zeeb 66792daf3a6SBjoern A. Zeeb if (value > 95) 66892daf3a6SBjoern A. Zeeb return -EINVAL; 66992daf3a6SBjoern A. Zeeb 67092daf3a6SBjoern A. Zeeb mutex_lock(&mvm->mutex); 67192daf3a6SBjoern A. Zeeb 67292daf3a6SBjoern A. Zeeb mvmvif->dbgfs_quota_min = 0; 67392daf3a6SBjoern A. Zeeb ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, 67492daf3a6SBjoern A. Zeeb iwl_dbgfs_quota_check, &ret); 67592daf3a6SBjoern A. Zeeb if (ret == 0) { 67692daf3a6SBjoern A. Zeeb mvmvif->dbgfs_quota_min = value; 67792daf3a6SBjoern A. Zeeb iwl_mvm_update_quotas(mvm, false, NULL); 67892daf3a6SBjoern A. Zeeb } 67992daf3a6SBjoern A. Zeeb mutex_unlock(&mvm->mutex); 68092daf3a6SBjoern A. Zeeb 68192daf3a6SBjoern A. Zeeb return ret ?: count; 68292daf3a6SBjoern A. Zeeb } 68392daf3a6SBjoern A. Zeeb 68492daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_quota_min_read(struct file *file, 68592daf3a6SBjoern A. Zeeb char __user *user_buf, 68692daf3a6SBjoern A. Zeeb size_t count, loff_t *ppos) 68792daf3a6SBjoern A. Zeeb { 68892daf3a6SBjoern A. Zeeb struct ieee80211_vif *vif = file->private_data; 68992daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 69092daf3a6SBjoern A. Zeeb char buf[10]; 69192daf3a6SBjoern A. Zeeb int len; 69292daf3a6SBjoern A. Zeeb 69392daf3a6SBjoern A. Zeeb len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min); 69492daf3a6SBjoern A. Zeeb 69592daf3a6SBjoern A. Zeeb return simple_read_from_buffer(user_buf, count, ppos, buf, len); 69692daf3a6SBjoern A. Zeeb } 69792daf3a6SBjoern A. Zeeb 69892daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ 69992daf3a6SBjoern A. Zeeb _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 70092daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ 70192daf3a6SBjoern A. Zeeb _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) 70292daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \ 70392daf3a6SBjoern A. Zeeb debugfs_create_file(#name, mode, parent, vif, \ 70492daf3a6SBjoern A. Zeeb &iwl_dbgfs_##name##_ops); \ 70592daf3a6SBjoern A. Zeeb } while (0) 70692daf3a6SBjoern A. Zeeb 70792daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(mac_params); 70892daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); 70992daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); 71092daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); 71192daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); 71292daf3a6SBjoern A. Zeeb MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10); 71392daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); 71492daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); 71592daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); 71692daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff); 71792daf3a6SBjoern A. Zeeb 71892daf3a6SBjoern A. Zeeb 71992daf3a6SBjoern A. Zeeb void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 72092daf3a6SBjoern A. Zeeb { 72192daf3a6SBjoern A. Zeeb struct dentry *dbgfs_dir = vif->debugfs_dir; 72292daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 72392daf3a6SBjoern A. Zeeb #if defined(__linux__) 72492daf3a6SBjoern A. Zeeb char buf[100]; 72592daf3a6SBjoern A. Zeeb #endif 72692daf3a6SBjoern A. Zeeb 72792daf3a6SBjoern A. Zeeb /* 72892daf3a6SBjoern A. Zeeb * Check if debugfs directory already exist before creating it. 72992daf3a6SBjoern A. Zeeb * This may happen when, for example, resetting hw or suspend-resume 73092daf3a6SBjoern A. Zeeb */ 73192daf3a6SBjoern A. Zeeb if (!dbgfs_dir || mvmvif->dbgfs_dir) 73292daf3a6SBjoern A. Zeeb return; 73392daf3a6SBjoern A. Zeeb 73492daf3a6SBjoern A. Zeeb mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); 73592daf3a6SBjoern A. Zeeb if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) { 73692daf3a6SBjoern A. Zeeb IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n", 73792daf3a6SBjoern A. Zeeb dbgfs_dir); 73892daf3a6SBjoern A. Zeeb return; 73992daf3a6SBjoern A. Zeeb } 74092daf3a6SBjoern A. Zeeb 74192daf3a6SBjoern A. Zeeb if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && 74292daf3a6SBjoern A. Zeeb ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || 74392daf3a6SBjoern A. Zeeb (vif->type == NL80211_IFTYPE_STATION && vif->p2p))) 74492daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600); 74592daf3a6SBjoern A. Zeeb 74692daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400); 74792daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400); 74892daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600); 74992daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600); 75092daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600); 75192daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600); 75292daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600); 75392daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400); 75492daf3a6SBjoern A. Zeeb 75592daf3a6SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && 75692daf3a6SBjoern A. Zeeb mvmvif == mvm->bf_allowed_vif) 75792daf3a6SBjoern A. Zeeb MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600); 75892daf3a6SBjoern A. Zeeb 75992daf3a6SBjoern A. Zeeb #if defined(__linux__) 76092daf3a6SBjoern A. Zeeb /* 76192daf3a6SBjoern A. Zeeb * Create symlink for convenience pointing to interface specific 76292daf3a6SBjoern A. Zeeb * debugfs entries for the driver. For example, under 76392daf3a6SBjoern A. Zeeb * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/ 76492daf3a6SBjoern A. Zeeb * find 76592daf3a6SBjoern A. Zeeb * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ 76692daf3a6SBjoern A. Zeeb */ 76792daf3a6SBjoern A. Zeeb snprintf(buf, 100, "../../../%pd3/%pd", 76892daf3a6SBjoern A. Zeeb dbgfs_dir, 76992daf3a6SBjoern A. Zeeb mvmvif->dbgfs_dir); 77092daf3a6SBjoern A. Zeeb 77192daf3a6SBjoern A. Zeeb mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, 77292daf3a6SBjoern A. Zeeb mvm->debugfs_dir, buf); 77392daf3a6SBjoern A. Zeeb #endif 77492daf3a6SBjoern A. Zeeb } 77592daf3a6SBjoern A. Zeeb 77692daf3a6SBjoern A. Zeeb void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 77792daf3a6SBjoern A. Zeeb { 77892daf3a6SBjoern A. Zeeb struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 77992daf3a6SBjoern A. Zeeb 78092daf3a6SBjoern A. Zeeb debugfs_remove(mvmvif->dbgfs_slink); 78192daf3a6SBjoern A. Zeeb mvmvif->dbgfs_slink = NULL; 78292daf3a6SBjoern A. Zeeb 78392daf3a6SBjoern A. Zeeb debugfs_remove_recursive(mvmvif->dbgfs_dir); 78492daf3a6SBjoern A. Zeeb mvmvif->dbgfs_dir = NULL; 78592daf3a6SBjoern A. Zeeb } 786