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