xref: /freebsd/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c (revision 07f6575585bf69ae48dffe87c4578057ae4782d8)
192daf3a6SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
292daf3a6SBjoern A. Zeeb /*
3a4128aadSBjoern A. Zeeb  * Copyright (C) 2012-2014, 2018-2024 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 
iwl_dbgfs_update_pm(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_dbgfs_pm_mask param,int val)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 
iwl_dbgfs_pm_params_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)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 
iwl_dbgfs_tx_pwr_lmt_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
iwl_dbgfs_pm_params_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
iwl_dbgfs_mac_params_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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 
1859af1bba4SBjoern A. Zeeb 	ap_sta_id = mvmvif->deflink.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");
2179af1bba4SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(mvmvif->deflink.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",
2209af1bba4SBjoern A. Zeeb 				 i, mvmvif->deflink.queue_params[i].txop,
2219af1bba4SBjoern A. Zeeb 				 mvmvif->deflink.queue_params[i].cw_min,
2229af1bba4SBjoern A. Zeeb 				 mvmvif->deflink.queue_params[i].cw_max,
2239af1bba4SBjoern A. Zeeb 				 mvmvif->deflink.queue_params[i].aifs,
2249af1bba4SBjoern A. Zeeb 				 mvmvif->deflink.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 
iwl_dbgfs_update_bf(struct ieee80211_vif * vif,enum iwl_dbgfs_bf_mask param,int value)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 
iwl_dbgfs_bf_params_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)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)
387a4128aadSBjoern A. Zeeb 		ret = iwl_mvm_disable_beacon_filter(mvm, vif);
38892daf3a6SBjoern A. Zeeb 	else
389a4128aadSBjoern A. Zeeb 		ret = iwl_mvm_enable_beacon_filter(mvm, vif);
39092daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
39192daf3a6SBjoern A. Zeeb 
39292daf3a6SBjoern A. Zeeb 	return ret ?: count;
39392daf3a6SBjoern A. Zeeb }
39492daf3a6SBjoern A. Zeeb 
iwl_dbgfs_bf_params_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)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);
413a4128aadSBjoern A. Zeeb 	if (mvmvif->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 
iwl_dbgfs_os_device_timediff_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)44492daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
44592daf3a6SBjoern A. Zeeb 						 char __user *user_buf,
44692daf3a6SBjoern A. Zeeb 						 size_t count, loff_t *ppos)
44792daf3a6SBjoern A. Zeeb {
44892daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
44992daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
45092daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
45192daf3a6SBjoern A. Zeeb 	u32 curr_gp2;
45292daf3a6SBjoern A. Zeeb 	u64 curr_os;
45392daf3a6SBjoern A. Zeeb 	s64 diff;
45492daf3a6SBjoern A. Zeeb 	char buf[64];
45592daf3a6SBjoern A. Zeeb 	const size_t bufsz = sizeof(buf);
45692daf3a6SBjoern A. Zeeb 	int pos = 0;
45792daf3a6SBjoern A. Zeeb 
45892daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
45992daf3a6SBjoern A. Zeeb 	iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, &curr_os, NULL);
46092daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
46192daf3a6SBjoern A. Zeeb 
46292daf3a6SBjoern A. Zeeb 	do_div(curr_os, NSEC_PER_USEC);
46392daf3a6SBjoern A. Zeeb 	diff = curr_os - curr_gp2;
46492daf3a6SBjoern A. Zeeb 	pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
46592daf3a6SBjoern A. Zeeb 
46692daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
46792daf3a6SBjoern A. Zeeb }
46892daf3a6SBjoern A. Zeeb 
iwl_dbgfs_low_latency_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)46992daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
47092daf3a6SBjoern A. Zeeb 					   size_t count, loff_t *ppos)
47192daf3a6SBjoern A. Zeeb {
47292daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
47392daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
47492daf3a6SBjoern A. Zeeb 	u8 value;
47592daf3a6SBjoern A. Zeeb 	int ret;
47692daf3a6SBjoern A. Zeeb 
47792daf3a6SBjoern A. Zeeb 	ret = kstrtou8(buf, 0, &value);
47892daf3a6SBjoern A. Zeeb 	if (ret)
47992daf3a6SBjoern A. Zeeb 		return ret;
48092daf3a6SBjoern A. Zeeb 	if (value > 1)
48192daf3a6SBjoern A. Zeeb 		return -EINVAL;
48292daf3a6SBjoern A. Zeeb 
48392daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
48492daf3a6SBjoern A. Zeeb 	iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
48592daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
48692daf3a6SBjoern A. Zeeb 
48792daf3a6SBjoern A. Zeeb 	return count;
48892daf3a6SBjoern A. Zeeb }
48992daf3a6SBjoern A. Zeeb 
49092daf3a6SBjoern A. Zeeb static ssize_t
iwl_dbgfs_low_latency_force_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)49192daf3a6SBjoern A. Zeeb iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf,
49292daf3a6SBjoern A. Zeeb 				  size_t count, loff_t *ppos)
49392daf3a6SBjoern A. Zeeb {
49492daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
49592daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
49692daf3a6SBjoern A. Zeeb 	u8 value;
49792daf3a6SBjoern A. Zeeb 	int ret;
49892daf3a6SBjoern A. Zeeb 
49992daf3a6SBjoern A. Zeeb 	ret = kstrtou8(buf, 0, &value);
50092daf3a6SBjoern A. Zeeb 	if (ret)
50192daf3a6SBjoern A. Zeeb 		return ret;
50292daf3a6SBjoern A. Zeeb 
50392daf3a6SBjoern A. Zeeb 	if (value > NUM_LOW_LATENCY_FORCE)
50492daf3a6SBjoern A. Zeeb 		return -EINVAL;
50592daf3a6SBjoern A. Zeeb 
50692daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
50792daf3a6SBjoern A. Zeeb 	if (value == LOW_LATENCY_FORCE_UNSET) {
50892daf3a6SBjoern A. Zeeb 		iwl_mvm_update_low_latency(mvm, vif, false,
50992daf3a6SBjoern A. Zeeb 					   LOW_LATENCY_DEBUGFS_FORCE);
51092daf3a6SBjoern A. Zeeb 		iwl_mvm_update_low_latency(mvm, vif, false,
51192daf3a6SBjoern A. Zeeb 					   LOW_LATENCY_DEBUGFS_FORCE_ENABLE);
51292daf3a6SBjoern A. Zeeb 	} else {
51392daf3a6SBjoern A. Zeeb 		iwl_mvm_update_low_latency(mvm, vif,
51492daf3a6SBjoern A. Zeeb 					   value == LOW_LATENCY_FORCE_ON,
51592daf3a6SBjoern A. Zeeb 					   LOW_LATENCY_DEBUGFS_FORCE);
51692daf3a6SBjoern A. Zeeb 		iwl_mvm_update_low_latency(mvm, vif, true,
51792daf3a6SBjoern A. Zeeb 					   LOW_LATENCY_DEBUGFS_FORCE_ENABLE);
51892daf3a6SBjoern A. Zeeb 	}
51992daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
52092daf3a6SBjoern A. Zeeb 	return count;
52192daf3a6SBjoern A. Zeeb }
52292daf3a6SBjoern A. Zeeb 
iwl_dbgfs_low_latency_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)52392daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
52492daf3a6SBjoern A. Zeeb 					  char __user *user_buf,
52592daf3a6SBjoern A. Zeeb 					  size_t count, loff_t *ppos)
52692daf3a6SBjoern A. Zeeb {
52792daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
52892daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
52992daf3a6SBjoern A. Zeeb 	char format[] = "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n"
53092daf3a6SBjoern A. Zeeb 			"dbgfs_force_enable=%d\ndbgfs_force=%d\nactual=%d\n";
53192daf3a6SBjoern A. Zeeb 
53292daf3a6SBjoern A. Zeeb 	/*
53392daf3a6SBjoern A. Zeeb 	 * all values in format are boolean so the size of format is enough
53492daf3a6SBjoern A. Zeeb 	 * for holding the result string
53592daf3a6SBjoern A. Zeeb 	 */
53692daf3a6SBjoern A. Zeeb 	char buf[sizeof(format) + 1] = {};
53792daf3a6SBjoern A. Zeeb 	int len;
53892daf3a6SBjoern A. Zeeb 
53992daf3a6SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf) - 1, format,
54092daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
54192daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
54292daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency & LOW_LATENCY_VCMD),
54392daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE),
54492daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency &
54592daf3a6SBjoern A. Zeeb 			   LOW_LATENCY_DEBUGFS_FORCE_ENABLE),
54692daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE),
54792daf3a6SBjoern A. Zeeb 			!!(mvmvif->low_latency_actual));
54892daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
54992daf3a6SBjoern A. Zeeb }
55092daf3a6SBjoern A. Zeeb 
iwl_dbgfs_uapsd_misbehaving_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)55192daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
55292daf3a6SBjoern A. Zeeb 						char __user *user_buf,
55392daf3a6SBjoern A. Zeeb 						size_t count, loff_t *ppos)
55492daf3a6SBjoern A. Zeeb {
55592daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
55692daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
55792daf3a6SBjoern A. Zeeb 	char buf[20];
55892daf3a6SBjoern A. Zeeb 	int len;
55992daf3a6SBjoern A. Zeeb 
56092daf3a6SBjoern A. Zeeb #if defined(__linux__)
5619af1bba4SBjoern A. Zeeb 	len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_ap_addr);
56292daf3a6SBjoern A. Zeeb #elif defined(__FreeBSD__)
5639af1bba4SBjoern A. Zeeb 	len = sprintf(buf, "%6D\n", mvmvif->uapsd_misbehaving_ap_addr, ":");
56492daf3a6SBjoern A. Zeeb #endif
56592daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
56692daf3a6SBjoern A. Zeeb }
56792daf3a6SBjoern A. Zeeb 
iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)56892daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
56992daf3a6SBjoern A. Zeeb 						 char *buf, size_t count,
57092daf3a6SBjoern A. Zeeb 						 loff_t *ppos)
57192daf3a6SBjoern A. Zeeb {
57292daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
57392daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
57492daf3a6SBjoern A. Zeeb 	bool ret;
57592daf3a6SBjoern A. Zeeb 
57692daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
5779af1bba4SBjoern A. Zeeb 	ret = mac_pton(buf, mvmvif->uapsd_misbehaving_ap_addr);
57892daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
57992daf3a6SBjoern A. Zeeb 
58092daf3a6SBjoern A. Zeeb 	return ret ? count : -EINVAL;
58192daf3a6SBjoern A. Zeeb }
58292daf3a6SBjoern A. Zeeb 
iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)58392daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
58492daf3a6SBjoern A. Zeeb 					  size_t count, loff_t *ppos)
58592daf3a6SBjoern A. Zeeb {
58692daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
58792daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
588a4128aadSBjoern A. Zeeb 	struct ieee80211_bss_conf *link_conf;
58992daf3a6SBjoern A. Zeeb 	u16 value;
590a4128aadSBjoern A. Zeeb 	int link_id, ret = -EINVAL;
59192daf3a6SBjoern A. Zeeb 
59292daf3a6SBjoern A. Zeeb 	ret = kstrtou16(buf, 0, &value);
59392daf3a6SBjoern A. Zeeb 	if (ret)
59492daf3a6SBjoern A. Zeeb 		return ret;
59592daf3a6SBjoern A. Zeeb 
59692daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
59792daf3a6SBjoern A. Zeeb 
59892daf3a6SBjoern A. Zeeb 	mvm->dbgfs_rx_phyinfo = value;
59992daf3a6SBjoern A. Zeeb 
600a4128aadSBjoern A. Zeeb 	for_each_vif_active_link(vif, link_conf, link_id) {
601a4128aadSBjoern A. Zeeb 		struct ieee80211_chanctx_conf *chanctx_conf;
602a4128aadSBjoern A. Zeeb 		struct cfg80211_chan_def min_def, ap_def;
603a4128aadSBjoern A. Zeeb 		struct iwl_mvm_phy_ctxt *phy_ctxt;
604a4128aadSBjoern A. Zeeb 		u8 chains_static, chains_dynamic;
605a4128aadSBjoern A. Zeeb 
606a4128aadSBjoern A. Zeeb 		rcu_read_lock();
607a4128aadSBjoern A. Zeeb 		chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
608a4128aadSBjoern A. Zeeb 		if (!chanctx_conf) {
609a4128aadSBjoern A. Zeeb 			rcu_read_unlock();
610a4128aadSBjoern A. Zeeb 			continue;
611a4128aadSBjoern A. Zeeb 		}
612a4128aadSBjoern A. Zeeb 		/* A command can't be sent with RCU lock held, so copy
613a4128aadSBjoern A. Zeeb 		 * everything here and use it after unlocking
614a4128aadSBjoern A. Zeeb 		 */
615a4128aadSBjoern A. Zeeb 		min_def = chanctx_conf->min_def;
616a4128aadSBjoern A. Zeeb 		ap_def = chanctx_conf->ap;
617a4128aadSBjoern A. Zeeb 		chains_static = chanctx_conf->rx_chains_static;
618a4128aadSBjoern A. Zeeb 		chains_dynamic = chanctx_conf->rx_chains_dynamic;
619a4128aadSBjoern A. Zeeb 		rcu_read_unlock();
620a4128aadSBjoern A. Zeeb 
621a4128aadSBjoern A. Zeeb 		phy_ctxt = mvmvif->link[link_id]->phy_ctxt;
622a4128aadSBjoern A. Zeeb 		if (!phy_ctxt)
623a4128aadSBjoern A. Zeeb 			continue;
624a4128aadSBjoern A. Zeeb 
625a4128aadSBjoern A. Zeeb 		ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, &ap_def,
626a4128aadSBjoern A. Zeeb 					       chains_static, chains_dynamic);
627a4128aadSBjoern A. Zeeb 	}
628a4128aadSBjoern A. Zeeb 
62992daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
63092daf3a6SBjoern A. Zeeb 
63192daf3a6SBjoern A. Zeeb 	return ret ?: count;
63292daf3a6SBjoern A. Zeeb }
63392daf3a6SBjoern A. Zeeb 
iwl_dbgfs_rx_phyinfo_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)63492daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
63592daf3a6SBjoern A. Zeeb 					 char __user *user_buf,
63692daf3a6SBjoern A. Zeeb 					 size_t count, loff_t *ppos)
63792daf3a6SBjoern A. Zeeb {
63892daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
63992daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
64092daf3a6SBjoern A. Zeeb 	char buf[8];
64192daf3a6SBjoern A. Zeeb 	int len;
64292daf3a6SBjoern A. Zeeb 
64392daf3a6SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf), "0x%04x\n",
64492daf3a6SBjoern A. Zeeb 			mvmvif->mvm->dbgfs_rx_phyinfo);
64592daf3a6SBjoern A. Zeeb 
64692daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
64792daf3a6SBjoern A. Zeeb }
64892daf3a6SBjoern A. Zeeb 
iwl_dbgfs_quota_check(void * data,u8 * mac,struct ieee80211_vif * vif)64992daf3a6SBjoern A. Zeeb static void iwl_dbgfs_quota_check(void *data, u8 *mac,
65092daf3a6SBjoern A. Zeeb 				  struct ieee80211_vif *vif)
65192daf3a6SBjoern A. Zeeb {
65292daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
65392daf3a6SBjoern A. Zeeb 	int *ret = data;
65492daf3a6SBjoern A. Zeeb 
65592daf3a6SBjoern A. Zeeb 	if (mvmvif->dbgfs_quota_min)
65692daf3a6SBjoern A. Zeeb 		*ret = -EINVAL;
65792daf3a6SBjoern A. Zeeb }
65892daf3a6SBjoern A. Zeeb 
iwl_dbgfs_quota_min_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)65992daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
66092daf3a6SBjoern A. Zeeb 					 size_t count, loff_t *ppos)
66192daf3a6SBjoern A. Zeeb {
66292daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
66392daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
66492daf3a6SBjoern A. Zeeb 	u16 value;
66592daf3a6SBjoern A. Zeeb 	int ret;
66692daf3a6SBjoern A. Zeeb 
66792daf3a6SBjoern A. Zeeb 	ret = kstrtou16(buf, 0, &value);
66892daf3a6SBjoern A. Zeeb 	if (ret)
66992daf3a6SBjoern A. Zeeb 		return ret;
67092daf3a6SBjoern A. Zeeb 
67192daf3a6SBjoern A. Zeeb 	if (value > 95)
67292daf3a6SBjoern A. Zeeb 		return -EINVAL;
67392daf3a6SBjoern A. Zeeb 
67492daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
67592daf3a6SBjoern A. Zeeb 
67692daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_quota_min = 0;
67792daf3a6SBjoern A. Zeeb 	ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
67892daf3a6SBjoern A. Zeeb 				     iwl_dbgfs_quota_check, &ret);
67992daf3a6SBjoern A. Zeeb 	if (ret == 0) {
68092daf3a6SBjoern A. Zeeb 		mvmvif->dbgfs_quota_min = value;
68192daf3a6SBjoern A. Zeeb 		iwl_mvm_update_quotas(mvm, false, NULL);
68292daf3a6SBjoern A. Zeeb 	}
68392daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
68492daf3a6SBjoern A. Zeeb 
68592daf3a6SBjoern A. Zeeb 	return ret ?: count;
68692daf3a6SBjoern A. Zeeb }
68792daf3a6SBjoern A. Zeeb 
iwl_dbgfs_quota_min_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)68892daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
68992daf3a6SBjoern A. Zeeb 					char __user *user_buf,
69092daf3a6SBjoern A. Zeeb 					size_t count, loff_t *ppos)
69192daf3a6SBjoern A. Zeeb {
69292daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
69392daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
69492daf3a6SBjoern A. Zeeb 	char buf[10];
69592daf3a6SBjoern A. Zeeb 	int len;
69692daf3a6SBjoern A. Zeeb 
69792daf3a6SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
69892daf3a6SBjoern A. Zeeb 
69992daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
70092daf3a6SBjoern A. Zeeb }
70192daf3a6SBjoern A. Zeeb 
iwl_dbgfs_max_tx_op_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)702a4128aadSBjoern A. Zeeb static ssize_t iwl_dbgfs_max_tx_op_write(struct ieee80211_vif *vif, char *buf,
703a4128aadSBjoern A. Zeeb 					 size_t count, loff_t *ppos)
704a4128aadSBjoern A. Zeeb {
705a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
706a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
707a4128aadSBjoern A. Zeeb 	u16 value;
708a4128aadSBjoern A. Zeeb 	int ret;
709a4128aadSBjoern A. Zeeb 
710a4128aadSBjoern A. Zeeb 	ret = kstrtou16(buf, 0, &value);
711a4128aadSBjoern A. Zeeb 	if (ret)
712a4128aadSBjoern A. Zeeb 		return ret;
713a4128aadSBjoern A. Zeeb 
714a4128aadSBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
715a4128aadSBjoern A. Zeeb 	mvmvif->max_tx_op = value;
716a4128aadSBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
717a4128aadSBjoern A. Zeeb 
718a4128aadSBjoern A. Zeeb 	return count;
719a4128aadSBjoern A. Zeeb }
720a4128aadSBjoern A. Zeeb 
iwl_dbgfs_max_tx_op_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)721a4128aadSBjoern A. Zeeb static ssize_t iwl_dbgfs_max_tx_op_read(struct file *file,
722a4128aadSBjoern A. Zeeb 					char __user *user_buf,
723a4128aadSBjoern A. Zeeb 					size_t count, loff_t *ppos)
724a4128aadSBjoern A. Zeeb {
725a4128aadSBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
726a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
727a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
728a4128aadSBjoern A. Zeeb 	char buf[10];
729a4128aadSBjoern A. Zeeb 	int len;
730a4128aadSBjoern A. Zeeb 
731a4128aadSBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
732a4128aadSBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf), "%hu\n", mvmvif->max_tx_op);
733a4128aadSBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
734a4128aadSBjoern A. Zeeb 
735a4128aadSBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
736a4128aadSBjoern A. Zeeb }
737a4128aadSBjoern A. Zeeb 
iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)738a4128aadSBjoern A. Zeeb static ssize_t iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif *vif,
739a4128aadSBjoern A. Zeeb 					    char *buf, size_t count,
740a4128aadSBjoern A. Zeeb 					    loff_t *ppos)
741a4128aadSBjoern A. Zeeb {
742a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
743a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
744a4128aadSBjoern A. Zeeb 	u32 action;
745a4128aadSBjoern A. Zeeb 	int ret;
746a4128aadSBjoern A. Zeeb 
747a4128aadSBjoern A. Zeeb 	if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
748a4128aadSBjoern A. Zeeb 		return -EINVAL;
749a4128aadSBjoern A. Zeeb 
750a4128aadSBjoern A. Zeeb 	if (kstrtou32(buf, 0, &action))
751a4128aadSBjoern A. Zeeb 		return -EINVAL;
752a4128aadSBjoern A. Zeeb 
753a4128aadSBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
754a4128aadSBjoern A. Zeeb 
755a4128aadSBjoern A. Zeeb 	if (!action) {
756a4128aadSBjoern A. Zeeb 		ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false);
757a4128aadSBjoern A. Zeeb 	} else if (action == 1) {
758a4128aadSBjoern A. Zeeb 		ret = iwl_mvm_int_mlo_scan(mvm, vif);
759a4128aadSBjoern A. Zeeb 	} else {
760a4128aadSBjoern A. Zeeb 		ret = -EINVAL;
761a4128aadSBjoern A. Zeeb 	}
762a4128aadSBjoern A. Zeeb 
763a4128aadSBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
764a4128aadSBjoern A. Zeeb 
765a4128aadSBjoern A. Zeeb 	return ret ?: count;
766a4128aadSBjoern A. Zeeb }
767a4128aadSBjoern A. Zeeb 
iwl_dbgfs_esr_disable_reason_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)768a4128aadSBjoern A. Zeeb static ssize_t iwl_dbgfs_esr_disable_reason_read(struct file *file,
769a4128aadSBjoern A. Zeeb 						 char __user *user_buf,
770a4128aadSBjoern A. Zeeb 						 size_t count, loff_t *ppos)
771a4128aadSBjoern A. Zeeb {
772a4128aadSBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
773a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
774a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
775a4128aadSBjoern A. Zeeb 	unsigned long esr_mask;
776a4128aadSBjoern A. Zeeb 	char *buf;
777a4128aadSBjoern A. Zeeb 	int bufsz, pos, i;
778a4128aadSBjoern A. Zeeb 	ssize_t rv;
779a4128aadSBjoern A. Zeeb 
780a4128aadSBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
781a4128aadSBjoern A. Zeeb 	esr_mask = mvmvif->esr_disable_reason;
782a4128aadSBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
783a4128aadSBjoern A. Zeeb 
784a4128aadSBjoern A. Zeeb 	bufsz = hweight32(esr_mask) * 32 + 40;
785a4128aadSBjoern A. Zeeb 	buf = kmalloc(bufsz, GFP_KERNEL);
786a4128aadSBjoern A. Zeeb 	if (!buf)
787a4128aadSBjoern A. Zeeb 		return -ENOMEM;
788a4128aadSBjoern A. Zeeb 
789a4128aadSBjoern A. Zeeb 	pos = scnprintf(buf, bufsz, "EMLSR state: '0x%lx'\nreasons:\n",
790a4128aadSBjoern A. Zeeb 			esr_mask);
791a4128aadSBjoern A. Zeeb 	for_each_set_bit(i, &esr_mask, BITS_PER_LONG)
792a4128aadSBjoern A. Zeeb 		pos += scnprintf(buf + pos, bufsz - pos, " - %s\n",
793a4128aadSBjoern A. Zeeb 				 iwl_get_esr_state_string(BIT(i)));
794a4128aadSBjoern A. Zeeb 
795a4128aadSBjoern A. Zeeb 	rv = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
796a4128aadSBjoern A. Zeeb 	kfree(buf);
797a4128aadSBjoern A. Zeeb 	return rv;
798a4128aadSBjoern A. Zeeb }
799a4128aadSBjoern A. Zeeb 
iwl_dbgfs_esr_disable_reason_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)800a4128aadSBjoern A. Zeeb static ssize_t iwl_dbgfs_esr_disable_reason_write(struct ieee80211_vif *vif,
801a4128aadSBjoern A. Zeeb 						  char *buf, size_t count,
802a4128aadSBjoern A. Zeeb 						  loff_t *ppos)
803a4128aadSBjoern A. Zeeb {
804a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
805a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
806a4128aadSBjoern A. Zeeb 	u32 reason;
807a4128aadSBjoern A. Zeeb 	u8 block;
808a4128aadSBjoern A. Zeeb 	int ret;
809a4128aadSBjoern A. Zeeb 
810a4128aadSBjoern A. Zeeb 	ret = sscanf(buf, "%u %hhu", &reason, &block);
811a4128aadSBjoern A. Zeeb 	if (ret < 0)
812a4128aadSBjoern A. Zeeb 		return ret;
813a4128aadSBjoern A. Zeeb 
814a4128aadSBjoern A. Zeeb 	if (hweight16(reason) != 1 || !(reason & IWL_MVM_BLOCK_ESR_REASONS))
815a4128aadSBjoern A. Zeeb 		return -EINVAL;
816a4128aadSBjoern A. Zeeb 
817a4128aadSBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
818a4128aadSBjoern A. Zeeb 	if (block)
819a4128aadSBjoern A. Zeeb 		iwl_mvm_block_esr(mvm, vif, reason,
820a4128aadSBjoern A. Zeeb 				  iwl_mvm_get_primary_link(vif));
821a4128aadSBjoern A. Zeeb 	else
822a4128aadSBjoern A. Zeeb 		iwl_mvm_unblock_esr(mvm, vif, reason);
823a4128aadSBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
824a4128aadSBjoern A. Zeeb 
825a4128aadSBjoern A. Zeeb 	return count;
826a4128aadSBjoern A. Zeeb }
827a4128aadSBjoern A. Zeeb 
82892daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
82992daf3a6SBjoern A. Zeeb 	_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
83092daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
83192daf3a6SBjoern A. Zeeb 	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
83292daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {		\
83392daf3a6SBjoern A. Zeeb 		debugfs_create_file(#name, mode, parent, vif,		\
83492daf3a6SBjoern A. Zeeb 				    &iwl_dbgfs_##name##_ops);		\
83592daf3a6SBjoern A. Zeeb 	} while (0)
83692daf3a6SBjoern A. Zeeb 
83792daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(mac_params);
83892daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
83992daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
84092daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
84192daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
84292daf3a6SBjoern A. Zeeb MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10);
84392daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
84492daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
84592daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
84692daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
847a4128aadSBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(max_tx_op, 10);
848a4128aadSBjoern A. Zeeb MVM_DEBUGFS_WRITE_FILE_OPS(int_mlo_scan, 32);
849a4128aadSBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(esr_disable_reason, 32);
85092daf3a6SBjoern A. Zeeb 
iwl_mvm_vif_add_debugfs(struct ieee80211_hw * hw,struct ieee80211_vif * vif)851a4128aadSBjoern A. Zeeb void iwl_mvm_vif_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
85292daf3a6SBjoern A. Zeeb {
853a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
85492daf3a6SBjoern A. Zeeb 	struct dentry *dbgfs_dir = vif->debugfs_dir;
85592daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
85692daf3a6SBjoern A. Zeeb 
85792daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
85892daf3a6SBjoern A. Zeeb 	if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) {
85992daf3a6SBjoern A. Zeeb 		IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
86092daf3a6SBjoern A. Zeeb 			dbgfs_dir);
86192daf3a6SBjoern A. Zeeb 		return;
86292daf3a6SBjoern A. Zeeb 	}
86392daf3a6SBjoern A. Zeeb 
86492daf3a6SBjoern A. Zeeb 	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
86592daf3a6SBjoern A. Zeeb 	    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
86692daf3a6SBjoern A. Zeeb 	     (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
86792daf3a6SBjoern A. Zeeb 		MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
86892daf3a6SBjoern A. Zeeb 
86992daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
87092daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
87192daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
87292daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600);
87392daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
87492daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
87592daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
87692daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
877a4128aadSBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(max_tx_op, mvmvif->dbgfs_dir, 0600);
878a4128aadSBjoern A. Zeeb 	debugfs_create_bool("ftm_unprotected", 0200, mvmvif->dbgfs_dir,
879a4128aadSBjoern A. Zeeb 			    &mvmvif->ftm_unprotected);
880a4128aadSBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(int_mlo_scan, mvmvif->dbgfs_dir, 0200);
881a4128aadSBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(esr_disable_reason, mvmvif->dbgfs_dir, 0600);
88292daf3a6SBjoern A. Zeeb 
88392daf3a6SBjoern A. Zeeb 	if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
88492daf3a6SBjoern A. Zeeb 	    mvmvif == mvm->bf_allowed_vif)
88592daf3a6SBjoern A. Zeeb 		MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
886a4128aadSBjoern A. Zeeb }
887a4128aadSBjoern A. Zeeb 
iwl_mvm_vif_dbgfs_add_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif)888a4128aadSBjoern A. Zeeb void iwl_mvm_vif_dbgfs_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
889a4128aadSBjoern A. Zeeb {
890a4128aadSBjoern A. Zeeb 	struct dentry *dbgfs_dir = vif->debugfs_dir;
891*07f65755SBjoern A. Zeeb #if defined(__linux__)
892a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
893a4128aadSBjoern A. Zeeb 	char buf[3 * 3 + 11 + (NL80211_WIPHY_NAME_MAXLEN + 1) +
894a4128aadSBjoern A. Zeeb 		 (7 + IFNAMSIZ + 1) + 6 + 1];
895a4128aadSBjoern A. Zeeb 	char name[7 + IFNAMSIZ + 1];
896*07f65755SBjoern A. Zeeb #endif
897a4128aadSBjoern A. Zeeb 
898a4128aadSBjoern A. Zeeb 	/* this will happen in monitor mode */
899a4128aadSBjoern A. Zeeb 	if (!dbgfs_dir)
900a4128aadSBjoern A. Zeeb 		return;
90192daf3a6SBjoern A. Zeeb 
90292daf3a6SBjoern A. Zeeb #if defined(__linux__)
90392daf3a6SBjoern A. Zeeb 	/*
90492daf3a6SBjoern A. Zeeb 	 * Create symlink for convenience pointing to interface specific
90592daf3a6SBjoern A. Zeeb 	 * debugfs entries for the driver. For example, under
90692daf3a6SBjoern A. Zeeb 	 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
90792daf3a6SBjoern A. Zeeb 	 * find
90892daf3a6SBjoern A. Zeeb 	 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
90992daf3a6SBjoern A. Zeeb 	 */
910a4128aadSBjoern A. Zeeb 	snprintf(name, sizeof(name), "%pd", dbgfs_dir);
911a4128aadSBjoern A. Zeeb 	snprintf(buf, sizeof(buf), "../../../%pd3/iwlmvm", dbgfs_dir);
91292daf3a6SBjoern A. Zeeb 
913a4128aadSBjoern A. Zeeb 	mvmvif->dbgfs_slink =
914a4128aadSBjoern A. Zeeb 		debugfs_create_symlink(name, mvm->debugfs_dir, buf);
91592daf3a6SBjoern A. Zeeb #endif
91692daf3a6SBjoern A. Zeeb }
91792daf3a6SBjoern A. Zeeb 
iwl_mvm_vif_dbgfs_rm_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif)918a4128aadSBjoern A. Zeeb void iwl_mvm_vif_dbgfs_rm_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
91992daf3a6SBjoern A. Zeeb {
92092daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
92192daf3a6SBjoern A. Zeeb 
92292daf3a6SBjoern A. Zeeb 	debugfs_remove(mvmvif->dbgfs_slink);
92392daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_slink = NULL;
924a4128aadSBjoern A. Zeeb }
92592daf3a6SBjoern A. Zeeb 
926a4128aadSBjoern A. Zeeb #define MVM_DEBUGFS_WRITE_LINK_FILE_OPS(name, bufsz)			\
927a4128aadSBjoern A. Zeeb 	_MVM_DEBUGFS_WRITE_FILE_OPS(link_##name, bufsz,			\
928a4128aadSBjoern A. Zeeb 				    struct ieee80211_bss_conf)
929a4128aadSBjoern A. Zeeb #define MVM_DEBUGFS_READ_WRITE_LINK_FILE_OPS(name, bufsz)		\
930a4128aadSBjoern A. Zeeb 	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(link_##name, bufsz,		\
931a4128aadSBjoern A. Zeeb 					 struct ieee80211_bss_conf)
932a4128aadSBjoern A. Zeeb #define MVM_DEBUGFS_ADD_LINK_FILE(name, parent, mode)			\
933a4128aadSBjoern A. Zeeb 	debugfs_create_file(#name, mode, parent, link_conf,		\
934a4128aadSBjoern A. Zeeb 			    &iwl_dbgfs_link_##name##_ops)
935a4128aadSBjoern A. Zeeb 
iwl_mvm_debugfs_add_link_files(struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct dentry * mvm_dir)936a4128aadSBjoern A. Zeeb static void iwl_mvm_debugfs_add_link_files(struct ieee80211_vif *vif,
937a4128aadSBjoern A. Zeeb 					   struct ieee80211_bss_conf *link_conf,
938a4128aadSBjoern A. Zeeb 					   struct dentry *mvm_dir)
939a4128aadSBjoern A. Zeeb {
940a4128aadSBjoern A. Zeeb 	/* Add per-link files here*/
941a4128aadSBjoern A. Zeeb }
942a4128aadSBjoern A. Zeeb 
iwl_mvm_link_add_debugfs(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,struct dentry * dir)943a4128aadSBjoern A. Zeeb void iwl_mvm_link_add_debugfs(struct ieee80211_hw *hw,
944a4128aadSBjoern A. Zeeb 			      struct ieee80211_vif *vif,
945a4128aadSBjoern A. Zeeb 			      struct ieee80211_bss_conf *link_conf,
946a4128aadSBjoern A. Zeeb 			      struct dentry *dir)
947a4128aadSBjoern A. Zeeb {
948a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
949a4128aadSBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
950a4128aadSBjoern A. Zeeb 	unsigned int link_id = link_conf->link_id;
951a4128aadSBjoern A. Zeeb 	struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
952a4128aadSBjoern A. Zeeb 	struct dentry *mvm_dir;
953a4128aadSBjoern A. Zeeb 
954a4128aadSBjoern A. Zeeb 	if (WARN_ON(!link_info) || !dir)
955a4128aadSBjoern A. Zeeb 		return;
956a4128aadSBjoern A. Zeeb 
957a4128aadSBjoern A. Zeeb 	if (dir == vif->debugfs_dir) {
958a4128aadSBjoern A. Zeeb 		WARN_ON(!mvmvif->dbgfs_dir);
959a4128aadSBjoern A. Zeeb 		mvm_dir = mvmvif->dbgfs_dir;
960a4128aadSBjoern A. Zeeb 	} else {
961a4128aadSBjoern A. Zeeb 		mvm_dir = debugfs_create_dir("iwlmvm", dir);
962a4128aadSBjoern A. Zeeb 		if (IS_ERR_OR_NULL(mvm_dir)) {
963a4128aadSBjoern A. Zeeb 			IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
964a4128aadSBjoern A. Zeeb 				dir);
965a4128aadSBjoern A. Zeeb 			return;
966a4128aadSBjoern A. Zeeb 		}
967a4128aadSBjoern A. Zeeb 	}
968a4128aadSBjoern A. Zeeb 
969a4128aadSBjoern A. Zeeb 	iwl_mvm_debugfs_add_link_files(vif, link_conf, mvm_dir);
97092daf3a6SBjoern A. Zeeb }
971