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