1bdcd8170SKalle Valo /* 2bdcd8170SKalle Valo * Copyright (c) 2004-2011 Atheros Communications Inc. 3bdcd8170SKalle Valo * 4bdcd8170SKalle Valo * Permission to use, copy, modify, and/or distribute this software for any 5bdcd8170SKalle Valo * purpose with or without fee is hereby granted, provided that the above 6bdcd8170SKalle Valo * copyright notice and this permission notice appear in all copies. 7bdcd8170SKalle Valo * 8bdcd8170SKalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9bdcd8170SKalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10bdcd8170SKalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11bdcd8170SKalle Valo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12bdcd8170SKalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13bdcd8170SKalle Valo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14bdcd8170SKalle Valo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15bdcd8170SKalle Valo */ 16bdcd8170SKalle Valo 17bdcd8170SKalle Valo #include "core.h" 18bdf5396bSKalle Valo 19bdf5396bSKalle Valo #include <linux/circ_buf.h> 20*939f1cceSKalle Valo #include <linux/fs.h> 21bdf5396bSKalle Valo 22bdcd8170SKalle Valo #include "debug.h" 23bdf5396bSKalle Valo #include "target.h" 24bdf5396bSKalle Valo 25bdf5396bSKalle Valo struct ath6kl_fwlog_slot { 26bdf5396bSKalle Valo __le32 timestamp; 27bdf5396bSKalle Valo __le32 length; 28bdf5396bSKalle Valo 29bdf5396bSKalle Valo /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ 30bdf5396bSKalle Valo u8 payload[0]; 31bdf5396bSKalle Valo }; 32bdf5396bSKalle Valo 33bdf5396bSKalle Valo #define ATH6KL_FWLOG_SIZE 32768 34bdf5396bSKalle Valo #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ 35bdf5396bSKalle Valo ATH6KL_FWLOG_PAYLOAD_SIZE) 36*939f1cceSKalle Valo #define ATH6KL_FWLOG_VALID_MASK 0x1ffff 37bdcd8170SKalle Valo 38bdcd8170SKalle Valo int ath6kl_printk(const char *level, const char *fmt, ...) 39bdcd8170SKalle Valo { 40bdcd8170SKalle Valo struct va_format vaf; 41bdcd8170SKalle Valo va_list args; 42bdcd8170SKalle Valo int rtn; 43bdcd8170SKalle Valo 44bdcd8170SKalle Valo va_start(args, fmt); 45bdcd8170SKalle Valo 46bdcd8170SKalle Valo vaf.fmt = fmt; 47bdcd8170SKalle Valo vaf.va = &args; 48bdcd8170SKalle Valo 49bdcd8170SKalle Valo rtn = printk("%sath6kl: %pV", level, &vaf); 50bdcd8170SKalle Valo 51bdcd8170SKalle Valo va_end(args); 52bdcd8170SKalle Valo 53bdcd8170SKalle Valo return rtn; 54bdcd8170SKalle Valo } 55bdcd8170SKalle Valo 56bdcd8170SKalle Valo #ifdef CONFIG_ATH6KL_DEBUG 57bdcd8170SKalle Valo void ath6kl_dump_registers(struct ath6kl_device *dev, 58bdcd8170SKalle Valo struct ath6kl_irq_proc_registers *irq_proc_reg, 59bdcd8170SKalle Valo struct ath6kl_irq_enable_reg *irq_enable_reg) 60bdcd8170SKalle Valo { 61bdcd8170SKalle Valo 62bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); 63bdcd8170SKalle Valo 64bdcd8170SKalle Valo if (irq_proc_reg != NULL) { 65bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 66bdcd8170SKalle Valo "Host Int status: 0x%x\n", 67bdcd8170SKalle Valo irq_proc_reg->host_int_status); 68bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 69bdcd8170SKalle Valo "CPU Int status: 0x%x\n", 70bdcd8170SKalle Valo irq_proc_reg->cpu_int_status); 71bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 72bdcd8170SKalle Valo "Error Int status: 0x%x\n", 73bdcd8170SKalle Valo irq_proc_reg->error_int_status); 74bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 75bdcd8170SKalle Valo "Counter Int status: 0x%x\n", 76bdcd8170SKalle Valo irq_proc_reg->counter_int_status); 77bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 78bdcd8170SKalle Valo "Mbox Frame: 0x%x\n", 79bdcd8170SKalle Valo irq_proc_reg->mbox_frame); 80bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 81bdcd8170SKalle Valo "Rx Lookahead Valid: 0x%x\n", 82bdcd8170SKalle Valo irq_proc_reg->rx_lkahd_valid); 83bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 84bdcd8170SKalle Valo "Rx Lookahead 0: 0x%x\n", 85bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[0]); 86bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 87bdcd8170SKalle Valo "Rx Lookahead 1: 0x%x\n", 88bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[1]); 89bdcd8170SKalle Valo 90bdcd8170SKalle Valo if (dev->ar->mbox_info.gmbox_addr != 0) { 91bdcd8170SKalle Valo /* 92bdcd8170SKalle Valo * If the target supports GMBOX hardware, dump some 93bdcd8170SKalle Valo * additional state. 94bdcd8170SKalle Valo */ 95bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 96bdcd8170SKalle Valo "GMBOX Host Int status 2: 0x%x\n", 97bdcd8170SKalle Valo irq_proc_reg->host_int_status2); 98bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 99bdcd8170SKalle Valo "GMBOX RX Avail: 0x%x\n", 100bdcd8170SKalle Valo irq_proc_reg->gmbox_rx_avail); 101bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 102bdcd8170SKalle Valo "GMBOX lookahead alias 0: 0x%x\n", 103bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[0]); 104bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 105bdcd8170SKalle Valo "GMBOX lookahead alias 1: 0x%x\n", 106bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[1]); 107bdcd8170SKalle Valo } 108bdcd8170SKalle Valo 109bdcd8170SKalle Valo } 110bdcd8170SKalle Valo 111bdcd8170SKalle Valo if (irq_enable_reg != NULL) { 112bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 113bdcd8170SKalle Valo "Int status Enable: 0x%x\n", 114bdcd8170SKalle Valo irq_enable_reg->int_status_en); 115bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", 116bdcd8170SKalle Valo irq_enable_reg->cntr_int_status_en); 117bdcd8170SKalle Valo } 118bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); 119bdcd8170SKalle Valo } 120bdcd8170SKalle Valo 121bdcd8170SKalle Valo static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) 122bdcd8170SKalle Valo { 123bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 124bdcd8170SKalle Valo "--- endpoint: %d svc_id: 0x%X ---\n", 125bdcd8170SKalle Valo ep_dist->endpoint, ep_dist->svc_id); 126bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n", 127bdcd8170SKalle Valo ep_dist->dist_flags); 128bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n", 129bdcd8170SKalle Valo ep_dist->cred_norm); 130bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n", 131bdcd8170SKalle Valo ep_dist->cred_min); 132bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n", 133bdcd8170SKalle Valo ep_dist->credits); 134bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n", 135bdcd8170SKalle Valo ep_dist->cred_assngd); 136bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n", 137bdcd8170SKalle Valo ep_dist->seek_cred); 138bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n", 139bdcd8170SKalle Valo ep_dist->cred_sz); 140bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n", 141bdcd8170SKalle Valo ep_dist->cred_per_msg); 142bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n", 143bdcd8170SKalle Valo ep_dist->cred_to_dist); 144bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n", 145bdcd8170SKalle Valo get_queue_depth(&((struct htc_endpoint *) 146bdcd8170SKalle Valo ep_dist->htc_rsvd)->txq)); 147bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 148bdcd8170SKalle Valo "----------------------------------\n"); 149bdcd8170SKalle Valo } 150bdcd8170SKalle Valo 151bdcd8170SKalle Valo void dump_cred_dist_stats(struct htc_target *target) 152bdcd8170SKalle Valo { 153bdcd8170SKalle Valo struct htc_endpoint_credit_dist *ep_list; 154bdcd8170SKalle Valo 155bdcd8170SKalle Valo if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC)) 156bdcd8170SKalle Valo return; 157bdcd8170SKalle Valo 158bdcd8170SKalle Valo list_for_each_entry(ep_list, &target->cred_dist_list, list) 159bdcd8170SKalle Valo dump_cred_dist(ep_list); 160bdcd8170SKalle Valo 161bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n", 162bdcd8170SKalle Valo target->cred_dist_cntxt, NULL); 163bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n", 164bdcd8170SKalle Valo target->cred_dist_cntxt->total_avail_credits, 165bdcd8170SKalle Valo target->cred_dist_cntxt->cur_free_credits); 166bdcd8170SKalle Valo } 167bdcd8170SKalle Valo 16803f68a95SVasanthakumar Thiagarajan static int ath6kl_debugfs_open(struct inode *inode, struct file *file) 16903f68a95SVasanthakumar Thiagarajan { 17003f68a95SVasanthakumar Thiagarajan file->private_data = inode->i_private; 17103f68a95SVasanthakumar Thiagarajan return 0; 17203f68a95SVasanthakumar Thiagarajan } 17303f68a95SVasanthakumar Thiagarajan 174bdf5396bSKalle Valo static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, 175bdf5396bSKalle Valo size_t buf_len) 176bdf5396bSKalle Valo { 177bdf5396bSKalle Valo struct circ_buf *fwlog = &ar->debug.fwlog_buf; 178bdf5396bSKalle Valo size_t space; 179bdf5396bSKalle Valo int i; 180bdf5396bSKalle Valo 181bdf5396bSKalle Valo /* entries must all be equal size */ 182bdf5396bSKalle Valo if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) 183bdf5396bSKalle Valo return; 184bdf5396bSKalle Valo 185bdf5396bSKalle Valo space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); 186bdf5396bSKalle Valo if (space < buf_len) 187bdf5396bSKalle Valo /* discard oldest slot */ 188bdf5396bSKalle Valo fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & 189bdf5396bSKalle Valo (ATH6KL_FWLOG_SIZE - 1); 190bdf5396bSKalle Valo 191bdf5396bSKalle Valo for (i = 0; i < buf_len; i += space) { 192bdf5396bSKalle Valo space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, 193bdf5396bSKalle Valo ATH6KL_FWLOG_SIZE); 194bdf5396bSKalle Valo 195bdf5396bSKalle Valo if ((size_t) space > buf_len - i) 196bdf5396bSKalle Valo space = buf_len - i; 197bdf5396bSKalle Valo 198bdf5396bSKalle Valo memcpy(&fwlog->buf[fwlog->head], buf, space); 199bdf5396bSKalle Valo fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); 200bdf5396bSKalle Valo } 201bdf5396bSKalle Valo 202bdf5396bSKalle Valo } 203bdf5396bSKalle Valo 204bdf5396bSKalle Valo void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) 205bdf5396bSKalle Valo { 206bdf5396bSKalle Valo struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; 207bdf5396bSKalle Valo size_t slot_len; 208bdf5396bSKalle Valo 209bdf5396bSKalle Valo if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) 210bdf5396bSKalle Valo return; 211bdf5396bSKalle Valo 212bdf5396bSKalle Valo spin_lock_bh(&ar->debug.fwlog_lock); 213bdf5396bSKalle Valo 214bdf5396bSKalle Valo slot->timestamp = cpu_to_le32(jiffies); 215bdf5396bSKalle Valo slot->length = cpu_to_le32(len); 216bdf5396bSKalle Valo memcpy(slot->payload, buf, len); 217bdf5396bSKalle Valo 218bdf5396bSKalle Valo slot_len = sizeof(*slot) + len; 219bdf5396bSKalle Valo 220bdf5396bSKalle Valo if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) 221bdf5396bSKalle Valo memset(slot->payload + len, 0, 222bdf5396bSKalle Valo ATH6KL_FWLOG_SLOT_SIZE - slot_len); 223bdf5396bSKalle Valo 224bdf5396bSKalle Valo ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); 225bdf5396bSKalle Valo 226bdf5396bSKalle Valo spin_unlock_bh(&ar->debug.fwlog_lock); 227bdf5396bSKalle Valo } 228bdf5396bSKalle Valo 229bdf5396bSKalle Valo static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) 230bdf5396bSKalle Valo { 231bdf5396bSKalle Valo return CIRC_CNT(ar->debug.fwlog_buf.head, 232bdf5396bSKalle Valo ar->debug.fwlog_buf.tail, 233bdf5396bSKalle Valo ATH6KL_FWLOG_SLOT_SIZE) == 0; 234bdf5396bSKalle Valo } 235bdf5396bSKalle Valo 236bdf5396bSKalle Valo static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, 237bdf5396bSKalle Valo size_t count, loff_t *ppos) 238bdf5396bSKalle Valo { 239bdf5396bSKalle Valo struct ath6kl *ar = file->private_data; 240bdf5396bSKalle Valo struct circ_buf *fwlog = &ar->debug.fwlog_buf; 241bdf5396bSKalle Valo size_t len = 0, buf_len = count; 242bdf5396bSKalle Valo ssize_t ret_cnt; 243bdf5396bSKalle Valo char *buf; 244bdf5396bSKalle Valo int ccnt; 245bdf5396bSKalle Valo 246bdf5396bSKalle Valo buf = vmalloc(buf_len); 247bdf5396bSKalle Valo if (!buf) 248bdf5396bSKalle Valo return -ENOMEM; 249bdf5396bSKalle Valo 250bdf5396bSKalle Valo spin_lock_bh(&ar->debug.fwlog_lock); 251bdf5396bSKalle Valo 252bdf5396bSKalle Valo while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { 253bdf5396bSKalle Valo ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, 254bdf5396bSKalle Valo ATH6KL_FWLOG_SIZE); 255bdf5396bSKalle Valo 256bdf5396bSKalle Valo if ((size_t) ccnt > buf_len - len) 257bdf5396bSKalle Valo ccnt = buf_len - len; 258bdf5396bSKalle Valo 259bdf5396bSKalle Valo memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); 260bdf5396bSKalle Valo len += ccnt; 261bdf5396bSKalle Valo 262bdf5396bSKalle Valo fwlog->tail = (fwlog->tail + ccnt) & 263bdf5396bSKalle Valo (ATH6KL_FWLOG_SIZE - 1); 264bdf5396bSKalle Valo } 265bdf5396bSKalle Valo 266bdf5396bSKalle Valo spin_unlock_bh(&ar->debug.fwlog_lock); 267bdf5396bSKalle Valo 268bdf5396bSKalle Valo if (WARN_ON(len > buf_len)) 269bdf5396bSKalle Valo len = buf_len; 270bdf5396bSKalle Valo 271bdf5396bSKalle Valo ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 272bdf5396bSKalle Valo 273bdf5396bSKalle Valo vfree(buf); 274bdf5396bSKalle Valo 275bdf5396bSKalle Valo return ret_cnt; 276bdf5396bSKalle Valo } 277bdf5396bSKalle Valo 278bdf5396bSKalle Valo static const struct file_operations fops_fwlog = { 279bdf5396bSKalle Valo .open = ath6kl_debugfs_open, 280bdf5396bSKalle Valo .read = ath6kl_fwlog_read, 281bdf5396bSKalle Valo .owner = THIS_MODULE, 282bdf5396bSKalle Valo .llseek = default_llseek, 283bdf5396bSKalle Valo }; 284bdf5396bSKalle Valo 285*939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, 286*939f1cceSKalle Valo size_t count, loff_t *ppos) 287*939f1cceSKalle Valo { 288*939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 289*939f1cceSKalle Valo char buf[16]; 290*939f1cceSKalle Valo int len; 291*939f1cceSKalle Valo 292*939f1cceSKalle Valo len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); 293*939f1cceSKalle Valo 294*939f1cceSKalle Valo return simple_read_from_buffer(user_buf, count, ppos, buf, len); 295*939f1cceSKalle Valo } 296*939f1cceSKalle Valo 297*939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_write(struct file *file, 298*939f1cceSKalle Valo const char __user *user_buf, 299*939f1cceSKalle Valo size_t count, loff_t *ppos) 300*939f1cceSKalle Valo { 301*939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 302*939f1cceSKalle Valo int ret; 303*939f1cceSKalle Valo 304*939f1cceSKalle Valo ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); 305*939f1cceSKalle Valo if (ret) 306*939f1cceSKalle Valo return ret; 307*939f1cceSKalle Valo 308*939f1cceSKalle Valo ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, 309*939f1cceSKalle Valo ATH6KL_FWLOG_VALID_MASK, 310*939f1cceSKalle Valo ar->debug.fwlog_mask); 311*939f1cceSKalle Valo if (ret) 312*939f1cceSKalle Valo return ret; 313*939f1cceSKalle Valo 314*939f1cceSKalle Valo return count; 315*939f1cceSKalle Valo } 316*939f1cceSKalle Valo 317*939f1cceSKalle Valo static const struct file_operations fops_fwlog_mask = { 318*939f1cceSKalle Valo .open = ath6kl_debugfs_open, 319*939f1cceSKalle Valo .read = ath6kl_fwlog_mask_read, 320*939f1cceSKalle Valo .write = ath6kl_fwlog_mask_write, 321*939f1cceSKalle Valo .owner = THIS_MODULE, 322*939f1cceSKalle Valo .llseek = default_llseek, 323*939f1cceSKalle Valo }; 324*939f1cceSKalle Valo 32503f68a95SVasanthakumar Thiagarajan static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, 32603f68a95SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 32703f68a95SVasanthakumar Thiagarajan { 32803f68a95SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 32903f68a95SVasanthakumar Thiagarajan struct target_stats *tgt_stats = &ar->target_stats; 33003f68a95SVasanthakumar Thiagarajan char *buf; 33103f68a95SVasanthakumar Thiagarajan unsigned int len = 0, buf_len = 1500; 33203f68a95SVasanthakumar Thiagarajan int i; 33303f68a95SVasanthakumar Thiagarajan long left; 33403f68a95SVasanthakumar Thiagarajan ssize_t ret_cnt; 33503f68a95SVasanthakumar Thiagarajan 33603f68a95SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 33703f68a95SVasanthakumar Thiagarajan if (!buf) 33803f68a95SVasanthakumar Thiagarajan return -ENOMEM; 33903f68a95SVasanthakumar Thiagarajan 34003f68a95SVasanthakumar Thiagarajan if (down_interruptible(&ar->sem)) { 34103f68a95SVasanthakumar Thiagarajan kfree(buf); 34203f68a95SVasanthakumar Thiagarajan return -EBUSY; 34303f68a95SVasanthakumar Thiagarajan } 34403f68a95SVasanthakumar Thiagarajan 34503f68a95SVasanthakumar Thiagarajan set_bit(STATS_UPDATE_PEND, &ar->flag); 34603f68a95SVasanthakumar Thiagarajan 34703f68a95SVasanthakumar Thiagarajan if (ath6kl_wmi_get_stats_cmd(ar->wmi)) { 34803f68a95SVasanthakumar Thiagarajan up(&ar->sem); 34903f68a95SVasanthakumar Thiagarajan kfree(buf); 35003f68a95SVasanthakumar Thiagarajan return -EIO; 35103f68a95SVasanthakumar Thiagarajan } 35203f68a95SVasanthakumar Thiagarajan 35303f68a95SVasanthakumar Thiagarajan left = wait_event_interruptible_timeout(ar->event_wq, 35403f68a95SVasanthakumar Thiagarajan !test_bit(STATS_UPDATE_PEND, 35503f68a95SVasanthakumar Thiagarajan &ar->flag), WMI_TIMEOUT); 35603f68a95SVasanthakumar Thiagarajan 35703f68a95SVasanthakumar Thiagarajan up(&ar->sem); 35803f68a95SVasanthakumar Thiagarajan 35903f68a95SVasanthakumar Thiagarajan if (left <= 0) { 36003f68a95SVasanthakumar Thiagarajan kfree(buf); 36103f68a95SVasanthakumar Thiagarajan return -ETIMEDOUT; 36203f68a95SVasanthakumar Thiagarajan } 36303f68a95SVasanthakumar Thiagarajan 36403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "\n"); 36503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 36603f68a95SVasanthakumar Thiagarajan "Target Tx stats"); 36703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n\n", 36803f68a95SVasanthakumar Thiagarajan "================="); 36903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 37003f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->tx_ucast_pkt); 37103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 37203f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->tx_bcast_pkt); 37303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 37403f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->tx_ucast_byte); 37503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 37603f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->tx_bcast_byte); 37703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 37803f68a95SVasanthakumar Thiagarajan "Rts success cnt", tgt_stats->tx_rts_success_cnt); 37903f68a95SVasanthakumar Thiagarajan for (i = 0; i < 4; i++) 38003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 38103f68a95SVasanthakumar Thiagarajan "%18s %d %10llu\n", "PER on ac", 38203f68a95SVasanthakumar Thiagarajan i, tgt_stats->tx_pkt_per_ac[i]); 38303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 38403f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->tx_err); 38503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 38603f68a95SVasanthakumar Thiagarajan "Fail count", tgt_stats->tx_fail_cnt); 38703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 38803f68a95SVasanthakumar Thiagarajan "Retry count", tgt_stats->tx_retry_cnt); 38903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 39003f68a95SVasanthakumar Thiagarajan "Multi retry cnt", tgt_stats->tx_mult_retry_cnt); 39103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 39203f68a95SVasanthakumar Thiagarajan "Rts fail cnt", tgt_stats->tx_rts_fail_cnt); 39303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n", 39403f68a95SVasanthakumar Thiagarajan "TKIP counter measure used", 39503f68a95SVasanthakumar Thiagarajan tgt_stats->tkip_cnter_measures_invoked); 39603f68a95SVasanthakumar Thiagarajan 39703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 39803f68a95SVasanthakumar Thiagarajan "Target Rx stats"); 39903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 40003f68a95SVasanthakumar Thiagarajan "================="); 40103f68a95SVasanthakumar Thiagarajan 40203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 40303f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->rx_ucast_pkt); 40403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 40503f68a95SVasanthakumar Thiagarajan "Ucast Rate", tgt_stats->rx_ucast_rate); 40603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 40703f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->rx_bcast_pkt); 40803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 40903f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->rx_ucast_byte); 41003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41103f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->rx_bcast_byte); 41203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41303f68a95SVasanthakumar Thiagarajan "Fragmented pkt", tgt_stats->rx_frgment_pkt); 41403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41503f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->rx_err); 41603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41703f68a95SVasanthakumar Thiagarajan "CRC Err", tgt_stats->rx_crc_err); 41803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41903f68a95SVasanthakumar Thiagarajan "Key chache miss", tgt_stats->rx_key_cache_miss); 42003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 42103f68a95SVasanthakumar Thiagarajan "Decrypt Err", tgt_stats->rx_decrypt_err); 42203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 42303f68a95SVasanthakumar Thiagarajan "Duplicate frame", tgt_stats->rx_dupl_frame); 42403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 42503f68a95SVasanthakumar Thiagarajan "Tkip Mic failure", tgt_stats->tkip_local_mic_fail); 42603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 42703f68a95SVasanthakumar Thiagarajan "TKIP format err", tgt_stats->tkip_fmt_err); 42803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 42903f68a95SVasanthakumar Thiagarajan "CCMP format Err", tgt_stats->ccmp_fmt_err); 43003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n", 43103f68a95SVasanthakumar Thiagarajan "CCMP Replay Err", tgt_stats->ccmp_replays); 43203f68a95SVasanthakumar Thiagarajan 43303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 43403f68a95SVasanthakumar Thiagarajan "Misc Target stats"); 43503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 43603f68a95SVasanthakumar Thiagarajan "================="); 43703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 43803f68a95SVasanthakumar Thiagarajan "Beacon Miss count", tgt_stats->cs_bmiss_cnt); 43903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44003f68a95SVasanthakumar Thiagarajan "Num Connects", tgt_stats->cs_connect_cnt); 44103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44203f68a95SVasanthakumar Thiagarajan "Num disconnects", tgt_stats->cs_discon_cnt); 44303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 44403f68a95SVasanthakumar Thiagarajan "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); 44503f68a95SVasanthakumar Thiagarajan 44603f68a95SVasanthakumar Thiagarajan if (len > buf_len) 44703f68a95SVasanthakumar Thiagarajan len = buf_len; 44803f68a95SVasanthakumar Thiagarajan 44903f68a95SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 45003f68a95SVasanthakumar Thiagarajan 45103f68a95SVasanthakumar Thiagarajan kfree(buf); 45203f68a95SVasanthakumar Thiagarajan return ret_cnt; 45303f68a95SVasanthakumar Thiagarajan } 45403f68a95SVasanthakumar Thiagarajan 45503f68a95SVasanthakumar Thiagarajan static const struct file_operations fops_tgt_stats = { 45603f68a95SVasanthakumar Thiagarajan .read = read_file_tgt_stats, 45703f68a95SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 45803f68a95SVasanthakumar Thiagarajan .owner = THIS_MODULE, 45903f68a95SVasanthakumar Thiagarajan .llseek = default_llseek, 46003f68a95SVasanthakumar Thiagarajan }; 46103f68a95SVasanthakumar Thiagarajan 46278fc4856SVasanthakumar Thiagarajan #define print_credit_info(fmt_str, ep_list_field) \ 46378fc4856SVasanthakumar Thiagarajan (len += scnprintf(buf + len, buf_len - len, fmt_str, \ 46478fc4856SVasanthakumar Thiagarajan ep_list->ep_list_field)) 46578fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_DISPLAY_STRING_LEN 200 46678fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_LEN 128 46778fc4856SVasanthakumar Thiagarajan 46878fc4856SVasanthakumar Thiagarajan static ssize_t read_file_credit_dist_stats(struct file *file, 46978fc4856SVasanthakumar Thiagarajan char __user *user_buf, 47078fc4856SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 47178fc4856SVasanthakumar Thiagarajan { 47278fc4856SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 47378fc4856SVasanthakumar Thiagarajan struct htc_target *target = ar->htc_target; 47478fc4856SVasanthakumar Thiagarajan struct htc_endpoint_credit_dist *ep_list; 47578fc4856SVasanthakumar Thiagarajan char *buf; 47678fc4856SVasanthakumar Thiagarajan unsigned int buf_len, len = 0; 47778fc4856SVasanthakumar Thiagarajan ssize_t ret_cnt; 47878fc4856SVasanthakumar Thiagarajan 47978fc4856SVasanthakumar Thiagarajan buf_len = CREDIT_INFO_DISPLAY_STRING_LEN + 48078fc4856SVasanthakumar Thiagarajan get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN; 48178fc4856SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 48278fc4856SVasanthakumar Thiagarajan if (!buf) 48378fc4856SVasanthakumar Thiagarajan return -ENOMEM; 48478fc4856SVasanthakumar Thiagarajan 48578fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 48678fc4856SVasanthakumar Thiagarajan "Total Avail Credits: ", 48778fc4856SVasanthakumar Thiagarajan target->cred_dist_cntxt->total_avail_credits); 48878fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 48978fc4856SVasanthakumar Thiagarajan "Free credits :", 49078fc4856SVasanthakumar Thiagarajan target->cred_dist_cntxt->cur_free_credits); 49178fc4856SVasanthakumar Thiagarajan 49278fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 49378fc4856SVasanthakumar Thiagarajan " Epid Flags Cred_norm Cred_min Credits Cred_assngd" 49478fc4856SVasanthakumar Thiagarajan " Seek_cred Cred_sz Cred_per_msg Cred_to_dist" 49578fc4856SVasanthakumar Thiagarajan " qdepth\n"); 49678fc4856SVasanthakumar Thiagarajan 49778fc4856SVasanthakumar Thiagarajan list_for_each_entry(ep_list, &target->cred_dist_list, list) { 49878fc4856SVasanthakumar Thiagarajan print_credit_info(" %2d", endpoint); 49978fc4856SVasanthakumar Thiagarajan print_credit_info("%10x", dist_flags); 50078fc4856SVasanthakumar Thiagarajan print_credit_info("%8d", cred_norm); 50178fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_min); 50278fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", credits); 50378fc4856SVasanthakumar Thiagarajan print_credit_info("%10d", cred_assngd); 50478fc4856SVasanthakumar Thiagarajan print_credit_info("%13d", seek_cred); 50578fc4856SVasanthakumar Thiagarajan print_credit_info("%12d", cred_sz); 50678fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_per_msg); 50778fc4856SVasanthakumar Thiagarajan print_credit_info("%14d", cred_to_dist); 50878fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%12d\n", 50978fc4856SVasanthakumar Thiagarajan get_queue_depth(&((struct htc_endpoint *) 51078fc4856SVasanthakumar Thiagarajan ep_list->htc_rsvd)->txq)); 51178fc4856SVasanthakumar Thiagarajan } 51278fc4856SVasanthakumar Thiagarajan 51378fc4856SVasanthakumar Thiagarajan if (len > buf_len) 51478fc4856SVasanthakumar Thiagarajan len = buf_len; 51578fc4856SVasanthakumar Thiagarajan 51678fc4856SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 51778fc4856SVasanthakumar Thiagarajan kfree(buf); 51878fc4856SVasanthakumar Thiagarajan return ret_cnt; 51978fc4856SVasanthakumar Thiagarajan } 52078fc4856SVasanthakumar Thiagarajan 52178fc4856SVasanthakumar Thiagarajan static const struct file_operations fops_credit_dist_stats = { 52278fc4856SVasanthakumar Thiagarajan .read = read_file_credit_dist_stats, 52378fc4856SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 52478fc4856SVasanthakumar Thiagarajan .owner = THIS_MODULE, 52578fc4856SVasanthakumar Thiagarajan .llseek = default_llseek, 52678fc4856SVasanthakumar Thiagarajan }; 52778fc4856SVasanthakumar Thiagarajan 528d999ba3eSVasanthakumar Thiagarajan int ath6kl_debug_init(struct ath6kl *ar) 529d999ba3eSVasanthakumar Thiagarajan { 530bdf5396bSKalle Valo ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); 531bdf5396bSKalle Valo if (ar->debug.fwlog_buf.buf == NULL) 532bdf5396bSKalle Valo return -ENOMEM; 533bdf5396bSKalle Valo 534bdf5396bSKalle Valo ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); 535bdf5396bSKalle Valo if (ar->debug.fwlog_tmp == NULL) { 536bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 537bdf5396bSKalle Valo return -ENOMEM; 538bdf5396bSKalle Valo } 539bdf5396bSKalle Valo 540bdf5396bSKalle Valo spin_lock_init(&ar->debug.fwlog_lock); 541bdf5396bSKalle Valo 542*939f1cceSKalle Valo /* 543*939f1cceSKalle Valo * Actually we are lying here but don't know how to read the mask 544*939f1cceSKalle Valo * value from the firmware. 545*939f1cceSKalle Valo */ 546*939f1cceSKalle Valo ar->debug.fwlog_mask = 0; 547*939f1cceSKalle Valo 548d999ba3eSVasanthakumar Thiagarajan ar->debugfs_phy = debugfs_create_dir("ath6kl", 549d999ba3eSVasanthakumar Thiagarajan ar->wdev->wiphy->debugfsdir); 550bdf5396bSKalle Valo if (!ar->debugfs_phy) { 551bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 552bdf5396bSKalle Valo kfree(ar->debug.fwlog_tmp); 553d999ba3eSVasanthakumar Thiagarajan return -ENOMEM; 554bdf5396bSKalle Valo } 555d999ba3eSVasanthakumar Thiagarajan 55603f68a95SVasanthakumar Thiagarajan debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, 55703f68a95SVasanthakumar Thiagarajan &fops_tgt_stats); 55803f68a95SVasanthakumar Thiagarajan 55978fc4856SVasanthakumar Thiagarajan debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar, 56078fc4856SVasanthakumar Thiagarajan &fops_credit_dist_stats); 56178fc4856SVasanthakumar Thiagarajan 562bdf5396bSKalle Valo debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, 563bdf5396bSKalle Valo &fops_fwlog); 564bdf5396bSKalle Valo 565*939f1cceSKalle Valo debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, 566*939f1cceSKalle Valo ar, &fops_fwlog_mask); 567*939f1cceSKalle Valo 568d999ba3eSVasanthakumar Thiagarajan return 0; 569d999ba3eSVasanthakumar Thiagarajan } 570bdf5396bSKalle Valo 571bdf5396bSKalle Valo void ath6kl_debug_cleanup(struct ath6kl *ar) 572bdf5396bSKalle Valo { 573bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 574bdf5396bSKalle Valo kfree(ar->debug.fwlog_tmp); 575bdf5396bSKalle Valo } 576bdf5396bSKalle Valo 577bdcd8170SKalle Valo #endif 578