1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (c) 2017-2019, Silicon Laboratories, Inc.
6 * Copyright (c) 2010, ST-Ericsson
8 #include <linux/debugfs.h>
9 #include <linux/seq_file.h>
10 #include <linux/crc32.h>
17 #include "hif_tx_mib.h"
19 #define CREATE_TRACE_POINTS
22 static const struct trace_print_flags hif_msg_print_map
[] = {
26 static const struct trace_print_flags hif_mib_print_map
[] = {
30 static const struct trace_print_flags wfx_reg_print_map
[] = {
34 static const char *get_symbol(unsigned long val
,
35 const struct trace_print_flags
*symbol_array
)
39 for (i
= 0; symbol_array
[i
].mask
!= -1; i
++) {
40 if (val
== symbol_array
[i
].mask
)
41 return symbol_array
[i
].name
;
47 const char *get_hif_name(unsigned long id
)
49 return get_symbol(id
, hif_msg_print_map
);
52 const char *get_mib_name(unsigned long id
)
54 return get_symbol(id
, hif_mib_print_map
);
57 const char *get_reg_name(unsigned long id
)
59 return get_symbol(id
, wfx_reg_print_map
);
62 static int wfx_counters_show(struct seq_file
*seq
, void *v
)
65 struct wfx_dev
*wdev
= seq
->private;
66 struct hif_mib_extended_count_table counters
;
68 ret
= hif_get_counters_table(wdev
, &counters
);
74 #define PUT_COUNTER(name) \
75 seq_printf(seq, "%24s %d\n", #name ":",\
76 le32_to_cpu(counters.count_##name))
78 PUT_COUNTER(tx_packets
);
79 PUT_COUNTER(tx_multicast_frames
);
80 PUT_COUNTER(tx_frames_success
);
81 PUT_COUNTER(tx_frame_failures
);
82 PUT_COUNTER(tx_frames_retried
);
83 PUT_COUNTER(tx_frames_multi_retried
);
85 PUT_COUNTER(rts_success
);
86 PUT_COUNTER(rts_failures
);
87 PUT_COUNTER(ack_failures
);
89 PUT_COUNTER(rx_packets
);
90 PUT_COUNTER(rx_frames_success
);
91 PUT_COUNTER(rx_packet_errors
);
92 PUT_COUNTER(plcp_errors
);
93 PUT_COUNTER(fcs_errors
);
94 PUT_COUNTER(rx_decryption_failures
);
95 PUT_COUNTER(rx_mic_failures
);
96 PUT_COUNTER(rx_no_key_failures
);
97 PUT_COUNTER(rx_frame_duplicates
);
98 PUT_COUNTER(rx_multicast_frames
);
99 PUT_COUNTER(rx_cmacicv_errors
);
100 PUT_COUNTER(rx_cmac_replays
);
101 PUT_COUNTER(rx_mgmt_ccmp_replays
);
103 PUT_COUNTER(rx_beacon
);
104 PUT_COUNTER(miss_beacon
);
110 DEFINE_SHOW_ATTRIBUTE(wfx_counters
);
112 static const char * const channel_names
[] = {
117 /* Entries 4 and 5 does not exist */
136 static int wfx_rx_stats_show(struct seq_file
*seq
, void *v
)
138 struct wfx_dev
*wdev
= seq
->private;
139 struct hif_rx_stats
*st
= &wdev
->rx_stats
;
142 mutex_lock(&wdev
->rx_stats_lock
);
143 seq_printf(seq
, "Timestamp: %dus\n", st
->date
);
144 seq_printf(seq
, "Low power clock: frequency %uHz, external %s\n",
146 st
->is_ext_pwr_clk
? "yes" : "no");
148 "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n",
149 st
->nb_rx_frame
, st
->per_total
, st
->throughput
);
150 seq_puts(seq
, " Num. of PER RSSI SNR CFO\n");
151 seq_puts(seq
, " frames (x10e4) (dBm) (dB) (kHz)\n");
152 for (i
= 0; i
< ARRAY_SIZE(channel_names
); i
++) {
153 if (channel_names
[i
])
154 seq_printf(seq
, "%5s %8d %8d %8d %8d %8d\n",
155 channel_names
[i
], st
->nb_rx_by_rate
[i
],
156 st
->per
[i
], st
->rssi
[i
] / 100,
157 st
->snr
[i
] / 100, st
->cfo
[i
]);
159 mutex_unlock(&wdev
->rx_stats_lock
);
163 DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats
);
165 static ssize_t
wfx_send_pds_write(struct file
*file
,
166 const char __user
*user_buf
,
167 size_t count
, loff_t
*ppos
)
169 struct wfx_dev
*wdev
= file
->private_data
;
174 dev_dbg(wdev
->dev
, "PDS data must be written in one transaction");
177 buf
= memdup_user(user_buf
, count
);
180 *ppos
= *ppos
+ count
;
181 ret
= wfx_send_pds(wdev
, buf
, count
);
188 static const struct file_operations wfx_send_pds_fops
= {
190 .write
= wfx_send_pds_write
,
193 static ssize_t
wfx_burn_slk_key_write(struct file
*file
,
194 const char __user
*user_buf
,
195 size_t count
, loff_t
*ppos
)
197 struct wfx_dev
*wdev
= file
->private_data
;
199 dev_info(wdev
->dev
, "this driver does not support secure link\n");
203 static const struct file_operations wfx_burn_slk_key_fops
= {
205 .write
= wfx_burn_slk_key_write
,
208 struct dbgfs_hif_msg
{
209 struct wfx_dev
*wdev
;
210 struct completion complete
;
215 static ssize_t
wfx_send_hif_msg_write(struct file
*file
,
216 const char __user
*user_buf
,
217 size_t count
, loff_t
*ppos
)
219 struct dbgfs_hif_msg
*context
= file
->private_data
;
220 struct wfx_dev
*wdev
= context
->wdev
;
221 struct hif_msg
*request
;
223 if (completion_done(&context
->complete
)) {
224 dev_dbg(wdev
->dev
, "read previous result before start a new one\n");
227 if (count
< sizeof(struct hif_msg
))
230 // wfx_cmd_send() chekc that reply buffer is wide enough, but do not
231 // return precise length read. User have to know how many bytes should
232 // be read. Filling reply buffer with a memory pattern may help user.
233 memset(context
->reply
, 0xFF, sizeof(context
->reply
));
234 request
= memdup_user(user_buf
, count
);
236 return PTR_ERR(request
);
237 if (request
->len
!= count
) {
241 context
->ret
= wfx_cmd_send(wdev
, request
, context
->reply
,
242 sizeof(context
->reply
), false);
245 complete(&context
->complete
);
249 static ssize_t
wfx_send_hif_msg_read(struct file
*file
, char __user
*user_buf
,
250 size_t count
, loff_t
*ppos
)
252 struct dbgfs_hif_msg
*context
= file
->private_data
;
255 if (count
> sizeof(context
->reply
))
257 ret
= wait_for_completion_interruptible(&context
->complete
);
260 if (context
->ret
< 0)
262 // Be carefull, write() is waiting for a full message while read()
263 // only return a payload
264 if (copy_to_user(user_buf
, context
->reply
, count
))
270 static int wfx_send_hif_msg_open(struct inode
*inode
, struct file
*file
)
272 struct dbgfs_hif_msg
*context
= kzalloc(sizeof(*context
), GFP_KERNEL
);
276 context
->wdev
= inode
->i_private
;
277 init_completion(&context
->complete
);
278 file
->private_data
= context
;
282 static int wfx_send_hif_msg_release(struct inode
*inode
, struct file
*file
)
284 struct dbgfs_hif_msg
*context
= file
->private_data
;
290 static const struct file_operations wfx_send_hif_msg_fops
= {
291 .open
= wfx_send_hif_msg_open
,
292 .release
= wfx_send_hif_msg_release
,
293 .write
= wfx_send_hif_msg_write
,
294 .read
= wfx_send_hif_msg_read
,
297 int wfx_debug_init(struct wfx_dev
*wdev
)
301 d
= debugfs_create_dir("wfx", wdev
->hw
->wiphy
->debugfsdir
);
302 debugfs_create_file("counters", 0444, d
, wdev
, &wfx_counters_fops
);
303 debugfs_create_file("rx_stats", 0444, d
, wdev
, &wfx_rx_stats_fops
);
304 debugfs_create_file("send_pds", 0200, d
, wdev
, &wfx_send_pds_fops
);
305 debugfs_create_file("burn_slk_key", 0200, d
, wdev
,
306 &wfx_burn_slk_key_fops
);
307 debugfs_create_file("send_hif_msg", 0600, d
, wdev
,
308 &wfx_send_hif_msg_fops
);