1 | /* |
2 | * Copyright (c) 2014 Redpine Signals Inc. |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include "rsi_debugfs.h" |
18 | #include "rsi_sdio.h" |
19 | |
20 | /** |
21 | * rsi_sdio_stats_read() - This function returns the sdio status of the driver. |
22 | * @seq: Pointer to the sequence file structure. |
23 | * @data: Pointer to the data. |
24 | * |
25 | * Return: 0 on success, -1 on failure. |
26 | */ |
27 | static int rsi_sdio_stats_read(struct seq_file *seq, void *data) |
28 | { |
29 | struct rsi_common *common = seq->private; |
30 | struct rsi_hw *adapter = common->priv; |
31 | struct rsi_91x_sdiodev *dev = adapter->rsi_dev; |
32 | |
33 | seq_printf(m: seq, fmt: "total_sdio_interrupts: %d\n" , |
34 | dev->rx_info.sdio_int_counter); |
35 | seq_printf(m: seq, fmt: "sdio_msdu_pending_intr_count: %d\n" , |
36 | dev->rx_info.total_sdio_msdu_pending_intr); |
37 | seq_printf(m: seq, fmt: "sdio_buff_full_count : %d\n" , |
38 | dev->rx_info.buf_full_counter); |
39 | seq_printf(m: seq, fmt: "sdio_buf_semi_full_count %d\n" , |
40 | dev->rx_info.buf_semi_full_counter); |
41 | seq_printf(m: seq, fmt: "sdio_unknown_intr_count: %d\n" , |
42 | dev->rx_info.total_sdio_unknown_intr); |
43 | /* RX Path Stats */ |
44 | seq_printf(m: seq, fmt: "BUFFER FULL STATUS : %d\n" , |
45 | dev->rx_info.buffer_full); |
46 | seq_printf(m: seq, fmt: "SEMI BUFFER FULL STATUS : %d\n" , |
47 | dev->rx_info.semi_buffer_full); |
48 | seq_printf(m: seq, fmt: "MGMT BUFFER FULL STATUS : %d\n" , |
49 | dev->rx_info.mgmt_buffer_full); |
50 | seq_printf(m: seq, fmt: "BUFFER FULL COUNTER : %d\n" , |
51 | dev->rx_info.buf_full_counter); |
52 | seq_printf(m: seq, fmt: "BUFFER SEMI FULL COUNTER : %d\n" , |
53 | dev->rx_info.buf_semi_full_counter); |
54 | seq_printf(m: seq, fmt: "MGMT BUFFER FULL COUNTER : %d\n" , |
55 | dev->rx_info.mgmt_buf_full_counter); |
56 | |
57 | return 0; |
58 | } |
59 | |
60 | /** |
61 | * rsi_sdio_stats_open() - This function calls single open function of seq_file |
62 | * to open file and read contents from it. |
63 | * @inode: Pointer to the inode structure. |
64 | * @file: Pointer to the file structure. |
65 | * |
66 | * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. |
67 | */ |
68 | static int rsi_sdio_stats_open(struct inode *inode, |
69 | struct file *file) |
70 | { |
71 | return single_open(file, rsi_sdio_stats_read, inode->i_private); |
72 | } |
73 | |
74 | /** |
75 | * rsi_version_read() - This function gives driver and firmware version number. |
76 | * @seq: Pointer to the sequence file structure. |
77 | * @data: Pointer to the data. |
78 | * |
79 | * Return: 0 on success, -1 on failure. |
80 | */ |
81 | static int rsi_version_read(struct seq_file *seq, void *data) |
82 | { |
83 | struct rsi_common *common = seq->private; |
84 | |
85 | seq_printf(m: seq, fmt: "LMAC : %d.%d.%d.%d\n" , |
86 | common->lmac_ver.major, |
87 | common->lmac_ver.minor, |
88 | common->lmac_ver.release_num, |
89 | common->lmac_ver.patch_num); |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | /** |
95 | * rsi_version_open() - This function calls single open function of seq_file to |
96 | * open file and read contents from it. |
97 | * @inode: Pointer to the inode structure. |
98 | * @file: Pointer to the file structure. |
99 | * |
100 | * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. |
101 | */ |
102 | static int rsi_version_open(struct inode *inode, |
103 | struct file *file) |
104 | { |
105 | return single_open(file, rsi_version_read, inode->i_private); |
106 | } |
107 | |
108 | /** |
109 | * rsi_stats_read() - This function return the status of the driver. |
110 | * @seq: Pointer to the sequence file structure. |
111 | * @data: Pointer to the data. |
112 | * |
113 | * Return: 0 on success, -1 on failure. |
114 | */ |
115 | static int rsi_stats_read(struct seq_file *seq, void *data) |
116 | { |
117 | struct rsi_common *common = seq->private; |
118 | |
119 | static const unsigned char fsm_state[][32] = { |
120 | "FSM_FW_NOT_LOADED" , |
121 | "FSM_CARD_NOT_READY" , |
122 | "FSM_COMMON_DEV_PARAMS_SENT" , |
123 | "FSM_BOOT_PARAMS_SENT" , |
124 | "FSM_EEPROM_READ_MAC_ADDR" , |
125 | "FSM_EEPROM_READ_RF_TYPE" , |
126 | "FSM_RESET_MAC_SENT" , |
127 | "FSM_RADIO_CAPS_SENT" , |
128 | "FSM_BB_RF_PROG_SENT" , |
129 | "FSM_MAC_INIT_DONE" |
130 | }; |
131 | seq_puts(m: seq, s: "==> RSI STA DRIVER STATUS <==\n" ); |
132 | seq_puts(m: seq, s: "DRIVER_FSM_STATE: " ); |
133 | |
134 | BUILD_BUG_ON(ARRAY_SIZE(fsm_state) != NUM_FSM_STATES); |
135 | |
136 | if (common->fsm_state <= FSM_MAC_INIT_DONE) |
137 | seq_printf(m: seq, fmt: "%s" , fsm_state[common->fsm_state]); |
138 | |
139 | seq_printf(m: seq, fmt: "(%d)\n\n" , common->fsm_state); |
140 | |
141 | /* Mgmt TX Path Stats */ |
142 | seq_printf(m: seq, fmt: "total_mgmt_pkt_send : %d\n" , |
143 | common->tx_stats.total_tx_pkt_send[MGMT_SOFT_Q]); |
144 | seq_printf(m: seq, fmt: "total_mgmt_pkt_queued : %d\n" , |
145 | skb_queue_len(list_: &common->tx_queue[MGMT_SOFT_Q])); |
146 | seq_printf(m: seq, fmt: "total_mgmt_pkt_freed : %d\n" , |
147 | common->tx_stats.total_tx_pkt_freed[MGMT_SOFT_Q]); |
148 | |
149 | /* Data TX Path Stats */ |
150 | seq_printf(m: seq, fmt: "total_data_vo_pkt_send: %8d\t" , |
151 | common->tx_stats.total_tx_pkt_send[VO_Q]); |
152 | seq_printf(m: seq, fmt: "total_data_vo_pkt_queued: %8d\t" , |
153 | skb_queue_len(list_: &common->tx_queue[VO_Q])); |
154 | seq_printf(m: seq, fmt: "total_vo_pkt_freed: %8d\n" , |
155 | common->tx_stats.total_tx_pkt_freed[VO_Q]); |
156 | seq_printf(m: seq, fmt: "total_data_vi_pkt_send: %8d\t" , |
157 | common->tx_stats.total_tx_pkt_send[VI_Q]); |
158 | seq_printf(m: seq, fmt: "total_data_vi_pkt_queued: %8d\t" , |
159 | skb_queue_len(list_: &common->tx_queue[VI_Q])); |
160 | seq_printf(m: seq, fmt: "total_vi_pkt_freed: %8d\n" , |
161 | common->tx_stats.total_tx_pkt_freed[VI_Q]); |
162 | seq_printf(m: seq, fmt: "total_data_be_pkt_send: %8d\t" , |
163 | common->tx_stats.total_tx_pkt_send[BE_Q]); |
164 | seq_printf(m: seq, fmt: "total_data_be_pkt_queued: %8d\t" , |
165 | skb_queue_len(list_: &common->tx_queue[BE_Q])); |
166 | seq_printf(m: seq, fmt: "total_be_pkt_freed: %8d\n" , |
167 | common->tx_stats.total_tx_pkt_freed[BE_Q]); |
168 | seq_printf(m: seq, fmt: "total_data_bk_pkt_send: %8d\t" , |
169 | common->tx_stats.total_tx_pkt_send[BK_Q]); |
170 | seq_printf(m: seq, fmt: "total_data_bk_pkt_queued: %8d\t" , |
171 | skb_queue_len(list_: &common->tx_queue[BK_Q])); |
172 | seq_printf(m: seq, fmt: "total_bk_pkt_freed: %8d\n" , |
173 | common->tx_stats.total_tx_pkt_freed[BK_Q]); |
174 | |
175 | seq_puts(m: seq, s: "\n" ); |
176 | return 0; |
177 | } |
178 | |
179 | /** |
180 | * rsi_stats_open() - This function calls single open function of seq_file to |
181 | * open file and read contents from it. |
182 | * @inode: Pointer to the inode structure. |
183 | * @file: Pointer to the file structure. |
184 | * |
185 | * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. |
186 | */ |
187 | static int rsi_stats_open(struct inode *inode, |
188 | struct file *file) |
189 | { |
190 | return single_open(file, rsi_stats_read, inode->i_private); |
191 | } |
192 | |
193 | /** |
194 | * rsi_debug_zone_read() - This function display the currently enabled debug zones. |
195 | * @seq: Pointer to the sequence file structure. |
196 | * @data: Pointer to the data. |
197 | * |
198 | * Return: 0 on success, -1 on failure. |
199 | */ |
200 | static int rsi_debug_zone_read(struct seq_file *seq, void *data) |
201 | { |
202 | rsi_dbg(FSM_ZONE, fmt: "%x: rsi_enabled zone" , rsi_zone_enabled); |
203 | seq_printf(m: seq, fmt: "The zones available are %#x\n" , |
204 | rsi_zone_enabled); |
205 | return 0; |
206 | } |
207 | |
208 | /** |
209 | * rsi_debug_read() - This function calls single open function of seq_file to |
210 | * open file and read contents from it. |
211 | * @inode: Pointer to the inode structure. |
212 | * @file: Pointer to the file structure. |
213 | * |
214 | * Return: Pointer to the opened file status: 0 on success, ENOMEM on failure. |
215 | */ |
216 | static int rsi_debug_read(struct inode *inode, |
217 | struct file *file) |
218 | { |
219 | return single_open(file, rsi_debug_zone_read, inode->i_private); |
220 | } |
221 | |
222 | /** |
223 | * rsi_debug_zone_write() - This function writes into hal queues as per user |
224 | * requirement. |
225 | * @filp: Pointer to the file structure. |
226 | * @buff: Pointer to the character buffer. |
227 | * @len: Length of the data to be written into buffer. |
228 | * @data: Pointer to the data. |
229 | * |
230 | * Return: len: Number of bytes read. |
231 | */ |
232 | static ssize_t rsi_debug_zone_write(struct file *filp, |
233 | const char __user *buff, |
234 | size_t len, |
235 | loff_t *data) |
236 | { |
237 | unsigned long dbg_zone; |
238 | int ret; |
239 | |
240 | if (!len) |
241 | return 0; |
242 | |
243 | ret = kstrtoul_from_user(s: buff, count: len, base: 16, res: &dbg_zone); |
244 | |
245 | if (ret) |
246 | return ret; |
247 | |
248 | rsi_zone_enabled = dbg_zone; |
249 | return len; |
250 | } |
251 | |
252 | #define FOPS(fopen) { \ |
253 | .owner = THIS_MODULE, \ |
254 | .open = (fopen), \ |
255 | .read = seq_read, \ |
256 | .llseek = seq_lseek, \ |
257 | } |
258 | |
259 | #define FOPS_RW(fopen, fwrite) { \ |
260 | .owner = THIS_MODULE, \ |
261 | .open = (fopen), \ |
262 | .read = seq_read, \ |
263 | .llseek = seq_lseek, \ |
264 | .write = (fwrite), \ |
265 | } |
266 | |
267 | static const struct rsi_dbg_files dev_debugfs_files[] = { |
268 | {"version" , 0644, FOPS(rsi_version_open),}, |
269 | {"stats" , 0644, FOPS(rsi_stats_open),}, |
270 | {"debug_zone" , 0666, FOPS_RW(rsi_debug_read, rsi_debug_zone_write),}, |
271 | {"sdio_stats" , 0644, FOPS(rsi_sdio_stats_open),}, |
272 | }; |
273 | |
274 | /** |
275 | * rsi_init_dbgfs() - This function initializes the dbgfs entry. |
276 | * @adapter: Pointer to the adapter structure. |
277 | * |
278 | * Return: 0 on success, -1 on failure. |
279 | */ |
280 | int rsi_init_dbgfs(struct rsi_hw *adapter) |
281 | { |
282 | struct rsi_common *common = adapter->priv; |
283 | struct rsi_debugfs *dev_dbgfs; |
284 | char devdir[6]; |
285 | int ii; |
286 | const struct rsi_dbg_files *files; |
287 | |
288 | dev_dbgfs = kzalloc(size: sizeof(*dev_dbgfs), GFP_KERNEL); |
289 | if (!dev_dbgfs) |
290 | return -ENOMEM; |
291 | |
292 | adapter->dfsentry = dev_dbgfs; |
293 | |
294 | snprintf(buf: devdir, size: sizeof(devdir), fmt: "%s" , |
295 | wiphy_name(wiphy: adapter->hw->wiphy)); |
296 | |
297 | dev_dbgfs->subdir = debugfs_create_dir(name: devdir, NULL); |
298 | |
299 | for (ii = 0; ii < adapter->num_debugfs_entries; ii++) { |
300 | files = &dev_debugfs_files[ii]; |
301 | dev_dbgfs->rsi_files[ii] = |
302 | debugfs_create_file(name: files->name, |
303 | mode: files->perms, |
304 | parent: dev_dbgfs->subdir, |
305 | data: common, |
306 | fops: &files->fops); |
307 | } |
308 | return 0; |
309 | } |
310 | EXPORT_SYMBOL_GPL(rsi_init_dbgfs); |
311 | |
312 | /** |
313 | * rsi_remove_dbgfs() - Removes the previously created dbgfs file entries |
314 | * in the reverse order of creation. |
315 | * @adapter: Pointer to the adapter structure. |
316 | * |
317 | * Return: None. |
318 | */ |
319 | void rsi_remove_dbgfs(struct rsi_hw *adapter) |
320 | { |
321 | struct rsi_debugfs *dev_dbgfs = adapter->dfsentry; |
322 | |
323 | if (!dev_dbgfs) |
324 | return; |
325 | |
326 | debugfs_remove_recursive(dentry: dev_dbgfs->subdir); |
327 | } |
328 | EXPORT_SYMBOL_GPL(rsi_remove_dbgfs); |
329 | |