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