192daf3a6SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
292daf3a6SBjoern A. Zeeb /*
39af1bba4SBjoern A. Zeeb  * Copyright (C) 2012-2014, 2018-2023 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)
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 
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);
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 
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;
58892daf3a6SBjoern A. Zeeb 	struct ieee80211_chanctx_conf *chanctx_conf;
58992daf3a6SBjoern A. Zeeb 	struct iwl_mvm_phy_ctxt *phy_ctxt;
59092daf3a6SBjoern A. Zeeb 	u16 value;
59192daf3a6SBjoern A. Zeeb 	int ret;
59292daf3a6SBjoern A. Zeeb 
59392daf3a6SBjoern A. Zeeb 	ret = kstrtou16(buf, 0, &value);
59492daf3a6SBjoern A. Zeeb 	if (ret)
59592daf3a6SBjoern A. Zeeb 		return ret;
59692daf3a6SBjoern A. Zeeb 
59792daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
59892daf3a6SBjoern A. Zeeb 	rcu_read_lock();
59992daf3a6SBjoern A. Zeeb 
60092daf3a6SBjoern A. Zeeb 	chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
60192daf3a6SBjoern A. Zeeb 	/* make sure the channel context is assigned */
60292daf3a6SBjoern A. Zeeb 	if (!chanctx_conf) {
60392daf3a6SBjoern A. Zeeb 		rcu_read_unlock();
60492daf3a6SBjoern A. Zeeb 		mutex_unlock(&mvm->mutex);
60592daf3a6SBjoern A. Zeeb 		return -EINVAL;
60692daf3a6SBjoern A. Zeeb 	}
60792daf3a6SBjoern A. Zeeb 
60892daf3a6SBjoern A. Zeeb 	phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
60992daf3a6SBjoern A. Zeeb 	rcu_read_unlock();
61092daf3a6SBjoern A. Zeeb 
61192daf3a6SBjoern A. Zeeb 	mvm->dbgfs_rx_phyinfo = value;
61292daf3a6SBjoern A. Zeeb 
61392daf3a6SBjoern A. Zeeb 	ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
61492daf3a6SBjoern A. Zeeb 				       chanctx_conf->rx_chains_static,
61592daf3a6SBjoern A. Zeeb 				       chanctx_conf->rx_chains_dynamic);
61692daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
61792daf3a6SBjoern A. Zeeb 
61892daf3a6SBjoern A. Zeeb 	return ret ?: count;
61992daf3a6SBjoern A. Zeeb }
62092daf3a6SBjoern A. Zeeb 
iwl_dbgfs_rx_phyinfo_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)62192daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
62292daf3a6SBjoern A. Zeeb 					 char __user *user_buf,
62392daf3a6SBjoern A. Zeeb 					 size_t count, loff_t *ppos)
62492daf3a6SBjoern A. Zeeb {
62592daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
62692daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
62792daf3a6SBjoern A. Zeeb 	char buf[8];
62892daf3a6SBjoern A. Zeeb 	int len;
62992daf3a6SBjoern A. Zeeb 
63092daf3a6SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf), "0x%04x\n",
63192daf3a6SBjoern A. Zeeb 			mvmvif->mvm->dbgfs_rx_phyinfo);
63292daf3a6SBjoern A. Zeeb 
63392daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
63492daf3a6SBjoern A. Zeeb }
63592daf3a6SBjoern A. Zeeb 
iwl_dbgfs_quota_check(void * data,u8 * mac,struct ieee80211_vif * vif)63692daf3a6SBjoern A. Zeeb static void iwl_dbgfs_quota_check(void *data, u8 *mac,
63792daf3a6SBjoern A. Zeeb 				  struct ieee80211_vif *vif)
63892daf3a6SBjoern A. Zeeb {
63992daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
64092daf3a6SBjoern A. Zeeb 	int *ret = data;
64192daf3a6SBjoern A. Zeeb 
64292daf3a6SBjoern A. Zeeb 	if (mvmvif->dbgfs_quota_min)
64392daf3a6SBjoern A. Zeeb 		*ret = -EINVAL;
64492daf3a6SBjoern A. Zeeb }
64592daf3a6SBjoern A. Zeeb 
iwl_dbgfs_quota_min_write(struct ieee80211_vif * vif,char * buf,size_t count,loff_t * ppos)64692daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
64792daf3a6SBjoern A. Zeeb 					 size_t count, loff_t *ppos)
64892daf3a6SBjoern A. Zeeb {
64992daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
65092daf3a6SBjoern A. Zeeb 	struct iwl_mvm *mvm = mvmvif->mvm;
65192daf3a6SBjoern A. Zeeb 	u16 value;
65292daf3a6SBjoern A. Zeeb 	int ret;
65392daf3a6SBjoern A. Zeeb 
65492daf3a6SBjoern A. Zeeb 	ret = kstrtou16(buf, 0, &value);
65592daf3a6SBjoern A. Zeeb 	if (ret)
65692daf3a6SBjoern A. Zeeb 		return ret;
65792daf3a6SBjoern A. Zeeb 
65892daf3a6SBjoern A. Zeeb 	if (value > 95)
65992daf3a6SBjoern A. Zeeb 		return -EINVAL;
66092daf3a6SBjoern A. Zeeb 
66192daf3a6SBjoern A. Zeeb 	mutex_lock(&mvm->mutex);
66292daf3a6SBjoern A. Zeeb 
66392daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_quota_min = 0;
66492daf3a6SBjoern A. Zeeb 	ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
66592daf3a6SBjoern A. Zeeb 				     iwl_dbgfs_quota_check, &ret);
66692daf3a6SBjoern A. Zeeb 	if (ret == 0) {
66792daf3a6SBjoern A. Zeeb 		mvmvif->dbgfs_quota_min = value;
66892daf3a6SBjoern A. Zeeb 		iwl_mvm_update_quotas(mvm, false, NULL);
66992daf3a6SBjoern A. Zeeb 	}
67092daf3a6SBjoern A. Zeeb 	mutex_unlock(&mvm->mutex);
67192daf3a6SBjoern A. Zeeb 
67292daf3a6SBjoern A. Zeeb 	return ret ?: count;
67392daf3a6SBjoern A. Zeeb }
67492daf3a6SBjoern A. Zeeb 
iwl_dbgfs_quota_min_read(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)67592daf3a6SBjoern A. Zeeb static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
67692daf3a6SBjoern A. Zeeb 					char __user *user_buf,
67792daf3a6SBjoern A. Zeeb 					size_t count, loff_t *ppos)
67892daf3a6SBjoern A. Zeeb {
67992daf3a6SBjoern A. Zeeb 	struct ieee80211_vif *vif = file->private_data;
68092daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
68192daf3a6SBjoern A. Zeeb 	char buf[10];
68292daf3a6SBjoern A. Zeeb 	int len;
68392daf3a6SBjoern A. Zeeb 
68492daf3a6SBjoern A. Zeeb 	len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
68592daf3a6SBjoern A. Zeeb 
68692daf3a6SBjoern A. Zeeb 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
68792daf3a6SBjoern A. Zeeb }
68892daf3a6SBjoern A. Zeeb 
68992daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
69092daf3a6SBjoern A. Zeeb 	_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
69192daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
69292daf3a6SBjoern A. Zeeb 	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
69392daf3a6SBjoern A. Zeeb #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {		\
69492daf3a6SBjoern A. Zeeb 		debugfs_create_file(#name, mode, parent, vif,		\
69592daf3a6SBjoern A. Zeeb 				    &iwl_dbgfs_##name##_ops);		\
69692daf3a6SBjoern A. Zeeb 	} while (0)
69792daf3a6SBjoern A. Zeeb 
69892daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(mac_params);
69992daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
70092daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
70192daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
70292daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
70392daf3a6SBjoern A. Zeeb MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10);
70492daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
70592daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
70692daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
70792daf3a6SBjoern A. Zeeb MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
70892daf3a6SBjoern A. Zeeb 
70992daf3a6SBjoern A. Zeeb 
iwl_mvm_vif_dbgfs_register(struct iwl_mvm * mvm,struct ieee80211_vif * vif)71092daf3a6SBjoern A. Zeeb void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
71192daf3a6SBjoern A. Zeeb {
71292daf3a6SBjoern A. Zeeb 	struct dentry *dbgfs_dir = vif->debugfs_dir;
71392daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
71492daf3a6SBjoern A. Zeeb #if defined(__linux__)
71592daf3a6SBjoern A. Zeeb 	char buf[100];
71692daf3a6SBjoern A. Zeeb #endif
71792daf3a6SBjoern A. Zeeb 
71892daf3a6SBjoern A. Zeeb 	/*
71992daf3a6SBjoern A. Zeeb 	 * Check if debugfs directory already exist before creating it.
72092daf3a6SBjoern A. Zeeb 	 * This may happen when, for example, resetting hw or suspend-resume
72192daf3a6SBjoern A. Zeeb 	 */
72292daf3a6SBjoern A. Zeeb 	if (!dbgfs_dir || mvmvif->dbgfs_dir)
72392daf3a6SBjoern A. Zeeb 		return;
72492daf3a6SBjoern A. Zeeb 
72592daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
72692daf3a6SBjoern A. Zeeb 	if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) {
72792daf3a6SBjoern A. Zeeb 		IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
72892daf3a6SBjoern A. Zeeb 			dbgfs_dir);
72992daf3a6SBjoern A. Zeeb 		return;
73092daf3a6SBjoern A. Zeeb 	}
73192daf3a6SBjoern A. Zeeb 
73292daf3a6SBjoern A. Zeeb 	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
73392daf3a6SBjoern A. Zeeb 	    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
73492daf3a6SBjoern A. Zeeb 	     (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
73592daf3a6SBjoern A. Zeeb 		MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
73692daf3a6SBjoern A. Zeeb 
73792daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
73892daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
73992daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
74092daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600);
74192daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
74292daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
74392daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
74492daf3a6SBjoern A. Zeeb 	MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
74592daf3a6SBjoern A. Zeeb 
74692daf3a6SBjoern A. Zeeb 	if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
74792daf3a6SBjoern A. Zeeb 	    mvmvif == mvm->bf_allowed_vif)
74892daf3a6SBjoern A. Zeeb 		MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
74992daf3a6SBjoern A. Zeeb 
75092daf3a6SBjoern A. Zeeb #if defined(__linux__)
75192daf3a6SBjoern A. Zeeb 	/*
75292daf3a6SBjoern A. Zeeb 	 * Create symlink for convenience pointing to interface specific
75392daf3a6SBjoern A. Zeeb 	 * debugfs entries for the driver. For example, under
75492daf3a6SBjoern A. Zeeb 	 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
75592daf3a6SBjoern A. Zeeb 	 * find
75692daf3a6SBjoern A. Zeeb 	 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
75792daf3a6SBjoern A. Zeeb 	 */
75892daf3a6SBjoern A. Zeeb 	snprintf(buf, 100, "../../../%pd3/%pd",
75992daf3a6SBjoern A. Zeeb 		 dbgfs_dir,
76092daf3a6SBjoern A. Zeeb 		 mvmvif->dbgfs_dir);
76192daf3a6SBjoern A. Zeeb 
76292daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
76392daf3a6SBjoern A. Zeeb 						     mvm->debugfs_dir, buf);
76492daf3a6SBjoern A. Zeeb #endif
76592daf3a6SBjoern A. Zeeb }
76692daf3a6SBjoern A. Zeeb 
iwl_mvm_vif_dbgfs_clean(struct iwl_mvm * mvm,struct ieee80211_vif * vif)76792daf3a6SBjoern A. Zeeb void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
76892daf3a6SBjoern A. Zeeb {
76992daf3a6SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
77092daf3a6SBjoern A. Zeeb 
77192daf3a6SBjoern A. Zeeb 	debugfs_remove(mvmvif->dbgfs_slink);
77292daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_slink = NULL;
77392daf3a6SBjoern A. Zeeb 
77492daf3a6SBjoern A. Zeeb 	debugfs_remove_recursive(mvmvif->dbgfs_dir);
77592daf3a6SBjoern A. Zeeb 	mvmvif->dbgfs_dir = NULL;
77692daf3a6SBjoern A. Zeeb }
777