Merge branch 'spi-4.18' into spi-4.19 for DSPI dep
[linux-2.6-microblaze.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         iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
524         do_div(curr_os, NSEC_PER_USEC);
525         diff = curr_os - curr_gp2;
526         pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
527
528         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
529 }
530
531 static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
532                                           char *buf,
533                                           size_t count, loff_t *ppos)
534 {
535         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
536         struct iwl_mvm *mvm = mvmvif->mvm;
537         u32 value;
538         int ret = -EINVAL;
539         char *data;
540
541         mutex_lock(&mvm->mutex);
542
543         data = iwl_dbgfs_is_match("tof_disabled=", buf);
544         if (data) {
545                 ret = kstrtou32(data, 10, &value);
546                 if (ret == 0)
547                         mvm->tof_data.tof_cfg.tof_disabled = value;
548                 goto out;
549         }
550
551         data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
552         if (data) {
553                 ret = kstrtou32(data, 10, &value);
554                 if (ret == 0)
555                         mvm->tof_data.tof_cfg.one_sided_disabled = value;
556                 goto out;
557         }
558
559         data = iwl_dbgfs_is_match("is_debug_mode=", buf);
560         if (data) {
561                 ret = kstrtou32(data, 10, &value);
562                 if (ret == 0)
563                         mvm->tof_data.tof_cfg.is_debug_mode = value;
564                 goto out;
565         }
566
567         data = iwl_dbgfs_is_match("is_buf=", buf);
568         if (data) {
569                 ret = kstrtou32(data, 10, &value);
570                 if (ret == 0)
571                         mvm->tof_data.tof_cfg.is_buf_required = value;
572                 goto out;
573         }
574
575         data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
576         if (data) {
577                 ret = kstrtou32(data, 10, &value);
578                 if (ret == 0 && value) {
579                         ret = iwl_mvm_tof_config_cmd(mvm);
580                         goto out;
581                 }
582         }
583
584 out:
585         mutex_unlock(&mvm->mutex);
586
587         return ret ?: count;
588 }
589
590 static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
591                                          char __user *user_buf,
592                                          size_t count, loff_t *ppos)
593 {
594         struct ieee80211_vif *vif = file->private_data;
595         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
596         struct iwl_mvm *mvm = mvmvif->mvm;
597         char buf[256];
598         int pos = 0;
599         const size_t bufsz = sizeof(buf);
600         struct iwl_tof_config_cmd *cmd;
601
602         cmd = &mvm->tof_data.tof_cfg;
603
604         mutex_lock(&mvm->mutex);
605
606         pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
607                          cmd->tof_disabled);
608         pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
609                          cmd->one_sided_disabled);
610         pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
611                          cmd->is_debug_mode);
612         pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
613                          cmd->is_buf_required);
614
615         mutex_unlock(&mvm->mutex);
616
617         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
618 }
619
620 static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
621                                                     char *buf,
622                                                     size_t count, loff_t *ppos)
623 {
624         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
625         struct iwl_mvm *mvm = mvmvif->mvm;
626         u32 value;
627         int ret = 0;
628         char *data;
629
630         mutex_lock(&mvm->mutex);
631
632         data = iwl_dbgfs_is_match("burst_period=", buf);
633         if (data) {
634                 ret = kstrtou32(data, 10, &value);
635                 if (!ret)
636                         mvm->tof_data.responder_cfg.burst_period =
637                                                         cpu_to_le16(value);
638                 goto out;
639         }
640
641         data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
642         if (data) {
643                 ret = kstrtou32(data, 10, &value);
644                 if (ret == 0)
645                         mvm->tof_data.responder_cfg.min_delta_ftm = value;
646                 goto out;
647         }
648
649         data = iwl_dbgfs_is_match("burst_duration=", buf);
650         if (data) {
651                 ret = kstrtou32(data, 10, &value);
652                 if (ret == 0)
653                         mvm->tof_data.responder_cfg.burst_duration = value;
654                 goto out;
655         }
656
657         data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
658         if (data) {
659                 ret = kstrtou32(data, 10, &value);
660                 if (ret == 0)
661                         mvm->tof_data.responder_cfg.num_of_burst_exp = value;
662                 goto out;
663         }
664
665         data = iwl_dbgfs_is_match("abort_responder=", buf);
666         if (data) {
667                 ret = kstrtou32(data, 10, &value);
668                 if (ret == 0)
669                         mvm->tof_data.responder_cfg.abort_responder = value;
670                 goto out;
671         }
672
673         data = iwl_dbgfs_is_match("get_ch_est=", buf);
674         if (data) {
675                 ret = kstrtou32(data, 10, &value);
676                 if (ret == 0)
677                         mvm->tof_data.responder_cfg.get_ch_est = value;
678                 goto out;
679         }
680
681         data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
682         if (data) {
683                 ret = kstrtou32(data, 10, &value);
684                 if (ret == 0)
685                         mvm->tof_data.responder_cfg.recv_sta_req_params = value;
686                 goto out;
687         }
688
689         data = iwl_dbgfs_is_match("channel_num=", buf);
690         if (data) {
691                 ret = kstrtou32(data, 10, &value);
692                 if (ret == 0)
693                         mvm->tof_data.responder_cfg.channel_num = value;
694                 goto out;
695         }
696
697         data = iwl_dbgfs_is_match("bandwidth=", buf);
698         if (data) {
699                 ret = kstrtou32(data, 10, &value);
700                 if (ret == 0)
701                         mvm->tof_data.responder_cfg.bandwidth = value;
702                 goto out;
703         }
704
705         data = iwl_dbgfs_is_match("rate=", buf);
706         if (data) {
707                 ret = kstrtou32(data, 10, &value);
708                 if (ret == 0)
709                         mvm->tof_data.responder_cfg.rate = value;
710                 goto out;
711         }
712
713         data = iwl_dbgfs_is_match("bssid=", buf);
714         if (data) {
715                 u8 *mac = mvm->tof_data.responder_cfg.bssid;
716
717                 if (!mac_pton(data, mac)) {
718                         ret = -EINVAL;
719                         goto out;
720                 }
721         }
722
723         data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
724         if (data) {
725                 ret = kstrtou32(data, 10, &value);
726                 if (ret == 0)
727                         mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
728                                                         cpu_to_le16(value);
729                 goto out;
730         }
731
732         data = iwl_dbgfs_is_match("toa_offset=", buf);
733         if (data) {
734                 ret = kstrtou32(data, 10, &value);
735                 if (ret == 0)
736                         mvm->tof_data.responder_cfg.toa_offset =
737                                                         cpu_to_le16(value);
738                 goto out;
739         }
740
741         data = iwl_dbgfs_is_match("center_freq=", buf);
742         if (data) {
743                 struct iwl_tof_responder_config_cmd *cmd =
744                         &mvm->tof_data.responder_cfg;
745
746                 ret = kstrtou32(data, 10, &value);
747                 if (ret == 0 && value) {
748                         enum nl80211_band band = (cmd->channel_num <= 14) ?
749                                                    NL80211_BAND_2GHZ :
750                                                    NL80211_BAND_5GHZ;
751                         struct ieee80211_channel chn = {
752                                 .band = band,
753                                 .center_freq = ieee80211_channel_to_frequency(
754                                         cmd->channel_num, band),
755                                 };
756                         struct cfg80211_chan_def chandef = {
757                                 .chan =  &chn,
758                                 .center_freq1 =
759                                         ieee80211_channel_to_frequency(value,
760                                                                        band),
761                         };
762
763                         cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
764                 }
765                 goto out;
766         }
767
768         data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
769         if (data) {
770                 ret = kstrtou32(data, 10, &value);
771                 if (ret == 0)
772                         mvm->tof_data.responder_cfg.ftm_per_burst = value;
773                 goto out;
774         }
775
776         data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
777         if (data) {
778                 ret = kstrtou32(data, 10, &value);
779                 if (ret == 0)
780                         mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
781                 goto out;
782         }
783
784         data = iwl_dbgfs_is_match("asap_mode=", buf);
785         if (data) {
786                 ret = kstrtou32(data, 10, &value);
787                 if (ret == 0)
788                         mvm->tof_data.responder_cfg.asap_mode = value;
789                 goto out;
790         }
791
792         data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
793         if (data) {
794                 ret = kstrtou32(data, 10, &value);
795                 if (ret == 0 && value) {
796                         ret = iwl_mvm_tof_responder_cmd(mvm, vif);
797                         goto out;
798                 }
799         }
800
801 out:
802         mutex_unlock(&mvm->mutex);
803
804         return ret ?: count;
805 }
806
807 static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
808                                                    char __user *user_buf,
809                                                    size_t count, loff_t *ppos)
810 {
811         struct ieee80211_vif *vif = file->private_data;
812         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
813         struct iwl_mvm *mvm = mvmvif->mvm;
814         char buf[256];
815         int pos = 0;
816         const size_t bufsz = sizeof(buf);
817         struct iwl_tof_responder_config_cmd *cmd;
818
819         cmd = &mvm->tof_data.responder_cfg;
820
821         mutex_lock(&mvm->mutex);
822
823         pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
824                          le16_to_cpu(cmd->burst_period));
825         pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
826                          cmd->burst_duration);
827         pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
828                          cmd->bandwidth);
829         pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
830                          cmd->channel_num);
831         pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
832                          cmd->ctrl_ch_position);
833         pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
834                          cmd->bssid);
835         pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
836                          cmd->min_delta_ftm);
837         pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
838                          cmd->num_of_burst_exp);
839         pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
840         pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
841                          cmd->abort_responder);
842         pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
843                          cmd->get_ch_est);
844         pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
845                          cmd->recv_sta_req_params);
846         pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
847                          cmd->ftm_per_burst);
848         pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
849                          cmd->ftm_resp_ts_avail);
850         pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
851                          cmd->asap_mode);
852         pos += scnprintf(buf + pos, bufsz - pos,
853                          "tsf_timer_offset_msecs = %d\n",
854                          le16_to_cpu(cmd->tsf_timer_offset_msecs));
855         pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
856                          le16_to_cpu(cmd->toa_offset));
857
858         mutex_unlock(&mvm->mutex);
859
860         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
861 }
862
863 static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
864                                                  char *buf, size_t count,
865                                                  loff_t *ppos)
866 {
867         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
868         struct iwl_mvm *mvm = mvmvif->mvm;
869         u32 value;
870         int ret = 0;
871         char *data;
872
873         mutex_lock(&mvm->mutex);
874
875         data = iwl_dbgfs_is_match("request_id=", buf);
876         if (data) {
877                 ret = kstrtou32(data, 10, &value);
878                 if (ret == 0)
879                         mvm->tof_data.range_req.request_id = value;
880                 goto out;
881         }
882
883         data = iwl_dbgfs_is_match("initiator=", buf);
884         if (data) {
885                 ret = kstrtou32(data, 10, &value);
886                 if (ret == 0)
887                         mvm->tof_data.range_req.initiator = value;
888                 goto out;
889         }
890
891         data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
892         if (data) {
893                 ret = kstrtou32(data, 10, &value);
894                 if (ret == 0)
895                         mvm->tof_data.range_req.one_sided_los_disable = value;
896                 goto out;
897         }
898
899         data = iwl_dbgfs_is_match("req_timeout=", buf);
900         if (data) {
901                 ret = kstrtou32(data, 10, &value);
902                 if (ret == 0)
903                         mvm->tof_data.range_req.req_timeout = value;
904                 goto out;
905         }
906
907         data = iwl_dbgfs_is_match("report_policy=", buf);
908         if (data) {
909                 ret = kstrtou32(data, 10, &value);
910                 if (ret == 0)
911                         mvm->tof_data.range_req.report_policy = value;
912                 goto out;
913         }
914
915         data = iwl_dbgfs_is_match("macaddr_random=", buf);
916         if (data) {
917                 ret = kstrtou32(data, 10, &value);
918                 if (ret == 0)
919                         mvm->tof_data.range_req.macaddr_random = value;
920                 goto out;
921         }
922
923         data = iwl_dbgfs_is_match("num_of_ap=", buf);
924         if (data) {
925                 ret = kstrtou32(data, 10, &value);
926                 if (ret == 0)
927                         mvm->tof_data.range_req.num_of_ap = value;
928                 goto out;
929         }
930
931         data = iwl_dbgfs_is_match("macaddr_template=", buf);
932         if (data) {
933                 u8 mac[ETH_ALEN];
934
935                 if (!mac_pton(data, mac)) {
936                         ret = -EINVAL;
937                         goto out;
938                 }
939                 memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
940                 goto out;
941         }
942
943         data = iwl_dbgfs_is_match("macaddr_mask=", buf);
944         if (data) {
945                 u8 mac[ETH_ALEN];
946
947                 if (!mac_pton(data, mac)) {
948                         ret = -EINVAL;
949                         goto out;
950                 }
951                 memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
952                 goto out;
953         }
954
955         data = iwl_dbgfs_is_match("ap=", buf);
956         if (data) {
957                 struct iwl_tof_range_req_ap_entry ap = {};
958                 int size = sizeof(struct iwl_tof_range_req_ap_entry);
959                 u16 burst_period;
960                 u8 *mac = ap.bssid;
961                 unsigned int i;
962
963                 if (sscanf(data, "%u %hhd %hhd %hhd"
964                            "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
965                            "%hhd %hhd %hd"
966                            "%hhd %hhd %d"
967                            "%hhx %hhd %hhd %hhd",
968                            &i, &ap.channel_num, &ap.bandwidth,
969                            &ap.ctrl_ch_position,
970                            mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
971                            &ap.measure_type, &ap.num_of_bursts,
972                            &burst_period,
973                            &ap.samples_per_burst, &ap.retries_per_sample,
974                            &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
975                            &ap.enable_dyn_ack, &ap.rssi) != 20) {
976                         ret = -EINVAL;
977                         goto out;
978                 }
979                 if (i >= IWL_MVM_TOF_MAX_APS) {
980                         IWL_ERR(mvm, "Invalid AP index %d\n", i);
981                         ret = -EINVAL;
982                         goto out;
983                 }
984
985                 ap.burst_period = cpu_to_le16(burst_period);
986
987                 memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
988                 goto out;
989         }
990
991         data = iwl_dbgfs_is_match("send_range_request=", buf);
992         if (data) {
993                 ret = kstrtou32(data, 10, &value);
994                 if (ret == 0 && value)
995                         ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
996                 goto out;
997         }
998
999         ret = -EINVAL;
1000 out:
1001         mutex_unlock(&mvm->mutex);
1002         return ret ?: count;
1003 }
1004
1005 static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
1006                                                 char __user *user_buf,
1007                                                 size_t count, loff_t *ppos)
1008 {
1009         struct ieee80211_vif *vif = file->private_data;
1010         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1011         struct iwl_mvm *mvm = mvmvif->mvm;
1012         char buf[512];
1013         int pos = 0;
1014         const size_t bufsz = sizeof(buf);
1015         struct iwl_tof_range_req_cmd *cmd;
1016         int i;
1017
1018         cmd = &mvm->tof_data.range_req;
1019
1020         mutex_lock(&mvm->mutex);
1021
1022         pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
1023                          cmd->request_id);
1024         pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
1025                          cmd->initiator);
1026         pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
1027                          cmd->one_sided_los_disable);
1028         pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
1029                          cmd->req_timeout);
1030         pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
1031                          cmd->report_policy);
1032         pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
1033                          cmd->macaddr_random);
1034         pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
1035                          cmd->macaddr_template);
1036         pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
1037                          cmd->macaddr_mask);
1038         pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
1039                          cmd->num_of_ap);
1040         for (i = 0; i < cmd->num_of_ap; i++) {
1041                 struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
1042
1043                 pos += scnprintf(buf + pos, bufsz - pos,
1044                                 "ap %.2d: channel_num=%hhd bw=%hhd"
1045                                 " control=%hhd bssid=%pM type=%hhd"
1046                                 " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
1047                                 " retries=%hhd tsf_delta=%d"
1048                                 " tsf_delta_direction=%hhd location_req=0x%hhx "
1049                                 " asap=%hhd enable=%hhd rssi=%hhd\n",
1050                                 i, ap->channel_num, ap->bandwidth,
1051                                 ap->ctrl_ch_position, ap->bssid,
1052                                 ap->measure_type, ap->num_of_bursts,
1053                                 ap->burst_period, ap->samples_per_burst,
1054                                 ap->retries_per_sample, ap->tsf_delta,
1055                                 ap->tsf_delta_direction,
1056                                 ap->location_req, ap->asap_mode,
1057                                 ap->enable_dyn_ack, ap->rssi);
1058         }
1059
1060         mutex_unlock(&mvm->mutex);
1061
1062         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1063 }
1064
1065 static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
1066                                                  char *buf,
1067                                                  size_t count, loff_t *ppos)
1068 {
1069         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1070         struct iwl_mvm *mvm = mvmvif->mvm;
1071         u32 value;
1072         int ret = 0;
1073         char *data;
1074
1075         mutex_lock(&mvm->mutex);
1076
1077         data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
1078         if (data) {
1079                 ret = kstrtou32(data, 10, &value);
1080                 if (ret == 0)
1081                         mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
1082                                                         cpu_to_le16(value);
1083                 goto out;
1084         }
1085
1086         data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
1087         if (data) {
1088                 ret = kstrtou32(data, 10, &value);
1089                 if (ret == 0)
1090                         mvm->tof_data.range_req_ext.min_delta_ftm = value;
1091                 goto out;
1092         }
1093
1094         data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
1095         if (data) {
1096                 ret = kstrtou32(data, 10, &value);
1097                 if (ret == 0)
1098                         mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
1099                                                                         value;
1100                 goto out;
1101         }
1102
1103         data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
1104         if (data) {
1105                 ret = kstrtou32(data, 10, &value);
1106                 if (ret == 0)
1107                         mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
1108                                                                         value;
1109                 goto out;
1110         }
1111
1112         data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
1113         if (data) {
1114                 ret = kstrtou32(data, 10, &value);
1115                 if (ret == 0)
1116                         mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
1117                                                                         value;
1118                 goto out;
1119         }
1120
1121         data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
1122         if (data) {
1123                 ret = kstrtou32(data, 10, &value);
1124                 if (ret == 0 && value)
1125                         ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
1126                 goto out;
1127         }
1128
1129         ret = -EINVAL;
1130 out:
1131         mutex_unlock(&mvm->mutex);
1132         return ret ?: count;
1133 }
1134
1135 static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
1136                                                 char __user *user_buf,
1137                                                 size_t count, loff_t *ppos)
1138 {
1139         struct ieee80211_vif *vif = file->private_data;
1140         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1141         struct iwl_mvm *mvm = mvmvif->mvm;
1142         char buf[256];
1143         int pos = 0;
1144         const size_t bufsz = sizeof(buf);
1145         struct iwl_tof_range_req_ext_cmd *cmd;
1146
1147         cmd = &mvm->tof_data.range_req_ext;
1148
1149         mutex_lock(&mvm->mutex);
1150
1151         pos += scnprintf(buf + pos, bufsz - pos,
1152                          "tsf_timer_offset_msec = %hd\n",
1153                          cmd->tsf_timer_offset_msec);
1154         pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
1155                          cmd->min_delta_ftm);
1156         pos += scnprintf(buf + pos, bufsz - pos,
1157                          "ftm_format_and_bw20M = %hhd\n",
1158                          cmd->ftm_format_and_bw20M);
1159         pos += scnprintf(buf + pos, bufsz - pos,
1160                          "ftm_format_and_bw40M = %hhd\n",
1161                          cmd->ftm_format_and_bw40M);
1162         pos += scnprintf(buf + pos, bufsz - pos,
1163                          "ftm_format_and_bw80M = %hhd\n",
1164                          cmd->ftm_format_and_bw80M);
1165
1166         mutex_unlock(&mvm->mutex);
1167         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1168 }
1169
1170 static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
1171                                                char *buf,
1172                                                size_t count, loff_t *ppos)
1173 {
1174         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1175         struct iwl_mvm *mvm = mvmvif->mvm;
1176         u32 value;
1177         int abort_id, ret = 0;
1178         char *data;
1179
1180         mutex_lock(&mvm->mutex);
1181
1182         data = iwl_dbgfs_is_match("abort_id=", buf);
1183         if (data) {
1184                 ret = kstrtou32(data, 10, &value);
1185                 if (ret == 0)
1186                         mvm->tof_data.last_abort_id = value;
1187                 goto out;
1188         }
1189
1190         data = iwl_dbgfs_is_match("send_range_abort=", buf);
1191         if (data) {
1192                 ret = kstrtou32(data, 10, &value);
1193                 if (ret == 0 && value) {
1194                         abort_id = mvm->tof_data.last_abort_id;
1195                         ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
1196                         goto out;
1197                 }
1198         }
1199
1200 out:
1201         mutex_unlock(&mvm->mutex);
1202         return ret ?: count;
1203 }
1204
1205 static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
1206                                               char __user *user_buf,
1207                                               size_t count, loff_t *ppos)
1208 {
1209         struct ieee80211_vif *vif = file->private_data;
1210         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1211         struct iwl_mvm *mvm = mvmvif->mvm;
1212         char buf[32];
1213         int pos = 0;
1214         const size_t bufsz = sizeof(buf);
1215         int last_abort_id;
1216
1217         mutex_lock(&mvm->mutex);
1218         last_abort_id = mvm->tof_data.last_abort_id;
1219         mutex_unlock(&mvm->mutex);
1220
1221         pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
1222                          last_abort_id);
1223         return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1224 }
1225
1226 static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
1227                                                  char __user *user_buf,
1228                                                  size_t count, loff_t *ppos)
1229 {
1230         struct ieee80211_vif *vif = file->private_data;
1231         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1232         struct iwl_mvm *mvm = mvmvif->mvm;
1233         char *buf;
1234         int pos = 0;
1235         const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
1236         struct iwl_tof_range_rsp_ntfy *cmd;
1237         int i, ret;
1238
1239         buf = kzalloc(bufsz, GFP_KERNEL);
1240         if (!buf)
1241                 return -ENOMEM;
1242
1243         mutex_lock(&mvm->mutex);
1244         cmd = &mvm->tof_data.range_resp;
1245
1246         pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
1247                          cmd->request_id);
1248         pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
1249                          cmd->request_status);
1250         pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
1251                          cmd->last_in_batch);
1252         pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
1253                          cmd->num_of_aps);
1254         for (i = 0; i < cmd->num_of_aps; i++) {
1255                 struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
1256
1257                 pos += scnprintf(buf + pos, bufsz - pos,
1258                                 "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
1259                                 " rtt=%d rtt_var=%d rtt_spread=%d"
1260                                 " rssi=%hhd  rssi_spread=%hhd"
1261                                 " range=%d range_var=%d"
1262                                 " time_stamp=%d\n",
1263                                 i, ap->bssid, ap->measure_status,
1264                                 ap->measure_bw,
1265                                 ap->rtt, ap->rtt_variance, ap->rtt_spread,
1266                                 ap->rssi, ap->rssi_spread, ap->range,
1267                                 ap->range_variance, ap->timestamp);
1268         }
1269         mutex_unlock(&mvm->mutex);
1270
1271         ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1272         kfree(buf);
1273         return ret;
1274 }
1275
1276 static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
1277                                            size_t count, loff_t *ppos)
1278 {
1279         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1280         struct iwl_mvm *mvm = mvmvif->mvm;
1281         u8 value;
1282         int ret;
1283
1284         ret = kstrtou8(buf, 0, &value);
1285         if (ret)
1286                 return ret;
1287         if (value > 1)
1288                 return -EINVAL;
1289
1290         mutex_lock(&mvm->mutex);
1291         iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
1292         mutex_unlock(&mvm->mutex);
1293
1294         return count;
1295 }
1296
1297 static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
1298                                           char __user *user_buf,
1299                                           size_t count, loff_t *ppos)
1300 {
1301         struct ieee80211_vif *vif = file->private_data;
1302         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1303         char buf[30] = {};
1304         int len;
1305
1306         len = scnprintf(buf, sizeof(buf) - 1,
1307                         "traffic=%d\ndbgfs=%d\nvcmd=%d\n",
1308                         !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
1309                         !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
1310                         !!(mvmvif->low_latency & LOW_LATENCY_VCMD));
1311         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1312 }
1313
1314 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
1315                                                 char __user *user_buf,
1316                                                 size_t count, loff_t *ppos)
1317 {
1318         struct ieee80211_vif *vif = file->private_data;
1319         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1320         char buf[20];
1321         int len;
1322
1323         len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
1324         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1325 }
1326
1327 static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
1328                                                  char *buf, size_t count,
1329                                                  loff_t *ppos)
1330 {
1331         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1332         struct iwl_mvm *mvm = mvmvif->mvm;
1333         bool ret;
1334
1335         mutex_lock(&mvm->mutex);
1336         ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
1337         mutex_unlock(&mvm->mutex);
1338
1339         return ret ? count : -EINVAL;
1340 }
1341
1342 static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf,
1343                                           size_t count, loff_t *ppos)
1344 {
1345         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1346         struct iwl_mvm *mvm = mvmvif->mvm;
1347         struct ieee80211_chanctx_conf *chanctx_conf;
1348         struct iwl_mvm_phy_ctxt *phy_ctxt;
1349         u16 value;
1350         int ret;
1351
1352         ret = kstrtou16(buf, 0, &value);
1353         if (ret)
1354                 return ret;
1355
1356         mutex_lock(&mvm->mutex);
1357         rcu_read_lock();
1358
1359         chanctx_conf = rcu_dereference(vif->chanctx_conf);
1360         /* make sure the channel context is assigned */
1361         if (!chanctx_conf) {
1362                 rcu_read_unlock();
1363                 mutex_unlock(&mvm->mutex);
1364                 return -EINVAL;
1365         }
1366
1367         phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv];
1368         rcu_read_unlock();
1369
1370         mvm->dbgfs_rx_phyinfo = value;
1371
1372         ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def,
1373                                        chanctx_conf->rx_chains_static,
1374                                        chanctx_conf->rx_chains_dynamic);
1375         mutex_unlock(&mvm->mutex);
1376
1377         return ret ?: count;
1378 }
1379
1380 static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
1381                                          char __user *user_buf,
1382                                          size_t count, loff_t *ppos)
1383 {
1384         struct ieee80211_vif *vif = file->private_data;
1385         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1386         char buf[8];
1387         int len;
1388
1389         len = scnprintf(buf, sizeof(buf), "0x%04x\n",
1390                         mvmvif->mvm->dbgfs_rx_phyinfo);
1391
1392         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1393 }
1394
1395 static void iwl_dbgfs_quota_check(void *data, u8 *mac,
1396                                   struct ieee80211_vif *vif)
1397 {
1398         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1399         int *ret = data;
1400
1401         if (mvmvif->dbgfs_quota_min)
1402                 *ret = -EINVAL;
1403 }
1404
1405 static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
1406                                          size_t count, loff_t *ppos)
1407 {
1408         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1409         struct iwl_mvm *mvm = mvmvif->mvm;
1410         u16 value;
1411         int ret;
1412
1413         ret = kstrtou16(buf, 0, &value);
1414         if (ret)
1415                 return ret;
1416
1417         if (value > 95)
1418                 return -EINVAL;
1419
1420         mutex_lock(&mvm->mutex);
1421
1422         mvmvif->dbgfs_quota_min = 0;
1423         ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
1424                                      iwl_dbgfs_quota_check, &ret);
1425         if (ret == 0) {
1426                 mvmvif->dbgfs_quota_min = value;
1427                 iwl_mvm_update_quotas(mvm, false, NULL);
1428         }
1429         mutex_unlock(&mvm->mutex);
1430
1431         return ret ?: count;
1432 }
1433
1434 static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
1435                                         char __user *user_buf,
1436                                         size_t count, loff_t *ppos)
1437 {
1438         struct ieee80211_vif *vif = file->private_data;
1439         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1440         char buf[10];
1441         int len;
1442
1443         len = scnprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
1444
1445         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1446 }
1447
1448 static const char * const chanwidths[] = {
1449         [NL80211_CHAN_WIDTH_20_NOHT] = "noht",
1450         [NL80211_CHAN_WIDTH_20] = "ht20",
1451         [NL80211_CHAN_WIDTH_40] = "ht40",
1452         [NL80211_CHAN_WIDTH_80] = "vht80",
1453         [NL80211_CHAN_WIDTH_80P80] = "vht80p80",
1454         [NL80211_CHAN_WIDTH_160] = "vht160",
1455 };
1456
1457 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1458         _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1459 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1460         _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
1461 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {               \
1462                 if (!debugfs_create_file(#name, mode, parent, vif,      \
1463                                          &iwl_dbgfs_##name##_ops))      \
1464                         goto err;                                       \
1465         } while (0)
1466
1467 MVM_DEBUGFS_READ_FILE_OPS(mac_params);
1468 MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
1469 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
1470 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
1471 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
1472 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
1473 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
1474 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
1475 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
1476 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
1477 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
1478 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
1479 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
1480 MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
1481 MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
1482
1483
1484 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1485 {
1486         struct dentry *dbgfs_dir = vif->debugfs_dir;
1487         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1488         char buf[100];
1489
1490         /*
1491          * Check if debugfs directory already exist before creating it.
1492          * This may happen when, for example, resetting hw or suspend-resume
1493          */
1494         if (!dbgfs_dir || mvmvif->dbgfs_dir)
1495                 return;
1496
1497         mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
1498
1499         if (!mvmvif->dbgfs_dir) {
1500                 IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
1501                         dbgfs_dir);
1502                 return;
1503         }
1504
1505         if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
1506             ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
1507              (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
1508                 MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600);
1509
1510         MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
1511         MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
1512         MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
1513         MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
1514         MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
1515         MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
1516         MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400);
1517
1518         if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
1519             mvmvif == mvm->bf_allowed_vif)
1520                 MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
1521
1522         if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
1523             !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
1524                 if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
1525                         MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
1526                                                  mvmvif->dbgfs_dir, 0600);
1527
1528                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
1529                                          0600);
1530                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
1531                                          0600);
1532                 MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
1533                                          0600);
1534                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
1535                                          0600);
1536                 MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
1537                                          0400);
1538         }
1539
1540         /*
1541          * Create symlink for convenience pointing to interface specific
1542          * debugfs entries for the driver. For example, under
1543          * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
1544          * find
1545          * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
1546          */
1547         snprintf(buf, 100, "../../../%pd3/%pd",
1548                  dbgfs_dir,
1549                  mvmvif->dbgfs_dir);
1550
1551         mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
1552                                                      mvm->debugfs_dir, buf);
1553         if (!mvmvif->dbgfs_slink)
1554                 IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
1555                         dbgfs_dir);
1556         return;
1557 err:
1558         IWL_ERR(mvm, "Can't create debugfs entity\n");
1559 }
1560
1561 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
1562 {
1563         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1564
1565         debugfs_remove(mvmvif->dbgfs_slink);
1566         mvmvif->dbgfs_slink = NULL;
1567
1568         debugfs_remove_recursive(mvmvif->dbgfs_dir);
1569         mvmvif->dbgfs_dir = NULL;
1570 }