ath6kl: Add debugfs entry to dump target stats
[pandora-kernel.git] / drivers / net / wireless / ath / ath6kl / debug.c
1 /*
2  * Copyright (c) 2004-2011 Atheros Communications 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 "core.h"
18 #include "debug.h"
19
20 int ath6kl_printk(const char *level, const char *fmt, ...)
21 {
22         struct va_format vaf;
23         va_list args;
24         int rtn;
25
26         va_start(args, fmt);
27
28         vaf.fmt = fmt;
29         vaf.va = &args;
30
31         rtn = printk("%sath6kl: %pV", level, &vaf);
32
33         va_end(args);
34
35         return rtn;
36 }
37
38 #ifdef CONFIG_ATH6KL_DEBUG
39 void ath6kl_dump_registers(struct ath6kl_device *dev,
40                            struct ath6kl_irq_proc_registers *irq_proc_reg,
41                            struct ath6kl_irq_enable_reg *irq_enable_reg)
42 {
43
44         ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
45
46         if (irq_proc_reg != NULL) {
47                 ath6kl_dbg(ATH6KL_DBG_ANY,
48                         "Host Int status:           0x%x\n",
49                         irq_proc_reg->host_int_status);
50                 ath6kl_dbg(ATH6KL_DBG_ANY,
51                            "CPU Int status:            0x%x\n",
52                         irq_proc_reg->cpu_int_status);
53                 ath6kl_dbg(ATH6KL_DBG_ANY,
54                            "Error Int status:          0x%x\n",
55                         irq_proc_reg->error_int_status);
56                 ath6kl_dbg(ATH6KL_DBG_ANY,
57                            "Counter Int status:        0x%x\n",
58                         irq_proc_reg->counter_int_status);
59                 ath6kl_dbg(ATH6KL_DBG_ANY,
60                            "Mbox Frame:                0x%x\n",
61                         irq_proc_reg->mbox_frame);
62                 ath6kl_dbg(ATH6KL_DBG_ANY,
63                            "Rx Lookahead Valid:        0x%x\n",
64                         irq_proc_reg->rx_lkahd_valid);
65                 ath6kl_dbg(ATH6KL_DBG_ANY,
66                            "Rx Lookahead 0:            0x%x\n",
67                         irq_proc_reg->rx_lkahd[0]);
68                 ath6kl_dbg(ATH6KL_DBG_ANY,
69                            "Rx Lookahead 1:            0x%x\n",
70                         irq_proc_reg->rx_lkahd[1]);
71
72                 if (dev->ar->mbox_info.gmbox_addr != 0) {
73                         /*
74                          * If the target supports GMBOX hardware, dump some
75                          * additional state.
76                          */
77                         ath6kl_dbg(ATH6KL_DBG_ANY,
78                                 "GMBOX Host Int status 2:   0x%x\n",
79                                 irq_proc_reg->host_int_status2);
80                         ath6kl_dbg(ATH6KL_DBG_ANY,
81                                 "GMBOX RX Avail:            0x%x\n",
82                                 irq_proc_reg->gmbox_rx_avail);
83                         ath6kl_dbg(ATH6KL_DBG_ANY,
84                                 "GMBOX lookahead alias 0:   0x%x\n",
85                                 irq_proc_reg->rx_gmbox_lkahd_alias[0]);
86                         ath6kl_dbg(ATH6KL_DBG_ANY,
87                                 "GMBOX lookahead alias 1:   0x%x\n",
88                                 irq_proc_reg->rx_gmbox_lkahd_alias[1]);
89                 }
90
91         }
92
93         if (irq_enable_reg != NULL) {
94                 ath6kl_dbg(ATH6KL_DBG_ANY,
95                         "Int status Enable:         0x%x\n",
96                         irq_enable_reg->int_status_en);
97                 ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
98                         irq_enable_reg->cntr_int_status_en);
99         }
100         ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
101 }
102
103 static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
104 {
105         ath6kl_dbg(ATH6KL_DBG_ANY,
106                    "--- endpoint: %d  svc_id: 0x%X ---\n",
107                    ep_dist->endpoint, ep_dist->svc_id);
108         ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags     : 0x%X\n",
109                    ep_dist->dist_flags);
110         ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm      : %d\n",
111                    ep_dist->cred_norm);
112         ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min       : %d\n",
113                    ep_dist->cred_min);
114         ath6kl_dbg(ATH6KL_DBG_ANY, " credits        : %d\n",
115                    ep_dist->credits);
116         ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd    : %d\n",
117                    ep_dist->cred_assngd);
118         ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred      : %d\n",
119                    ep_dist->seek_cred);
120         ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz        : %d\n",
121                    ep_dist->cred_sz);
122         ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg   : %d\n",
123                    ep_dist->cred_per_msg);
124         ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist   : %d\n",
125                    ep_dist->cred_to_dist);
126         ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth      : %d\n",
127                    get_queue_depth(&((struct htc_endpoint *)
128                                      ep_dist->htc_rsvd)->txq));
129         ath6kl_dbg(ATH6KL_DBG_ANY,
130                    "----------------------------------\n");
131 }
132
133 void dump_cred_dist_stats(struct htc_target *target)
134 {
135         struct htc_endpoint_credit_dist *ep_list;
136
137         if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
138                 return;
139
140         list_for_each_entry(ep_list, &target->cred_dist_list, list)
141                 dump_cred_dist(ep_list);
142
143         ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
144                    target->cred_dist_cntxt, NULL);
145         ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
146                    target->cred_dist_cntxt->total_avail_credits,
147                    target->cred_dist_cntxt->cur_free_credits);
148 }
149
150 static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
151 {
152         file->private_data = inode->i_private;
153         return 0;
154 }
155
156 static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
157                                    size_t count, loff_t *ppos)
158 {
159         struct ath6kl *ar = file->private_data;
160         struct target_stats *tgt_stats = &ar->target_stats;
161         char *buf;
162         unsigned int len = 0, buf_len = 1500;
163         int i;
164         long left;
165         ssize_t ret_cnt;
166
167         buf = kzalloc(buf_len, GFP_KERNEL);
168         if (!buf)
169                 return -ENOMEM;
170
171         if (down_interruptible(&ar->sem)) {
172                 kfree(buf);
173                 return -EBUSY;
174         }
175
176         set_bit(STATS_UPDATE_PEND, &ar->flag);
177
178         if (ath6kl_wmi_get_stats_cmd(ar->wmi)) {
179                 up(&ar->sem);
180                 kfree(buf);
181                 return -EIO;
182         }
183
184         left = wait_event_interruptible_timeout(ar->event_wq,
185                                                 !test_bit(STATS_UPDATE_PEND,
186                                                 &ar->flag), WMI_TIMEOUT);
187
188         up(&ar->sem);
189
190         if (left <= 0) {
191                 kfree(buf);
192                 return -ETIMEDOUT;
193         }
194
195         len += scnprintf(buf + len, buf_len - len, "\n");
196         len += scnprintf(buf + len, buf_len - len, "%25s\n",
197                          "Target Tx stats");
198         len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
199                          "=================");
200         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
201                          "Ucast packets", tgt_stats->tx_ucast_pkt);
202         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
203                          "Bcast packets", tgt_stats->tx_bcast_pkt);
204         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
205                          "Ucast byte", tgt_stats->tx_ucast_byte);
206         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
207                          "Bcast byte", tgt_stats->tx_bcast_byte);
208         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
209                          "Rts success cnt", tgt_stats->tx_rts_success_cnt);
210         for (i = 0; i < 4; i++)
211                 len += scnprintf(buf + len, buf_len - len,
212                                  "%18s %d %10llu\n", "PER on ac",
213                                  i, tgt_stats->tx_pkt_per_ac[i]);
214         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
215                          "Error", tgt_stats->tx_err);
216         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
217                          "Fail count", tgt_stats->tx_fail_cnt);
218         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
219                          "Retry count", tgt_stats->tx_retry_cnt);
220         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
221                          "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
222         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
223                          "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
224         len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
225                          "TKIP counter measure used",
226                          tgt_stats->tkip_cnter_measures_invoked);
227
228         len += scnprintf(buf + len, buf_len - len, "%25s\n",
229                          "Target Rx stats");
230         len += scnprintf(buf + len, buf_len - len, "%25s\n",
231                          "=================");
232
233         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
234                          "Ucast packets", tgt_stats->rx_ucast_pkt);
235         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
236                          "Ucast Rate", tgt_stats->rx_ucast_rate);
237         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
238                          "Bcast packets", tgt_stats->rx_bcast_pkt);
239         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
240                          "Ucast byte", tgt_stats->rx_ucast_byte);
241         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
242                          "Bcast byte", tgt_stats->rx_bcast_byte);
243         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
244                          "Fragmented pkt", tgt_stats->rx_frgment_pkt);
245         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
246                          "Error", tgt_stats->rx_err);
247         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
248                          "CRC Err", tgt_stats->rx_crc_err);
249         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
250                          "Key chache miss", tgt_stats->rx_key_cache_miss);
251         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
252                          "Decrypt Err", tgt_stats->rx_decrypt_err);
253         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
254                          "Duplicate frame", tgt_stats->rx_dupl_frame);
255         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
256                          "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
257         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
258                          "TKIP format err", tgt_stats->tkip_fmt_err);
259         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
260                          "CCMP format Err", tgt_stats->ccmp_fmt_err);
261         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
262                          "CCMP Replay Err", tgt_stats->ccmp_replays);
263
264         len += scnprintf(buf + len, buf_len - len, "%25s\n",
265                          "Misc Target stats");
266         len += scnprintf(buf + len, buf_len - len, "%25s\n",
267                          "=================");
268         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
269                          "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
270         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
271                          "Num Connects", tgt_stats->cs_connect_cnt);
272         len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
273                          "Num disconnects", tgt_stats->cs_discon_cnt);
274         len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
275                          "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
276
277         if (len > buf_len)
278                 len = buf_len;
279
280         ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
281
282         kfree(buf);
283         return ret_cnt;
284 }
285
286 static const struct file_operations fops_tgt_stats = {
287         .read = read_file_tgt_stats,
288         .open = ath6kl_debugfs_open,
289         .owner = THIS_MODULE,
290         .llseek = default_llseek,
291 };
292
293 int ath6kl_debug_init(struct ath6kl *ar)
294 {
295         ar->debugfs_phy = debugfs_create_dir("ath6kl",
296                                              ar->wdev->wiphy->debugfsdir);
297         if (!ar->debugfs_phy)
298                 return -ENOMEM;
299
300         debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
301                             &fops_tgt_stats);
302
303         return 0;
304 }
305 #endif