blob: 0b5cae54b86b2cb2196ab1eb0f6e41ef5010764c [file] [log] [blame]
Johannes Berg8ca151b2013-01-24 14:25:36 +01001/******************************************************************************
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 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +02008 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
Eliad Pellerc7792732015-04-19 11:41:04 +03009 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
Johannes Bergaab69302017-03-22 22:05:12 +010010 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
Johannes Berg8ca151b2013-01-24 14:25:36 +010011 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24 * USA
25 *
26 * The full GNU General Public License is included in this distribution
Emmanuel Grumbach410dc5a2013-02-18 09:22:28 +020027 * in the file called COPYING.
Johannes Berg8ca151b2013-01-24 14:25:36 +010028 *
29 * Contact Information:
Emmanuel Grumbachcb2f8272015-11-17 15:39:56 +020030 * Intel Linux Wireless <linuxwifi@intel.com>
Johannes Berg8ca151b2013-01-24 14:25:36 +010031 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32 *
33 * BSD LICENSE
34 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020035 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
Eliad Pellerc7792732015-04-19 11:41:04 +030036 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
Johannes Bergaab69302017-03-22 22:05:12 +010037 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
Johannes Berg8ca151b2013-01-24 14:25:36 +010038 * All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 *
44 * * Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * * Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in
48 * the documentation and/or other materials provided with the
49 * distribution.
50 * * Neither the name Intel Corporation nor the names of its
51 * contributors may be used to endorse or promote products derived
52 * from this software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
64 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 *
66 *****************************************************************************/
Emmanuel Grumbach192c80a2014-03-19 08:25:05 +020067#include <linux/vmalloc.h>
Emmanuel Grumbach9e7dce22015-10-26 16:14:06 +020068#include <linux/ieee80211.h>
Sara Sharon854d7732016-03-22 15:55:58 +020069#include <linux/netdevice.h>
Emmanuel Grumbach192c80a2014-03-19 08:25:05 +020070
Johannes Berg8ca151b2013-01-24 14:25:36 +010071#include "mvm.h"
72#include "sta.h"
73#include "iwl-io.h"
Johannes Berg820a1a52013-11-12 16:58:41 +010074#include "debugfs.h"
Johannes Bergd962f9b2017-06-01 10:22:09 +020075#include "fw/error-dump.h"
Johannes Berg8ca151b2013-01-24 14:25:36 +010076
Chaya Rachel Ivgi00f481b2016-02-24 12:19:22 +020077static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
78 char __user *user_buf,
79 size_t count, loff_t *ppos)
80{
81 struct iwl_mvm *mvm = file->private_data;
82 char buf[16];
83 int pos, budget;
84
Johannes Bergaab69302017-03-22 22:05:12 +010085 if (!iwl_mvm_firmware_running(mvm) ||
Johannes Berg702e9752017-06-02 11:56:58 +020086 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
Chaya Rachel Ivgi00f481b2016-02-24 12:19:22 +020087 return -EIO;
88
89 mutex_lock(&mvm->mutex);
90 budget = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_REPORT, 0);
91 mutex_unlock(&mvm->mutex);
92
93 if (budget < 0)
94 return budget;
95
96 pos = scnprintf(buf, sizeof(buf), "%d\n", budget);
97
98 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
99}
100
101static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf,
102 size_t count, loff_t *ppos)
103{
104 int ret;
105
Johannes Bergaab69302017-03-22 22:05:12 +0100106 if (!iwl_mvm_firmware_running(mvm) ||
Johannes Berg702e9752017-06-02 11:56:58 +0200107 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
Chaya Rachel Ivgi00f481b2016-02-24 12:19:22 +0200108 return -EIO;
109
110 mutex_lock(&mvm->mutex);
111 ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_STOP, 0);
112 mutex_unlock(&mvm->mutex);
113
114 return ret ?: count;
115}
116
Chaya Rachel Ivgi61d8c622017-06-27 14:13:02 +0300117static ssize_t iwl_dbgfs_force_ctkill_write(struct iwl_mvm *mvm, char *buf,
118 size_t count, loff_t *ppos)
119{
120 if (!iwl_mvm_firmware_running(mvm) ||
121 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
122 return -EIO;
123
124 iwl_mvm_enter_ctkill(mvm);
125
126 return count;
127}
128
Johannes Berg1fa3f572013-11-13 09:10:21 +0100129static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
Johannes Berg8ca151b2013-01-24 14:25:36 +0100130 size_t count, loff_t *ppos)
131{
Johannes Berg8a0bd162013-11-12 16:48:03 +0100132 int ret;
Mordechai Goodsteind167e812017-05-10 16:42:53 +0300133 u32 flush_arg;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100134
Johannes Bergaab69302017-03-22 22:05:12 +0100135 if (!iwl_mvm_firmware_running(mvm) ||
Johannes Berg702e9752017-06-02 11:56:58 +0200136 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100137 return -EIO;
138
Mordechai Goodsteind167e812017-05-10 16:42:53 +0300139 if (kstrtou32(buf, 0, &flush_arg))
Johannes Berg8ca151b2013-01-24 14:25:36 +0100140 return -EINVAL;
141
Mordechai Goodsteind167e812017-05-10 16:42:53 +0300142 if (iwl_mvm_has_new_tx_api(mvm)) {
143 IWL_DEBUG_TX_QUEUES(mvm,
144 "FLUSHING all tids queues on sta_id = %d\n",
145 flush_arg);
146 mutex_lock(&mvm->mutex);
147 ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count;
148 mutex_unlock(&mvm->mutex);
149 return ret;
150 }
151
152 IWL_DEBUG_TX_QUEUES(mvm, "FLUSHING queues mask to flush = 0x%x\n",
153 flush_arg);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100154
155 mutex_lock(&mvm->mutex);
Mordechai Goodsteind167e812017-05-10 16:42:53 +0300156 ret = iwl_mvm_flush_tx_path(mvm, flush_arg, 0) ? : count;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100157 mutex_unlock(&mvm->mutex);
158
159 return ret;
160}
161
Johannes Berg1fa3f572013-11-13 09:10:21 +0100162static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
Johannes Berg8ca151b2013-01-24 14:25:36 +0100163 size_t count, loff_t *ppos)
164{
Emmanuel Grumbachf327b042014-01-14 08:30:32 +0200165 struct iwl_mvm_sta *mvmsta;
Johannes Berg8a0bd162013-11-12 16:48:03 +0100166 int sta_id, drain, ret;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100167
Johannes Bergaab69302017-03-22 22:05:12 +0100168 if (!iwl_mvm_firmware_running(mvm) ||
Johannes Berg702e9752017-06-02 11:56:58 +0200169 mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100170 return -EIO;
171
Johannes Berg8ca151b2013-01-24 14:25:36 +0100172 if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
173 return -EINVAL;
Johannes Berg60765a42013-10-25 13:06:06 +0200174 if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
175 return -EINVAL;
176 if (drain < 0 || drain > 1)
177 return -EINVAL;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100178
179 mutex_lock(&mvm->mutex);
180
Emmanuel Grumbachf327b042014-01-14 08:30:32 +0200181 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
182
183 if (!mvmsta)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100184 ret = -ENOENT;
185 else
Emmanuel Grumbachf327b042014-01-14 08:30:32 +0200186 ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100187
188 mutex_unlock(&mvm->mutex);
189
190 return ret;
191}
192
193static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
194 size_t count, loff_t *ppos)
195{
196 struct iwl_mvm *mvm = file->private_data;
197 const struct fw_img *img;
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200198 unsigned int ofs, len;
199 size_t ret;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100200 u8 *ptr;
201
Johannes Bergaab69302017-03-22 22:05:12 +0100202 if (!iwl_mvm_firmware_running(mvm))
Johannes Berg60191d92013-05-15 13:08:51 +0200203 return -EINVAL;
204
Johannes Berg8ca151b2013-01-24 14:25:36 +0100205 /* default is to dump the entire data segment */
Johannes Berg702e9752017-06-02 11:56:58 +0200206 img = &mvm->fw->img[mvm->fwrt.cur_fw_img];
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200207 ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
208 len = img->sec[IWL_UCODE_SECTION_DATA].len;
209
Emmanuel Grumbach01e0efe2014-01-06 09:05:54 +0200210 if (mvm->dbgfs_sram_len) {
Johannes Berg60191d92013-05-15 13:08:51 +0200211 ofs = mvm->dbgfs_sram_offset;
212 len = mvm->dbgfs_sram_len;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100213 }
Johannes Berg8ca151b2013-01-24 14:25:36 +0100214
Johannes Berg8ca151b2013-01-24 14:25:36 +0100215 ptr = kzalloc(len, GFP_KERNEL);
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200216 if (!ptr)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100217 return -ENOMEM;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100218
Johannes Berg60191d92013-05-15 13:08:51 +0200219 iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100220
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200221 ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100222
Johannes Berg8ca151b2013-01-24 14:25:36 +0100223 kfree(ptr);
224
225 return ret;
226}
227
Johannes Berg1fa3f572013-11-13 09:10:21 +0100228static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
229 size_t count, loff_t *ppos)
Johannes Berg8ca151b2013-01-24 14:25:36 +0100230{
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200231 const struct fw_img *img;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100232 u32 offset, len;
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200233 u32 img_offset, img_len;
234
Johannes Bergaab69302017-03-22 22:05:12 +0100235 if (!iwl_mvm_firmware_running(mvm))
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200236 return -EINVAL;
237
Johannes Berg702e9752017-06-02 11:56:58 +0200238 img = &mvm->fw->img[mvm->fwrt.cur_fw_img];
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200239 img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
240 img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100241
Johannes Berg8ca151b2013-01-24 14:25:36 +0100242 if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
243 if ((offset & 0x3) || (len & 0x3))
244 return -EINVAL;
Emmanuel Grumbachd5103422013-12-24 14:58:29 +0200245
246 if (offset + len > img_offset + img_len)
247 return -EINVAL;
248
Johannes Berg8ca151b2013-01-24 14:25:36 +0100249 mvm->dbgfs_sram_offset = offset;
250 mvm->dbgfs_sram_len = len;
251 } else {
252 mvm->dbgfs_sram_offset = 0;
253 mvm->dbgfs_sram_len = 0;
254 }
255
256 return count;
257}
258
Matti Gottlieb7280d1f2014-07-17 16:41:14 +0300259static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
260 char __user *user_buf,
261 size_t count, loff_t *ppos)
262{
263 struct iwl_mvm *mvm = file->private_data;
264 char buf[16];
265 int pos;
266
267 if (!mvm->temperature_test)
268 pos = scnprintf(buf , sizeof(buf), "disabled\n");
269 else
270 pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
271
272 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
273}
274
275/*
276 * Set NIC Temperature
277 * Cause the driver to ignore the actual NIC temperature reported by the FW
278 * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -
279 * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX
280 * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE
281 */
282static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
283 char *buf, size_t count,
284 loff_t *ppos)
285{
286 int temperature;
287
Johannes Bergaab69302017-03-22 22:05:12 +0100288 if (!iwl_mvm_firmware_running(mvm) && !mvm->temperature_test)
Luciano Coelhoa26d4e72014-08-20 10:21:07 +0300289 return -EIO;
290
Matti Gottlieb7280d1f2014-07-17 16:41:14 +0300291 if (kstrtoint(buf, 10, &temperature))
292 return -EINVAL;
293 /* not a legal temperature */
294 if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX &&
295 temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) ||
296 temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN)
297 return -EINVAL;
298
299 mutex_lock(&mvm->mutex);
300 if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) {
Luciano Coelhob689fa72014-08-20 17:26:58 +0300301 if (!mvm->temperature_test)
302 goto out;
303
Matti Gottlieb7280d1f2014-07-17 16:41:14 +0300304 mvm->temperature_test = false;
Luciano Coelhob689fa72014-08-20 17:26:58 +0300305 /* Since we can't read the temp while awake, just set
306 * it to zero until we get the next RX stats from the
307 * firmware.
308 */
309 mvm->temperature = 0;
Matti Gottlieb7280d1f2014-07-17 16:41:14 +0300310 } else {
311 mvm->temperature_test = true;
312 mvm->temperature = temperature;
313 }
314 IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
315 mvm->temperature_test ? "En" : "Dis" ,
316 mvm->temperature);
317 /* handle the temperature change */
318 iwl_mvm_tt_handler(mvm);
Luciano Coelhob689fa72014-08-20 17:26:58 +0300319
320out:
Matti Gottlieb7280d1f2014-07-17 16:41:14 +0300321 mutex_unlock(&mvm->mutex);
322
323 return count;
324}
325
Luciano Coelhoc549e392014-09-04 15:58:47 +0300326static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
327 char __user *user_buf,
328 size_t count, loff_t *ppos)
329{
330 struct iwl_mvm *mvm = file->private_data;
331 char buf[16];
Chaya Rachel Ivgi78693182015-12-27 13:45:42 +0200332 int pos, ret;
333 s32 temp;
Luciano Coelhoc549e392014-09-04 15:58:47 +0300334
Johannes Bergaab69302017-03-22 22:05:12 +0100335 if (!iwl_mvm_firmware_running(mvm))
Luciano Coelhoc549e392014-09-04 15:58:47 +0300336 return -EIO;
337
338 mutex_lock(&mvm->mutex);
Chaya Rachel Ivgi78693182015-12-27 13:45:42 +0200339 ret = iwl_mvm_get_temp(mvm, &temp);
Luciano Coelhoc549e392014-09-04 15:58:47 +0300340 mutex_unlock(&mvm->mutex);
341
Chaya Rachel Ivgi78693182015-12-27 13:45:42 +0200342 if (ret)
343 return -EIO;
Luciano Coelhoc549e392014-09-04 15:58:47 +0300344
345 pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
346
347 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
348}
349
Haim Dreyfusse6ee0652017-05-15 14:27:21 +0300350#ifdef CONFIG_ACPI
351static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file,
352 char __user *user_buf,
353 size_t count, loff_t *ppos)
354{
355 struct iwl_mvm *mvm = file->private_data;
356 char buf[256];
357 int pos = 0;
358 int bufsz = sizeof(buf);
359 int tbl_idx;
360 u8 *value;
361
362 if (!iwl_mvm_firmware_running(mvm))
363 return -EIO;
364
365 mutex_lock(&mvm->mutex);
366 tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);
367 if (tbl_idx < 0) {
368 mutex_unlock(&mvm->mutex);
369 return tbl_idx;
370 }
371
372 if (!tbl_idx) {
373 pos = scnprintf(buf, bufsz,
374 "SAR geographic profile disabled\n");
375 } else {
376 value = &mvm->geo_profiles[tbl_idx - 1].values[0];
377
378 pos += scnprintf(buf + pos, bufsz - pos,
379 "Use geographic profile %d\n", tbl_idx);
380 pos += scnprintf(buf + pos, bufsz - pos,
381 "2.4GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n",
382 value[1], value[2], value[0]);
383 pos += scnprintf(buf + pos, bufsz - pos,
384 "5.2GHz:\n\tChain A offset: %hhd dBm\n\tChain B offset: %hhd dBm\n\tmax tx power: %hhd dBm\n",
385 value[4], value[5], value[3]);
386 }
387 mutex_unlock(&mvm->mutex);
388
389 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
390}
391#endif
392
Johannes Berg8ca151b2013-01-24 14:25:36 +0100393static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
394 size_t count, loff_t *ppos)
395{
396 struct iwl_mvm *mvm = file->private_data;
397 struct ieee80211_sta *sta;
398 char buf[400];
399 int i, pos = 0, bufsz = sizeof(buf);
400
401 mutex_lock(&mvm->mutex);
402
Sara Sharon0ae98812017-01-04 14:53:58 +0200403 for (i = 0; i < ARRAY_SIZE(mvm->fw_id_to_mac_id); i++) {
Johannes Berg8ca151b2013-01-24 14:25:36 +0100404 pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
405 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
406 lockdep_is_held(&mvm->mutex));
407 if (!sta)
408 pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
409 else if (IS_ERR(sta))
410 pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
411 PTR_ERR(sta));
412 else
413 pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
414 sta->addr);
415 }
416
417 mutex_unlock(&mvm->mutex);
418
419 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
420}
421
Alexander Bondar64b928c2013-09-03 14:18:03 +0300422static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
423 char __user *user_buf,
Johannes Berg8ca151b2013-01-24 14:25:36 +0100424 size_t count, loff_t *ppos)
425{
426 struct iwl_mvm *mvm = file->private_data;
Alexander Bondar64b928c2013-09-03 14:18:03 +0300427 char buf[64];
428 int bufsz = sizeof(buf);
429 int pos = 0;
430
431 pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n",
432 mvm->disable_power_off);
433 pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n",
434 mvm->disable_power_off_d3);
435
436 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
437}
438
Johannes Berg1fa3f572013-11-13 09:10:21 +0100439static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
Alexander Bondar64b928c2013-09-03 14:18:03 +0300440 size_t count, loff_t *ppos)
441{
Johannes Berg1fa3f572013-11-13 09:10:21 +0100442 int ret, val;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100443
Johannes Bergaab69302017-03-22 22:05:12 +0100444 if (!iwl_mvm_firmware_running(mvm))
Johannes Berg8ca151b2013-01-24 14:25:36 +0100445 return -EIO;
446
Alexander Bondar64b928c2013-09-03 14:18:03 +0300447 if (!strncmp("disable_power_off_d0=", buf, 21)) {
448 if (sscanf(buf + 21, "%d", &val) != 1)
449 return -EINVAL;
450 mvm->disable_power_off = val;
451 } else if (!strncmp("disable_power_off_d3=", buf, 21)) {
452 if (sscanf(buf + 21, "%d", &val) != 1)
453 return -EINVAL;
454 mvm->disable_power_off_d3 = val;
455 } else {
Johannes Berg8ca151b2013-01-24 14:25:36 +0100456 return -EINVAL;
Alexander Bondar64b928c2013-09-03 14:18:03 +0300457 }
Johannes Berg8ca151b2013-01-24 14:25:36 +0100458
Alexander Bondar64b928c2013-09-03 14:18:03 +0300459 mutex_lock(&mvm->mutex);
Emmanuel Grumbachc1cb92f2014-01-28 10:17:18 +0200460 ret = iwl_mvm_power_update_device(mvm);
Alexander Bondar64b928c2013-09-03 14:18:03 +0300461 mutex_unlock(&mvm->mutex);
Johannes Berg8ca151b2013-01-24 14:25:36 +0100462
Alexander Bondar64b928c2013-09-03 14:18:03 +0300463 return ret ?: count;
Johannes Berg8ca151b2013-01-24 14:25:36 +0100464}
465
Emmanuel Grumbach10942342013-02-19 11:02:36 +0200466#define BT_MBOX_MSG(_notif, _num, _field) \
467 ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
468 >> BT_MBOX##_num##_##_field##_POS)
469
470
471#define BT_MBOX_PRINT(_num, _field, _end) \
472 pos += scnprintf(buf + pos, bufsz - pos, \
473 "\t%s: %d%s", \
474 #_field, \
475 BT_MBOX_MSG(notif, _num, _field), \
476 true ? "\n" : ", ");
477
Emmanuel Grumbach160be572014-07-02 17:33:52 +0300478static
479int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf,
480 int pos, int bufsz)
Emmanuel Grumbach10942342013-02-19 11:02:36 +0200481{
Emmanuel Grumbach10942342013-02-19 11:02:36 +0200482 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
483
484 BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
485 BT_MBOX_PRINT(0, LE_PROF1, false);
486 BT_MBOX_PRINT(0, LE_PROF2, false);
487 BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
488 BT_MBOX_PRINT(0, CHL_SEQ_N, false);
489 BT_MBOX_PRINT(0, INBAND_S, false);
490 BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
491 BT_MBOX_PRINT(0, LE_SCAN, false);
492 BT_MBOX_PRINT(0, LE_ADV, false);
493 BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
494 BT_MBOX_PRINT(0, OPEN_CON_1, true);
495
496 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
497
498 BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
499 BT_MBOX_PRINT(1, IP_SR, false);
500 BT_MBOX_PRINT(1, LE_MSTR, false);
501 BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
502 BT_MBOX_PRINT(1, MSG_TYPE, false);
503 BT_MBOX_PRINT(1, SSN, true);
504
505 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
506
507 BT_MBOX_PRINT(2, SNIFF_ACT, false);
508 BT_MBOX_PRINT(2, PAG, false);
509 BT_MBOX_PRINT(2, INQUIRY, false);
510 BT_MBOX_PRINT(2, CONN, false);
511 BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
512 BT_MBOX_PRINT(2, DISC, false);
513 BT_MBOX_PRINT(2, SCO_TX_ACT, false);
514 BT_MBOX_PRINT(2, SCO_RX_ACT, false);
515 BT_MBOX_PRINT(2, ESCO_RE_TX, false);
516 BT_MBOX_PRINT(2, SCO_DURATION, true);
517
518 pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
519
520 BT_MBOX_PRINT(3, SCO_STATE, false);
521 BT_MBOX_PRINT(3, SNIFF_STATE, false);
522 BT_MBOX_PRINT(3, A2DP_STATE, false);
523 BT_MBOX_PRINT(3, ACL_STATE, false);
524 BT_MBOX_PRINT(3, MSTR_STATE, false);
525 BT_MBOX_PRINT(3, OBX_STATE, false);
526 BT_MBOX_PRINT(3, OPEN_CON_2, false);
527 BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
528 BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
529 BT_MBOX_PRINT(3, INBAND_P, false);
530 BT_MBOX_PRINT(3, MSG_TYPE_2, false);
531 BT_MBOX_PRINT(3, SSN_2, false);
532 BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
533
Emmanuel Grumbach160be572014-07-02 17:33:52 +0300534 return pos;
535}
536
Emmanuel Grumbach160be572014-07-02 17:33:52 +0300537static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
538 size_t count, loff_t *ppos)
539{
540 struct iwl_mvm *mvm = file->private_data;
Sara Sharon97f95c92016-03-07 16:55:20 +0200541 struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
Emmanuel Grumbach160be572014-07-02 17:33:52 +0300542 char *buf;
543 int ret, pos = 0, bufsz = sizeof(char) * 1024;
544
545 buf = kmalloc(bufsz, GFP_KERNEL);
546 if (!buf)
547 return -ENOMEM;
548
549 mutex_lock(&mvm->mutex);
550
Sara Sharon97f95c92016-03-07 16:55:20 +0200551 pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz);
Emmanuel Grumbach160be572014-07-02 17:33:52 +0300552
Sara Sharon97f95c92016-03-07 16:55:20 +0200553 pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n",
554 notif->bt_ci_compliance);
555 pos += scnprintf(buf + pos, bufsz - pos, "primary_ch_lut = %d\n",
556 le32_to_cpu(notif->primary_ch_lut));
557 pos += scnprintf(buf + pos, bufsz - pos, "secondary_ch_lut = %d\n",
558 le32_to_cpu(notif->secondary_ch_lut));
559 pos += scnprintf(buf + pos,
560 bufsz - pos, "bt_activity_grading = %d\n",
561 le32_to_cpu(notif->bt_activity_grading));
562 pos += scnprintf(buf + pos, bufsz - pos,
563 "antenna isolation = %d CORUN LUT index = %d\n",
564 mvm->last_ant_isol, mvm->last_corun_lut);
565 pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n",
566 (notif->ttc_rrc_status >> 4) & 0xF);
567 pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n",
568 notif->ttc_rrc_status & 0xF);
Emmanuel Grumbach10942342013-02-19 11:02:36 +0200569
Moshe Harelc725a462015-10-27 14:04:12 +0200570 pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n",
571 IWL_MVM_BT_COEX_SYNC2SCO);
572 pos += scnprintf(buf + pos, bufsz - pos, "mplut = %d\n",
573 IWL_MVM_BT_COEX_MPLUT);
574 pos += scnprintf(buf + pos, bufsz - pos, "corunning = %d\n",
575 IWL_MVM_BT_COEX_CORUNNING);
576
Emmanuel Grumbach10942342013-02-19 11:02:36 +0200577 mutex_unlock(&mvm->mutex);
578
579 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
580 kfree(buf);
581
582 return ret;
583}
584#undef BT_MBOX_PRINT
585
Emmanuel Grumbach2de13ca2013-06-30 07:43:28 +0300586static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
587 size_t count, loff_t *ppos)
588{
589 struct iwl_mvm *mvm = file->private_data;
Sara Sharon97f95c92016-03-07 16:55:20 +0200590 struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
Emmanuel Grumbach2de13ca2013-06-30 07:43:28 +0300591 char buf[256];
592 int bufsz = sizeof(buf);
593 int pos = 0;
594
595 mutex_lock(&mvm->mutex);
596
Sara Sharon97f95c92016-03-07 16:55:20 +0200597 pos += scnprintf(buf + pos, bufsz - pos, "Channel inhibition CMD\n");
598 pos += scnprintf(buf + pos, bufsz - pos,
599 "\tPrimary Channel Bitmap 0x%016llx\n",
600 le64_to_cpu(cmd->bt_primary_ci));
601 pos += scnprintf(buf + pos, bufsz - pos,
602 "\tSecondary Channel Bitmap 0x%016llx\n",
603 le64_to_cpu(cmd->bt_secondary_ci));
Emmanuel Grumbach2de13ca2013-06-30 07:43:28 +0300604
605 mutex_unlock(&mvm->mutex);
606
607 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
608}
609
Emmanuel Grumbachcdb00562014-03-16 21:55:43 +0200610static ssize_t
611iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf,
612 size_t count, loff_t *ppos)
613{
614 u32 bt_tx_prio;
615
616 if (sscanf(buf, "%u", &bt_tx_prio) != 1)
617 return -EINVAL;
618 if (bt_tx_prio > 4)
619 return -EINVAL;
620
621 mvm->bt_tx_prio = bt_tx_prio;
622
623 return count;
624}
625
Emmanuel Grumbacha39979a2014-05-28 12:06:41 +0300626static ssize_t
627iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
628 size_t count, loff_t *ppos)
629{
630 static const char * const modes_str[BT_FORCE_ANT_MAX] = {
631 [BT_FORCE_ANT_DIS] = "dis",
632 [BT_FORCE_ANT_AUTO] = "auto",
633 [BT_FORCE_ANT_BT] = "bt",
634 [BT_FORCE_ANT_WIFI] = "wifi",
635 };
636 int ret, bt_force_ant_mode;
637
638 for (bt_force_ant_mode = 0;
639 bt_force_ant_mode < ARRAY_SIZE(modes_str);
640 bt_force_ant_mode++) {
641 if (!strcmp(buf, modes_str[bt_force_ant_mode]))
642 break;
643 }
644
645 if (bt_force_ant_mode >= ARRAY_SIZE(modes_str))
646 return -EINVAL;
647
648 ret = 0;
649 mutex_lock(&mvm->mutex);
650 if (mvm->bt_force_ant_mode == bt_force_ant_mode)
651 goto out;
652
653 mvm->bt_force_ant_mode = bt_force_ant_mode;
654 IWL_DEBUG_COEX(mvm, "Force mode: %s\n",
655 modes_str[mvm->bt_force_ant_mode]);
Johannes Berg504bd622017-03-22 22:19:41 +0100656
657 if (iwl_mvm_firmware_running(mvm))
Emmanuel Grumbachb3de3ef2017-05-29 14:01:06 +0300658 ret = iwl_mvm_send_bt_init_conf(mvm);
Johannes Berg504bd622017-03-22 22:19:41 +0100659 else
660 ret = 0;
Emmanuel Grumbacha39979a2014-05-28 12:06:41 +0300661
662out:
663 mutex_unlock(&mvm->mutex);
664 return ret ?: count;
665}
666
Johannes Berg93d17cc2015-01-15 12:59:26 +0100667#define PRINT_STATS_LE32(_struct, _memb) \
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300668 pos += scnprintf(buf + pos, bufsz - pos, \
Johannes Berg93d17cc2015-01-15 12:59:26 +0100669 fmt_table, #_memb, \
670 le32_to_cpu(_struct->_memb))
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300671
672static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
673 char __user *user_buf, size_t count,
674 loff_t *ppos)
675{
676 struct iwl_mvm *mvm = file->private_data;
677 static const char *fmt_table = "\t%-30s %10u\n";
678 static const char *fmt_header = "%-32s\n";
679 int pos = 0;
680 char *buf;
681 int ret;
Liad Kaufman678d9b62017-05-18 18:00:49 +0300682 size_t bufsz;
Luciano Coelho3f617282013-10-14 13:18:41 +0300683
Liad Kaufman678d9b62017-05-18 18:00:49 +0300684 if (iwl_mvm_has_new_rx_stats_api(mvm))
685 bufsz = ((sizeof(struct mvm_statistics_rx) /
686 sizeof(__le32)) * 43) + (4 * 33) + 1;
687 else
688 /* 43 = size of each data line; 33 = size of each header */
689 bufsz = ((sizeof(struct mvm_statistics_rx_v3) /
690 sizeof(__le32)) * 43) + (4 * 33) + 1;
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300691
692 buf = kzalloc(bufsz, GFP_KERNEL);
693 if (!buf)
694 return -ENOMEM;
695
696 mutex_lock(&mvm->mutex);
697
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300698 pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
699 "Statistics_Rx - OFDM");
Liad Kaufman678d9b62017-05-18 18:00:49 +0300700 if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
701 struct mvm_statistics_rx_phy_v2 *ofdm = &mvm->rx_stats_v3.ofdm;
702
703 PRINT_STATS_LE32(ofdm, ina_cnt);
704 PRINT_STATS_LE32(ofdm, fina_cnt);
705 PRINT_STATS_LE32(ofdm, plcp_err);
706 PRINT_STATS_LE32(ofdm, crc32_err);
707 PRINT_STATS_LE32(ofdm, overrun_err);
708 PRINT_STATS_LE32(ofdm, early_overrun_err);
709 PRINT_STATS_LE32(ofdm, crc32_good);
710 PRINT_STATS_LE32(ofdm, false_alarm_cnt);
711 PRINT_STATS_LE32(ofdm, fina_sync_err_cnt);
712 PRINT_STATS_LE32(ofdm, sfd_timeout);
713 PRINT_STATS_LE32(ofdm, fina_timeout);
714 PRINT_STATS_LE32(ofdm, unresponded_rts);
715 PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
716 PRINT_STATS_LE32(ofdm, sent_ack_cnt);
717 PRINT_STATS_LE32(ofdm, sent_cts_cnt);
718 PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
719 PRINT_STATS_LE32(ofdm, dsp_self_kill);
720 PRINT_STATS_LE32(ofdm, mh_format_err);
721 PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum);
722 PRINT_STATS_LE32(ofdm, reserved);
723 } else {
724 struct mvm_statistics_rx_phy *ofdm = &mvm->rx_stats.ofdm;
725
726 PRINT_STATS_LE32(ofdm, unresponded_rts);
727 PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
728 PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
729 PRINT_STATS_LE32(ofdm, dsp_self_kill);
730 PRINT_STATS_LE32(ofdm, reserved);
731 }
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300732
733 pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
734 "Statistics_Rx - CCK");
Liad Kaufman678d9b62017-05-18 18:00:49 +0300735 if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
736 struct mvm_statistics_rx_phy_v2 *cck = &mvm->rx_stats_v3.cck;
737
738 PRINT_STATS_LE32(cck, ina_cnt);
739 PRINT_STATS_LE32(cck, fina_cnt);
740 PRINT_STATS_LE32(cck, plcp_err);
741 PRINT_STATS_LE32(cck, crc32_err);
742 PRINT_STATS_LE32(cck, overrun_err);
743 PRINT_STATS_LE32(cck, early_overrun_err);
744 PRINT_STATS_LE32(cck, crc32_good);
745 PRINT_STATS_LE32(cck, false_alarm_cnt);
746 PRINT_STATS_LE32(cck, fina_sync_err_cnt);
747 PRINT_STATS_LE32(cck, sfd_timeout);
748 PRINT_STATS_LE32(cck, fina_timeout);
749 PRINT_STATS_LE32(cck, unresponded_rts);
750 PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
751 PRINT_STATS_LE32(cck, sent_ack_cnt);
752 PRINT_STATS_LE32(cck, sent_cts_cnt);
753 PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
754 PRINT_STATS_LE32(cck, dsp_self_kill);
755 PRINT_STATS_LE32(cck, mh_format_err);
756 PRINT_STATS_LE32(cck, re_acq_main_rssi_sum);
757 PRINT_STATS_LE32(cck, reserved);
758 } else {
759 struct mvm_statistics_rx_phy *cck = &mvm->rx_stats.cck;
760
761 PRINT_STATS_LE32(cck, unresponded_rts);
762 PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
763 PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
764 PRINT_STATS_LE32(cck, dsp_self_kill);
765 PRINT_STATS_LE32(cck, reserved);
766 }
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300767
768 pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
769 "Statistics_Rx - GENERAL");
Liad Kaufman678d9b62017-05-18 18:00:49 +0300770 if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
771 struct mvm_statistics_rx_non_phy_v3 *general =
772 &mvm->rx_stats_v3.general;
773
774 PRINT_STATS_LE32(general, bogus_cts);
775 PRINT_STATS_LE32(general, bogus_ack);
776 PRINT_STATS_LE32(general, non_bssid_frames);
777 PRINT_STATS_LE32(general, filtered_frames);
778 PRINT_STATS_LE32(general, non_channel_beacons);
779 PRINT_STATS_LE32(general, channel_beacons);
780 PRINT_STATS_LE32(general, num_missed_bcon);
781 PRINT_STATS_LE32(general, adc_rx_saturation_time);
782 PRINT_STATS_LE32(general, ina_detection_search_time);
783 PRINT_STATS_LE32(general, beacon_silence_rssi_a);
784 PRINT_STATS_LE32(general, beacon_silence_rssi_b);
785 PRINT_STATS_LE32(general, beacon_silence_rssi_c);
786 PRINT_STATS_LE32(general, interference_data_flag);
787 PRINT_STATS_LE32(general, channel_load);
788 PRINT_STATS_LE32(general, dsp_false_alarms);
789 PRINT_STATS_LE32(general, beacon_rssi_a);
790 PRINT_STATS_LE32(general, beacon_rssi_b);
791 PRINT_STATS_LE32(general, beacon_rssi_c);
792 PRINT_STATS_LE32(general, beacon_energy_a);
793 PRINT_STATS_LE32(general, beacon_energy_b);
794 PRINT_STATS_LE32(general, beacon_energy_c);
795 PRINT_STATS_LE32(general, num_bt_kills);
796 PRINT_STATS_LE32(general, mac_id);
797 PRINT_STATS_LE32(general, directed_data_mpdu);
798 } else {
799 struct mvm_statistics_rx_non_phy *general =
800 &mvm->rx_stats.general;
801
802 PRINT_STATS_LE32(general, bogus_cts);
803 PRINT_STATS_LE32(general, bogus_ack);
804 PRINT_STATS_LE32(general, non_channel_beacons);
805 PRINT_STATS_LE32(general, channel_beacons);
806 PRINT_STATS_LE32(general, num_missed_bcon);
807 PRINT_STATS_LE32(general, adc_rx_saturation_time);
808 PRINT_STATS_LE32(general, ina_detection_search_time);
809 PRINT_STATS_LE32(general, beacon_silence_rssi_a);
810 PRINT_STATS_LE32(general, beacon_silence_rssi_b);
811 PRINT_STATS_LE32(general, beacon_silence_rssi_c);
812 PRINT_STATS_LE32(general, interference_data_flag);
813 PRINT_STATS_LE32(general, channel_load);
814 PRINT_STATS_LE32(general, beacon_rssi_a);
815 PRINT_STATS_LE32(general, beacon_rssi_b);
816 PRINT_STATS_LE32(general, beacon_rssi_c);
817 PRINT_STATS_LE32(general, beacon_energy_a);
818 PRINT_STATS_LE32(general, beacon_energy_b);
819 PRINT_STATS_LE32(general, beacon_energy_c);
820 PRINT_STATS_LE32(general, num_bt_kills);
821 PRINT_STATS_LE32(general, mac_id);
822 }
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300823
824 pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
825 "Statistics_Rx - HT");
Liad Kaufman678d9b62017-05-18 18:00:49 +0300826 if (!iwl_mvm_has_new_rx_stats_api(mvm)) {
827 struct mvm_statistics_rx_ht_phy_v1 *ht =
828 &mvm->rx_stats_v3.ofdm_ht;
829
830 PRINT_STATS_LE32(ht, plcp_err);
831 PRINT_STATS_LE32(ht, overrun_err);
832 PRINT_STATS_LE32(ht, early_overrun_err);
833 PRINT_STATS_LE32(ht, crc32_good);
834 PRINT_STATS_LE32(ht, crc32_err);
835 PRINT_STATS_LE32(ht, mh_format_err);
836 PRINT_STATS_LE32(ht, agg_crc32_good);
837 PRINT_STATS_LE32(ht, agg_mpdu_cnt);
838 PRINT_STATS_LE32(ht, agg_cnt);
839 PRINT_STATS_LE32(ht, unsupport_mcs);
840 } else {
841 struct mvm_statistics_rx_ht_phy *ht =
842 &mvm->rx_stats.ofdm_ht;
843
844 PRINT_STATS_LE32(ht, mh_format_err);
845 PRINT_STATS_LE32(ht, agg_mpdu_cnt);
846 PRINT_STATS_LE32(ht, agg_cnt);
847 PRINT_STATS_LE32(ht, unsupport_mcs);
848 }
Matti Gottlieb3848ab62013-07-30 15:29:37 +0300849
850 mutex_unlock(&mvm->mutex);
851
852 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
853 kfree(buf);
854
855 return ret;
856}
857#undef PRINT_STAT_LE32
858
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200859static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
860 char __user *user_buf, size_t count,
861 loff_t *ppos,
862 struct iwl_mvm_frame_stats *stats)
863{
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200864 char *buff, *pos, *endpos;
865 int idx, i;
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200866 int ret;
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200867 static const size_t bufsz = 1024;
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200868
869 buff = kmalloc(bufsz, GFP_KERNEL);
870 if (!buff)
871 return -ENOMEM;
872
873 spin_lock_bh(&mvm->drv_stats_lock);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200874
875 pos = buff;
876 endpos = pos + bufsz;
877
878 pos += scnprintf(pos, endpos - pos,
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200879 "Legacy/HT/VHT\t:\t%d/%d/%d\n",
880 stats->legacy_frames,
881 stats->ht_frames,
882 stats->vht_frames);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200883 pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200884 stats->bw_20_frames,
885 stats->bw_40_frames,
886 stats->bw_80_frames);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200887 pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200888 stats->ngi_frames,
889 stats->sgi_frames);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200890 pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200891 stats->siso_frames,
892 stats->mimo2_frames);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200893 pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200894 stats->fail_frames,
895 stats->success_frames);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200896 pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200897 stats->agg_frames);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200898 pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200899 stats->ampdu_count);
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200900 pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200901 stats->ampdu_count > 0 ?
902 (stats->agg_frames / stats->ampdu_count) : 0);
903
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200904 pos += scnprintf(pos, endpos - pos, "Last Rates\n");
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200905
906 idx = stats->last_frame_idx - 1;
907 for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
908 idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
909 if (stats->last_rates[idx] == 0)
910 continue;
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200911 pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200912 (int)(ARRAY_SIZE(stats->last_rates) - i));
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200913 pos += rs_pretty_print_rate(pos, stats->last_rates[idx]);
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200914 }
915 spin_unlock_bh(&mvm->drv_stats_lock);
916
Eyal Shapiraf754b5c2014-02-24 10:24:34 +0200917 ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
Eyal Shapira5fc0f762014-01-28 01:35:32 +0200918 kfree(buff);
919
920 return ret;
921}
922
923static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
924 char __user *user_buf, size_t count,
925 loff_t *ppos)
926{
927 struct iwl_mvm *mvm = file->private_data;
928
929 return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
930 &mvm->drv_rx_stats);
931}
932
Johannes Berg1fa3f572013-11-13 09:10:21 +0100933static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
Emmanuel Grumbach490953a2013-03-04 08:53:07 +0200934 size_t count, loff_t *ppos)
935{
Luca Coelho758d1a82016-11-09 10:02:46 +0200936 int __maybe_unused ret;
Emmanuel Grumbach490953a2013-03-04 08:53:07 +0200937
Johannes Berg504bd622017-03-22 22:19:41 +0100938 if (!iwl_mvm_firmware_running(mvm))
939 return -EIO;
940
Emmanuel Grumbach490953a2013-03-04 08:53:07 +0200941 mutex_lock(&mvm->mutex);
942
Eran Harary291aa7c2013-07-03 11:00:06 +0300943 /* allow one more restart that we're provoking here */
Johannes Berg3b37f4c2017-05-30 16:45:31 +0200944 if (mvm->fw_restart >= 0)
945 mvm->fw_restart++;
Eran Harary291aa7c2013-07-03 11:00:06 +0300946
Emmanuel Grumbach490953a2013-03-04 08:53:07 +0200947 /* take the return value to make compiler happy - it will fail anyway */
Emmanuel Grumbacha1022922014-05-12 11:36:41 +0300948 ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL);
Emmanuel Grumbach490953a2013-03-04 08:53:07 +0200949
950 mutex_unlock(&mvm->mutex);
951
Emmanuel Grumbach490953a2013-03-04 08:53:07 +0200952 return count;
953}
954
Johannes Berg1fa3f572013-11-13 09:10:21 +0100955static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
Alexander Bondar119663c2013-10-17 14:26:50 +0200956 size_t count, loff_t *ppos)
957{
Johannes Berg504bd622017-03-22 22:19:41 +0100958 int ret;
959
960 if (!iwl_mvm_firmware_running(mvm))
961 return -EIO;
962
963 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
Eliad Peller576eeee2014-07-01 18:38:38 +0300964 if (ret)
965 return ret;
966
Liad Kaufman4c9706d2014-04-27 16:46:09 +0300967 iwl_force_nmi(mvm->trans);
Alexander Bondar119663c2013-10-17 14:26:50 +0200968
Eliad Peller576eeee2014-07-01 18:38:38 +0300969 iwl_mvm_unref(mvm, IWL_MVM_REF_NMI);
970
Alexander Bondar119663c2013-10-17 14:26:50 +0200971 return count;
972}
973
Oren Givon91b05d12013-08-19 08:36:48 +0300974static ssize_t
975iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
976 char __user *user_buf,
977 size_t count, loff_t *ppos)
978{
979 struct iwl_mvm *mvm = file->private_data;
980 int pos = 0;
981 char buf[32];
982 const size_t bufsz = sizeof(buf);
983
984 /* print which antennas were set for the scan command by the user */
985 pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: ");
986 if (mvm->scan_rx_ant & ANT_A)
987 pos += scnprintf(buf + pos, bufsz - pos, "A");
988 if (mvm->scan_rx_ant & ANT_B)
989 pos += scnprintf(buf + pos, bufsz - pos, "B");
990 if (mvm->scan_rx_ant & ANT_C)
991 pos += scnprintf(buf + pos, bufsz - pos, "C");
992 pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
993
994 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
995}
996
997static ssize_t
Johannes Berg1fa3f572013-11-13 09:10:21 +0100998iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
Oren Givon91b05d12013-08-19 08:36:48 +0300999 size_t count, loff_t *ppos)
1000{
Oren Givon91b05d12013-08-19 08:36:48 +03001001 u8 scan_rx_ant;
1002
Johannes Berg504bd622017-03-22 22:19:41 +01001003 if (!iwl_mvm_firmware_running(mvm))
1004 return -EIO;
1005
Oren Givon91b05d12013-08-19 08:36:48 +03001006 if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
1007 return -EINVAL;
1008 if (scan_rx_ant > ANT_ABC)
1009 return -EINVAL;
Moshe Harela0544272014-12-08 21:13:14 +02001010 if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm)))
Oren Givon91b05d12013-08-19 08:36:48 +03001011 return -EINVAL;
1012
David Spinadeld2496222014-05-20 12:46:37 +03001013 if (mvm->scan_rx_ant != scan_rx_ant) {
1014 mvm->scan_rx_ant = scan_rx_ant;
Johannes Berg859d9142015-06-01 17:11:11 +02001015 if (fw_has_capa(&mvm->fw->ucode_capa,
1016 IWL_UCODE_TLV_CAPA_UMAC_SCAN))
David Spinadeld2496222014-05-20 12:46:37 +03001017 iwl_mvm_config_scan(mvm);
1018 }
Oren Givon91b05d12013-08-19 08:36:48 +03001019
1020 return count;
1021}
1022
Sara Sharon43413a92015-12-31 11:49:18 +02001023static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
1024 char *buf, size_t count,
1025 loff_t *ppos)
1026{
1027 struct iwl_rss_config_cmd cmd = {
1028 .flags = cpu_to_le32(IWL_RSS_ENABLE),
1029 .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
Sara Sharon854d7732016-03-22 15:55:58 +02001030 IWL_RSS_HASH_TYPE_IPV4_UDP |
Sara Sharon43413a92015-12-31 11:49:18 +02001031 IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
1032 IWL_RSS_HASH_TYPE_IPV6_TCP |
Sara Sharon854d7732016-03-22 15:55:58 +02001033 IWL_RSS_HASH_TYPE_IPV6_UDP |
Sara Sharon43413a92015-12-31 11:49:18 +02001034 IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
1035 };
1036 int ret, i, num_repeats, nbytes = count / 2;
1037
1038 ret = hex2bin(cmd.indirection_table, buf, nbytes);
1039 if (ret)
1040 return ret;
1041
1042 /*
1043 * The input is the redirection table, partial or full.
1044 * Repeat the pattern if needed.
1045 * For example, input of 01020F will be repeated 42 times,
1046 * indirecting RSS hash results to queues 1, 2, 15 (skipping
1047 * queues 3 - 14).
1048 */
1049 num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes;
1050 for (i = 1; i < num_repeats; i++)
1051 memcpy(&cmd.indirection_table[i * nbytes],
1052 cmd.indirection_table, nbytes);
1053 /* handle cut in the middle pattern for the last places */
1054 memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
1055 ARRAY_SIZE(cmd.indirection_table) % nbytes);
1056
Sara Sharon854d7732016-03-22 15:55:58 +02001057 netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key));
Sara Sharon43413a92015-12-31 11:49:18 +02001058
1059 mutex_lock(&mvm->mutex);
Johannes Berg504bd622017-03-22 22:19:41 +01001060 if (iwl_mvm_firmware_running(mvm))
1061 ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0,
1062 sizeof(cmd), &cmd);
1063 else
1064 ret = 0;
Sara Sharon43413a92015-12-31 11:49:18 +02001065 mutex_unlock(&mvm->mutex);
1066
1067 return ret ?: count;
1068}
1069
Sara Sharon4857d6c2016-08-09 20:03:52 +03001070static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm,
1071 char *buf, size_t count,
1072 loff_t *ppos)
1073{
1074 struct iwl_rx_cmd_buffer rxb = {
1075 ._rx_page_order = 0,
1076 .truesize = 0, /* not used */
1077 ._offset = 0,
1078 };
1079 struct iwl_rx_packet *pkt;
1080 struct iwl_rx_mpdu_desc *desc;
1081 int bin_len = count / 2;
1082 int ret = -EINVAL;
1083
Johannes Berg504bd622017-03-22 22:19:41 +01001084 if (!iwl_mvm_firmware_running(mvm))
1085 return -EIO;
1086
Sara Sharon4857d6c2016-08-09 20:03:52 +03001087 /* supporting only 9000 descriptor */
1088 if (!mvm->trans->cfg->mq_rx_supported)
1089 return -ENOTSUPP;
1090
1091 rxb._page = alloc_pages(GFP_ATOMIC, 0);
1092 if (!rxb._page)
1093 return -ENOMEM;
1094 pkt = rxb_addr(&rxb);
1095
1096 ret = hex2bin(page_address(rxb._page), buf, bin_len);
1097 if (ret)
1098 goto out;
1099
1100 /* avoid invalid memory access */
1101 if (bin_len < sizeof(*pkt) + sizeof(*desc))
1102 goto out;
1103
1104 /* check this is RX packet */
1105 if (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd) !=
1106 WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD))
1107 goto out;
1108
1109 /* check the length in metadata matches actual received length */
1110 desc = (void *)pkt->data;
1111 if (le16_to_cpu(desc->mpdu_len) !=
1112 (bin_len - sizeof(*desc) - sizeof(*pkt)))
1113 goto out;
1114
1115 local_bh_disable();
1116 iwl_mvm_rx_mpdu_mq(mvm, NULL, &rxb, 0);
1117 local_bh_enable();
1118 ret = 0;
1119
1120out:
1121 iwl_free_rxb(&rxb);
1122
1123 return ret ?: count;
1124}
1125
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001126static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
1127 char __user *user_buf,
1128 size_t count, loff_t *ppos)
1129{
1130 struct iwl_mvm *mvm = file->private_data;
Emmanuel Grumbachd2709ad2015-01-29 14:58:06 +02001131 int conf;
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001132 char buf[8];
1133 const size_t bufsz = sizeof(buf);
1134 int pos = 0;
1135
1136 mutex_lock(&mvm->mutex);
Johannes Berg7174beb2017-06-01 16:03:19 +02001137 conf = mvm->fwrt.dump.conf;
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001138 mutex_unlock(&mvm->mutex);
1139
1140 pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
1141
1142 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1143}
1144
Golan Ben Ami321c2102015-07-27 17:02:35 +03001145/*
1146 * Enable / Disable continuous recording.
1147 * Cause the FW to start continuous recording, by sending the relevant hcmd.
1148 * Enable: input of every integer larger than 0, ENABLE_CONT_RECORDING.
1149 * Disable: for 0 as input, DISABLE_CONT_RECORDING.
1150 */
1151static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
1152 char *buf, size_t count,
1153 loff_t *ppos)
1154{
1155 struct iwl_trans *trans = mvm->trans;
1156 const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
1157 struct iwl_continuous_record_cmd cont_rec = {};
1158 int ret, rec_mode;
1159
Johannes Berg504bd622017-03-22 22:19:41 +01001160 if (!iwl_mvm_firmware_running(mvm))
1161 return -EIO;
1162
Golan Ben Ami321c2102015-07-27 17:02:35 +03001163 if (!dest)
1164 return -EOPNOTSUPP;
1165
1166 if (dest->monitor_mode != SMEM_MODE ||
Sara Sharon6e584872017-03-22 14:07:50 +02001167 trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
Golan Ben Ami321c2102015-07-27 17:02:35 +03001168 return -EOPNOTSUPP;
1169
Johannes Berg27e070d2016-01-14 10:55:22 +01001170 ret = kstrtoint(buf, 0, &rec_mode);
Golan Ben Ami321c2102015-07-27 17:02:35 +03001171 if (ret)
1172 return ret;
1173
1174 cont_rec.record_mode.enable_recording = rec_mode ?
1175 cpu_to_le16(ENABLE_CONT_RECORDING) :
1176 cpu_to_le16(DISABLE_CONT_RECORDING);
1177
1178 mutex_lock(&mvm->mutex);
1179 ret = iwl_mvm_send_cmd_pdu(mvm, LDBG_CONFIG_CMD, 0,
1180 sizeof(cont_rec), &cont_rec);
1181 mutex_unlock(&mvm->mutex);
1182
1183 return ret ?: count;
1184}
1185
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001186static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
1187 char *buf, size_t count,
1188 loff_t *ppos)
1189{
Dan Carpenter8e8114d2015-08-21 11:48:21 +03001190 unsigned int conf_id;
1191 int ret;
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001192
Johannes Berg504bd622017-03-22 22:19:41 +01001193 if (!iwl_mvm_firmware_running(mvm))
1194 return -EIO;
1195
Dan Carpenter8e8114d2015-08-21 11:48:21 +03001196 ret = kstrtouint(buf, 0, &conf_id);
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001197 if (ret)
1198 return ret;
1199
Emmanuel Grumbachd2709ad2015-01-29 14:58:06 +02001200 if (WARN_ON(conf_id >= FW_DBG_CONF_MAX))
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001201 return -EINVAL;
1202
1203 mutex_lock(&mvm->mutex);
Johannes Berg7174beb2017-06-01 16:03:19 +02001204 ret = iwl_fw_start_dbg_conf(&mvm->fwrt, conf_id);
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001205 mutex_unlock(&mvm->mutex);
1206
1207 return ret ?: count;
1208}
1209
1210static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
1211 char *buf, size_t count,
1212 loff_t *ppos)
1213{
Johannes Berg504bd622017-03-22 22:19:41 +01001214 int ret;
Liad Kaufmane93475a2015-01-04 11:03:13 +02001215
Johannes Berg504bd622017-03-22 22:19:41 +01001216 if (!iwl_mvm_firmware_running(mvm))
1217 return -EIO;
1218
1219 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
Liad Kaufmane93475a2015-01-04 11:03:13 +02001220 if (ret)
1221 return ret;
Dan Carpenter251fe092017-03-23 13:40:00 +03001222 if (count == 0)
1223 return 0;
Liad Kaufmane93475a2015-01-04 11:03:13 +02001224
Johannes Berg7174beb2017-06-01 16:03:19 +02001225 iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf,
1226 (count - 1), NULL);
Liad Kaufmane93475a2015-01-04 11:03:13 +02001227
1228 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001229
1230 return count;
1231}
1232
Emmanuel Grumbach9e7dce22015-10-26 16:14:06 +02001233static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
1234 char *buf, size_t count,
1235 loff_t *ppos)
1236{
1237 unsigned int max_amsdu_len;
1238 int ret;
1239
1240 ret = kstrtouint(buf, 0, &max_amsdu_len);
Dan Carpenter32afd152016-05-04 09:19:54 +03001241 if (ret)
1242 return ret;
Emmanuel Grumbach9e7dce22015-10-26 16:14:06 +02001243
1244 if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
1245 return -EINVAL;
1246 mvm->max_amsdu_len = max_amsdu_len;
1247
1248 return count;
1249}
1250
Eliad Pellerde06a592014-01-08 10:11:12 +02001251#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
1252#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1253static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
1254 char __user *user_buf,
1255 size_t count, loff_t *ppos)
1256{
1257 struct iwl_mvm *mvm = file->private_data;
1258 struct iwl_bcast_filter_cmd cmd;
1259 const struct iwl_fw_bcast_filter *filter;
1260 char *buf;
1261 int bufsz = 1024;
1262 int i, j, pos = 0;
1263 ssize_t ret;
1264
1265 buf = kzalloc(bufsz, GFP_KERNEL);
1266 if (!buf)
1267 return -ENOMEM;
1268
1269 mutex_lock(&mvm->mutex);
1270 if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
1271 ADD_TEXT("None\n");
1272 mutex_unlock(&mvm->mutex);
1273 goto out;
1274 }
1275 mutex_unlock(&mvm->mutex);
1276
1277 for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
1278 filter = &cmd.filters[i];
1279
1280 ADD_TEXT("Filter [%d]:\n", i);
1281 ADD_TEXT("\tDiscard=%d\n", filter->discard);
1282 ADD_TEXT("\tFrame Type: %s\n",
1283 filter->frame_type ? "IPv4" : "Generic");
1284
1285 for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
1286 const struct iwl_fw_bcast_filter_attr *attr;
1287
1288 attr = &filter->attrs[j];
1289 if (!attr->mask)
1290 break;
1291
1292 ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
1293 j, attr->offset,
1294 attr->offset_type ? "IP End" :
1295 "Payload Start",
1296 be32_to_cpu(attr->mask),
1297 be32_to_cpu(attr->val),
1298 le16_to_cpu(attr->reserved1));
1299 }
1300 }
1301out:
1302 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1303 kfree(buf);
1304 return ret;
1305}
1306
1307static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
1308 size_t count, loff_t *ppos)
1309{
1310 int pos, next_pos;
1311 struct iwl_fw_bcast_filter filter = {};
1312 struct iwl_bcast_filter_cmd cmd;
1313 u32 filter_id, attr_id, mask, value;
1314 int err = 0;
1315
1316 if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
1317 &filter.frame_type, &pos) != 3)
1318 return -EINVAL;
1319
1320 if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
1321 filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
1322 return -EINVAL;
1323
1324 for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
1325 attr_id++) {
1326 struct iwl_fw_bcast_filter_attr *attr =
1327 &filter.attrs[attr_id];
1328
1329 if (pos >= count)
1330 break;
1331
1332 if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
1333 &attr->offset, &attr->offset_type,
1334 &mask, &value, &next_pos) != 4)
1335 return -EINVAL;
1336
1337 attr->mask = cpu_to_be32(mask);
1338 attr->val = cpu_to_be32(value);
1339 if (mask)
1340 filter.num_attrs++;
1341
1342 pos += next_pos;
1343 }
1344
1345 mutex_lock(&mvm->mutex);
1346 memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
1347 &filter, sizeof(filter));
1348
1349 /* send updated bcast filtering configuration */
Johannes Berg504bd622017-03-22 22:19:41 +01001350 if (iwl_mvm_firmware_running(mvm) &&
1351 mvm->dbgfs_bcast_filtering.override &&
Eliad Pellerde06a592014-01-08 10:11:12 +02001352 iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
Emmanuel Grumbacha1022922014-05-12 11:36:41 +03001353 err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
Eliad Pellerde06a592014-01-08 10:11:12 +02001354 sizeof(cmd), &cmd);
1355 mutex_unlock(&mvm->mutex);
1356
1357 return err ?: count;
1358}
1359
1360static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
1361 char __user *user_buf,
1362 size_t count, loff_t *ppos)
1363{
1364 struct iwl_mvm *mvm = file->private_data;
1365 struct iwl_bcast_filter_cmd cmd;
1366 char *buf;
1367 int bufsz = 1024;
1368 int i, pos = 0;
1369 ssize_t ret;
1370
1371 buf = kzalloc(bufsz, GFP_KERNEL);
1372 if (!buf)
1373 return -ENOMEM;
1374
1375 mutex_lock(&mvm->mutex);
1376 if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
1377 ADD_TEXT("None\n");
1378 mutex_unlock(&mvm->mutex);
1379 goto out;
1380 }
1381 mutex_unlock(&mvm->mutex);
1382
1383 for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
1384 const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
1385
1386 ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
1387 i, mac->default_discard, mac->attached_filters);
1388 }
1389out:
1390 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1391 kfree(buf);
1392 return ret;
1393}
1394
1395static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
1396 char *buf, size_t count,
1397 loff_t *ppos)
1398{
1399 struct iwl_bcast_filter_cmd cmd;
1400 struct iwl_fw_bcast_mac mac = {};
1401 u32 mac_id, attached_filters;
1402 int err = 0;
1403
1404 if (!mvm->bcast_filters)
1405 return -ENOENT;
1406
1407 if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
1408 &attached_filters) != 3)
1409 return -EINVAL;
1410
1411 if (mac_id >= ARRAY_SIZE(cmd.macs) ||
1412 mac.default_discard > 1 ||
1413 attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
1414 return -EINVAL;
1415
1416 mac.attached_filters = cpu_to_le16(attached_filters);
1417
1418 mutex_lock(&mvm->mutex);
1419 memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
1420 &mac, sizeof(mac));
1421
1422 /* send updated bcast filtering configuration */
Johannes Berg504bd622017-03-22 22:19:41 +01001423 if (iwl_mvm_firmware_running(mvm) &&
1424 mvm->dbgfs_bcast_filtering.override &&
Eliad Pellerde06a592014-01-08 10:11:12 +02001425 iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
Emmanuel Grumbacha1022922014-05-12 11:36:41 +03001426 err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
Eliad Pellerde06a592014-01-08 10:11:12 +02001427 sizeof(cmd), &cmd);
1428 mutex_unlock(&mvm->mutex);
1429
1430 return err ?: count;
1431}
1432#endif
1433
Johannes Bergafc66bb2013-05-03 11:44:16 +02001434#ifdef CONFIG_PM_SLEEP
Johannes Berg1fa3f572013-11-13 09:10:21 +01001435static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
Johannes Bergafc66bb2013-05-03 11:44:16 +02001436 size_t count, loff_t *ppos)
1437{
Johannes Bergafc66bb2013-05-03 11:44:16 +02001438 int store;
1439
Johannes Bergafc66bb2013-05-03 11:44:16 +02001440 if (sscanf(buf, "%d", &store) != 1)
1441 return -EINVAL;
1442
1443 mvm->store_d3_resume_sram = store;
1444
1445 return count;
1446}
1447
1448static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
1449 size_t count, loff_t *ppos)
1450{
1451 struct iwl_mvm *mvm = file->private_data;
1452 const struct fw_img *img;
1453 int ofs, len, pos = 0;
1454 size_t bufsz, ret;
1455 char *buf;
1456 u8 *ptr = mvm->d3_resume_sram;
1457
1458 img = &mvm->fw->img[IWL_UCODE_WOWLAN];
1459 len = img->sec[IWL_UCODE_SECTION_DATA].len;
1460
1461 bufsz = len * 4 + 256;
1462 buf = kzalloc(bufsz, GFP_KERNEL);
1463 if (!buf)
1464 return -ENOMEM;
1465
1466 pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
1467 mvm->store_d3_resume_sram ? "en" : "dis");
1468
1469 if (ptr) {
1470 for (ofs = 0; ofs < len; ofs += 16) {
1471 pos += scnprintf(buf + pos, bufsz - pos,
Andy Shevchenko3cd6e2f2015-07-16 15:42:14 +03001472 "0x%.4x %16ph\n", ofs, ptr + ofs);
Johannes Bergafc66bb2013-05-03 11:44:16 +02001473 }
1474 } else {
1475 pos += scnprintf(buf + pos, bufsz - pos,
1476 "(no data captured)\n");
1477 }
1478
1479 ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1480
1481 kfree(buf);
1482
1483 return ret;
1484}
1485#endif
1486
Eliad Peller576eeee2014-07-01 18:38:38 +03001487#define PRINT_MVM_REF(ref) do { \
1488 if (mvm->refs[ref]) \
1489 pos += scnprintf(buf + pos, bufsz - pos, \
1490 "\t(0x%lx): %d %s\n", \
1491 BIT(ref), mvm->refs[ref], #ref); \
Eliad Peller70d6bab2013-11-05 14:45:16 +02001492} while (0)
1493
1494static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
1495 char __user *user_buf,
1496 size_t count, loff_t *ppos)
1497{
1498 struct iwl_mvm *mvm = file->private_data;
Eliad Peller576eeee2014-07-01 18:38:38 +03001499 int i, pos = 0;
Eliad Peller70d6bab2013-11-05 14:45:16 +02001500 char buf[256];
1501 const size_t bufsz = sizeof(buf);
Eliad Peller576eeee2014-07-01 18:38:38 +03001502 u32 refs = 0;
Eliad Peller70d6bab2013-11-05 14:45:16 +02001503
Eliad Peller576eeee2014-07-01 18:38:38 +03001504 for (i = 0; i < IWL_MVM_REF_COUNT; i++)
1505 if (mvm->refs[i])
1506 refs |= BIT(i);
1507
1508 pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n",
1509 refs);
Eliad Peller70d6bab2013-11-05 14:45:16 +02001510
1511 PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
1512 PRINT_MVM_REF(IWL_MVM_REF_SCAN);
1513 PRINT_MVM_REF(IWL_MVM_REF_ROC);
Eliad Pellerc7792732015-04-19 11:41:04 +03001514 PRINT_MVM_REF(IWL_MVM_REF_ROC_AUX);
Eliad Peller70d6bab2013-11-05 14:45:16 +02001515 PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
1516 PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
Eliad Peller0eb83652013-11-11 18:56:35 +02001517 PRINT_MVM_REF(IWL_MVM_REF_USER);
Johannes Berg34e611e2014-09-12 10:28:01 +02001518 PRINT_MVM_REF(IWL_MVM_REF_TX);
1519 PRINT_MVM_REF(IWL_MVM_REF_TX_AGG);
1520 PRINT_MVM_REF(IWL_MVM_REF_ADD_IF);
1521 PRINT_MVM_REF(IWL_MVM_REF_START_AP);
1522 PRINT_MVM_REF(IWL_MVM_REF_BSS_CHANGED);
1523 PRINT_MVM_REF(IWL_MVM_REF_PREPARE_TX);
1524 PRINT_MVM_REF(IWL_MVM_REF_PROTECT_TDLS);
1525 PRINT_MVM_REF(IWL_MVM_REF_CHECK_CTKILL);
1526 PRINT_MVM_REF(IWL_MVM_REF_PRPH_READ);
1527 PRINT_MVM_REF(IWL_MVM_REF_PRPH_WRITE);
1528 PRINT_MVM_REF(IWL_MVM_REF_NMI);
1529 PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
Eliad Pellerd15a7472014-03-27 18:53:12 +02001530 PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
Eliad Peller160acc02014-11-25 12:34:45 +02001531 PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
Liad Kaufmanfb2380a2015-01-01 17:42:46 +02001532 PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
Eliad Peller08f0d232015-12-10 15:47:11 +02001533 PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE);
Luca Coelho71b12302016-03-11 12:12:16 +02001534 PRINT_MVM_REF(IWL_MVM_REF_SENDING_CMD);
Luca Coelho16e4dd82016-03-30 15:05:56 +03001535 PRINT_MVM_REF(IWL_MVM_REF_RX);
Eliad Peller70d6bab2013-11-05 14:45:16 +02001536
1537 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1538}
1539
Eliad Peller0eb83652013-11-11 18:56:35 +02001540static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
1541 size_t count, loff_t *ppos)
1542{
1543 unsigned long value;
1544 int ret;
1545 bool taken;
1546
1547 ret = kstrtoul(buf, 10, &value);
1548 if (ret < 0)
1549 return ret;
1550
1551 mutex_lock(&mvm->mutex);
1552
Eliad Peller576eeee2014-07-01 18:38:38 +03001553 taken = mvm->refs[IWL_MVM_REF_USER];
Eliad Peller0eb83652013-11-11 18:56:35 +02001554 if (value == 1 && !taken)
1555 iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
1556 else if (value == 0 && taken)
1557 iwl_mvm_unref(mvm, IWL_MVM_REF_USER);
1558 else
1559 ret = -EINVAL;
1560
1561 mutex_unlock(&mvm->mutex);
1562
1563 if (ret < 0)
1564 return ret;
1565 return count;
1566}
1567
Johannes Berg1fa3f572013-11-13 09:10:21 +01001568#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
1569 _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
1570#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
1571 _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
Eliad Pellerde06a592014-01-08 10:11:12 +02001572#define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \
1573 if (!debugfs_create_file(alias, mode, parent, mvm, \
Johannes Berg8ca151b2013-01-24 14:25:36 +01001574 &iwl_dbgfs_##name##_ops)) \
1575 goto err; \
1576 } while (0)
Eliad Pellerde06a592014-01-08 10:11:12 +02001577#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
1578 MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
Johannes Berg8ca151b2013-01-24 14:25:36 +01001579
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001580static ssize_t
1581iwl_dbgfs_prph_reg_read(struct file *file,
1582 char __user *user_buf,
1583 size_t count, loff_t *ppos)
1584{
1585 struct iwl_mvm *mvm = file->private_data;
1586 int pos = 0;
1587 char buf[32];
1588 const size_t bufsz = sizeof(buf);
Eliad Peller576eeee2014-07-01 18:38:38 +03001589 int ret;
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001590
1591 if (!mvm->dbgfs_prph_reg_addr)
1592 return -EINVAL;
1593
Eliad Peller576eeee2014-07-01 18:38:38 +03001594 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ);
1595 if (ret)
1596 return ret;
1597
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001598 pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
1599 mvm->dbgfs_prph_reg_addr,
1600 iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
1601
Eliad Peller576eeee2014-07-01 18:38:38 +03001602 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ);
1603
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001604 return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
1605}
1606
1607static ssize_t
1608iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
1609 size_t count, loff_t *ppos)
1610{
1611 u8 args;
1612 u32 value;
Eliad Peller576eeee2014-07-01 18:38:38 +03001613 int ret;
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001614
1615 args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
1616 /* if we only want to set the reg address - nothing more to do */
1617 if (args == 1)
1618 goto out;
1619
1620 /* otherwise, make sure we have both address and value */
1621 if (args != 2)
1622 return -EINVAL;
1623
Eliad Peller576eeee2014-07-01 18:38:38 +03001624 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
1625 if (ret)
1626 return ret;
1627
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001628 iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
Eliad Peller576eeee2014-07-01 18:38:38 +03001629
1630 iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001631out:
1632 return count;
1633}
1634
Emmanuel Grumbache5046012015-08-17 10:45:50 +03001635static ssize_t
1636iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
1637 size_t count, loff_t *ppos)
1638{
1639 int ret;
1640
Johannes Berg504bd622017-03-22 22:19:41 +01001641 if (!iwl_mvm_firmware_running(mvm))
1642 return -EIO;
1643
Emmanuel Grumbache5046012015-08-17 10:45:50 +03001644 mutex_lock(&mvm->mutex);
1645 ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL);
1646 mutex_unlock(&mvm->mutex);
1647
1648 return ret ?: count;
1649}
1650
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001651MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
1652
Johannes Berg8ca151b2013-01-24 14:25:36 +01001653/* Device wide debugfs entries */
Chaya Rachel Ivgi00f481b2016-02-24 12:19:22 +02001654MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget);
1655MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8);
Chaya Rachel Ivgi61d8c622017-06-27 14:13:02 +03001656MVM_DEBUGFS_WRITE_FILE_OPS(force_ctkill, 8);
Johannes Berg1fa3f572013-11-13 09:10:21 +01001657MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
1658MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
Emmanuel Grumbache5046012015-08-17 10:45:50 +03001659MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8);
Johannes Berg1fa3f572013-11-13 09:10:21 +01001660MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
Matti Gottlieb7280d1f2014-07-17 16:41:14 +03001661MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
Luciano Coelhoc549e392014-09-04 15:58:47 +03001662MVM_DEBUGFS_READ_FILE_OPS(nic_temp);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001663MVM_DEBUGFS_READ_FILE_OPS(stations);
Emmanuel Grumbach10942342013-02-19 11:02:36 +02001664MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
Emmanuel Grumbach2de13ca2013-06-30 07:43:28 +03001665MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
Johannes Berg1fa3f572013-11-13 09:10:21 +01001666MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
Matti Gottlieb3848ab62013-07-30 15:29:37 +03001667MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
Eyal Shapira5fc0f762014-01-28 01:35:32 +02001668MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
Johannes Berg1fa3f572013-11-13 09:10:21 +01001669MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
1670MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
Emmanuel Grumbachcdb00562014-03-16 21:55:43 +02001671MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
Emmanuel Grumbacha39979a2014-05-28 12:06:41 +03001672MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
Johannes Berg1fa3f572013-11-13 09:10:21 +01001673MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
Eliad Peller0eb83652013-11-11 18:56:35 +02001674MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001675MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
Golan Ben-Amic91b8652015-11-30 14:30:21 +02001676MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
Golan Ben Ami321c2102015-07-27 17:02:35 +03001677MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
Emmanuel Grumbach9e7dce22015-10-26 16:14:06 +02001678MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
Sara Sharondd4d3162016-02-07 12:50:35 +02001679MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
1680 (IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
Sara Sharon4857d6c2016-08-09 20:03:52 +03001681MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
Oren Givon91b05d12013-08-19 08:36:48 +03001682
Eliad Pellerde06a592014-01-08 10:11:12 +02001683#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1684MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
1685MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
1686#endif
1687
Johannes Bergafc66bb2013-05-03 11:44:16 +02001688#ifdef CONFIG_PM_SLEEP
Johannes Berg1fa3f572013-11-13 09:10:21 +01001689MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
Johannes Bergafc66bb2013-05-03 11:44:16 +02001690#endif
Haim Dreyfusse6ee0652017-05-15 14:27:21 +03001691#ifdef CONFIG_ACPI
1692MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
1693#endif
Johannes Berg8ca151b2013-01-24 14:25:36 +01001694
Ido Yariv2b55f432016-08-23 14:44:59 -04001695static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
1696 size_t count, loff_t *ppos)
1697{
1698 struct iwl_mvm *mvm = file->private_data;
1699 struct iwl_dbg_mem_access_cmd cmd = {};
1700 struct iwl_dbg_mem_access_rsp *rsp;
1701 struct iwl_host_cmd hcmd = {
1702 .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
1703 .data = { &cmd, },
1704 .len = { sizeof(cmd) },
1705 };
Luca Coelho276c4b42016-09-28 11:32:35 +03001706 size_t delta;
1707 ssize_t ret, len;
Ido Yariv2b55f432016-08-23 14:44:59 -04001708
Johannes Berg504bd622017-03-22 22:19:41 +01001709 if (!iwl_mvm_firmware_running(mvm))
1710 return -EIO;
1711
Ido Yariv2b55f432016-08-23 14:44:59 -04001712 hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
1713 DEBUG_GROUP, 0);
1714 cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ);
1715
1716 /* Take care of alignment of both the position and the length */
1717 delta = *ppos & 0x3;
1718 cmd.addr = cpu_to_le32(*ppos - delta);
1719 cmd.len = cpu_to_le32(min(ALIGN(count + delta, 4) / 4,
1720 (size_t)DEBUG_MEM_MAX_SIZE_DWORDS));
1721
1722 mutex_lock(&mvm->mutex);
1723 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1724 mutex_unlock(&mvm->mutex);
1725
1726 if (ret < 0)
1727 return ret;
1728
1729 rsp = (void *)hcmd.resp_pkt->data;
1730 if (le32_to_cpu(rsp->status) != DEBUG_MEM_STATUS_SUCCESS) {
1731 ret = -ENXIO;
1732 goto out;
1733 }
1734
1735 len = min((size_t)le32_to_cpu(rsp->len) << 2,
1736 iwl_rx_packet_payload_len(hcmd.resp_pkt) - sizeof(*rsp));
1737 len = min(len - delta, count);
1738 if (len < 0) {
1739 ret = -EFAULT;
1740 goto out;
1741 }
1742
1743 ret = len - copy_to_user(user_buf, (void *)rsp->data + delta, len);
1744 *ppos += ret;
1745
1746out:
1747 iwl_free_resp(&hcmd);
1748 return ret;
1749}
1750
1751static ssize_t iwl_dbgfs_mem_write(struct file *file,
1752 const char __user *user_buf, size_t count,
1753 loff_t *ppos)
1754{
1755 struct iwl_mvm *mvm = file->private_data;
1756 struct iwl_dbg_mem_access_cmd *cmd;
1757 struct iwl_dbg_mem_access_rsp *rsp;
1758 struct iwl_host_cmd hcmd = {};
1759 size_t cmd_size;
1760 size_t data_size;
1761 u32 op, len;
1762 ssize_t ret;
1763
Johannes Berg504bd622017-03-22 22:19:41 +01001764 if (!iwl_mvm_firmware_running(mvm))
1765 return -EIO;
1766
Ido Yariv2b55f432016-08-23 14:44:59 -04001767 hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
1768 DEBUG_GROUP, 0);
1769
1770 if (*ppos & 0x3 || count < 4) {
1771 op = DEBUG_MEM_OP_WRITE_BYTES;
1772 len = min(count, (size_t)(4 - (*ppos & 0x3)));
1773 data_size = len;
1774 } else {
1775 op = DEBUG_MEM_OP_WRITE;
1776 len = min(count >> 2, (size_t)DEBUG_MEM_MAX_SIZE_DWORDS);
1777 data_size = len << 2;
1778 }
1779
1780 cmd_size = sizeof(*cmd) + ALIGN(data_size, 4);
1781 cmd = kzalloc(cmd_size, GFP_KERNEL);
1782 if (!cmd)
1783 return -ENOMEM;
1784
1785 cmd->op = cpu_to_le32(op);
1786 cmd->len = cpu_to_le32(len);
1787 cmd->addr = cpu_to_le32(*ppos);
1788 if (copy_from_user((void *)cmd->data, user_buf, data_size)) {
1789 kfree(cmd);
1790 return -EFAULT;
1791 }
1792
1793 hcmd.flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
1794 hcmd.data[0] = (void *)cmd;
1795 hcmd.len[0] = cmd_size;
1796
1797 mutex_lock(&mvm->mutex);
1798 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1799 mutex_unlock(&mvm->mutex);
1800
1801 kfree(cmd);
1802
1803 if (ret < 0)
1804 return ret;
1805
1806 rsp = (void *)hcmd.resp_pkt->data;
1807 if (rsp->status != DEBUG_MEM_STATUS_SUCCESS) {
1808 ret = -ENXIO;
1809 goto out;
1810 }
1811
1812 ret = data_size;
1813 *ppos += ret;
1814
1815out:
1816 iwl_free_resp(&hcmd);
1817 return ret;
1818}
1819
1820static const struct file_operations iwl_dbgfs_mem_ops = {
1821 .read = iwl_dbgfs_mem_read,
1822 .write = iwl_dbgfs_mem_write,
1823 .open = simple_open,
1824 .llseek = default_llseek,
1825};
1826
Johannes Berg8ca151b2013-01-24 14:25:36 +01001827int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
1828{
Eliad Pellerde06a592014-01-08 10:11:12 +02001829 struct dentry *bcast_dir __maybe_unused;
Johannes Berg8ca151b2013-01-24 14:25:36 +01001830 char buf[100];
1831
Johannes Bergd07913a2014-02-26 11:25:58 +01001832 spin_lock_init(&mvm->drv_stats_lock);
1833
Johannes Berg8ca151b2013-01-24 14:25:36 +01001834 mvm->debugfs_dir = dbgfs_dir;
1835
1836 MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
1837 MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
1838 MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
Matti Gottlieb7280d1f2014-07-17 16:41:14 +03001839 MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
1840 S_IWUSR | S_IRUSR);
Luciano Coelhoc549e392014-09-04 15:58:47 +03001841 MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
Chaya Rachel Ivgi00f481b2016-02-24 12:19:22 +02001842 MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR);
1843 MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR);
Chaya Rachel Ivgi61d8c622017-06-27 14:13:02 +03001844 MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, S_IWUSR);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001845 MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
Emmanuel Grumbach10942342013-02-19 11:02:36 +02001846 MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
Emmanuel Grumbach2de13ca2013-06-30 07:43:28 +03001847 MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
Emmanuel Grumbach639eaba2014-03-30 10:11:13 +03001848 MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
1849 S_IRUSR | S_IWUSR);
Matti Gottlieb3848ab62013-07-30 15:29:37 +03001850 MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
Eyal Shapira5fc0f762014-01-28 01:35:32 +02001851 MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
Emmanuel Grumbach490953a2013-03-04 08:53:07 +02001852 MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
Alexander Bondar119663c2013-10-17 14:26:50 +02001853 MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
Emmanuel Grumbachcdb00562014-03-16 21:55:43 +02001854 MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR);
Emmanuel Grumbacha39979a2014-05-28 12:06:41 +03001855 MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR);
Oren Givon91b05d12013-08-19 08:36:48 +03001856 MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
1857 S_IWUSR | S_IRUSR);
Eliad Pellerf3c221f2014-01-09 13:12:54 +02001858 MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
Eliad Peller0eb83652013-11-11 18:56:35 +02001859 MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
Emmanuel Grumbach8c23f952014-12-04 10:07:47 +02001860 MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
1861 MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
Emmanuel Grumbach9e7dce22015-10-26 16:14:06 +02001862 MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR);
Emmanuel Grumbache5046012015-08-17 10:45:50 +03001863 MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
Golan Ben Ami321c2102015-07-27 17:02:35 +03001864 MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
Sara Sharon43413a92015-12-31 11:49:18 +02001865 MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
Sara Sharon4857d6c2016-08-09 20:03:52 +03001866 MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR);
Haim Dreyfusse6ee0652017-05-15 14:27:21 +03001867#ifdef CONFIG_ACPI
1868 MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR);
1869#endif
1870
Luciano Coelhocb2513b2015-02-27 16:26:57 +02001871 if (!debugfs_create_bool("enable_scan_iteration_notif",
1872 S_IRUSR | S_IWUSR,
1873 mvm->debugfs_dir,
1874 &mvm->scan_iter_notif_enabled))
1875 goto err;
Andrei Otcheretianskic89e3332016-01-26 18:12:28 +02001876 if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR,
1877 mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
1878 goto err;
Eliad Pellerde06a592014-01-08 10:11:12 +02001879
1880#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
1881 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
1882 bcast_dir = debugfs_create_dir("bcast_filtering",
1883 mvm->debugfs_dir);
1884 if (!bcast_dir)
1885 goto err;
1886
1887 if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
1888 bcast_dir,
1889 &mvm->dbgfs_bcast_filtering.override))
1890 goto err;
1891
1892 MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
1893 bcast_dir, S_IWUSR | S_IRUSR);
1894 MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
1895 bcast_dir, S_IWUSR | S_IRUSR);
1896 }
1897#endif
1898
Johannes Bergafc66bb2013-05-03 11:44:16 +02001899#ifdef CONFIG_PM_SLEEP
1900 MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
Johannes Bergdebff612013-05-14 13:53:45 +02001901 MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
Johannes Bergb0114712013-06-12 14:55:40 +02001902 if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
1903 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
1904 goto err;
Luciano Coelho484b3d12015-03-30 20:46:32 +03001905 if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR,
1906 mvm->debugfs_dir, &mvm->last_netdetect_scans))
1907 goto err;
Johannes Bergafc66bb2013-05-03 11:44:16 +02001908#endif
Johannes Berg8ca151b2013-01-24 14:25:36 +01001909
Luciano Coelhobdd54832014-08-07 18:08:56 +03001910 if (!debugfs_create_u8("ps_disabled", S_IRUSR,
1911 mvm->debugfs_dir, &mvm->ps_disabled))
1912 goto err;
Emmanuel Grumbach086f7362013-11-18 17:00:03 +02001913 if (!debugfs_create_blob("nvm_hw", S_IRUSR,
1914 mvm->debugfs_dir, &mvm->nvm_hw_blob))
1915 goto err;
1916 if (!debugfs_create_blob("nvm_sw", S_IRUSR,
1917 mvm->debugfs_dir, &mvm->nvm_sw_blob))
1918 goto err;
1919 if (!debugfs_create_blob("nvm_calib", S_IRUSR,
1920 mvm->debugfs_dir, &mvm->nvm_calib_blob))
1921 goto err;
1922 if (!debugfs_create_blob("nvm_prod", S_IRUSR,
1923 mvm->debugfs_dir, &mvm->nvm_prod_blob))
1924 goto err;
Moshe Harel91fac942015-09-02 12:45:12 +03001925 if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR,
1926 mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
1927 goto err;
Emmanuel Grumbach086f7362013-11-18 17:00:03 +02001928
Ido Yariv2b55f432016-08-23 14:44:59 -04001929 debugfs_create_file("mem", S_IRUSR | S_IWUSR, dbgfs_dir, mvm,
1930 &iwl_dbgfs_mem_ops);
1931
Johannes Berg8ca151b2013-01-24 14:25:36 +01001932 /*
1933 * Create a symlink with mac80211. It will be removed when mac80211
1934 * exists (before the opmode exists which removes the target.)
1935 */
Al Viro27a22092016-08-07 12:21:25 -04001936 snprintf(buf, 100, "../../%pd2", dbgfs_dir->d_parent);
Johannes Berg8ca151b2013-01-24 14:25:36 +01001937 if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
1938 goto err;
1939
1940 return 0;
1941err:
1942 IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
1943 return -ENOMEM;
1944}