GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / net / wireless / intel / iwlwifi / mvm / debugfs-vif.c
1 /******************************************************************************
2  *
3  * This file is provided under a dual BSD/GPLv2 license.  When using or
4  * redistributing this file, you may do so under either license.
5  *
6  * GPL LICENSE SUMMARY
7  *
8  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
9  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of version 2 of the GNU General Public License as
14  * published by the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24  * USA
25  *
26  * The full GNU General Public License is included in this distribution
27  * in the file called COPYING.
28  *
29  * Contact Information:
30  *  Intel Linux Wireless <linuxwifi@intel.com>
31  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32  *
33  * BSD LICENSE
34  *
35  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
36  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
37  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  *
44  *  * Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  *  * Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in
48  *    the documentation and/or other materials provided with the
49  *    distribution.
50  *  * Neither the name Intel Corporation nor the names of its
51  *    contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
64  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  *
66  *****************************************************************************/
67 #include "mvm.h"
68 #include "fw/api/tof.h"
69 #include "debugfs.h"
70
71 static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
72                                  struct ieee80211_vif *vif,
73                                  enum iwl_dbgfs_pm_mask param, int val)
74 {
75         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
76         struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm;
77
78         dbgfs_pm->mask |= param;
79
80         switch (param) {
81         case MVM_DEBUGFS_PM_KEEP_ALIVE: {
82                 int dtimper = vif->bss_conf.dtim_period ?: 1;
83                 int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
84
85                 IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val);
86                 if (val * MSEC_PER_SEC < 3 * dtimper_msec)
87                         IWL_WARN(mvm,
88                                  "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
89                                  val * MSEC_PER_SEC, 3 * dtimper_msec);
90                 dbgfs_pm->keep_alive_seconds = val;
91                 break;
92         }
93         case MVM_DEBUGFS_PM_SKIP_OVER_DTIM:
94                 IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n",
95                                 val ? "enabled" : "disabled");
96                 dbgfs_pm->skip_over_dtim = val;
97                 break;
98         case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS:
99                 IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val);
100                 dbgfs_pm->skip_dtim_periods = val;
101                 break;
102         case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT:
103                 IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val);
104                 dbgfs_pm->rx_data_timeout = val;
105                 break;
106         case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT:
107                 IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val);
108                 dbgfs_pm->tx_data_timeout = val;
109                 break;
110         case MVM_DEBUGFS_PM_LPRX_ENA:
111                 IWL_DEBUG_POWER(mvm, "lprx %s\n", val ? "enabled" : "disabled");
112                 dbgfs_pm->lprx_ena = val;
113                 break;
114         case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD:
115                 IWL_DEBUG_POWER(mvm, "lprx_rssi_threshold=%d\n", val);
116                 dbgfs_pm->lprx_rssi_threshold = val;
117                 break;
118         case MVM_DEBUGFS_PM_SNOOZE_ENABLE:
119                 IWL_DEBUG_POWER(mvm, "snooze_enable=%d\n", val);
120                 dbgfs_pm->snooze_ena = val;
121                 break;
122         case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING:
123                 IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
124                 dbgfs_pm->uapsd_misbehaving = val;
125                 break;
126         case MVM_DEBUGFS_PM_USE_PS_POLL:
127                 IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
128                 dbgfs_pm->use_ps_poll = val;
129                 break;
130         }
131 }
132
133 static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
134                                          size_t count, loff_t *ppos)
135 {
136         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
137         struct iwl_mvm *mvm = mvmvif->mvm;
138         enum iwl_dbgfs_pm_mask param;
139         int val, ret;
140
141         if (!strncmp("keep_alive=", buf, 11)) {
142                 if (sscanf(buf + 11, "%d", &val) != 1)
143                         return -EINVAL;
144                 param = MVM_DEBUGFS_PM_KEEP_ALIVE;
145         } else if (!strncmp("skip_over_dtim=", buf, 15)) {
146                 if (sscanf(buf + 15, "%d", &val) != 1)
147                         return -EINVAL;
148                 param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM;
149         } else if (!strncmp("skip_dtim_periods=", buf, 18)) {
150                 if (sscanf(buf + 18, "%d", &val) != 1)
151                         return -EINVAL;
152                 param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS;
153         } else if (!strncmp("rx_data_timeout=", buf, 16)) {
154                 if (sscanf(buf + 16, "%d", &val) != 1)
155                         return -EINVAL;
156                 param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT;
157         } else if (!strncmp("tx_data_timeout=", buf, 16)) {
158                 if (sscanf(buf + 16, "%d", &val) != 1)
159                         return -EINVAL;
160                 param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
161         } else if (!strncmp("lprx=", buf, 5)) {
162                 if (sscanf(buf + 5, "%d", &val) != 1)
163                         return -EINVAL;
164                 param = MVM_DEBUGFS_PM_LPRX_ENA;
165         } else if (!strncmp("lprx_rssi_threshold=", buf, 20)) {
166                 if (sscanf(buf + 20, "%d", &val) != 1)
167                         return -EINVAL;
168                 if (val > POWER_LPRX_RSSI_THRESHOLD_MAX || val <
169                     POWER_LPRX_RSSI_THRESHOLD_MIN)
170                         return -EINVAL;
171                 param = MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD;
172         } else if (!strncmp("snooze_enable=", buf, 14)) {
173                 if (sscanf(buf + 14, "%d", &val) != 1)
174                         return -EINVAL;
175                 param = MVM_DEBUGFS_PM_SNOOZE_ENABLE;
176         } else if (!strncmp("uapsd_misbehaving=", buf, 18)) {
177                 if (sscanf(buf + 18, "%d", &val) != 1)
178                         return -EINVAL;
179                 param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
180         } else if (!strncmp("use_ps_poll=", buf, 12)) {
181                 if (sscanf(buf + 12, "%d", &val) != 1)
182                         return -EINVAL;
183                 param = MVM_DEBUGFS_PM_USE_PS_POLL;
184         } else {
185                 return -EINVAL;
186         }
187
188         mutex_lock(&mvm->mutex);
189         iwl_dbgfs_update_pm(mvm, vif, param, val);
190         ret = iwl_mvm_power_update_mac(mvm);
191         mutex_unlock(&mvm->mutex);
192
193         return ret ?: count;
194 }
195
196 static ssize_t iwl_dbgfs_tx_pwr_lmt_read(struct file *file,
197                                          char __user *user_buf,
198                                          size_t count, loff_t *ppos)
199 {
200         struct ieee80211_vif *vif = file->private_data;
201         char buf[64];
202         int bufsz = sizeof(buf);
203         int pos;
204
205         pos = scnprintf(buf, bufsz, "bss limit = %d\n",
206                         vif->bss_conf.txpower);
207
208         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
209 }
210
211 static ssize_t iwl_dbgfs_pm_params_read(struct file *file,
212                                         char __user *user_buf,
213                                         size_t count, loff_t *ppos)
214 {
215         struct ieee80211_vif *vif = file->private_data;
216         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
217         struct iwl_mvm *mvm = mvmvif->mvm;
218         char buf[512];
219         int bufsz = sizeof(buf);
220         int pos;
221
222         pos = iwl_mvm_power_mac_dbgfs_read(mvm, vif, buf, bufsz);
223
224         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
225 }
226
227 static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
228                                          char __user *user_buf,
229                                          size_t count, loff_t *ppos)
230 {
231         struct ieee80211_vif *vif = file->private_data;
232         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
233         struct iwl_mvm *mvm = mvmvif->mvm;
234         u8 ap_sta_id;
235         struct ieee80211_chanctx_conf *chanctx_conf;
236         char buf[512];
237         int bufsz = sizeof(buf);
238         int pos = 0;
239         int i;
240
241         mutex_lock(&mvm->mutex);
242
243         ap_sta_id = mvmvif->ap_sta_id;
244
245         switch (ieee80211_vif_type_p2p(vif)) {
246         case NL80211_IFTYPE_ADHOC:
247                 pos += scnprintf(buf+pos, bufsz-pos, "type: ibss\n");
248                 break;
249         case NL80211_IFTYPE_STATION:
250                 pos += scnprintf(buf+pos, bufsz-pos, "type: bss\n");
251                 break;
252         case NL80211_IFTYPE_AP:
253                 pos += scnprintf(buf+pos, bufsz-pos, "type: ap\n");
254                 break;
255         case NL80211_IFTYPE_P2P_CLIENT:
256                 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p client\n");
257                 break;
258         case NL80211_IFTYPE_P2P_GO:
259                 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p go\n");
260                 break;
261         case NL80211_IFTYPE_P2P_DEVICE:
262                 pos += scnprintf(buf+pos, bufsz-pos, "type: p2p dev\n");
263                 break;
264         default:
265                 break;
266         }
267
268         pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
269                          mvmvif->id, mvmvif->color);
270         pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
271                          vif->bss_conf.bssid);
272         pos += scnprintf(buf+pos, bufsz-pos, "Load: %d\n",
273                          mvm->tcm.result.load[mvmvif->id]);
274         pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
275         for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++)
276                 pos += scnprintf(buf+pos, bufsz-pos,
277                                  "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
278                                  i, mvmvif->queue_params[i].txop,
279                                  mvmvif->queue_params[i].cw_min,
280                                  mvmvif->queue_params[i].cw_max,
281                                  mvmvif->queue_params[i].aifs,
282                                  mvmvif->queue_params[i].uapsd);
283
284         if (vif->type == NL80211_IFTYPE_STATION &&
285             ap_sta_id != IWL_MVM_INVALID_STA) {
286                 struct iwl_mvm_sta *mvm_sta;
287
288                 mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id);
289                 if (mvm_sta) {
290                         pos += scnprintf(buf+pos, bufsz-pos,
291                                          "ap_sta_id %d - reduced Tx power %d\n",
292                                          ap_sta_id,
293                                          mvm_sta->bt_reduced_txpower);
294                 }
295         }
296
297         rcu_read_lock();
298         chanctx_conf = rcu_dereference(vif->chanctx_conf);
299         if (chanctx_conf)
300                 pos += scnprintf(buf+pos, bufsz-pos,
301                                  "idle rx chains %d, active rx chains: %d\n",
302                                  chanctx_conf->rx_chains_static,
303                                  chanctx_conf->rx_chains_dynamic);
304         rcu_read_unlock();
305
306         mutex_unlock(&mvm->mutex);
307
308         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
309 }
310
311 static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
312                                 enum iwl_dbgfs_bf_mask param, int value)
313 {
314         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
315         struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf;
316
317         dbgfs_bf->mask |= param;
318
319         switch (param) {
320         case MVM_DEBUGFS_BF_ENERGY_DELTA:
321                 dbgfs_bf->bf_energy_delta = value;
322                 break;
323         case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA:
324                 dbgfs_bf->bf_roaming_energy_delta = value;
325                 break;
326         case MVM_DEBUGFS_BF_ROAMING_STATE:
327                 dbgfs_bf->bf_roaming_state = value;
328                 break;
329         case MVM_DEBUGFS_BF_TEMP_THRESHOLD:
330                 dbgfs_bf->bf_temp_threshold = value;
331                 break;
332         case MVM_DEBUGFS_BF_TEMP_FAST_FILTER:
333                 dbgfs_bf->bf_temp_fast_filter = value;
334                 break;
335         case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER:
336                 dbgfs_bf->bf_temp_slow_filter = value;
337                 break;
338         case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER:
339                 dbgfs_bf->bf_enable_beacon_filter = value;
340                 break;
341         case MVM_DEBUGFS_BF_DEBUG_FLAG:
342                 dbgfs_bf->bf_debug_flag = value;
343                 break;
344         case MVM_DEBUGFS_BF_ESCAPE_TIMER:
345                 dbgfs_bf->bf_escape_timer = value;
346                 break;
347         case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT:
348                 dbgfs_bf->ba_enable_beacon_abort = value;
349                 break;
350         case MVM_DEBUGFS_BA_ESCAPE_TIMER:
351                 dbgfs_bf->ba_escape_timer = value;
352                 break;
353         }
354 }
355
356 static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf,
357                                          size_t count, loff_t *ppos)
358 {
359         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
360         struct iwl_mvm *mvm = mvmvif->mvm;
361         enum iwl_dbgfs_bf_mask param;
362         int value, ret = 0;
363
364         if (!strncmp("bf_energy_delta=", buf, 16)) {
365                 if (sscanf(buf+16, "%d", &value) != 1)
366                         return -EINVAL;
367                 if (value < IWL_BF_ENERGY_DELTA_MIN ||
368                     value > IWL_BF_ENERGY_DELTA_MAX)
369                         return -EINVAL;
370                 param = MVM_DEBUGFS_BF_ENERGY_DELTA;
371         } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) {
372                 if (sscanf(buf+24, "%d", &value) != 1)
373                         return -EINVAL;
374                 if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN ||
375                     value > IWL_BF_ROAMING_ENERGY_DELTA_MAX)
376                         return -EINVAL;
377                 param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA;
378         } else if (!strncmp("bf_roaming_state=", buf, 17)) {
379                 if (sscanf(buf+17, "%d", &value) != 1)
380                         return -EINVAL;
381                 if (value < IWL_BF_ROAMING_STATE_MIN ||
382                     value > IWL_BF_ROAMING_STATE_MAX)
383                         return -EINVAL;
384                 param = MVM_DEBUGFS_BF_ROAMING_STATE;
385         } else if (!strncmp("bf_temp_threshold=", buf, 18)) {
386                 if (sscanf(buf+18, "%d", &value) != 1)
387                         return -EINVAL;
388                 if (value < IWL_BF_TEMP_THRESHOLD_MIN ||
389                     value > IWL_BF_TEMP_THRESHOLD_MAX)
390                         return -EINVAL;
391                 param = MVM_DEBUGFS_BF_TEMP_THRESHOLD;
392         } else if (!strncmp("bf_temp_fast_filter=", buf, 20)) {
393                 if (sscanf(buf+20, "%d", &value) != 1)
394                         return -EINVAL;
395                 if (value < IWL_BF_TEMP_FAST_FILTER_MIN ||
396                     value > IWL_BF_TEMP_FAST_FILTER_MAX)
397                         return -EINVAL;
398                 param = MVM_DEBUGFS_BF_TEMP_FAST_FILTER;
399         } else if (!strncmp("bf_temp_slow_filter=", buf, 20)) {
400                 if (sscanf(buf+20, "%d", &value) != 1)
401                         return -EINVAL;
402                 if (value < IWL_BF_TEMP_SLOW_FILTER_MIN ||
403                     value > IWL_BF_TEMP_SLOW_FILTER_MAX)
404                         return -EINVAL;
405                 param = MVM_DEBUGFS_BF_TEMP_SLOW_FILTER;
406         } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) {
407                 if (sscanf(buf+24, "%d", &value) != 1)
408                         return -EINVAL;
409                 if (value < 0 || value > 1)
410                         return -EINVAL;
411                 param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER;
412         } else if (!strncmp("bf_debug_flag=", buf, 14)) {
413                 if (sscanf(buf+14, "%d", &value) != 1)
414                         return -EINVAL;
415                 if (value < 0 || value > 1)
416                         return -EINVAL;
417                 param = MVM_DEBUGFS_BF_DEBUG_FLAG;
418         } else if (!strncmp("bf_escape_timer=", buf, 16)) {
419                 if (sscanf(buf+16, "%d", &value) != 1)
420                         return -EINVAL;
421                 if (value < IWL_BF_ESCAPE_TIMER_MIN ||
422                     value > IWL_BF_ESCAPE_TIMER_MAX)
423                         return -EINVAL;
424                 param = MVM_DEBUGFS_BF_ESCAPE_TIMER;
425         } else if (!strncmp("ba_escape_timer=", buf, 16)) {
426                 if (sscanf(buf+16, "%d", &value) != 1)
427                         return -EINVAL;
428                 if (value < IWL_BA_ESCAPE_TIMER_MIN ||
429                     value > IWL_BA_ESCAPE_TIMER_MAX)
430                         return -EINVAL;
431                 param = MVM_DEBUGFS_BA_ESCAPE_TIMER;
432         } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) {
433                 if (sscanf(buf+23, "%d", &value) != 1)
434                         return -EINVAL;
435                 if (value < 0 || value > 1)
436                         return -EINVAL;
437                 param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT;
438         } else {
439                 return -EINVAL;
440         }
441
442         mutex_lock(&mvm->mutex);
443         iwl_dbgfs_update_bf(vif, param, value);
444         if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value)
445                 ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
446         else
447                 ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0);
448         mutex_unlock(&mvm->mutex);
449
450         return ret ?: count;
451 }
452
453 static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
454                                         char __user *user_buf,
455                                         size_t count, loff_t *ppos)
456 {
457         struct ieee80211_vif *vif = file->private_data;
458         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
459         char buf[256];
460         int pos = 0;
461         const size_t bufsz = sizeof(buf);
462         struct iwl_beacon_filter_cmd cmd = {
463                 IWL_BF_CMD_CONFIG_DEFAULTS,
464                 .bf_enable_beacon_filter =
465                         cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT),
466                 .ba_enable_beacon_abort =
467                         cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT),
468         };
469
470         iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
471         if (mvmvif->bf_data.bf_enabled)
472                 cmd.bf_enable_beacon_filter = cpu_to_le32(1);
473         else
474                 cmd.bf_enable_beacon_filter = 0;
475
476         pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n",
477                          le32_to_cpu(cmd.bf_energy_delta));
478         pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n",
479                          le32_to_cpu(cmd.bf_roaming_energy_delta));
480         pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n",
481                          le32_to_cpu(cmd.bf_roaming_state));
482         pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_threshold = %d\n",
483                          le32_to_cpu(cmd.bf_temp_threshold));
484         pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_fast_filter = %d\n",
485                          le32_to_cpu(cmd.bf_temp_fast_filter));
486         pos += scnprintf(buf+pos, bufsz-pos, "bf_temp_slow_filter = %d\n",
487                          le32_to_cpu(cmd.bf_temp_slow_filter));
488         pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n",
489                          le32_to_cpu(cmd.bf_enable_beacon_filter));
490         pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n",
491                          le32_to_cpu(cmd.bf_debug_flag));
492         pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n",
493                          le32_to_cpu(cmd.bf_escape_timer));
494         pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n",
495                          le32_to_cpu(cmd.ba_escape_timer));
496         pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n",
497                          le32_to_cpu(cmd.ba_enable_beacon_abort));
498
499         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
500 }
501
502 static inline char *iwl_dbgfs_is_match(char *name, char *buf)
503 {
504         int len = strlen(name);
505
506         return !strncmp(name, buf, len) ? buf + len : NULL;
507 }
508
509 static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
510                                                  char __user *user_buf,
511                                                  size_t count, loff_t *ppos)
512 {
513         struct ieee80211_vif *vif = file->private_data;
514         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
515         struct iwl_mvm *mvm = mvmvif->mvm;
516         u32 curr_gp2;
517         u64 curr_os;
518         s64 diff;
519         char buf[64];
520         const size_t bufsz = sizeof(buf);
521         int pos = 0;
522
523         mutex_lock(&mvm->mutex);
524         iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
525         mutex_unlock(&mvm->mutex);
526
527         do_div(curr_os, NSEC_PER_USEC);
528         diff = curr_os - curr_gp2;
529         pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
530
531         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
532 }
533
534 static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
535                                           char *buf,
536                                           size_t count, loff_t *ppos)
537 {
538         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
539         struct iwl_mvm *mvm = mvmvif->mvm;
540         u32 value;
541         int ret = -EINVAL;
542         char *data;
543
544         mutex_lock(&mvm->mutex);
545
546         data = iwl_dbgfs_is_match("tof_disabled=", buf);
547         if (data) {
548                 ret = kstrtou32(data, 10, &value);
549                 if (ret == 0)
550                         mvm->tof_data.tof_cfg.tof_disabled = value;
551                 goto out;
552         }
553
554         data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
555         if (data) {
556                 ret = kstrtou32(data, 10, &value);
557                 if (ret == 0)
558                         mvm->tof_data.tof_cfg.one_sided_disabled = value;
559                 goto out;
560         }
561
562         data = iwl_dbgfs_is_match("is_debug_mode=", buf);
563         if (data) {
564                 ret = kstrtou32(data, 10, &value);
565                 if (ret == 0)
566                         mvm->tof_data.tof_cfg.is_debug_mode = value;
567                 goto out;
568         }
569
570         data = iwl_dbgfs_is_match("is_buf=", buf);
571         if (data) {
572                 ret = kstrtou32(data, 10, &value);
573                 if (ret == 0)
574                         mvm->tof_data.tof_cfg.is_buf_required = value;
575                 goto out;
576         }
577
578         data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
579         if (data) {
580                 ret = kstrtou32(data, 10, &value);
581                 if (ret == 0 && value) {
582                         ret = iwl_mvm_tof_config_cmd(mvm);
583                         goto out;
584                 }
585         }
586
587 out:
588         mutex_unlock(&mvm->mutex);
589
590         return ret ?: count;
591 }
592
593 static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
594                                          char __user *user_buf,
595                                          size_t count, loff_t *ppos)
596 {
597         struct ieee80211_vif *vif = file->private_data;
598         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
599         struct iwl_mvm *mvm = mvmvif->mvm;
600         char buf[256];
601         int pos = 0;
602         const size_t bufsz = sizeof(buf);
603         struct iwl_tof_config_cmd *cmd;
604
605         cmd = &mvm->tof_data.tof_cfg;
606
607         mutex_lock(&mvm->mutex);
608
609         pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
610                          cmd->tof_disabled);
611         pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
612                          cmd->one_sided_disabled);
613         pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
614                          cmd->is_debug_mode);
615         pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
616                          cmd->is_buf_required);
617
618         mutex_unlock(&mvm->mutex);
619
620         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
621 }
622
623 static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
624                                                     char *buf,
625                                                     size_t count, loff_t *ppos)
626 {
627         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
628         struct iwl_mvm *mvm = mvmvif->mvm;
629         u32 value;
630         int ret = 0;
631         char *data;
632
633         mutex_lock(&mvm->mutex);
634
635         data = iwl_dbgfs_is_match("burst_period=", buf);
636         if (data) {
637                 ret = kstrtou32(data, 10, &value);
638                 if (!ret)
639                         mvm->tof_data.responder_cfg.burst_period =
640                                                         cpu_to_le16(value);
641                 goto out;
642         }
643
644         data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
645         if (data) {
646                 ret = kstrtou32(data, 10, &value);
647                 if (ret == 0)
648                         mvm->tof_data.responder_cfg.min_delta_ftm = value;
649                 goto out;
650         }
651
652         data = iwl_dbgfs_is_match("burst_duration=", buf);
653         if (data) {
654                 ret = kstrtou32(data, 10, &value);
655                 if (ret == 0)
656                         mvm->tof_data.responder_cfg.burst_duration = value;
657                 goto out;
658         }
659
660         data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
661         if (data) {
662                 ret = kstrtou32(data, 10, &value);
663                 if (ret == 0)
664                         mvm->tof_data.responder_cfg.num_of_burst_exp = value;
665                 goto out;
666         }
667
668         data = iwl_dbgfs_is_match("abort_responder=", buf);
669         if (data) {
670                 ret = kstrtou32(data, 10, &value);
671                 if (ret == 0)
672                         mvm->tof_data.responder_cfg.abort_responder = value;
673                 goto out;
674         }
675
676         data = iwl_dbgfs_is_match("get_ch_est=", buf);
677         if (data) {
678                 ret = kstrtou32(data, 10, &value);
679                 if (ret == 0)
680                         mvm->tof_data.responder_cfg.get_ch_est = value;
681                 goto out;
682         }
683
684         data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
685         if (data) {
686                 ret = kstrtou32(data, 10, &value);
687                 if (ret == 0)
688                         mvm->tof_data.responder_cfg.recv_sta_req_params = value;
689                 goto out;
690         }
691
692         data = iwl_dbgfs_is_match("channel_num=", buf);
693         if (data) {
694                 ret = kstrtou32(data, 10, &value);
695                 if (ret == 0)
696                         mvm->tof_data.responder_cfg.channel_num = value;
697                 goto out;
698         }
699
700         data = iwl_dbgfs_is_match("bandwidth=", buf);
701         if (data) {
702                 ret = kstrtou32(data, 10, &value);
703                 if (ret == 0)
704                         mvm->tof_data.responder_cfg.bandwidth = value;
705                 goto out;
706         }
707
708         data = iwl_dbgfs_is_match("rate=", buf);
709         if (data) {
710                 ret = kstrtou32(data, 10, &value);
711                 if (ret == 0)
712                         mvm->tof_data.responder_cfg.rate = value;
713                 goto out;
714         }
715
716         data = iwl_dbgfs_is_match("bssid=", buf);
717         if (data) {
718                 u8 *mac = mvm->tof_data.responder_cfg.bssid;
719
720                 if (!mac_pton(data, mac)) {
721                         ret = -EINVAL;
722                         goto out;
723                 }
724         }
725
726         data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
727         if (data) {
728                 ret = kstrtou32(data, 10, &value);
729                 if (ret == 0)
730                         mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
731                                                         cpu_to_le16(value);
732                 goto out;
733         }
734
735         data = iwl_dbgfs_is_match("toa_offset=", buf);
736         if (data) {
737                 ret = kstrtou32(data, 10, &value);
738                 if (ret == 0)
739                         mvm->tof_data.responder_cfg.toa_offset =
740                                                         cpu_to_le16(value);
741                 goto out;
742         }
743
744         data = iwl_dbgfs_is_match("center_freq=", buf);
745         if (data) {
746                 struct iwl_tof_responder_config_cmd *cmd =
747                         &mvm->tof_data.responder_cfg;
748
749                 ret = kstrtou32(data, 10, &value);
750                 if (ret == 0 && value) {
751                         enum nl80211_band band = (cmd->channel_num <= 14) ?
752                                                    NL80211_BAND_2GHZ :
753                                                    NL80211_BAND_5GHZ;
754                         struct ieee80211_channel chn = {
755                                 .band = band,
756                                 .center_freq = ieee80211_channel_to_frequency(
757                                         cmd->channel_num, band),
758                                 };
759                         struct cfg80211_chan_def chandef = {
760                                 .chan =  &chn,
761                                 .center_freq1 =
762                                         ieee80211_channel_to_frequency(value,
763                                                                        band),
764                         };
765
766                         cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
767                 }
768                 goto out;
769         }
770
771         data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
772         if (data) {
773                 ret = kstrtou32(data, 10, &value);
774                 if (ret == 0)
775                         mvm->tof_data.responder_cfg.ftm_per_burst = value;
776                 goto out;
777         }
778
779         data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
780         if (data) {
781                 ret = kstrtou32(data, 10, &value);
782                 if (ret == 0)
783                         mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
784                 goto out;
785         }
786
787         data = iwl_dbgfs_is_match("asap_mode=", buf);
788         if (data) {
789                 ret = kstrtou32(data, 10, &value);
790                 if (ret == 0)
791                         mvm->tof_data.responder_cfg.asap_mode = value;
792                 goto out;
793         }
794
795         data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
796         if (data) {
797                 ret = kstrtou32(data, 10, &value);
798                 if (ret == 0 && value) {
799                         ret = iwl_mvm_tof_responder_cmd(mvm, vif);
800                         goto out;
801                 }
802         }
803
804 out:
805         mutex_unlock(&mvm->mutex);
806
807         return ret ?: count;
808 }
809
810 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
811                                                    char __user *user_buf,
812                                                    size_t count, loff_t *ppos)
813 {
814         struct ieee80211_vif *vif = file->private_data;
815         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
816         struct iwl_mvm *mvm = mvmvif->mvm;
817         char buf[256];
818         int pos = 0;
819         const size_t bufsz = sizeof(buf);
820         struct iwl_tof_responder_config_cmd *cmd;
821
822         cmd = &mvm->tof_data.responder_cfg;
823
824         mutex_lock(&mvm->mutex);
825
826         pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
827                          le16_to_cpu(cmd->burst_period));
828         pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
829                          cmd->burst_duration);
830         pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
831                          cmd->bandwidth);
832         pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
833                          cmd->channel_num);
834         pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
835                          cmd->ctrl_ch_position);
836         pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
837                          cmd->bssid);
838         pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
839                          cmd->min_delta_ftm);
840         pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
841                          cmd->num_of_burst_exp);
842         pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
843         pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
844                          cmd->abort_responder);
845         pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
846                          cmd->get_ch_est);
847         pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
848                          cmd->recv_sta_req_params);
849         pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
850                          cmd->ftm_per_burst);
851         pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
852                          cmd->ftm_resp_ts_avail);
853         pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
854                          cmd->asap_mode);
855         pos += scnprintf(buf + pos, bufsz - pos,
856                          "tsf_timer_offset_msecs = %d\n",
857                          le16_to_cpu(cmd->tsf_timer_offset_msecs));
858         pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
859                          le16_to_cpu(cmd->toa_offset));
860
861         mutex_unlock(&mvm->mutex);
862
863         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
864 }
865
866 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
867                                                  char *buf, size_t count,
868                                                  loff_t *ppos)
869 {
870         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
871         struct iwl_mvm *mvm = mvmvif->mvm;
872         u32 value;
873         int ret = 0;
874         char *data;
875
876         mutex_lock(&mvm->mutex);
877
878         data = iwl_dbgfs_is_match("request_id=", buf);
879         if (data) {
880                 ret = kstrtou32(data, 10, &value);
881                 if (ret == 0)
882                         mvm->tof_data.range_req.request_id = value;
883                 goto out;
884         }
885
886         data = iwl_dbgfs_is_match("initiator=", buf);
887         if (data) {
888                 ret = kstrtou32(data, 10, &value);
889                 if (ret == 0)
890                         mvm->tof_data.range_req.initiator = value;
891                 goto out;
892         }
893
894         data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
895         if (data) {
896                 ret = kstrtou32(data, 10, &value);
897                 if (ret == 0)
898                         mvm->tof_data.range_req.one_sided_los_disable = value;
899                 goto out;
900         }
901
902         data = iwl_dbgfs_is_match("req_timeout=", buf);
903         if (data) {
904                 ret = kstrtou32(data, 10, &value);
905                 if (ret == 0)
906                         mvm->tof_data.range_req.req_timeout = value;
907                 goto out;
908         }
909
910         data = iwl_dbgfs_is_match("report_policy=", buf);
911         if (data) {
912                 ret = kstrtou32(data, 10, &value);
913                 if (ret == 0)
914                         mvm->tof_data.range_req.report_policy = value;
915                 goto out;
916         }
917
918         data = iwl_dbgfs_is_match("macaddr_random=", buf);
919         if (data) {
920                 ret = kstrtou32(data, 10, &value);
921                 if (ret == 0)
922                         mvm->tof_data.range_req.macaddr_random = value;
923                 goto out;
924         }
925
926         data = iwl_dbgfs_is_match("num_of_ap=", buf);
927         if (data) {
928                 ret = kstrtou32(data, 10, &value);
929                 if (ret == 0)
930                         mvm->tof_data.range_req.num_of_ap = value;
931                 goto out;
932         }
933
934         data = iwl_dbgfs_is_match("macaddr_template=", buf);
935         if (data) {
936                 u8 mac[ETH_ALEN];
937
938                 if (!mac_pton(data, mac)) {
939                         ret = -EINVAL;
940                         goto out;
941                 }
942                 memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
943                 goto out;
944         }
945
946         data = iwl_dbgfs_is_match("macaddr_mask=", buf);
947         if (data) {
948                 u8 mac[ETH_ALEN];
949
950                 if (!mac_pton(data, mac)) {
951                         ret = -EINVAL;
952                         goto out;
953                 }
954                 memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
955                 goto out;
956         }
957
958         data = iwl_dbgfs_is_match("ap=", buf);
959         if (data) {
960                 struct iwl_tof_range_req_ap_entry ap = {};
961                 int size = sizeof(struct iwl_tof_range_req_ap_entry);
962                 u16 burst_period;
963                 u8 *mac = ap.bssid;
964                 unsigned int i;
965
966                 if (sscanf(data, "%u %hhd %hhd %hhd"
967                            "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
968                            "%hhd %hhd %hd"
969                            "%hhd %hhd %d"
970                            "%hhx %hhd %hhd %hhd",
971                            &i, &ap.channel_num, &ap.bandwidth,
972                            &ap.ctrl_ch_position,
973                            mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
974                            &ap.measure_type, &ap.num_of_bursts,
975                            &burst_period,
976                            &ap.samples_per_burst, &ap.retries_per_sample,
977                            &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
978                            &ap.enable_dyn_ack, &ap.rssi) != 20) {
979                         ret = -EINVAL;
980                         goto out;
981                 }
982                 if (i >= IWL_MVM_TOF_MAX_APS) {
983                         IWL_ERR(mvm, "Invalid AP index %d\n", i);
984                         ret = -EINVAL;
985                         goto out;
986                 }
987
988                 ap.burst_period = cpu_to_le16(burst_period);
989
990                 memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
991                 goto out;
992         }
993
994         data = iwl_dbgfs_is_match("send_range_request=", buf);
995         if (data) {
996                 ret = kstrtou32(data, 10, &value);
997                 if (ret == 0 && value)
998                         ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
999                 goto out;
1000         }
1001
1002         ret = -EINVAL;
1003 out:
1004         mutex_unlock(&mvm->mutex);
1005         return ret ?: count;
1006 }
1007
1008 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
1009                                                 char __user *user_buf,
1010                                                 size_t count, loff_t *ppos)
1011 {
1012         struct ieee80211_vif *vif = file->private_data;
1013         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1014         struct iwl_mvm *mvm = mvmvif->mvm;
1015         char buf[512];
1016         int pos = 0;
1017         const size_t bufsz = sizeof(buf);
1018         struct iwl_tof_range_req_cmd *cmd;
1019         int i;
1020
1021         cmd = &mvm->tof_data.range_req;
1022
1023         mutex_lock(&mvm->mutex);
1024
1025         pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
1026                          cmd->request_id);
1027         pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
1028                          cmd->initiator);
1029         pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
1030                          cmd->one_sided_los_disable);
1031         pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
1032                          cmd->req_timeout);
1033         pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
1034                          cmd->report_policy);
1035         pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
1036                          cmd->macaddr_random);
1037         pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
1038                          cmd->macaddr_template);
1039         pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
1040                          cmd->macaddr_mask);
1041         pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
1042                          cmd->num_of_ap);
1043         for (i = 0; i < cmd->num_of_ap; i++) {
1044                 struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1045
1046                 pos += scnprintf(buf + pos, bufsz - pos,
1047                                 "ap %.2d: channel_num=%hhd bw=%hhd"
1048                                 " control=%hhd bssid=%pM type=%hhd"
1049                                 " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1050                                 " retries=%hhd tsf_delta=%d"
1051                                 " tsf_delta_direction=%hhd location_req=0x%hhx "
1052                                 " asap=%hhd enable=%hhd rssi=%hhd\n",
1053                                 i, ap->channel_num, ap->bandwidth,
1054                                 ap->ctrl_ch_position, ap->bssid,
1055                                 ap->measure_type, ap->num_of_bursts,
1056                                 ap->burst_period, ap->samples_per_burst,
1057                                 ap->retries_per_sample, ap->tsf_delta,
1058                                 ap->tsf_delta_direction,
1059                                 ap->location_req, ap->asap_mode,
1060                                 ap->enable_dyn_ack, ap->rssi);
1061         }
1062
1063         mutex_unlock(&mvm->mutex);
1064
1065         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1066 }
1067
1068 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1069                                                  char *buf,
1070                                                  size_t count, loff_t *ppos)
1071 {
1072         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1073         struct iwl_mvm *mvm = mvmvif->mvm;
1074         u32 value;
1075         int ret = 0;
1076         char *data;
1077
1078         mutex_lock(&mvm->mutex);
1079
1080         data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1081         if (data) {
1082                 ret = kstrtou32(data, 10, &value);
1083                 if (ret == 0)
1084                         mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1085                                                         cpu_to_le16(value);
1086                 goto out;
1087         }
1088
1089         data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1090         if (data) {
1091                 ret = kstrtou32(data, 10, &value);
1092                 if (ret == 0)
1093                         mvm->tof_data.range_req_ext.min_delta_ftm = value;
1094                 goto out;
1095         }
1096
1097         data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1098         if (data) {
1099                 ret = kstrtou32(data, 10, &value);
1100                 if (ret == 0)
1101                         mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1102                                                                         value;
1103                 goto out;
1104         }
1105
1106         data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1107         if (data) {
1108                 ret = kstrtou32(data, 10, &value);
1109                 if (ret == 0)
1110                         mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1111                                                                         value;
1112                 goto out;
1113         }
1114
1115         data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1116         if (data) {
1117                 ret = kstrtou32(data, 10, &value);
1118                 if (ret == 0)
1119                         mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1120                                                                         value;
1121                 goto out;
1122         }
1123
1124         data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1125         if (data) {
1126                 ret = kstrtou32(data, 10, &value);
1127                 if (ret == 0 && value)
1128                         ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
1129                 goto out;
1130         }
1131
1132         ret = -EINVAL;
1133 out:
1134         mutex_unlock(&mvm->mutex);
1135         return ret ?: count;
1136 }
1137
1138 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1139                                                 char __user *user_buf,
1140                                                 size_t count, loff_t *ppos)
1141 {
1142         struct ieee80211_vif *vif = file->private_data;
1143         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1144         struct iwl_mvm *mvm = mvmvif->mvm;
1145         char buf[256];
1146         int pos = 0;
1147         const size_t bufsz = sizeof(buf);
1148         struct iwl_tof_range_req_ext_cmd *cmd;
1149
1150         cmd = &mvm->tof_data.range_req_ext;
1151
1152         mutex_lock(&mvm->mutex);
1153
1154         pos += scnprintf(buf + pos, bufsz - pos,
1155                          "tsf_timer_offset_msec = %hd\n",
1156                          cmd->tsf_timer_offset_msec);
1157         pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
1158                          cmd->min_delta_ftm);
1159         pos += scnprintf(buf + pos, bufsz - pos,
1160                          "ftm_format_and_bw20M = %hhd\n",
1161                          cmd->ftm_format_and_bw20M);
1162         pos += scnprintf(buf + pos, bufsz - pos,
1163                          "ftm_format_and_bw40M = %hhd\n",
1164                          cmd->ftm_format_and_bw40M);
1165         pos += scnprintf(buf + pos, bufsz - pos,
1166                          "ftm_format_and_bw80M = %hhd\n",
1167                          cmd->ftm_format_and_bw80M);
1168
1169         mutex_unlock(&mvm->mutex);
1170         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1171 }
1172
1173 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1174                                                char *buf,
1175                                                size_t count, loff_t *ppos)
1176 {
1177         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1178         struct iwl_mvm *mvm = mvmvif->mvm;
1179         u32 value;
1180         int abort_id, ret = 0;
1181         char *data;
1182
1183         mutex_lock(&mvm->mutex);
1184
1185         data = iwl_dbgfs_is_match("abort_id=", buf);
1186         if (data) {
1187                 ret = kstrtou32(data, 10, &value);
1188                 if (ret == 0)
1189                         mvm->tof_data.last_abort_id = value;
1190                 goto out;
1191         }
1192
1193         data = iwl_dbgfs_is_match("send_range_abort=", buf);
1194         if (data) {
1195                 ret = kstrtou32(data, 10, &value);
1196                 if (ret == 0 && value) {
1197                         abort_id = mvm->tof_data.last_abort_id;
1198                         ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1199                         goto out;
1200                 }
1201         }
1202
1203 out:
1204         mutex_unlock(&mvm->mutex);
1205         return ret ?: count;
1206 }
1207
1208 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1209                                               char __user *user_buf,
1210                                               size_t count, loff_t *ppos)
1211 {
1212         struct ieee80211_vif *vif = file->private_data;
1213         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1214         struct iwl_mvm *mvm = mvmvif->mvm;
1215         char buf[32];
1216         int pos = 0;
1217         const size_t bufsz = sizeof(buf);
1218         int last_abort_id;
1219
1220         mutex_lock(&mvm->mutex);
1221         last_abort_id = mvm->tof_data.last_abort_id;
1222         mutex_unlock(&mvm->mutex);
1223
1224         pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1225                          last_abort_id);
1226         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1227 }
1228
1229 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1230                                                  char __user *user_buf,
1231                                                  size_t count, loff_t *ppos)
1232 {
1233         struct ieee80211_vif *vif = file->private_data;
1234         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1235         struct iwl_mvm *mvm = mvmvif->mvm;
1236         char *buf;
1237         int pos = 0;
1238         const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1239         struct iwl_tof_range_rsp_ntfy *cmd;
1240         int i, ret;
1241
1242         buf = kzalloc(bufsz, GFP_KERNEL);
1243         if (!buf)
1244                 return -ENOMEM;
1245
1246         mutex_lock(&mvm->mutex);
1247         cmd = &mvm->tof_data.range_resp;
1248
1249         pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1250                          cmd->request_id);
1251         pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1252                          cmd->request_status);
1253         pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1254                          cmd->last_in_batch);
1255         pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1256                          cmd->num_of_aps);
1257         for (i = 0; i < cmd->num_of_aps; i++) {
1258                 struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1259
1260                 pos += scnprintf(buf + pos, bufsz - pos,
1261                                 "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1262                                 " rtt=%d rtt_var=%d rtt_spread=%d"
1263                                 " rssi=%hhd  rssi_spread=%hhd"
1264                                 " range=%d range_var=%d"
1265                                 " time_stamp=%d\n",
1266                                 i, ap->bssid, ap->measure_status,
1267                                 ap->measure_bw,
1268                                 ap->rtt, ap->rtt_variance, ap->rtt_spread,
1269                                 ap->rssi, ap->rssi_spread, ap->range,
1270                                 ap->range_variance, ap->timestamp);
1271         }
1272         mutex_unlock(&mvm->mutex);
1273
1274         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1275         kfree(buf);
1276         return ret;
1277 }
1278
1279 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1280                                            size_t count, loff_t *ppos)
1281 {
1282         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1283         struct iwl_mvm *mvm = mvmvif->mvm;
1284         u8 value;
1285         int ret;
1286
1287         ret = kstrtou8(buf, 0, &value);
1288         if (ret)
1289                 return ret;
1290         if (value > 1)
1291                 return -EINVAL;
1292
1293         mutex_lock(&mvm->mutex);
1294         iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
1295         mutex_unlock(&mvm->mutex);
1296
1297         return count;
1298 }
1299
1300 static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1301                                           char __user *user_buf,
1302                                           size_t count, loff_t *ppos)
1303 {
1304         struct ieee80211_vif *vif = file->private_data;
1305         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1306         char buf[30] = {};
1307         int len;
1308
1309         len = scnprintf(buf, sizeof(buf) - 1,
1310                         "traffic=%d\ndbgfs=%d\nvcmd=%d\n",
1311                         !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
1312                         !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
1313                         !!(mvmvif->low_latency & LOW_LATENCY_VCMD));
1314         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1315 }
1316
1317 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1318                                                 char __user *user_buf,
1319                                                 size_t count, loff_t *ppos)
1320 {
1321         struct ieee80211_vif *vif = file->private_data;
1322         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1323         char buf[20];
1324         int len;
1325
1326         len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1327         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1328 }
1329
1330 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1331                                                  char *buf, size_t count,
1332                                                  loff_t *ppos)
1333 {
1334         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1335         struct iwl_mvm *mvm = mvmvif->mvm;
1336         bool ret;
1337
1338         mutex_lock(&mvm->mutex);
1339         ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1340         mutex_unlock(&mvm->mutex);
1341
1342         return ret ? count : -EINVAL;
1343 }
1344
1345 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1346                                           size_t count, loff_t *ppos)
1347 {
1348         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1349         struct iwl_mvm *mvm = mvmvif->mvm;
1350         struct ieee80211_chanctx_conf *chanctx_conf;
1351         struct iwl_mvm_phy_ctxt *phy_ctxt;
1352         u16 value;
1353         int ret;
1354
1355         ret = kstrtou16(buf, 0, &value);
1356         if (ret)
1357                 return ret;
1358
1359         mutex_lock(&mvm->mutex);
1360         rcu_read_lock();
1361
1362         chanctx_conf = rcu_dereference(vif->chanctx_conf);
1363         /* make sure the channel context is assigned */
1364         if (!chanctx_conf) {
1365                 rcu_read_unlock();
1366                 mutex_unlock(&mvm->mutex);
1367                 return -EINVAL;
1368         }
1369
1370         phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1371         rcu_read_unlock();
1372
1373         mvm->dbgfs_rx_phyinfo = value;
1374
1375         ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1376                                        chanctx_conf->rx_chains_static,
1377                                        chanctx_conf->rx_chains_dynamic);
1378         mutex_unlock(&mvm->mutex);
1379
1380         return ret ?: count;
1381 }
1382
1383 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1384                                          char __user *user_buf,
1385                                          size_t count, loff_t *ppos)
1386 {
1387         struct ieee80211_vif *vif = file->private_data;
1388         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1389         char buf[8];
1390         int len;
1391
1392         len = scnprintf(buf, sizeof(buf), "0x%04x\n",
1393                         mvmvif->mvm->dbgfs_rx_phyinfo);
1394
1395         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1396 }
1397
1398 static void iwl_dbgfs_quota_check(void *data, u8 *mac,
1399                                   struct ieee80211_vif *vif)
1400 {
1401         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1402         int *ret = data;
1403
1404         if (mvmvif->dbgfs_quota_min)
1405                 *ret = -EINVAL;
1406 }
1407
1408 static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
1409                                          size_t count, loff_t *ppos)
1410 {
1411         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1412         struct iwl_mvm *mvm = mvmvif->mvm;
1413         u16 value;
1414         int ret;
1415
1416         ret = kstrtou16(buf, 0, &value);
1417         if (ret)
1418                 return ret;
1419
1420         if (value > 95)
1421                 return -EINVAL;
1422
1423         mutex_lock(&mvm->mutex);
1424
1425         mvmvif->dbgfs_quota_min = 0;
1426         ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1427                                      iwl_dbgfs_quota_check, &ret);
1428         if (ret == 0) {
1429                 mvmvif->dbgfs_quota_min = value;
1430                 iwl_mvm_update_quotas(mvm, false, NULL);
1431         }
1432         mutex_unlock(&mvm->mutex);
1433
1434         return ret ?: count;
1435 }
1436
1437 static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
1438                                         char __user *user_buf,
1439                                         size_t count, loff_t *ppos)
1440 {
1441         struct ieee80211_vif *vif = file->private_data;
1442         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1443         char buf[10];
1444         int len;
1445
1446         len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
1447
1448         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1449 }
1450
1451 static const char * const chanwidths[] = {
1452         [NL80211_CHAN_WIDTH_20_NOHT] = "noht",
1453         [NL80211_CHAN_WIDTH_20] = "ht20",
1454         [NL80211_CHAN_WIDTH_40] = "ht40",
1455         [NL80211_CHAN_WIDTH_80] = "vht80",
1456         [NL80211_CHAN_WIDTH_80P80] = "vht80p80",
1457         [NL80211_CHAN_WIDTH_160] = "vht160",
1458 };
1459
1460 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1461         _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1462 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1463         _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1464 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {               \
1465                 if (!debugfs_create_file(#name, mode, parent, vif,      \
1466                                          &iwl_dbgfs_##name##_ops))      \
1467                         goto err;                                       \
1468         } while (0)
1469
1470 MVM_DEBUGFS_READ_FILE_OPS(mac_params);
1471 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
1472 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1473 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
1474 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
1475 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
1476 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
1477 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1478 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1479 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1480 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1481 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1482 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
1483 MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
1484 MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
1485
1486
1487 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1488 {
1489         struct dentry *dbgfs_dir = vif->debugfs_dir;
1490         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1491         char buf[100];
1492
1493         /*
1494          * Check if debugfs directory already exist before creating it.
1495          * This may happen when, for example, resetting hw or suspend-resume
1496          */
1497         if (!dbgfs_dir || mvmvif->dbgfs_dir)
1498                 return;
1499
1500         mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
1501
1502         if (!mvmvif->dbgfs_dir) {
1503                 IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
1504                         dbgfs_dir);
1505                 return;
1506         }
1507
1508         if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1509             ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1510              (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
1511                 MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
1512
1513         MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
1514         MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
1515         MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
1516         MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
1517         MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
1518         MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
1519         MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
1520
1521         if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1522             mvmvif == mvm->bf_allowed_vif)
1523                 MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
1524
1525         if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1526             !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1527                 if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1528                         MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1529                                                  mvmvif->dbgfs_dir, 0600);
1530
1531                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1532                                          0600);
1533                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1534                                          0600);
1535                 MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1536                                          0600);
1537                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1538                                          0600);
1539                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1540                                          0400);
1541         }
1542
1543         /*
1544          * Create symlink for convenience pointing to interface specific
1545          * debugfs entries for the driver. For example, under
1546          * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1547          * find
1548          * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1549          */
1550         snprintf(buf, 100, "../../../%pd3/%pd",
1551                  dbgfs_dir,
1552                  mvmvif->dbgfs_dir);
1553
1554         mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1555                                                      mvm->debugfs_dir, buf);
1556         if (!mvmvif->dbgfs_slink)
1557                 IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
1558                         dbgfs_dir);
1559         return;
1560 err:
1561         IWL_ERR(mvm, "Can't create debugfs entity\n");
1562 }
1563
1564 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1565 {
1566         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1567
1568         debugfs_remove(mvmvif->dbgfs_slink);
1569         mvmvif->dbgfs_slink = NULL;
1570
1571         debugfs_remove_recursive(mvmvif->dbgfs_dir);
1572         mvmvif->dbgfs_dir = NULL;
1573 }