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 - 2013 Intel Corporation. All rights reserved.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24 * The full GNU General Public License is included in this distribution
25 * in the file called LICENSE.GPL.
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
33 * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 *****************************************************************************/
67 struct iwl_dbgfs_mvm_ctx
{
69 struct ieee80211_vif
*vif
;
72 static int iwl_dbgfs_open_file_generic(struct inode
*inode
, struct file
*file
)
74 file
->private_data
= inode
->i_private
;
78 static ssize_t
iwl_dbgfs_tx_flush_write(struct file
*file
,
79 const char __user
*user_buf
,
80 size_t count
, loff_t
*ppos
)
82 struct iwl_mvm
*mvm
= file
->private_data
;
88 if (!mvm
->ucode_loaded
|| mvm
->cur_ucode
!= IWL_UCODE_REGULAR
)
91 memset(buf
, 0, sizeof(buf
));
92 buf_size
= min(count
, sizeof(buf
) - 1);
93 if (copy_from_user(buf
, user_buf
, buf_size
))
96 if (sscanf(buf
, "%x", &scd_q_msk
) != 1)
99 IWL_ERR(mvm
, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk
);
101 mutex_lock(&mvm
->mutex
);
102 ret
= iwl_mvm_flush_tx_path(mvm
, scd_q_msk
, true) ? : count
;
103 mutex_unlock(&mvm
->mutex
);
108 static ssize_t
iwl_dbgfs_sta_drain_write(struct file
*file
,
109 const char __user
*user_buf
,
110 size_t count
, loff_t
*ppos
)
112 struct iwl_mvm
*mvm
= file
->private_data
;
113 struct ieee80211_sta
*sta
;
116 int buf_size
, sta_id
, drain
, ret
;
118 if (!mvm
->ucode_loaded
|| mvm
->cur_ucode
!= IWL_UCODE_REGULAR
)
121 memset(buf
, 0, sizeof(buf
));
122 buf_size
= min(count
, sizeof(buf
) - 1);
123 if (copy_from_user(buf
, user_buf
, buf_size
))
126 if (sscanf(buf
, "%d %d", &sta_id
, &drain
) != 2)
129 mutex_lock(&mvm
->mutex
);
131 sta
= rcu_dereference_protected(mvm
->fw_id_to_mac_id
[sta_id
],
132 lockdep_is_held(&mvm
->mutex
));
133 if (IS_ERR_OR_NULL(sta
))
136 ret
= iwl_mvm_drain_sta(mvm
, (void *)sta
->drv_priv
, drain
) ? :
139 mutex_unlock(&mvm
->mutex
);
144 static ssize_t
iwl_dbgfs_sram_read(struct file
*file
, char __user
*user_buf
,
145 size_t count
, loff_t
*ppos
)
147 struct iwl_mvm
*mvm
= file
->private_data
;
148 const struct fw_img
*img
;
149 int ofs
, len
, pos
= 0;
154 /* default is to dump the entire data segment */
155 if (!mvm
->dbgfs_sram_offset
&& !mvm
->dbgfs_sram_len
) {
156 mvm
->dbgfs_sram_offset
= 0x800000;
157 if (!mvm
->ucode_loaded
)
159 img
= &mvm
->fw
->img
[mvm
->cur_ucode
];
160 mvm
->dbgfs_sram_len
= img
->sec
[IWL_UCODE_SECTION_DATA
].len
;
162 len
= mvm
->dbgfs_sram_len
;
164 bufsz
= len
* 4 + 256;
165 buf
= kzalloc(bufsz
, GFP_KERNEL
);
169 ptr
= kzalloc(len
, GFP_KERNEL
);
175 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "sram_len: 0x%x\n", len
);
176 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "sram_offset: 0x%x\n",
177 mvm
->dbgfs_sram_offset
);
179 iwl_trans_read_mem_bytes(mvm
->trans
,
180 mvm
->dbgfs_sram_offset
,
182 for (ofs
= 0; ofs
< len
; ofs
+= 16) {
183 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "0x%.4x ", ofs
);
184 hex_dump_to_buffer(ptr
+ ofs
, 16, 16, 1, buf
+ pos
,
186 pos
+= strlen(buf
+ pos
);
191 ret
= simple_read_from_buffer(user_buf
, count
, ppos
, buf
, pos
);
199 static ssize_t
iwl_dbgfs_sram_write(struct file
*file
,
200 const char __user
*user_buf
, size_t count
,
203 struct iwl_mvm
*mvm
= file
->private_data
;
208 memset(buf
, 0, sizeof(buf
));
209 buf_size
= min(count
, sizeof(buf
) - 1);
210 if (copy_from_user(buf
, user_buf
, buf_size
))
213 if (sscanf(buf
, "%x,%x", &offset
, &len
) == 2) {
214 if ((offset
& 0x3) || (len
& 0x3))
216 mvm
->dbgfs_sram_offset
= offset
;
217 mvm
->dbgfs_sram_len
= len
;
219 mvm
->dbgfs_sram_offset
= 0;
220 mvm
->dbgfs_sram_len
= 0;
226 static ssize_t
iwl_dbgfs_stations_read(struct file
*file
, char __user
*user_buf
,
227 size_t count
, loff_t
*ppos
)
229 struct iwl_mvm
*mvm
= file
->private_data
;
230 struct ieee80211_sta
*sta
;
232 int i
, pos
= 0, bufsz
= sizeof(buf
);
234 mutex_lock(&mvm
->mutex
);
236 for (i
= 0; i
< IWL_MVM_STATION_COUNT
; i
++) {
237 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%.2d: ", i
);
238 sta
= rcu_dereference_protected(mvm
->fw_id_to_mac_id
[i
],
239 lockdep_is_held(&mvm
->mutex
));
241 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "N/A\n");
242 else if (IS_ERR(sta
))
243 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%ld\n",
246 pos
+= scnprintf(buf
+ pos
, bufsz
- pos
, "%pM\n",
250 mutex_unlock(&mvm
->mutex
);
252 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, pos
);
255 static ssize_t
iwl_dbgfs_power_down_allow_write(struct file
*file
,
256 const char __user
*user_buf
,
257 size_t count
, loff_t
*ppos
)
259 struct iwl_mvm
*mvm
= file
->private_data
;
263 if (!mvm
->ucode_loaded
)
266 if (copy_from_user(buf
, user_buf
, sizeof(buf
)))
269 if (sscanf(buf
, "%d", &allow
) != 1)
272 IWL_DEBUG_POWER(mvm
, "%s device power down\n",
273 allow
? "allow" : "prevent");
276 * TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
282 static ssize_t
iwl_dbgfs_power_down_d3_allow_write(struct file
*file
,
283 const char __user
*user_buf
,
284 size_t count
, loff_t
*ppos
)
286 struct iwl_mvm
*mvm
= file
->private_data
;
290 if (copy_from_user(buf
, user_buf
, sizeof(buf
)))
293 if (sscanf(buf
, "%d", &allow
) != 1)
296 IWL_DEBUG_POWER(mvm
, "%s device power down in d3\n",
297 allow
? "allow" : "prevent");
300 * TODO: When WoWLAN FW alive notification happens, driver will send
301 * REPLY_DEBUG_CMD setting power_down_allow flag according to
302 * mvm->prevent_power_down_d3
304 mvm
->prevent_power_down_d3
= !allow
;
309 #define MVM_DEBUGFS_READ_FILE_OPS(name) \
310 static const struct file_operations iwl_dbgfs_##name##_ops = { \
311 .read = iwl_dbgfs_##name##_read, \
312 .open = iwl_dbgfs_open_file_generic, \
313 .llseek = generic_file_llseek, \
316 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name) \
317 static const struct file_operations iwl_dbgfs_##name##_ops = { \
318 .write = iwl_dbgfs_##name##_write, \
319 .read = iwl_dbgfs_##name##_read, \
320 .open = iwl_dbgfs_open_file_generic, \
321 .llseek = generic_file_llseek, \
324 #define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
325 static const struct file_operations iwl_dbgfs_##name##_ops = { \
326 .write = iwl_dbgfs_##name##_write, \
327 .open = iwl_dbgfs_open_file_generic, \
328 .llseek = generic_file_llseek, \
331 #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) do { \
332 if (!debugfs_create_file(#name, mode, parent, mvm, \
333 &iwl_dbgfs_##name##_ops)) \
337 #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do { \
338 if (!debugfs_create_file(#name, mode, parent, vif, \
339 &iwl_dbgfs_##name##_ops)) \
343 /* Device wide debugfs entries */
344 MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush
);
345 MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain
);
346 MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram
);
347 MVM_DEBUGFS_READ_FILE_OPS(stations
);
348 MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow
);
349 MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow
);
351 int iwl_mvm_dbgfs_register(struct iwl_mvm
*mvm
, struct dentry
*dbgfs_dir
)
355 mvm
->debugfs_dir
= dbgfs_dir
;
357 MVM_DEBUGFS_ADD_FILE(tx_flush
, mvm
->debugfs_dir
, S_IWUSR
);
358 MVM_DEBUGFS_ADD_FILE(sta_drain
, mvm
->debugfs_dir
, S_IWUSR
);
359 MVM_DEBUGFS_ADD_FILE(sram
, mvm
->debugfs_dir
, S_IWUSR
| S_IRUSR
);
360 MVM_DEBUGFS_ADD_FILE(stations
, dbgfs_dir
, S_IRUSR
);
361 MVM_DEBUGFS_ADD_FILE(power_down_allow
, mvm
->debugfs_dir
, S_IWUSR
);
362 MVM_DEBUGFS_ADD_FILE(power_down_d3_allow
, mvm
->debugfs_dir
, S_IWUSR
);
365 * Create a symlink with mac80211. It will be removed when mac80211
366 * exists (before the opmode exists which removes the target.)
368 snprintf(buf
, 100, "../../%s/%s",
369 dbgfs_dir
->d_parent
->d_parent
->d_name
.name
,
370 dbgfs_dir
->d_parent
->d_name
.name
);
371 if (!debugfs_create_symlink("iwlwifi", mvm
->hw
->wiphy
->debugfsdir
, buf
))
376 IWL_ERR(mvm
, "Can't create the mvm debugfs directory\n");
This page took 0.048003 seconds and 6 git commands to generate.