1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. |
5 | * |
6 | * Contact Information: |
7 | * Intel Linux Wireless <ilw@linux.intel.com> |
8 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
9 | *****************************************************************************/ |
10 | #include <linux/ieee80211.h> |
11 | #include <linux/export.h> |
12 | #include <net/mac80211.h> |
13 | |
14 | #include "common.h" |
15 | |
16 | static void |
17 | il_clear_traffic_stats(struct il_priv *il) |
18 | { |
19 | memset(&il->tx_stats, 0, sizeof(struct traffic_stats)); |
20 | memset(&il->rx_stats, 0, sizeof(struct traffic_stats)); |
21 | } |
22 | |
23 | /* |
24 | * il_update_stats function record all the MGMT, CTRL and DATA pkt for |
25 | * both TX and Rx . Use debugfs to display the rx/rx_stats |
26 | */ |
27 | void |
28 | il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len) |
29 | { |
30 | struct traffic_stats *stats; |
31 | |
32 | if (is_tx) |
33 | stats = &il->tx_stats; |
34 | else |
35 | stats = &il->rx_stats; |
36 | |
37 | if (ieee80211_is_mgmt(fc)) { |
38 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { |
39 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): |
40 | stats->mgmt[MANAGEMENT_ASSOC_REQ]++; |
41 | break; |
42 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): |
43 | stats->mgmt[MANAGEMENT_ASSOC_RESP]++; |
44 | break; |
45 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): |
46 | stats->mgmt[MANAGEMENT_REASSOC_REQ]++; |
47 | break; |
48 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): |
49 | stats->mgmt[MANAGEMENT_REASSOC_RESP]++; |
50 | break; |
51 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): |
52 | stats->mgmt[MANAGEMENT_PROBE_REQ]++; |
53 | break; |
54 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): |
55 | stats->mgmt[MANAGEMENT_PROBE_RESP]++; |
56 | break; |
57 | case cpu_to_le16(IEEE80211_STYPE_BEACON): |
58 | stats->mgmt[MANAGEMENT_BEACON]++; |
59 | break; |
60 | case cpu_to_le16(IEEE80211_STYPE_ATIM): |
61 | stats->mgmt[MANAGEMENT_ATIM]++; |
62 | break; |
63 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): |
64 | stats->mgmt[MANAGEMENT_DISASSOC]++; |
65 | break; |
66 | case cpu_to_le16(IEEE80211_STYPE_AUTH): |
67 | stats->mgmt[MANAGEMENT_AUTH]++; |
68 | break; |
69 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): |
70 | stats->mgmt[MANAGEMENT_DEAUTH]++; |
71 | break; |
72 | case cpu_to_le16(IEEE80211_STYPE_ACTION): |
73 | stats->mgmt[MANAGEMENT_ACTION]++; |
74 | break; |
75 | } |
76 | } else if (ieee80211_is_ctl(fc)) { |
77 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { |
78 | case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): |
79 | stats->ctrl[CONTROL_BACK_REQ]++; |
80 | break; |
81 | case cpu_to_le16(IEEE80211_STYPE_BACK): |
82 | stats->ctrl[CONTROL_BACK]++; |
83 | break; |
84 | case cpu_to_le16(IEEE80211_STYPE_PSPOLL): |
85 | stats->ctrl[CONTROL_PSPOLL]++; |
86 | break; |
87 | case cpu_to_le16(IEEE80211_STYPE_RTS): |
88 | stats->ctrl[CONTROL_RTS]++; |
89 | break; |
90 | case cpu_to_le16(IEEE80211_STYPE_CTS): |
91 | stats->ctrl[CONTROL_CTS]++; |
92 | break; |
93 | case cpu_to_le16(IEEE80211_STYPE_ACK): |
94 | stats->ctrl[CONTROL_ACK]++; |
95 | break; |
96 | case cpu_to_le16(IEEE80211_STYPE_CFEND): |
97 | stats->ctrl[CONTROL_CFEND]++; |
98 | break; |
99 | case cpu_to_le16(IEEE80211_STYPE_CFENDACK): |
100 | stats->ctrl[CONTROL_CFENDACK]++; |
101 | break; |
102 | } |
103 | } else { |
104 | /* data */ |
105 | stats->data_cnt++; |
106 | stats->data_bytes += len; |
107 | } |
108 | } |
109 | EXPORT_SYMBOL(il_update_stats); |
110 | |
111 | /* create and remove of files */ |
112 | #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ |
113 | debugfs_create_file(#name, mode, parent, il, \ |
114 | &il_dbgfs_##name##_ops); \ |
115 | } while (0) |
116 | |
117 | #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ |
118 | debugfs_create_bool(#name, 0600, parent, ptr); \ |
119 | } while (0) |
120 | |
121 | /* file operation */ |
122 | #define DEBUGFS_READ_FUNC(name) \ |
123 | static ssize_t il_dbgfs_##name##_read(struct file *file, \ |
124 | char __user *user_buf, \ |
125 | size_t count, loff_t *ppos); |
126 | |
127 | #define DEBUGFS_WRITE_FUNC(name) \ |
128 | static ssize_t il_dbgfs_##name##_write(struct file *file, \ |
129 | const char __user *user_buf, \ |
130 | size_t count, loff_t *ppos); |
131 | |
132 | |
133 | #define DEBUGFS_READ_FILE_OPS(name) \ |
134 | DEBUGFS_READ_FUNC(name); \ |
135 | static const struct file_operations il_dbgfs_##name##_ops = { \ |
136 | .read = il_dbgfs_##name##_read, \ |
137 | .open = simple_open, \ |
138 | .llseek = generic_file_llseek, \ |
139 | }; |
140 | |
141 | #define DEBUGFS_WRITE_FILE_OPS(name) \ |
142 | DEBUGFS_WRITE_FUNC(name); \ |
143 | static const struct file_operations il_dbgfs_##name##_ops = { \ |
144 | .write = il_dbgfs_##name##_write, \ |
145 | .open = simple_open, \ |
146 | .llseek = generic_file_llseek, \ |
147 | }; |
148 | |
149 | #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ |
150 | DEBUGFS_READ_FUNC(name); \ |
151 | DEBUGFS_WRITE_FUNC(name); \ |
152 | static const struct file_operations il_dbgfs_##name##_ops = { \ |
153 | .write = il_dbgfs_##name##_write, \ |
154 | .read = il_dbgfs_##name##_read, \ |
155 | .open = simple_open, \ |
156 | .llseek = generic_file_llseek, \ |
157 | }; |
158 | |
159 | static const char * |
160 | il_get_mgmt_string(int cmd) |
161 | { |
162 | switch (cmd) { |
163 | IL_CMD(MANAGEMENT_ASSOC_REQ); |
164 | IL_CMD(MANAGEMENT_ASSOC_RESP); |
165 | IL_CMD(MANAGEMENT_REASSOC_REQ); |
166 | IL_CMD(MANAGEMENT_REASSOC_RESP); |
167 | IL_CMD(MANAGEMENT_PROBE_REQ); |
168 | IL_CMD(MANAGEMENT_PROBE_RESP); |
169 | IL_CMD(MANAGEMENT_BEACON); |
170 | IL_CMD(MANAGEMENT_ATIM); |
171 | IL_CMD(MANAGEMENT_DISASSOC); |
172 | IL_CMD(MANAGEMENT_AUTH); |
173 | IL_CMD(MANAGEMENT_DEAUTH); |
174 | IL_CMD(MANAGEMENT_ACTION); |
175 | default: |
176 | return "UNKNOWN" ; |
177 | |
178 | } |
179 | } |
180 | |
181 | static const char * |
182 | il_get_ctrl_string(int cmd) |
183 | { |
184 | switch (cmd) { |
185 | IL_CMD(CONTROL_BACK_REQ); |
186 | IL_CMD(CONTROL_BACK); |
187 | IL_CMD(CONTROL_PSPOLL); |
188 | IL_CMD(CONTROL_RTS); |
189 | IL_CMD(CONTROL_CTS); |
190 | IL_CMD(CONTROL_ACK); |
191 | IL_CMD(CONTROL_CFEND); |
192 | IL_CMD(CONTROL_CFENDACK); |
193 | default: |
194 | return "UNKNOWN" ; |
195 | |
196 | } |
197 | } |
198 | |
199 | static ssize_t |
200 | il_dbgfs_tx_stats_read(struct file *file, char __user *user_buf, size_t count, |
201 | loff_t *ppos) |
202 | { |
203 | |
204 | struct il_priv *il = file->private_data; |
205 | char *buf; |
206 | int pos = 0; |
207 | |
208 | int cnt; |
209 | ssize_t ret; |
210 | const size_t bufsz = |
211 | 100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); |
212 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
213 | if (!buf) |
214 | return -ENOMEM; |
215 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Management:\n" ); |
216 | for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { |
217 | pos += |
218 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\t%25s\t\t: %u\n" , |
219 | il_get_mgmt_string(cmd: cnt), il->tx_stats.mgmt[cnt]); |
220 | } |
221 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Control\n" ); |
222 | for (cnt = 0; cnt < CONTROL_MAX; cnt++) { |
223 | pos += |
224 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\t%25s\t\t: %u\n" , |
225 | il_get_ctrl_string(cmd: cnt), il->tx_stats.ctrl[cnt]); |
226 | } |
227 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Data:\n" ); |
228 | pos += |
229 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\tcnt: %u\n" , |
230 | il->tx_stats.data_cnt); |
231 | pos += |
232 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\tbytes: %llu\n" , |
233 | il->tx_stats.data_bytes); |
234 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
235 | kfree(objp: buf); |
236 | return ret; |
237 | } |
238 | |
239 | static ssize_t |
240 | il_dbgfs_clear_traffic_stats_write(struct file *file, |
241 | const char __user *user_buf, size_t count, |
242 | loff_t *ppos) |
243 | { |
244 | struct il_priv *il = file->private_data; |
245 | u32 clear_flag; |
246 | char buf[8]; |
247 | int buf_size; |
248 | |
249 | memset(buf, 0, sizeof(buf)); |
250 | buf_size = min(count, sizeof(buf) - 1); |
251 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
252 | return -EFAULT; |
253 | if (sscanf(buf, "%x" , &clear_flag) != 1) |
254 | return -EFAULT; |
255 | il_clear_traffic_stats(il); |
256 | |
257 | return count; |
258 | } |
259 | |
260 | static ssize_t |
261 | il_dbgfs_rx_stats_read(struct file *file, char __user *user_buf, size_t count, |
262 | loff_t *ppos) |
263 | { |
264 | |
265 | struct il_priv *il = file->private_data; |
266 | char *buf; |
267 | int pos = 0; |
268 | int cnt; |
269 | ssize_t ret; |
270 | const size_t bufsz = |
271 | 100 + sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX); |
272 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
273 | if (!buf) |
274 | return -ENOMEM; |
275 | |
276 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Management:\n" ); |
277 | for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) { |
278 | pos += |
279 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\t%25s\t\t: %u\n" , |
280 | il_get_mgmt_string(cmd: cnt), il->rx_stats.mgmt[cnt]); |
281 | } |
282 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Control:\n" ); |
283 | for (cnt = 0; cnt < CONTROL_MAX; cnt++) { |
284 | pos += |
285 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\t%25s\t\t: %u\n" , |
286 | il_get_ctrl_string(cmd: cnt), il->rx_stats.ctrl[cnt]); |
287 | } |
288 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Data:\n" ); |
289 | pos += |
290 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\tcnt: %u\n" , |
291 | il->rx_stats.data_cnt); |
292 | pos += |
293 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\tbytes: %llu\n" , |
294 | il->rx_stats.data_bytes); |
295 | |
296 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
297 | kfree(objp: buf); |
298 | return ret; |
299 | } |
300 | |
301 | #define BYTE1_MASK 0x000000ff; |
302 | #define BYTE2_MASK 0x0000ffff; |
303 | #define BYTE3_MASK 0x00ffffff; |
304 | static ssize_t |
305 | il_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, |
306 | loff_t *ppos) |
307 | { |
308 | u32 val; |
309 | char *buf; |
310 | ssize_t ret; |
311 | int i; |
312 | int pos = 0; |
313 | struct il_priv *il = file->private_data; |
314 | size_t bufsz; |
315 | |
316 | /* default is to dump the entire data segment */ |
317 | if (!il->dbgfs_sram_offset && !il->dbgfs_sram_len) { |
318 | il->dbgfs_sram_offset = 0x800000; |
319 | if (il->ucode_type == UCODE_INIT) |
320 | il->dbgfs_sram_len = il->ucode_init_data.len; |
321 | else |
322 | il->dbgfs_sram_len = il->ucode_data.len; |
323 | } |
324 | bufsz = 30 + il->dbgfs_sram_len * sizeof(char) * 10; |
325 | buf = kmalloc(size: bufsz, GFP_KERNEL); |
326 | if (!buf) |
327 | return -ENOMEM; |
328 | pos += |
329 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "sram_len: 0x%x\n" , |
330 | il->dbgfs_sram_len); |
331 | pos += |
332 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "sram_offset: 0x%x\n" , |
333 | il->dbgfs_sram_offset); |
334 | for (i = il->dbgfs_sram_len; i > 0; i -= 4) { |
335 | val = |
336 | il_read_targ_mem(il, |
337 | addr: il->dbgfs_sram_offset + |
338 | il->dbgfs_sram_len - i); |
339 | if (i < 4) { |
340 | switch (i) { |
341 | case 1: |
342 | val &= BYTE1_MASK; |
343 | break; |
344 | case 2: |
345 | val &= BYTE2_MASK; |
346 | break; |
347 | case 3: |
348 | val &= BYTE3_MASK; |
349 | break; |
350 | } |
351 | } |
352 | if (!(i % 16)) |
353 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
354 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "0x%08x " , val); |
355 | } |
356 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
357 | |
358 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
359 | kfree(objp: buf); |
360 | return ret; |
361 | } |
362 | |
363 | static ssize_t |
364 | il_dbgfs_sram_write(struct file *file, const char __user *user_buf, |
365 | size_t count, loff_t *ppos) |
366 | { |
367 | struct il_priv *il = file->private_data; |
368 | char buf[64]; |
369 | int buf_size; |
370 | u32 offset, len; |
371 | |
372 | memset(buf, 0, sizeof(buf)); |
373 | buf_size = min(count, sizeof(buf) - 1); |
374 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
375 | return -EFAULT; |
376 | |
377 | if (sscanf(buf, "%x,%x" , &offset, &len) == 2) { |
378 | il->dbgfs_sram_offset = offset; |
379 | il->dbgfs_sram_len = len; |
380 | } else { |
381 | il->dbgfs_sram_offset = 0; |
382 | il->dbgfs_sram_len = 0; |
383 | } |
384 | |
385 | return count; |
386 | } |
387 | |
388 | static ssize_t |
389 | il_dbgfs_stations_read(struct file *file, char __user *user_buf, size_t count, |
390 | loff_t *ppos) |
391 | { |
392 | struct il_priv *il = file->private_data; |
393 | struct il_station_entry *station; |
394 | int max_sta = il->hw_params.max_stations; |
395 | char *buf; |
396 | int i, j, pos = 0; |
397 | ssize_t ret; |
398 | /* Add 30 for initial string */ |
399 | const size_t bufsz = 30 + sizeof(char) * 500 * (il->num_stations); |
400 | |
401 | buf = kmalloc(size: bufsz, GFP_KERNEL); |
402 | if (!buf) |
403 | return -ENOMEM; |
404 | |
405 | pos += |
406 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "num of stations: %d\n\n" , |
407 | il->num_stations); |
408 | |
409 | for (i = 0; i < max_sta; i++) { |
410 | station = &il->stations[i]; |
411 | if (!station->used) |
412 | continue; |
413 | pos += |
414 | scnprintf(buf: buf + pos, size: bufsz - pos, |
415 | fmt: "station %d - addr: %pM, flags: %#x\n" , i, |
416 | station->sta.sta.addr, |
417 | station->sta.station_flags_msk); |
418 | pos += |
419 | scnprintf(buf: buf + pos, size: bufsz - pos, |
420 | fmt: "TID\tseq_num\ttxq_id\tframes\ttfds\t" ); |
421 | pos += |
422 | scnprintf(buf: buf + pos, size: bufsz - pos, |
423 | fmt: "start_idx\tbitmap\t\t\trate_n_flags\n" ); |
424 | |
425 | for (j = 0; j < MAX_TID_COUNT; j++) { |
426 | pos += |
427 | scnprintf(buf: buf + pos, size: bufsz - pos, |
428 | fmt: "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x" , |
429 | j, station->tid[j].seq_number, |
430 | station->tid[j].agg.txq_id, |
431 | station->tid[j].agg.frame_count, |
432 | station->tid[j].tfds_in_queue, |
433 | station->tid[j].agg.start_idx, |
434 | station->tid[j].agg.bitmap, |
435 | station->tid[j].agg.rate_n_flags); |
436 | |
437 | if (station->tid[j].agg.wait_for_ba) |
438 | pos += |
439 | scnprintf(buf: buf + pos, size: bufsz - pos, |
440 | fmt: " - waitforba" ); |
441 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
442 | } |
443 | |
444 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
445 | } |
446 | |
447 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
448 | kfree(objp: buf); |
449 | return ret; |
450 | } |
451 | |
452 | static ssize_t |
453 | il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count, |
454 | loff_t *ppos) |
455 | { |
456 | ssize_t ret; |
457 | struct il_priv *il = file->private_data; |
458 | int pos = 0, ofs = 0, buf_size = 0; |
459 | const u8 *ptr; |
460 | char *buf; |
461 | u16 eeprom_ver; |
462 | size_t eeprom_len = il->cfg->eeprom_size; |
463 | buf_size = 4 * eeprom_len + 256; |
464 | |
465 | if (eeprom_len % 16) { |
466 | IL_ERR("NVM size is not multiple of 16.\n" ); |
467 | return -ENODATA; |
468 | } |
469 | |
470 | ptr = il->eeprom; |
471 | if (!ptr) { |
472 | IL_ERR("Invalid EEPROM memory\n" ); |
473 | return -ENOMEM; |
474 | } |
475 | |
476 | /* 4 characters for byte 0xYY */ |
477 | buf = kzalloc(size: buf_size, GFP_KERNEL); |
478 | if (!buf) { |
479 | IL_ERR("Can not allocate Buffer\n" ); |
480 | return -ENOMEM; |
481 | } |
482 | eeprom_ver = il_eeprom_query16(il, EEPROM_VERSION); |
483 | pos += |
484 | scnprintf(buf: buf + pos, size: buf_size - pos, fmt: "EEPROM " "version: 0x%x\n" , |
485 | eeprom_ver); |
486 | for (ofs = 0; ofs < eeprom_len; ofs += 16) { |
487 | pos += scnprintf(buf: buf + pos, size: buf_size - pos, fmt: "0x%.4x %16ph\n" , |
488 | ofs, ptr + ofs); |
489 | } |
490 | |
491 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
492 | kfree(objp: buf); |
493 | return ret; |
494 | } |
495 | |
496 | static ssize_t |
497 | il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, |
498 | loff_t *ppos) |
499 | { |
500 | struct il_priv *il = file->private_data; |
501 | struct ieee80211_channel *channels = NULL; |
502 | const struct ieee80211_supported_band *supp_band = NULL; |
503 | int pos = 0, i, bufsz = PAGE_SIZE; |
504 | char *buf; |
505 | ssize_t ret; |
506 | |
507 | if (!test_bit(S_GEO_CONFIGURED, &il->status)) |
508 | return -EAGAIN; |
509 | |
510 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
511 | if (!buf) { |
512 | IL_ERR("Can not allocate Buffer\n" ); |
513 | return -ENOMEM; |
514 | } |
515 | |
516 | supp_band = il_get_hw_mode(il, band: NL80211_BAND_2GHZ); |
517 | if (supp_band) { |
518 | channels = supp_band->channels; |
519 | |
520 | pos += |
521 | scnprintf(buf: buf + pos, size: bufsz - pos, |
522 | fmt: "Displaying %d channels in 2.4GHz band 802.11bg):\n" , |
523 | supp_band->n_channels); |
524 | |
525 | for (i = 0; i < supp_band->n_channels; i++) |
526 | pos += |
527 | scnprintf(buf: buf + pos, size: bufsz - pos, |
528 | fmt: "%d: %ddBm: BSS%s%s, %s.\n" , |
529 | channels[i].hw_value, |
530 | channels[i].max_power, |
531 | channels[i]. |
532 | flags & IEEE80211_CHAN_RADAR ? |
533 | " (IEEE 802.11h required)" : "" , |
534 | ((channels[i]. |
535 | flags & IEEE80211_CHAN_NO_IR) || |
536 | (channels[i]. |
537 | flags & IEEE80211_CHAN_RADAR)) ? "" : |
538 | ", IBSS" , |
539 | channels[i]. |
540 | flags & IEEE80211_CHAN_NO_IR ? |
541 | "passive only" : "active/passive" ); |
542 | } |
543 | supp_band = il_get_hw_mode(il, band: NL80211_BAND_5GHZ); |
544 | if (supp_band) { |
545 | channels = supp_band->channels; |
546 | |
547 | pos += |
548 | scnprintf(buf: buf + pos, size: bufsz - pos, |
549 | fmt: "Displaying %d channels in 5.2GHz band (802.11a)\n" , |
550 | supp_band->n_channels); |
551 | |
552 | for (i = 0; i < supp_band->n_channels; i++) |
553 | pos += |
554 | scnprintf(buf: buf + pos, size: bufsz - pos, |
555 | fmt: "%d: %ddBm: BSS%s%s, %s.\n" , |
556 | channels[i].hw_value, |
557 | channels[i].max_power, |
558 | channels[i]. |
559 | flags & IEEE80211_CHAN_RADAR ? |
560 | " (IEEE 802.11h required)" : "" , |
561 | ((channels[i]. |
562 | flags & IEEE80211_CHAN_NO_IR) || |
563 | (channels[i]. |
564 | flags & IEEE80211_CHAN_RADAR)) ? "" : |
565 | ", IBSS" , |
566 | channels[i]. |
567 | flags & IEEE80211_CHAN_NO_IR ? |
568 | "passive only" : "active/passive" ); |
569 | } |
570 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
571 | kfree(objp: buf); |
572 | return ret; |
573 | } |
574 | |
575 | static ssize_t |
576 | il_dbgfs_status_read(struct file *file, char __user *user_buf, size_t count, |
577 | loff_t *ppos) |
578 | { |
579 | |
580 | struct il_priv *il = file->private_data; |
581 | char buf[512]; |
582 | int pos = 0; |
583 | const size_t bufsz = sizeof(buf); |
584 | |
585 | pos += |
586 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_HCMD_ACTIVE:\t %d\n" , |
587 | test_bit(S_HCMD_ACTIVE, &il->status)); |
588 | pos += |
589 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_INT_ENABLED:\t %d\n" , |
590 | test_bit(S_INT_ENABLED, &il->status)); |
591 | pos += |
592 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_RFKILL:\t %d\n" , |
593 | test_bit(S_RFKILL, &il->status)); |
594 | pos += |
595 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_CT_KILL:\t\t %d\n" , |
596 | test_bit(S_CT_KILL, &il->status)); |
597 | pos += |
598 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_INIT:\t\t %d\n" , |
599 | test_bit(S_INIT, &il->status)); |
600 | pos += |
601 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_ALIVE:\t\t %d\n" , |
602 | test_bit(S_ALIVE, &il->status)); |
603 | pos += |
604 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_READY:\t\t %d\n" , |
605 | test_bit(S_READY, &il->status)); |
606 | pos += |
607 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_TEMPERATURE:\t %d\n" , |
608 | test_bit(S_TEMPERATURE, &il->status)); |
609 | pos += |
610 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_GEO_CONFIGURED:\t %d\n" , |
611 | test_bit(S_GEO_CONFIGURED, &il->status)); |
612 | pos += |
613 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_EXIT_PENDING:\t %d\n" , |
614 | test_bit(S_EXIT_PENDING, &il->status)); |
615 | pos += |
616 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_STATS:\t %d\n" , |
617 | test_bit(S_STATS, &il->status)); |
618 | pos += |
619 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_SCANNING:\t %d\n" , |
620 | test_bit(S_SCANNING, &il->status)); |
621 | pos += |
622 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_SCAN_ABORTING:\t %d\n" , |
623 | test_bit(S_SCAN_ABORTING, &il->status)); |
624 | pos += |
625 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_SCAN_HW:\t\t %d\n" , |
626 | test_bit(S_SCAN_HW, &il->status)); |
627 | pos += |
628 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_POWER_PMI:\t %d\n" , |
629 | test_bit(S_POWER_PMI, &il->status)); |
630 | pos += |
631 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "S_FW_ERROR:\t %d\n" , |
632 | test_bit(S_FW_ERROR, &il->status)); |
633 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
634 | } |
635 | |
636 | static ssize_t |
637 | il_dbgfs_interrupt_read(struct file *file, char __user *user_buf, size_t count, |
638 | loff_t *ppos) |
639 | { |
640 | |
641 | struct il_priv *il = file->private_data; |
642 | int pos = 0; |
643 | int cnt = 0; |
644 | char *buf; |
645 | int bufsz = 24 * 64; /* 24 items * 64 char per item */ |
646 | ssize_t ret; |
647 | |
648 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
649 | if (!buf) { |
650 | IL_ERR("Can not allocate Buffer\n" ); |
651 | return -ENOMEM; |
652 | } |
653 | |
654 | pos += |
655 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Interrupt Statistics Report:\n" ); |
656 | |
657 | pos += |
658 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "HW Error:\t\t\t %u\n" , |
659 | il->isr_stats.hw); |
660 | pos += |
661 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "SW Error:\t\t\t %u\n" , |
662 | il->isr_stats.sw); |
663 | if (il->isr_stats.sw || il->isr_stats.hw) { |
664 | pos += |
665 | scnprintf(buf: buf + pos, size: bufsz - pos, |
666 | fmt: "\tLast Restarting Code: 0x%X\n" , |
667 | il->isr_stats.err_code); |
668 | } |
669 | #ifdef CONFIG_IWLEGACY_DEBUG |
670 | pos += |
671 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Frame transmitted:\t\t %u\n" , |
672 | il->isr_stats.sch); |
673 | pos += |
674 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Alive interrupt:\t\t %u\n" , |
675 | il->isr_stats.alive); |
676 | #endif |
677 | pos += |
678 | scnprintf(buf: buf + pos, size: bufsz - pos, |
679 | fmt: "HW RF KILL switch toggled:\t %u\n" , |
680 | il->isr_stats.rfkill); |
681 | |
682 | pos += |
683 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "CT KILL:\t\t\t %u\n" , |
684 | il->isr_stats.ctkill); |
685 | |
686 | pos += |
687 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Wakeup Interrupt:\t\t %u\n" , |
688 | il->isr_stats.wakeup); |
689 | |
690 | pos += |
691 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Rx command responses:\t\t %u\n" , |
692 | il->isr_stats.rx); |
693 | for (cnt = 0; cnt < IL_CN_MAX; cnt++) { |
694 | if (il->isr_stats.handlers[cnt] > 0) |
695 | pos += |
696 | scnprintf(buf: buf + pos, size: bufsz - pos, |
697 | fmt: "\tRx handler[%36s]:\t\t %u\n" , |
698 | il_get_cmd_string(cmd: cnt), |
699 | il->isr_stats.handlers[cnt]); |
700 | } |
701 | |
702 | pos += |
703 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Tx/FH interrupt:\t\t %u\n" , |
704 | il->isr_stats.tx); |
705 | |
706 | pos += |
707 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Unexpected INTA:\t\t %u\n" , |
708 | il->isr_stats.unhandled); |
709 | |
710 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
711 | kfree(objp: buf); |
712 | return ret; |
713 | } |
714 | |
715 | static ssize_t |
716 | il_dbgfs_interrupt_write(struct file *file, const char __user *user_buf, |
717 | size_t count, loff_t *ppos) |
718 | { |
719 | struct il_priv *il = file->private_data; |
720 | char buf[8]; |
721 | int buf_size; |
722 | u32 reset_flag; |
723 | |
724 | memset(buf, 0, sizeof(buf)); |
725 | buf_size = min(count, sizeof(buf) - 1); |
726 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
727 | return -EFAULT; |
728 | if (sscanf(buf, "%x" , &reset_flag) != 1) |
729 | return -EFAULT; |
730 | if (reset_flag == 0) |
731 | il_clear_isr_stats(il); |
732 | |
733 | return count; |
734 | } |
735 | |
736 | static ssize_t |
737 | il_dbgfs_qos_read(struct file *file, char __user *user_buf, size_t count, |
738 | loff_t *ppos) |
739 | { |
740 | struct il_priv *il = file->private_data; |
741 | int pos = 0, i; |
742 | char buf[256]; |
743 | const size_t bufsz = sizeof(buf); |
744 | |
745 | for (i = 0; i < AC_NUM; i++) { |
746 | pos += |
747 | scnprintf(buf: buf + pos, size: bufsz - pos, |
748 | fmt: "\tcw_min\tcw_max\taifsn\ttxop\n" ); |
749 | pos += |
750 | scnprintf(buf: buf + pos, size: bufsz - pos, |
751 | fmt: "AC[%d]\t%u\t%u\t%u\t%u\n" , i, |
752 | il->qos_data.def_qos_parm.ac[i].cw_min, |
753 | il->qos_data.def_qos_parm.ac[i].cw_max, |
754 | il->qos_data.def_qos_parm.ac[i].aifsn, |
755 | il->qos_data.def_qos_parm.ac[i].edca_txop); |
756 | } |
757 | |
758 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
759 | } |
760 | |
761 | static ssize_t |
762 | il_dbgfs_disable_ht40_write(struct file *file, const char __user *user_buf, |
763 | size_t count, loff_t *ppos) |
764 | { |
765 | struct il_priv *il = file->private_data; |
766 | char buf[8]; |
767 | int buf_size; |
768 | int ht40; |
769 | |
770 | memset(buf, 0, sizeof(buf)); |
771 | buf_size = min(count, sizeof(buf) - 1); |
772 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
773 | return -EFAULT; |
774 | if (sscanf(buf, "%d" , &ht40) != 1) |
775 | return -EFAULT; |
776 | if (!il_is_any_associated(il)) |
777 | il->disable_ht40 = ht40 ? true : false; |
778 | else { |
779 | IL_ERR("Sta associated with AP - " |
780 | "Change to 40MHz channel support is not allowed\n" ); |
781 | return -EINVAL; |
782 | } |
783 | |
784 | return count; |
785 | } |
786 | |
787 | static ssize_t |
788 | il_dbgfs_disable_ht40_read(struct file *file, char __user *user_buf, |
789 | size_t count, loff_t *ppos) |
790 | { |
791 | struct il_priv *il = file->private_data; |
792 | char buf[100]; |
793 | int pos = 0; |
794 | const size_t bufsz = sizeof(buf); |
795 | |
796 | pos += |
797 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "11n 40MHz Mode: %s\n" , |
798 | il->disable_ht40 ? "Disabled" : "Enabled" ); |
799 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
800 | } |
801 | |
802 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
803 | DEBUGFS_READ_FILE_OPS(nvm); |
804 | DEBUGFS_READ_FILE_OPS(stations); |
805 | DEBUGFS_READ_FILE_OPS(channels); |
806 | DEBUGFS_READ_FILE_OPS(status); |
807 | DEBUGFS_READ_WRITE_FILE_OPS(interrupt); |
808 | DEBUGFS_READ_FILE_OPS(qos); |
809 | DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); |
810 | |
811 | static ssize_t |
812 | il_dbgfs_tx_queue_read(struct file *file, char __user *user_buf, size_t count, |
813 | loff_t *ppos) |
814 | { |
815 | |
816 | struct il_priv *il = file->private_data; |
817 | struct il_tx_queue *txq; |
818 | struct il_queue *q; |
819 | char *buf; |
820 | int pos = 0; |
821 | int cnt; |
822 | int ret; |
823 | const size_t bufsz = |
824 | sizeof(char) * 64 * il->cfg->num_of_queues; |
825 | |
826 | if (!il->txq) { |
827 | IL_ERR("txq not ready\n" ); |
828 | return -EAGAIN; |
829 | } |
830 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
831 | if (!buf) |
832 | return -ENOMEM; |
833 | |
834 | for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { |
835 | txq = &il->txq[cnt]; |
836 | q = &txq->q; |
837 | pos += |
838 | scnprintf(buf: buf + pos, size: bufsz - pos, |
839 | fmt: "hwq %.2d: read=%u write=%u stop=%d" |
840 | " swq_id=%#.2x (ac %d/hwq %d)\n" , cnt, |
841 | q->read_ptr, q->write_ptr, |
842 | !!test_bit(cnt, il->queue_stopped), |
843 | txq->swq_id, txq->swq_id & 3, |
844 | (txq->swq_id >> 2) & 0x1f); |
845 | if (cnt >= 4) |
846 | continue; |
847 | /* for the ACs, display the stop count too */ |
848 | pos += |
849 | scnprintf(buf: buf + pos, size: bufsz - pos, |
850 | fmt: " stop-count: %d\n" , |
851 | atomic_read(v: &il->queue_stop_count[cnt])); |
852 | } |
853 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
854 | kfree(objp: buf); |
855 | return ret; |
856 | } |
857 | |
858 | static ssize_t |
859 | il_dbgfs_rx_queue_read(struct file *file, char __user *user_buf, size_t count, |
860 | loff_t *ppos) |
861 | { |
862 | |
863 | struct il_priv *il = file->private_data; |
864 | struct il_rx_queue *rxq = &il->rxq; |
865 | char buf[256]; |
866 | int pos = 0; |
867 | const size_t bufsz = sizeof(buf); |
868 | |
869 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "read: %u\n" , rxq->read); |
870 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "write: %u\n" , rxq->write); |
871 | pos += |
872 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "free_count: %u\n" , |
873 | rxq->free_count); |
874 | if (rxq->rb_stts) { |
875 | pos += |
876 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "closed_rb_num: %u\n" , |
877 | le16_to_cpu(rxq->rb_stts-> |
878 | closed_rb_num) & 0x0FFF); |
879 | } else { |
880 | pos += |
881 | scnprintf(buf: buf + pos, size: bufsz - pos, |
882 | fmt: "closed_rb_num: Not Allocated\n" ); |
883 | } |
884 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
885 | } |
886 | |
887 | static ssize_t |
888 | il_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, |
889 | size_t count, loff_t *ppos) |
890 | { |
891 | struct il_priv *il = file->private_data; |
892 | |
893 | return il->debugfs_ops->rx_stats_read(file, user_buf, count, ppos); |
894 | } |
895 | |
896 | static ssize_t |
897 | il_dbgfs_ucode_tx_stats_read(struct file *file, char __user *user_buf, |
898 | size_t count, loff_t *ppos) |
899 | { |
900 | struct il_priv *il = file->private_data; |
901 | |
902 | return il->debugfs_ops->tx_stats_read(file, user_buf, count, ppos); |
903 | } |
904 | |
905 | static ssize_t |
906 | il_dbgfs_ucode_general_stats_read(struct file *file, char __user *user_buf, |
907 | size_t count, loff_t *ppos) |
908 | { |
909 | struct il_priv *il = file->private_data; |
910 | |
911 | return il->debugfs_ops->general_stats_read(file, user_buf, count, ppos); |
912 | } |
913 | |
914 | static ssize_t |
915 | il_dbgfs_sensitivity_read(struct file *file, char __user *user_buf, |
916 | size_t count, loff_t *ppos) |
917 | { |
918 | |
919 | struct il_priv *il = file->private_data; |
920 | int pos = 0; |
921 | int cnt = 0; |
922 | char *buf; |
923 | int bufsz = sizeof(struct il_sensitivity_data) * 4 + 100; |
924 | ssize_t ret; |
925 | struct il_sensitivity_data *data; |
926 | |
927 | data = &il->sensitivity_data; |
928 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
929 | if (!buf) { |
930 | IL_ERR("Can not allocate Buffer\n" ); |
931 | return -ENOMEM; |
932 | } |
933 | |
934 | pos += |
935 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "auto_corr_ofdm:\t\t\t %u\n" , |
936 | data->auto_corr_ofdm); |
937 | pos += |
938 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "auto_corr_ofdm_mrc:\t\t %u\n" , |
939 | data->auto_corr_ofdm_mrc); |
940 | pos += |
941 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "auto_corr_ofdm_x1:\t\t %u\n" , |
942 | data->auto_corr_ofdm_x1); |
943 | pos += |
944 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "auto_corr_ofdm_mrc_x1:\t\t %u\n" , |
945 | data->auto_corr_ofdm_mrc_x1); |
946 | pos += |
947 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "auto_corr_cck:\t\t\t %u\n" , |
948 | data->auto_corr_cck); |
949 | pos += |
950 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "auto_corr_cck_mrc:\t\t %u\n" , |
951 | data->auto_corr_cck_mrc); |
952 | pos += |
953 | scnprintf(buf: buf + pos, size: bufsz - pos, |
954 | fmt: "last_bad_plcp_cnt_ofdm:\t\t %u\n" , |
955 | data->last_bad_plcp_cnt_ofdm); |
956 | pos += |
957 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "last_fa_cnt_ofdm:\t\t %u\n" , |
958 | data->last_fa_cnt_ofdm); |
959 | pos += |
960 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "last_bad_plcp_cnt_cck:\t\t %u\n" , |
961 | data->last_bad_plcp_cnt_cck); |
962 | pos += |
963 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "last_fa_cnt_cck:\t\t %u\n" , |
964 | data->last_fa_cnt_cck); |
965 | pos += |
966 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_curr_state:\t\t\t %u\n" , |
967 | data->nrg_curr_state); |
968 | pos += |
969 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_prev_state:\t\t\t %u\n" , |
970 | data->nrg_prev_state); |
971 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_value:\t\t\t" ); |
972 | for (cnt = 0; cnt < 10; cnt++) { |
973 | pos += |
974 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: " %u" , |
975 | data->nrg_value[cnt]); |
976 | } |
977 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
978 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_silence_rssi:\t\t" ); |
979 | for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) { |
980 | pos += |
981 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: " %u" , |
982 | data->nrg_silence_rssi[cnt]); |
983 | } |
984 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
985 | pos += |
986 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_silence_ref:\t\t %u\n" , |
987 | data->nrg_silence_ref); |
988 | pos += |
989 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_energy_idx:\t\t\t %u\n" , |
990 | data->nrg_energy_idx); |
991 | pos += |
992 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_silence_idx:\t\t %u\n" , |
993 | data->nrg_silence_idx); |
994 | pos += |
995 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_th_cck:\t\t\t %u\n" , |
996 | data->nrg_th_cck); |
997 | pos += |
998 | scnprintf(buf: buf + pos, size: bufsz - pos, |
999 | fmt: "nrg_auto_corr_silence_diff:\t %u\n" , |
1000 | data->nrg_auto_corr_silence_diff); |
1001 | pos += |
1002 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "num_in_cck_no_fa:\t\t %u\n" , |
1003 | data->num_in_cck_no_fa); |
1004 | pos += |
1005 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "nrg_th_ofdm:\t\t\t %u\n" , |
1006 | data->nrg_th_ofdm); |
1007 | |
1008 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
1009 | kfree(objp: buf); |
1010 | return ret; |
1011 | } |
1012 | |
1013 | static ssize_t |
1014 | il_dbgfs_chain_noise_read(struct file *file, char __user *user_buf, |
1015 | size_t count, loff_t *ppos) |
1016 | { |
1017 | |
1018 | struct il_priv *il = file->private_data; |
1019 | int pos = 0; |
1020 | int cnt = 0; |
1021 | char *buf; |
1022 | int bufsz = sizeof(struct il_chain_noise_data) * 4 + 100; |
1023 | ssize_t ret; |
1024 | struct il_chain_noise_data *data; |
1025 | |
1026 | data = &il->chain_noise_data; |
1027 | buf = kzalloc(size: bufsz, GFP_KERNEL); |
1028 | if (!buf) { |
1029 | IL_ERR("Can not allocate Buffer\n" ); |
1030 | return -ENOMEM; |
1031 | } |
1032 | |
1033 | pos += |
1034 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "active_chains:\t\t\t %u\n" , |
1035 | data->active_chains); |
1036 | pos += |
1037 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "chain_noise_a:\t\t\t %u\n" , |
1038 | data->chain_noise_a); |
1039 | pos += |
1040 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "chain_noise_b:\t\t\t %u\n" , |
1041 | data->chain_noise_b); |
1042 | pos += |
1043 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "chain_noise_c:\t\t\t %u\n" , |
1044 | data->chain_noise_c); |
1045 | pos += |
1046 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "chain_signal_a:\t\t\t %u\n" , |
1047 | data->chain_signal_a); |
1048 | pos += |
1049 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "chain_signal_b:\t\t\t %u\n" , |
1050 | data->chain_signal_b); |
1051 | pos += |
1052 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "chain_signal_c:\t\t\t %u\n" , |
1053 | data->chain_signal_c); |
1054 | pos += |
1055 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "beacon_count:\t\t\t %u\n" , |
1056 | data->beacon_count); |
1057 | |
1058 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "disconn_array:\t\t\t" ); |
1059 | for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { |
1060 | pos += |
1061 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: " %u" , |
1062 | data->disconn_array[cnt]); |
1063 | } |
1064 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
1065 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "delta_gain_code:\t\t" ); |
1066 | for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) { |
1067 | pos += |
1068 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: " %u" , |
1069 | data->delta_gain_code[cnt]); |
1070 | } |
1071 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\n" ); |
1072 | pos += |
1073 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "radio_write:\t\t\t %u\n" , |
1074 | data->radio_write); |
1075 | pos += |
1076 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "state:\t\t\t\t %u\n" , |
1077 | data->state); |
1078 | |
1079 | ret = simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
1080 | kfree(objp: buf); |
1081 | return ret; |
1082 | } |
1083 | |
1084 | static ssize_t |
1085 | il_dbgfs_power_save_status_read(struct file *file, char __user *user_buf, |
1086 | size_t count, loff_t *ppos) |
1087 | { |
1088 | struct il_priv *il = file->private_data; |
1089 | char buf[60]; |
1090 | int pos = 0; |
1091 | const size_t bufsz = sizeof(buf); |
1092 | u32 pwrsave_status; |
1093 | |
1094 | pwrsave_status = |
1095 | _il_rd(il, CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK; |
1096 | |
1097 | pos += scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "Power Save Status: " ); |
1098 | pos += |
1099 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "%s\n" , |
1100 | (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" : |
1101 | (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" : |
1102 | (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" : |
1103 | "error" ); |
1104 | |
1105 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
1106 | } |
1107 | |
1108 | static ssize_t |
1109 | il_dbgfs_clear_ucode_stats_write(struct file *file, |
1110 | const char __user *user_buf, size_t count, |
1111 | loff_t *ppos) |
1112 | { |
1113 | struct il_priv *il = file->private_data; |
1114 | char buf[8]; |
1115 | int buf_size; |
1116 | int clear; |
1117 | |
1118 | memset(buf, 0, sizeof(buf)); |
1119 | buf_size = min(count, sizeof(buf) - 1); |
1120 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
1121 | return -EFAULT; |
1122 | if (sscanf(buf, "%d" , &clear) != 1) |
1123 | return -EFAULT; |
1124 | |
1125 | /* make request to uCode to retrieve stats information */ |
1126 | mutex_lock(&il->mutex); |
1127 | il_send_stats_request(il, flags: CMD_SYNC, clear: true); |
1128 | mutex_unlock(lock: &il->mutex); |
1129 | |
1130 | return count; |
1131 | } |
1132 | |
1133 | static ssize_t |
1134 | il_dbgfs_rxon_flags_read(struct file *file, char __user *user_buf, |
1135 | size_t count, loff_t *ppos) |
1136 | { |
1137 | |
1138 | struct il_priv *il = file->private_data; |
1139 | int len = 0; |
1140 | char buf[20]; |
1141 | |
1142 | len = sprintf(buf, fmt: "0x%04X\n" , le32_to_cpu(il->active.flags)); |
1143 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: len); |
1144 | } |
1145 | |
1146 | static ssize_t |
1147 | il_dbgfs_rxon_filter_flags_read(struct file *file, char __user *user_buf, |
1148 | size_t count, loff_t *ppos) |
1149 | { |
1150 | |
1151 | struct il_priv *il = file->private_data; |
1152 | int len = 0; |
1153 | char buf[20]; |
1154 | |
1155 | len = |
1156 | sprintf(buf, fmt: "0x%04X\n" , le32_to_cpu(il->active.filter_flags)); |
1157 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: len); |
1158 | } |
1159 | |
1160 | static ssize_t |
1161 | il_dbgfs_fh_reg_read(struct file *file, char __user *user_buf, size_t count, |
1162 | loff_t *ppos) |
1163 | { |
1164 | struct il_priv *il = file->private_data; |
1165 | char *buf; |
1166 | int pos = 0; |
1167 | ssize_t ret = -EFAULT; |
1168 | |
1169 | if (il->ops->dump_fh) { |
1170 | ret = pos = il->ops->dump_fh(il, &buf, true); |
1171 | if (buf) { |
1172 | ret = |
1173 | simple_read_from_buffer(to: user_buf, count, ppos, from: buf, |
1174 | available: pos); |
1175 | kfree(objp: buf); |
1176 | } |
1177 | } |
1178 | |
1179 | return ret; |
1180 | } |
1181 | |
1182 | static ssize_t |
1183 | il_dbgfs_missed_beacon_read(struct file *file, char __user *user_buf, |
1184 | size_t count, loff_t *ppos) |
1185 | { |
1186 | |
1187 | struct il_priv *il = file->private_data; |
1188 | int pos = 0; |
1189 | char buf[12]; |
1190 | const size_t bufsz = sizeof(buf); |
1191 | |
1192 | pos += |
1193 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "%d\n" , |
1194 | il->missed_beacon_threshold); |
1195 | |
1196 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
1197 | } |
1198 | |
1199 | static ssize_t |
1200 | il_dbgfs_missed_beacon_write(struct file *file, const char __user *user_buf, |
1201 | size_t count, loff_t *ppos) |
1202 | { |
1203 | struct il_priv *il = file->private_data; |
1204 | char buf[8]; |
1205 | int buf_size; |
1206 | int missed; |
1207 | |
1208 | memset(buf, 0, sizeof(buf)); |
1209 | buf_size = min(count, sizeof(buf) - 1); |
1210 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
1211 | return -EFAULT; |
1212 | if (sscanf(buf, "%d" , &missed) != 1) |
1213 | return -EINVAL; |
1214 | |
1215 | if (missed < IL_MISSED_BEACON_THRESHOLD_MIN || |
1216 | missed > IL_MISSED_BEACON_THRESHOLD_MAX) |
1217 | il->missed_beacon_threshold = IL_MISSED_BEACON_THRESHOLD_DEF; |
1218 | else |
1219 | il->missed_beacon_threshold = missed; |
1220 | |
1221 | return count; |
1222 | } |
1223 | |
1224 | static ssize_t |
1225 | il_dbgfs_force_reset_read(struct file *file, char __user *user_buf, |
1226 | size_t count, loff_t *ppos) |
1227 | { |
1228 | |
1229 | struct il_priv *il = file->private_data; |
1230 | int pos = 0; |
1231 | char buf[300]; |
1232 | const size_t bufsz = sizeof(buf); |
1233 | struct il_force_reset *force_reset; |
1234 | |
1235 | force_reset = &il->force_reset; |
1236 | |
1237 | pos += |
1238 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\tnumber of reset request: %d\n" , |
1239 | force_reset->reset_request_count); |
1240 | pos += |
1241 | scnprintf(buf: buf + pos, size: bufsz - pos, |
1242 | fmt: "\tnumber of reset request success: %d\n" , |
1243 | force_reset->reset_success_count); |
1244 | pos += |
1245 | scnprintf(buf: buf + pos, size: bufsz - pos, |
1246 | fmt: "\tnumber of reset request reject: %d\n" , |
1247 | force_reset->reset_reject_count); |
1248 | pos += |
1249 | scnprintf(buf: buf + pos, size: bufsz - pos, fmt: "\treset duration: %lu\n" , |
1250 | force_reset->reset_duration); |
1251 | |
1252 | return simple_read_from_buffer(to: user_buf, count, ppos, from: buf, available: pos); |
1253 | } |
1254 | |
1255 | static ssize_t |
1256 | il_dbgfs_force_reset_write(struct file *file, const char __user *user_buf, |
1257 | size_t count, loff_t *ppos) |
1258 | { |
1259 | |
1260 | int ret; |
1261 | struct il_priv *il = file->private_data; |
1262 | |
1263 | ret = il_force_reset(il, external: true); |
1264 | |
1265 | return ret ? ret : count; |
1266 | } |
1267 | |
1268 | static ssize_t |
1269 | il_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf, |
1270 | size_t count, loff_t *ppos) |
1271 | { |
1272 | |
1273 | struct il_priv *il = file->private_data; |
1274 | char buf[8]; |
1275 | int buf_size; |
1276 | int timeout; |
1277 | |
1278 | memset(buf, 0, sizeof(buf)); |
1279 | buf_size = min(count, sizeof(buf) - 1); |
1280 | if (copy_from_user(to: buf, from: user_buf, n: buf_size)) |
1281 | return -EFAULT; |
1282 | if (sscanf(buf, "%d" , &timeout) != 1) |
1283 | return -EINVAL; |
1284 | if (timeout < 0 || timeout > IL_MAX_WD_TIMEOUT) |
1285 | timeout = IL_DEF_WD_TIMEOUT; |
1286 | |
1287 | il->cfg->wd_timeout = timeout; |
1288 | il_setup_watchdog(il); |
1289 | return count; |
1290 | } |
1291 | |
1292 | DEBUGFS_READ_FILE_OPS(rx_stats); |
1293 | DEBUGFS_READ_FILE_OPS(tx_stats); |
1294 | DEBUGFS_READ_FILE_OPS(rx_queue); |
1295 | DEBUGFS_READ_FILE_OPS(tx_queue); |
1296 | DEBUGFS_READ_FILE_OPS(ucode_rx_stats); |
1297 | DEBUGFS_READ_FILE_OPS(ucode_tx_stats); |
1298 | DEBUGFS_READ_FILE_OPS(ucode_general_stats); |
1299 | DEBUGFS_READ_FILE_OPS(sensitivity); |
1300 | DEBUGFS_READ_FILE_OPS(chain_noise); |
1301 | DEBUGFS_READ_FILE_OPS(power_save_status); |
1302 | DEBUGFS_WRITE_FILE_OPS(clear_ucode_stats); |
1303 | DEBUGFS_WRITE_FILE_OPS(clear_traffic_stats); |
1304 | DEBUGFS_READ_FILE_OPS(fh_reg); |
1305 | DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); |
1306 | DEBUGFS_READ_WRITE_FILE_OPS(force_reset); |
1307 | DEBUGFS_READ_FILE_OPS(rxon_flags); |
1308 | DEBUGFS_READ_FILE_OPS(rxon_filter_flags); |
1309 | DEBUGFS_WRITE_FILE_OPS(wd_timeout); |
1310 | |
1311 | /* |
1312 | * Create the debugfs files and directories |
1313 | * |
1314 | */ |
1315 | void |
1316 | il_dbgfs_register(struct il_priv *il, const char *name) |
1317 | { |
1318 | struct dentry *phyd = il->hw->wiphy->debugfsdir; |
1319 | struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug; |
1320 | |
1321 | dir_drv = debugfs_create_dir(name, parent: phyd); |
1322 | il->debugfs_dir = dir_drv; |
1323 | |
1324 | dir_data = debugfs_create_dir(name: "data" , parent: dir_drv); |
1325 | dir_rf = debugfs_create_dir(name: "rf" , parent: dir_drv); |
1326 | dir_debug = debugfs_create_dir(name: "debug" , parent: dir_drv); |
1327 | |
1328 | DEBUGFS_ADD_FILE(nvm, dir_data, 0400); |
1329 | DEBUGFS_ADD_FILE(sram, dir_data, 0600); |
1330 | DEBUGFS_ADD_FILE(stations, dir_data, 0400); |
1331 | DEBUGFS_ADD_FILE(channels, dir_data, 0400); |
1332 | DEBUGFS_ADD_FILE(status, dir_data, 0400); |
1333 | DEBUGFS_ADD_FILE(interrupt, dir_data, 0600); |
1334 | DEBUGFS_ADD_FILE(qos, dir_data, 0400); |
1335 | DEBUGFS_ADD_FILE(disable_ht40, dir_data, 0600); |
1336 | DEBUGFS_ADD_FILE(rx_stats, dir_debug, 0400); |
1337 | DEBUGFS_ADD_FILE(tx_stats, dir_debug, 0400); |
1338 | DEBUGFS_ADD_FILE(rx_queue, dir_debug, 0400); |
1339 | DEBUGFS_ADD_FILE(tx_queue, dir_debug, 0400); |
1340 | DEBUGFS_ADD_FILE(power_save_status, dir_debug, 0400); |
1341 | DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, 0200); |
1342 | DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, 0200); |
1343 | DEBUGFS_ADD_FILE(fh_reg, dir_debug, 0400); |
1344 | DEBUGFS_ADD_FILE(missed_beacon, dir_debug, 0200); |
1345 | DEBUGFS_ADD_FILE(force_reset, dir_debug, 0600); |
1346 | DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, 0400); |
1347 | DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, 0400); |
1348 | DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, 0400); |
1349 | |
1350 | if (il->cfg->sensitivity_calib_by_driver) |
1351 | DEBUGFS_ADD_FILE(sensitivity, dir_debug, 0400); |
1352 | if (il->cfg->chain_noise_calib_by_driver) |
1353 | DEBUGFS_ADD_FILE(chain_noise, dir_debug, 0400); |
1354 | DEBUGFS_ADD_FILE(rxon_flags, dir_debug, 0200); |
1355 | DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, 0200); |
1356 | DEBUGFS_ADD_FILE(wd_timeout, dir_debug, 0200); |
1357 | if (il->cfg->sensitivity_calib_by_driver) |
1358 | DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, |
1359 | &il->disable_sens_cal); |
1360 | if (il->cfg->chain_noise_calib_by_driver) |
1361 | DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, |
1362 | &il->disable_chain_noise_cal); |
1363 | DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &il->disable_tx_power_cal); |
1364 | } |
1365 | EXPORT_SYMBOL(il_dbgfs_register); |
1366 | |
1367 | /* |
1368 | * Remove the debugfs files and directories |
1369 | */ |
1370 | void |
1371 | il_dbgfs_unregister(struct il_priv *il) |
1372 | { |
1373 | if (!il->debugfs_dir) |
1374 | return; |
1375 | |
1376 | debugfs_remove_recursive(dentry: il->debugfs_dir); |
1377 | il->debugfs_dir = NULL; |
1378 | } |
1379 | EXPORT_SYMBOL(il_dbgfs_unregister); |
1380 | |