1 /******************************************************************************
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.
8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
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.
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.
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,
25 * The full GNU General Public License is included in this distribution
26 * in the file called COPYING.
28 * Contact Information:
29 * Intel Linux Wireless <ilw@linux.intel.com>
30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
34 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
35 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
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
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.
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.
64 *****************************************************************************/
68 static void iwl_dbgfs_update_pm(struct iwl_mvm
*mvm
,
69 struct ieee80211_vif
*vif
,
70 enum iwl_dbgfs_pm_mask param
, int val
)
72 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
73 struct iwl_dbgfs_pm
*dbgfs_pm
= &mvmvif
->dbgfs_pm
;
75 dbgfs_pm
->mask
|= param
;
78 case MVM_DEBUGFS_PM_KEEP_ALIVE
: {
79 int dtimper
= vif
->bss_conf
.dtim_period
?: 1;
80 int dtimper_msec
= dtimper
* vif
->bss_conf
.beacon_int
;
82 IWL_DEBUG_POWER(mvm
, "debugfs: set keep_alive= %d sec\n", val
);
83 if (val
* MSEC_PER_SEC
< 3 * dtimper_msec
)
85 "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n",
86 val
* MSEC_PER_SEC
, 3 * dtimper_msec
);
87 dbgfs_pm
->keep_alive_seconds
= val
;
90 case MVM_DEBUGFS_PM_SKIP_OVER_DTIM
:
91 IWL_DEBUG_POWER(mvm
, "skip_over_dtim %s\n",
92 val
? "enabled" : "disabled");
93 dbgfs_pm
->skip_over_dtim
= val
;
95 case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
:
96 IWL_DEBUG_POWER(mvm
, "skip_dtim_periods=%d\n", val
);
97 dbgfs_pm
->skip_dtim_periods
= val
;
99 case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
:
100 IWL_DEBUG_POWER(mvm
, "rx_data_timeout=%d\n", val
);
101 dbgfs_pm
->rx_data_timeout
= val
;
103 case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
:
104 IWL_DEBUG_POWER(mvm
, "tx_data_timeout=%d\n", val
);
105 dbgfs_pm
->tx_data_timeout
= val
;
107 case MVM_DEBUGFS_PM_LPRX_ENA
:
108 IWL_DEBUG_POWER(mvm
, "lprx %s\n", val
? "enabled" : "disabled");
109 dbgfs_pm
->lprx_ena
= val
;
111 case MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
:
112 IWL_DEBUG_POWER(mvm
, "lprx_rssi_threshold=%d\n", val
);
113 dbgfs_pm
->lprx_rssi_threshold
= val
;
115 case MVM_DEBUGFS_PM_SNOOZE_ENABLE
:
116 IWL_DEBUG_POWER(mvm
, "snooze_enable=%d\n", val
);
117 dbgfs_pm
->snooze_ena
= val
;
119 case MVM_DEBUGFS_PM_UAPSD_MISBEHAVING
:
120 IWL_DEBUG_POWER(mvm
, "uapsd_misbehaving_enable=%d\n", val
);
121 dbgfs_pm
->uapsd_misbehaving
= val
;
123 case MVM_DEBUGFS_PM_USE_PS_POLL
:
124 IWL_DEBUG_POWER(mvm
, "use_ps_poll=%d\n", val
);
125 dbgfs_pm
->use_ps_poll
= val
;
130 static ssize_t
iwl_dbgfs_pm_params_write(struct ieee80211_vif
*vif
, char *buf
,
131 size_t count
, loff_t
*ppos
)
133 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
134 struct iwl_mvm
*mvm
= mvmvif
->mvm
;
135 enum iwl_dbgfs_pm_mask param
;
138 if (!strncmp("keep_alive=", buf
, 11)) {
139 if (sscanf(buf
+ 11, "%d", &val
) != 1)
141 param
= MVM_DEBUGFS_PM_KEEP_ALIVE
;
142 } else if (!strncmp("skip_over_dtim=", buf
, 15)) {
143 if (sscanf(buf
+ 15, "%d", &val
) != 1)
145 param
= MVM_DEBUGFS_PM_SKIP_OVER_DTIM
;
146 } else if (!strncmp("skip_dtim_periods=", buf
, 18)) {
147 if (sscanf(buf
+ 18, "%d", &val
) != 1)
149 param
= MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS
;
150 } else if (!strncmp("rx_data_timeout=", buf
, 16)) {
151 if (sscanf(buf
+ 16, "%d", &val
) != 1)
153 param
= MVM_DEBUGFS_PM_RX_DATA_TIMEOUT
;
154 } else if (!strncmp("tx_data_timeout=", buf
, 16)) {
155 if (sscanf(buf
+ 16, "%d", &val
) != 1)
157 param
= MVM_DEBUGFS_PM_TX_DATA_TIMEOUT
;
158 } else if (!strncmp("lprx=", buf
, 5)) {
159 if (sscanf(buf
+ 5, "%d", &val
) != 1)
161 param
= MVM_DEBUGFS_PM_LPRX_ENA
;
162 } else if (!strncmp("lprx_rssi_threshold=", buf
, 20)) {
163 if (sscanf(buf
+ 20, "%d", &val
) != 1)
165 if (val
> POWER_LPRX_RSSI_THRESHOLD_MAX
|| val
<
166 POWER_LPRX_RSSI_THRESHOLD_MIN
)
168 param
= MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD
;
169 } else if (!strncmp("snooze_enable=", buf
, 14)) {
170 if (sscanf(buf
+ 14, "%d", &val
) != 1)
172 param
= MVM_DEBUGFS_PM_SNOOZE_ENABLE
;
173 } else if (!strncmp("uapsd_misbehaving=", buf
, 18)) {
174 if (sscanf(buf
+ 18, "%d", &val
) != 1)
176 param
= MVM_DEBUGFS_PM_UAPSD_MISBEHAVING
;
177 } else if (!strncmp("use_ps_poll=", buf
, 12)) {
178 if (sscanf(buf
+ 12, "%d", &val
) != 1)
180 param
= MVM_DEBUGFS_PM_USE_PS_POLL
;
185 mutex_lock(&mvm
->mutex
);
186 iwl_dbgfs_update_pm(mvm
, vif
, param
, val
);
187 ret
= iwl_mvm_power_update_mac(mvm
);
188 mutex_unlock(&mvm
->mutex
);
193 static ssize_t
iwl_dbgfs_pm_params_read(struct file
*file
,
194 char __user
*user_buf
,
195 size_t count
, loff_t
*ppos
)
197 struct ieee80211_vif
*vif
= file
->private_data
;
198 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
199 struct iwl_mvm
*mvm
= mvmvif
->mvm
;
201 int bufsz
= sizeof(buf
);
204 pos
= iwl_mvm_power_mac_dbgfs_read(mvm
, vif
, buf
, bufsz
);
206 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, pos
);
209 static ssize_t
iwl_dbgfs_mac_params_read(struct file
*file
,
210 char __user
*user_buf
,
211 size_t count
, loff_t
*ppos
)
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
;
217 struct ieee80211_chanctx_conf
*chanctx_conf
;
219 int bufsz
= sizeof(buf
);
223 mutex_lock(&mvm
->mutex
);
225 ap_sta_id
= mvmvif
->ap_sta_id
;
227 switch (ieee80211_vif_type_p2p(vif
)) {
228 case NL80211_IFTYPE_ADHOC
:
229 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "type: ibss\n");
231 case NL80211_IFTYPE_STATION
:
232 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "type: bss\n");
234 case NL80211_IFTYPE_AP
:
235 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "type: ap\n");
237 case NL80211_IFTYPE_P2P_CLIENT
:
238 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "type: p2p client\n");
240 case NL80211_IFTYPE_P2P_GO
:
241 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "type: p2p go\n");
243 case NL80211_IFTYPE_P2P_DEVICE
:
244 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "type: p2p dev\n");
250 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "mac id/color: %d / %d\n",
251 mvmvif
->id
, mvmvif
->color
);
252 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bssid: %pM\n",
253 vif
->bss_conf
.bssid
);
254 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "QoS:\n");
255 for (i
= 0; i
< ARRAY_SIZE(mvmvif
->queue_params
); i
++)
256 pos
+= scnprintf(buf
+pos
, bufsz
-pos
,
257 "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
258 i
, mvmvif
->queue_params
[i
].txop
,
259 mvmvif
->queue_params
[i
].cw_min
,
260 mvmvif
->queue_params
[i
].cw_max
,
261 mvmvif
->queue_params
[i
].aifs
,
262 mvmvif
->queue_params
[i
].uapsd
);
264 if (vif
->type
== NL80211_IFTYPE_STATION
&&
265 ap_sta_id
!= IWL_MVM_STATION_COUNT
) {
266 struct ieee80211_sta
*sta
;
268 sta
= rcu_dereference_protected(mvm
->fw_id_to_mac_id
[ap_sta_id
],
269 lockdep_is_held(&mvm
->mutex
));
270 if (!IS_ERR_OR_NULL(sta
)) {
271 struct iwl_mvm_sta
*mvm_sta
= iwl_mvm_sta_from_mac80211(sta
);
273 pos
+= scnprintf(buf
+pos
, bufsz
-pos
,
274 "ap_sta_id %d - reduced Tx power %d\n",
276 mvm_sta
->bt_reduced_txpower
);
281 chanctx_conf
= rcu_dereference(vif
->chanctx_conf
);
283 pos
+= scnprintf(buf
+pos
, bufsz
-pos
,
284 "idle rx chains %d, active rx chains: %d\n",
285 chanctx_conf
->rx_chains_static
,
286 chanctx_conf
->rx_chains_dynamic
);
289 mutex_unlock(&mvm
->mutex
);
291 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, pos
);
294 static void iwl_dbgfs_update_bf(struct ieee80211_vif
*vif
,
295 enum iwl_dbgfs_bf_mask param
, int value
)
297 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
298 struct iwl_dbgfs_bf
*dbgfs_bf
= &mvmvif
->dbgfs_bf
;
300 dbgfs_bf
->mask
|= param
;
303 case MVM_DEBUGFS_BF_ENERGY_DELTA
:
304 dbgfs_bf
->bf_energy_delta
= value
;
306 case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA
:
307 dbgfs_bf
->bf_roaming_energy_delta
= value
;
309 case MVM_DEBUGFS_BF_ROAMING_STATE
:
310 dbgfs_bf
->bf_roaming_state
= value
;
312 case MVM_DEBUGFS_BF_TEMP_THRESHOLD
:
313 dbgfs_bf
->bf_temp_threshold
= value
;
315 case MVM_DEBUGFS_BF_TEMP_FAST_FILTER
:
316 dbgfs_bf
->bf_temp_fast_filter
= value
;
318 case MVM_DEBUGFS_BF_TEMP_SLOW_FILTER
:
319 dbgfs_bf
->bf_temp_slow_filter
= value
;
321 case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
:
322 dbgfs_bf
->bf_enable_beacon_filter
= value
;
324 case MVM_DEBUGFS_BF_DEBUG_FLAG
:
325 dbgfs_bf
->bf_debug_flag
= value
;
327 case MVM_DEBUGFS_BF_ESCAPE_TIMER
:
328 dbgfs_bf
->bf_escape_timer
= value
;
330 case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT
:
331 dbgfs_bf
->ba_enable_beacon_abort
= value
;
333 case MVM_DEBUGFS_BA_ESCAPE_TIMER
:
334 dbgfs_bf
->ba_escape_timer
= value
;
339 static ssize_t
iwl_dbgfs_bf_params_write(struct ieee80211_vif
*vif
, char *buf
,
340 size_t count
, loff_t
*ppos
)
342 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
343 struct iwl_mvm
*mvm
= mvmvif
->mvm
;
344 enum iwl_dbgfs_bf_mask param
;
347 if (!strncmp("bf_energy_delta=", buf
, 16)) {
348 if (sscanf(buf
+16, "%d", &value
) != 1)
350 if (value
< IWL_BF_ENERGY_DELTA_MIN
||
351 value
> IWL_BF_ENERGY_DELTA_MAX
)
353 param
= MVM_DEBUGFS_BF_ENERGY_DELTA
;
354 } else if (!strncmp("bf_roaming_energy_delta=", buf
, 24)) {
355 if (sscanf(buf
+24, "%d", &value
) != 1)
357 if (value
< IWL_BF_ROAMING_ENERGY_DELTA_MIN
||
358 value
> IWL_BF_ROAMING_ENERGY_DELTA_MAX
)
360 param
= MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA
;
361 } else if (!strncmp("bf_roaming_state=", buf
, 17)) {
362 if (sscanf(buf
+17, "%d", &value
) != 1)
364 if (value
< IWL_BF_ROAMING_STATE_MIN
||
365 value
> IWL_BF_ROAMING_STATE_MAX
)
367 param
= MVM_DEBUGFS_BF_ROAMING_STATE
;
368 } else if (!strncmp("bf_temp_threshold=", buf
, 18)) {
369 if (sscanf(buf
+18, "%d", &value
) != 1)
371 if (value
< IWL_BF_TEMP_THRESHOLD_MIN
||
372 value
> IWL_BF_TEMP_THRESHOLD_MAX
)
374 param
= MVM_DEBUGFS_BF_TEMP_THRESHOLD
;
375 } else if (!strncmp("bf_temp_fast_filter=", buf
, 20)) {
376 if (sscanf(buf
+20, "%d", &value
) != 1)
378 if (value
< IWL_BF_TEMP_FAST_FILTER_MIN
||
379 value
> IWL_BF_TEMP_FAST_FILTER_MAX
)
381 param
= MVM_DEBUGFS_BF_TEMP_FAST_FILTER
;
382 } else if (!strncmp("bf_temp_slow_filter=", buf
, 20)) {
383 if (sscanf(buf
+20, "%d", &value
) != 1)
385 if (value
< IWL_BF_TEMP_SLOW_FILTER_MIN
||
386 value
> IWL_BF_TEMP_SLOW_FILTER_MAX
)
388 param
= MVM_DEBUGFS_BF_TEMP_SLOW_FILTER
;
389 } else if (!strncmp("bf_enable_beacon_filter=", buf
, 24)) {
390 if (sscanf(buf
+24, "%d", &value
) != 1)
392 if (value
< 0 || value
> 1)
394 param
= MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
;
395 } else if (!strncmp("bf_debug_flag=", buf
, 14)) {
396 if (sscanf(buf
+14, "%d", &value
) != 1)
398 if (value
< 0 || value
> 1)
400 param
= MVM_DEBUGFS_BF_DEBUG_FLAG
;
401 } else if (!strncmp("bf_escape_timer=", buf
, 16)) {
402 if (sscanf(buf
+16, "%d", &value
) != 1)
404 if (value
< IWL_BF_ESCAPE_TIMER_MIN
||
405 value
> IWL_BF_ESCAPE_TIMER_MAX
)
407 param
= MVM_DEBUGFS_BF_ESCAPE_TIMER
;
408 } else if (!strncmp("ba_escape_timer=", buf
, 16)) {
409 if (sscanf(buf
+16, "%d", &value
) != 1)
411 if (value
< IWL_BA_ESCAPE_TIMER_MIN
||
412 value
> IWL_BA_ESCAPE_TIMER_MAX
)
414 param
= MVM_DEBUGFS_BA_ESCAPE_TIMER
;
415 } else if (!strncmp("ba_enable_beacon_abort=", buf
, 23)) {
416 if (sscanf(buf
+23, "%d", &value
) != 1)
418 if (value
< 0 || value
> 1)
420 param
= MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT
;
425 mutex_lock(&mvm
->mutex
);
426 iwl_dbgfs_update_bf(vif
, param
, value
);
427 if (param
== MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER
&& !value
)
428 ret
= iwl_mvm_disable_beacon_filter(mvm
, vif
, 0);
430 ret
= iwl_mvm_enable_beacon_filter(mvm
, vif
, 0);
431 mutex_unlock(&mvm
->mutex
);
436 static ssize_t
iwl_dbgfs_bf_params_read(struct file
*file
,
437 char __user
*user_buf
,
438 size_t count
, loff_t
*ppos
)
440 struct ieee80211_vif
*vif
= file
->private_data
;
441 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
444 const size_t bufsz
= sizeof(buf
);
445 struct iwl_beacon_filter_cmd cmd
= {
446 IWL_BF_CMD_CONFIG_DEFAULTS
,
447 .bf_enable_beacon_filter
=
448 cpu_to_le32(IWL_BF_ENABLE_BEACON_FILTER_DEFAULT
),
449 .ba_enable_beacon_abort
=
450 cpu_to_le32(IWL_BA_ENABLE_BEACON_ABORT_DEFAULT
),
453 iwl_mvm_beacon_filter_debugfs_parameters(vif
, &cmd
);
454 if (mvmvif
->bf_data
.bf_enabled
)
455 cmd
.bf_enable_beacon_filter
= cpu_to_le32(1);
457 cmd
.bf_enable_beacon_filter
= 0;
459 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_energy_delta = %d\n",
460 le32_to_cpu(cmd
.bf_energy_delta
));
461 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_roaming_energy_delta = %d\n",
462 le32_to_cpu(cmd
.bf_roaming_energy_delta
));
463 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_roaming_state = %d\n",
464 le32_to_cpu(cmd
.bf_roaming_state
));
465 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_temp_threshold = %d\n",
466 le32_to_cpu(cmd
.bf_temp_threshold
));
467 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_temp_fast_filter = %d\n",
468 le32_to_cpu(cmd
.bf_temp_fast_filter
));
469 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_temp_slow_filter = %d\n",
470 le32_to_cpu(cmd
.bf_temp_slow_filter
));
471 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_enable_beacon_filter = %d\n",
472 le32_to_cpu(cmd
.bf_enable_beacon_filter
));
473 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_debug_flag = %d\n",
474 le32_to_cpu(cmd
.bf_debug_flag
));
475 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "bf_escape_timer = %d\n",
476 le32_to_cpu(cmd
.bf_escape_timer
));
477 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "ba_escape_timer = %d\n",
478 le32_to_cpu(cmd
.ba_escape_timer
));
479 pos
+= scnprintf(buf
+pos
, bufsz
-pos
, "ba_enable_beacon_abort = %d\n",
480 le32_to_cpu(cmd
.ba_enable_beacon_abort
));
482 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, pos
);
485 static ssize_t
iwl_dbgfs_low_latency_write(struct ieee80211_vif
*vif
, char *buf
,
486 size_t count
, loff_t
*ppos
)
488 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
489 struct iwl_mvm
*mvm
= mvmvif
->mvm
;
493 ret
= kstrtou8(buf
, 0, &value
);
499 mutex_lock(&mvm
->mutex
);
500 iwl_mvm_update_low_latency(mvm
, vif
, value
);
501 mutex_unlock(&mvm
->mutex
);
506 static ssize_t
iwl_dbgfs_low_latency_read(struct file
*file
,
507 char __user
*user_buf
,
508 size_t count
, loff_t
*ppos
)
510 struct ieee80211_vif
*vif
= file
->private_data
;
511 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
514 buf
[0] = mvmvif
->low_latency
? '1' : '0';
517 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, sizeof(buf
));
520 static ssize_t
iwl_dbgfs_uapsd_misbehaving_read(struct file
*file
,
521 char __user
*user_buf
,
522 size_t count
, loff_t
*ppos
)
524 struct ieee80211_vif
*vif
= file
->private_data
;
525 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
529 len
= sprintf(buf
, "%pM\n", mvmvif
->uapsd_misbehaving_bssid
);
530 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
533 static ssize_t
iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif
*vif
,
534 char *buf
, size_t count
,
537 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
538 struct iwl_mvm
*mvm
= mvmvif
->mvm
;
541 mutex_lock(&mvm
->mutex
);
542 ret
= mac_pton(buf
, mvmvif
->uapsd_misbehaving_bssid
);
543 mutex_unlock(&mvm
->mutex
);
545 return ret
? count
: -EINVAL
;
548 static ssize_t
iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif
*vif
, char *buf
,
549 size_t count
, loff_t
*ppos
)
551 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
552 struct iwl_mvm
*mvm
= mvmvif
->mvm
;
553 struct ieee80211_chanctx_conf
*chanctx_conf
;
554 struct iwl_mvm_phy_ctxt
*phy_ctxt
;
558 ret
= kstrtou16(buf
, 0, &value
);
562 mutex_lock(&mvm
->mutex
);
565 chanctx_conf
= rcu_dereference(vif
->chanctx_conf
);
566 /* make sure the channel context is assigned */
569 mutex_unlock(&mvm
->mutex
);
573 phy_ctxt
= &mvm
->phy_ctxts
[*(u16
*)chanctx_conf
->drv_priv
];
576 mvm
->dbgfs_rx_phyinfo
= value
;
578 ret
= iwl_mvm_phy_ctxt_changed(mvm
, phy_ctxt
, &chanctx_conf
->min_def
,
579 chanctx_conf
->rx_chains_static
,
580 chanctx_conf
->rx_chains_dynamic
);
581 mutex_unlock(&mvm
->mutex
);
586 static ssize_t
iwl_dbgfs_rx_phyinfo_read(struct file
*file
,
587 char __user
*user_buf
,
588 size_t count
, loff_t
*ppos
)
590 struct ieee80211_vif
*vif
= file
->private_data
;
591 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
594 snprintf(buf
, sizeof(buf
), "0x%04x\n", mvmvif
->mvm
->dbgfs_rx_phyinfo
);
596 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, sizeof(buf
));
599 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
600 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
601 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
602 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
603 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
604 if (!debugfs_create_file(#name, mode, parent, vif, \
605 &iwl_dbgfs_##name##_ops)) \
609 MVM_DEBUGFS_READ_FILE_OPS(mac_params
);
610 MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params
, 32);
611 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params
, 256);
612 MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency
, 10);
613 MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving
, 20);
614 MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo
, 10);
616 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
)
618 struct dentry
*dbgfs_dir
= vif
->debugfs_dir
;
619 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
623 * Check if debugfs directory already exist before creating it.
624 * This may happen when, for example, resetting hw or suspend-resume
626 if (!dbgfs_dir
|| mvmvif
->dbgfs_dir
)
629 mvmvif
->dbgfs_dir
= debugfs_create_dir("iwlmvm", dbgfs_dir
);
631 if (!mvmvif
->dbgfs_dir
) {
632 IWL_ERR(mvm
, "Failed to create debugfs directory under %s\n",
633 dbgfs_dir
->d_name
.name
);
637 if (iwlmvm_mod_params
.power_scheme
!= IWL_POWER_SCHEME_CAM
&&
638 ((vif
->type
== NL80211_IFTYPE_STATION
&& !vif
->p2p
) ||
639 (vif
->type
== NL80211_IFTYPE_STATION
&& vif
->p2p
&&
640 mvm
->fw
->ucode_capa
.flags
& IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM
)))
641 MVM_DEBUGFS_ADD_FILE_VIF(pm_params
, mvmvif
->dbgfs_dir
, S_IWUSR
|
644 MVM_DEBUGFS_ADD_FILE_VIF(mac_params
, mvmvif
->dbgfs_dir
, S_IRUSR
);
645 MVM_DEBUGFS_ADD_FILE_VIF(low_latency
, mvmvif
->dbgfs_dir
,
647 MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving
, mvmvif
->dbgfs_dir
,
649 MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo
, mvmvif
->dbgfs_dir
,
652 if (vif
->type
== NL80211_IFTYPE_STATION
&& !vif
->p2p
&&
653 mvmvif
== mvm
->bf_allowed_vif
)
654 MVM_DEBUGFS_ADD_FILE_VIF(bf_params
, mvmvif
->dbgfs_dir
,
658 * Create symlink for convenience pointing to interface specific
659 * debugfs entries for the driver. For example, under
660 * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
662 * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
664 snprintf(buf
, 100, "../../../%s/%s/%s/%s",
665 dbgfs_dir
->d_parent
->d_parent
->d_name
.name
,
666 dbgfs_dir
->d_parent
->d_name
.name
,
667 dbgfs_dir
->d_name
.name
,
668 mvmvif
->dbgfs_dir
->d_name
.name
);
670 mvmvif
->dbgfs_slink
= debugfs_create_symlink(dbgfs_dir
->d_name
.name
,
671 mvm
->debugfs_dir
, buf
);
672 if (!mvmvif
->dbgfs_slink
)
673 IWL_ERR(mvm
, "Can't create debugfs symbolic link under %s\n",
674 dbgfs_dir
->d_name
.name
);
677 IWL_ERR(mvm
, "Can't create debugfs entity\n");
680 void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm
*mvm
, struct ieee80211_vif
*vif
)
682 struct iwl_mvm_vif
*mvmvif
= iwl_mvm_vif_from_mac80211(vif
);
684 debugfs_remove(mvmvif
->dbgfs_slink
);
685 mvmvif
->dbgfs_slink
= NULL
;
687 debugfs_remove_recursive(mvmvif
->dbgfs_dir
);
688 mvmvif
->dbgfs_dir
= NULL
;