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> 20939f1cceSKalle Valo #include <linux/fs.h> 2162c83ac4SKalle Valo #include <linux/vmalloc.h> 22bdf5396bSKalle Valo 23bdcd8170SKalle Valo #include "debug.h" 24bdf5396bSKalle Valo #include "target.h" 25bdf5396bSKalle Valo 26bdf5396bSKalle Valo struct ath6kl_fwlog_slot { 27bdf5396bSKalle Valo __le32 timestamp; 28bdf5396bSKalle Valo __le32 length; 29bdf5396bSKalle Valo 30bdf5396bSKalle Valo /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ 31bdf5396bSKalle Valo u8 payload[0]; 32bdf5396bSKalle Valo }; 33bdf5396bSKalle Valo 34bdf5396bSKalle Valo #define ATH6KL_FWLOG_SIZE 32768 35bdf5396bSKalle Valo #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ 36bdf5396bSKalle Valo ATH6KL_FWLOG_PAYLOAD_SIZE) 37939f1cceSKalle Valo #define ATH6KL_FWLOG_VALID_MASK 0x1ffff 38bdcd8170SKalle Valo 39bdcd8170SKalle Valo int ath6kl_printk(const char *level, const char *fmt, ...) 40bdcd8170SKalle Valo { 41bdcd8170SKalle Valo struct va_format vaf; 42bdcd8170SKalle Valo va_list args; 43bdcd8170SKalle Valo int rtn; 44bdcd8170SKalle Valo 45bdcd8170SKalle Valo va_start(args, fmt); 46bdcd8170SKalle Valo 47bdcd8170SKalle Valo vaf.fmt = fmt; 48bdcd8170SKalle Valo vaf.va = &args; 49bdcd8170SKalle Valo 50bdcd8170SKalle Valo rtn = printk("%sath6kl: %pV", level, &vaf); 51bdcd8170SKalle Valo 52bdcd8170SKalle Valo va_end(args); 53bdcd8170SKalle Valo 54bdcd8170SKalle Valo return rtn; 55bdcd8170SKalle Valo } 56bdcd8170SKalle Valo 57bdcd8170SKalle Valo #ifdef CONFIG_ATH6KL_DEBUG 5891d57de5SVasanthakumar Thiagarajan 5991d57de5SVasanthakumar Thiagarajan #define REG_OUTPUT_LEN_PER_LINE 25 6091d57de5SVasanthakumar Thiagarajan #define REGTYPE_STR_LEN 100 6191d57de5SVasanthakumar Thiagarajan 6291d57de5SVasanthakumar Thiagarajan struct ath6kl_diag_reg_info { 6391d57de5SVasanthakumar Thiagarajan u32 reg_start; 6491d57de5SVasanthakumar Thiagarajan u32 reg_end; 6591d57de5SVasanthakumar Thiagarajan const char *reg_info; 6691d57de5SVasanthakumar Thiagarajan }; 6791d57de5SVasanthakumar Thiagarajan 6891d57de5SVasanthakumar Thiagarajan static const struct ath6kl_diag_reg_info diag_reg[] = { 6991d57de5SVasanthakumar Thiagarajan { 0x20000, 0x200fc, "General DMA and Rx registers" }, 7091d57de5SVasanthakumar Thiagarajan { 0x28000, 0x28900, "MAC PCU register & keycache" }, 7191d57de5SVasanthakumar Thiagarajan { 0x20800, 0x20a40, "QCU" }, 7291d57de5SVasanthakumar Thiagarajan { 0x21000, 0x212f0, "DCU" }, 7391d57de5SVasanthakumar Thiagarajan { 0x4000, 0x42e4, "RTC" }, 7491d57de5SVasanthakumar Thiagarajan { 0x540000, 0x540000 + (256 * 1024), "RAM" }, 7591d57de5SVasanthakumar Thiagarajan { 0x29800, 0x2B210, "Base Band" }, 7691d57de5SVasanthakumar Thiagarajan { 0x1C000, 0x1C748, "Analog" }, 7791d57de5SVasanthakumar Thiagarajan }; 7891d57de5SVasanthakumar Thiagarajan 79bdcd8170SKalle Valo void ath6kl_dump_registers(struct ath6kl_device *dev, 80bdcd8170SKalle Valo struct ath6kl_irq_proc_registers *irq_proc_reg, 81bdcd8170SKalle Valo struct ath6kl_irq_enable_reg *irq_enable_reg) 82bdcd8170SKalle Valo { 83bdcd8170SKalle Valo 84bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); 85bdcd8170SKalle Valo 86bdcd8170SKalle Valo if (irq_proc_reg != NULL) { 87bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 88bdcd8170SKalle Valo "Host Int status: 0x%x\n", 89bdcd8170SKalle Valo irq_proc_reg->host_int_status); 90bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 91bdcd8170SKalle Valo "CPU Int status: 0x%x\n", 92bdcd8170SKalle Valo irq_proc_reg->cpu_int_status); 93bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 94bdcd8170SKalle Valo "Error Int status: 0x%x\n", 95bdcd8170SKalle Valo irq_proc_reg->error_int_status); 96bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 97bdcd8170SKalle Valo "Counter Int status: 0x%x\n", 98bdcd8170SKalle Valo irq_proc_reg->counter_int_status); 99bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 100bdcd8170SKalle Valo "Mbox Frame: 0x%x\n", 101bdcd8170SKalle Valo irq_proc_reg->mbox_frame); 102bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 103bdcd8170SKalle Valo "Rx Lookahead Valid: 0x%x\n", 104bdcd8170SKalle Valo irq_proc_reg->rx_lkahd_valid); 105bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 106bdcd8170SKalle Valo "Rx Lookahead 0: 0x%x\n", 107bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[0]); 108bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 109bdcd8170SKalle Valo "Rx Lookahead 1: 0x%x\n", 110bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[1]); 111bdcd8170SKalle Valo 112bdcd8170SKalle Valo if (dev->ar->mbox_info.gmbox_addr != 0) { 113bdcd8170SKalle Valo /* 114bdcd8170SKalle Valo * If the target supports GMBOX hardware, dump some 115bdcd8170SKalle Valo * additional state. 116bdcd8170SKalle Valo */ 117bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 118bdcd8170SKalle Valo "GMBOX Host Int status 2: 0x%x\n", 119bdcd8170SKalle Valo irq_proc_reg->host_int_status2); 120bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 121bdcd8170SKalle Valo "GMBOX RX Avail: 0x%x\n", 122bdcd8170SKalle Valo irq_proc_reg->gmbox_rx_avail); 123bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 124bdcd8170SKalle Valo "GMBOX lookahead alias 0: 0x%x\n", 125bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[0]); 126bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 127bdcd8170SKalle Valo "GMBOX lookahead alias 1: 0x%x\n", 128bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[1]); 129bdcd8170SKalle Valo } 130bdcd8170SKalle Valo 131bdcd8170SKalle Valo } 132bdcd8170SKalle Valo 133bdcd8170SKalle Valo if (irq_enable_reg != NULL) { 134bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 135bdcd8170SKalle Valo "Int status Enable: 0x%x\n", 136bdcd8170SKalle Valo irq_enable_reg->int_status_en); 137bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", 138bdcd8170SKalle Valo irq_enable_reg->cntr_int_status_en); 139bdcd8170SKalle Valo } 140bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); 141bdcd8170SKalle Valo } 142bdcd8170SKalle Valo 143bdcd8170SKalle Valo static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) 144bdcd8170SKalle Valo { 145bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 146bdcd8170SKalle Valo "--- endpoint: %d svc_id: 0x%X ---\n", 147bdcd8170SKalle Valo ep_dist->endpoint, ep_dist->svc_id); 148bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n", 149bdcd8170SKalle Valo ep_dist->dist_flags); 150bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n", 151bdcd8170SKalle Valo ep_dist->cred_norm); 152bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n", 153bdcd8170SKalle Valo ep_dist->cred_min); 154bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n", 155bdcd8170SKalle Valo ep_dist->credits); 156bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n", 157bdcd8170SKalle Valo ep_dist->cred_assngd); 158bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n", 159bdcd8170SKalle Valo ep_dist->seek_cred); 160bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n", 161bdcd8170SKalle Valo ep_dist->cred_sz); 162bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n", 163bdcd8170SKalle Valo ep_dist->cred_per_msg); 164bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n", 165bdcd8170SKalle Valo ep_dist->cred_to_dist); 166bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n", 167bdcd8170SKalle Valo get_queue_depth(&((struct htc_endpoint *) 168bdcd8170SKalle Valo ep_dist->htc_rsvd)->txq)); 169bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 170bdcd8170SKalle Valo "----------------------------------\n"); 171bdcd8170SKalle Valo } 172bdcd8170SKalle Valo 173bdcd8170SKalle Valo void dump_cred_dist_stats(struct htc_target *target) 174bdcd8170SKalle Valo { 175bdcd8170SKalle Valo struct htc_endpoint_credit_dist *ep_list; 176bdcd8170SKalle Valo 177bdcd8170SKalle Valo if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC)) 178bdcd8170SKalle Valo return; 179bdcd8170SKalle Valo 180bdcd8170SKalle Valo list_for_each_entry(ep_list, &target->cred_dist_list, list) 181bdcd8170SKalle Valo dump_cred_dist(ep_list); 182bdcd8170SKalle Valo 183bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n", 184bdcd8170SKalle Valo target->cred_dist_cntxt, NULL); 185bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n", 186bdcd8170SKalle Valo target->cred_dist_cntxt->total_avail_credits, 187bdcd8170SKalle Valo target->cred_dist_cntxt->cur_free_credits); 188bdcd8170SKalle Valo } 189bdcd8170SKalle Valo 19003f68a95SVasanthakumar Thiagarajan static int ath6kl_debugfs_open(struct inode *inode, struct file *file) 19103f68a95SVasanthakumar Thiagarajan { 19203f68a95SVasanthakumar Thiagarajan file->private_data = inode->i_private; 19303f68a95SVasanthakumar Thiagarajan return 0; 19403f68a95SVasanthakumar Thiagarajan } 19503f68a95SVasanthakumar Thiagarajan 1969a730834SKalle Valo void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) 1979a730834SKalle Valo { 1989a730834SKalle Valo switch (war) { 1999a730834SKalle Valo case ATH6KL_WAR_INVALID_RATE: 2009a730834SKalle Valo ar->debug.war_stats.invalid_rate++; 2019a730834SKalle Valo break; 2029a730834SKalle Valo } 2039a730834SKalle Valo } 2049a730834SKalle Valo 2059a730834SKalle Valo static ssize_t read_file_war_stats(struct file *file, char __user *user_buf, 2069a730834SKalle Valo size_t count, loff_t *ppos) 2079a730834SKalle Valo { 2089a730834SKalle Valo struct ath6kl *ar = file->private_data; 2099a730834SKalle Valo char *buf; 2109a730834SKalle Valo unsigned int len = 0, buf_len = 1500; 2119a730834SKalle Valo ssize_t ret_cnt; 2129a730834SKalle Valo 2139a730834SKalle Valo buf = kzalloc(buf_len, GFP_KERNEL); 2149a730834SKalle Valo if (!buf) 2159a730834SKalle Valo return -ENOMEM; 2169a730834SKalle Valo 2179a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "\n"); 2189a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "%25s\n", 2199a730834SKalle Valo "Workaround stats"); 2209a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "%25s\n\n", 2219a730834SKalle Valo "================="); 2229a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "%20s %10u\n", 2239a730834SKalle Valo "Invalid rates", ar->debug.war_stats.invalid_rate); 2249a730834SKalle Valo 2259a730834SKalle Valo if (WARN_ON(len > buf_len)) 2269a730834SKalle Valo len = buf_len; 2279a730834SKalle Valo 2289a730834SKalle Valo ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 2299a730834SKalle Valo 2309a730834SKalle Valo kfree(buf); 2319a730834SKalle Valo return ret_cnt; 2329a730834SKalle Valo } 2339a730834SKalle Valo 2349a730834SKalle Valo static const struct file_operations fops_war_stats = { 2359a730834SKalle Valo .read = read_file_war_stats, 2369a730834SKalle Valo .open = ath6kl_debugfs_open, 2379a730834SKalle Valo .owner = THIS_MODULE, 2389a730834SKalle Valo .llseek = default_llseek, 2399a730834SKalle Valo }; 2409a730834SKalle Valo 241bdf5396bSKalle Valo static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, 242bdf5396bSKalle Valo size_t buf_len) 243bdf5396bSKalle Valo { 244bdf5396bSKalle Valo struct circ_buf *fwlog = &ar->debug.fwlog_buf; 245bdf5396bSKalle Valo size_t space; 246bdf5396bSKalle Valo int i; 247bdf5396bSKalle Valo 248bdf5396bSKalle Valo /* entries must all be equal size */ 249bdf5396bSKalle Valo if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) 250bdf5396bSKalle Valo return; 251bdf5396bSKalle Valo 252bdf5396bSKalle Valo space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); 253bdf5396bSKalle Valo if (space < buf_len) 254bdf5396bSKalle Valo /* discard oldest slot */ 255bdf5396bSKalle Valo fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & 256bdf5396bSKalle Valo (ATH6KL_FWLOG_SIZE - 1); 257bdf5396bSKalle Valo 258bdf5396bSKalle Valo for (i = 0; i < buf_len; i += space) { 259bdf5396bSKalle Valo space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, 260bdf5396bSKalle Valo ATH6KL_FWLOG_SIZE); 261bdf5396bSKalle Valo 262bdf5396bSKalle Valo if ((size_t) space > buf_len - i) 263bdf5396bSKalle Valo space = buf_len - i; 264bdf5396bSKalle Valo 265bdf5396bSKalle Valo memcpy(&fwlog->buf[fwlog->head], buf, space); 266bdf5396bSKalle Valo fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); 267bdf5396bSKalle Valo } 268bdf5396bSKalle Valo 269bdf5396bSKalle Valo } 270bdf5396bSKalle Valo 271bdf5396bSKalle Valo void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) 272bdf5396bSKalle Valo { 273bdf5396bSKalle Valo struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; 274bdf5396bSKalle Valo size_t slot_len; 275bdf5396bSKalle Valo 276bdf5396bSKalle Valo if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) 277bdf5396bSKalle Valo return; 278bdf5396bSKalle Valo 279bdf5396bSKalle Valo spin_lock_bh(&ar->debug.fwlog_lock); 280bdf5396bSKalle Valo 281bdf5396bSKalle Valo slot->timestamp = cpu_to_le32(jiffies); 282bdf5396bSKalle Valo slot->length = cpu_to_le32(len); 283bdf5396bSKalle Valo memcpy(slot->payload, buf, len); 284bdf5396bSKalle Valo 285bdf5396bSKalle Valo slot_len = sizeof(*slot) + len; 286bdf5396bSKalle Valo 287bdf5396bSKalle Valo if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) 288bdf5396bSKalle Valo memset(slot->payload + len, 0, 289bdf5396bSKalle Valo ATH6KL_FWLOG_SLOT_SIZE - slot_len); 290bdf5396bSKalle Valo 291bdf5396bSKalle Valo ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); 292bdf5396bSKalle Valo 293bdf5396bSKalle Valo spin_unlock_bh(&ar->debug.fwlog_lock); 294bdf5396bSKalle Valo } 295bdf5396bSKalle Valo 296bdf5396bSKalle Valo static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) 297bdf5396bSKalle Valo { 298bdf5396bSKalle Valo return CIRC_CNT(ar->debug.fwlog_buf.head, 299bdf5396bSKalle Valo ar->debug.fwlog_buf.tail, 300bdf5396bSKalle Valo ATH6KL_FWLOG_SLOT_SIZE) == 0; 301bdf5396bSKalle Valo } 302bdf5396bSKalle Valo 303bdf5396bSKalle Valo static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, 304bdf5396bSKalle Valo size_t count, loff_t *ppos) 305bdf5396bSKalle Valo { 306bdf5396bSKalle Valo struct ath6kl *ar = file->private_data; 307bdf5396bSKalle Valo struct circ_buf *fwlog = &ar->debug.fwlog_buf; 308bdf5396bSKalle Valo size_t len = 0, buf_len = count; 309bdf5396bSKalle Valo ssize_t ret_cnt; 310bdf5396bSKalle Valo char *buf; 311bdf5396bSKalle Valo int ccnt; 312bdf5396bSKalle Valo 313bdf5396bSKalle Valo buf = vmalloc(buf_len); 314bdf5396bSKalle Valo if (!buf) 315bdf5396bSKalle Valo return -ENOMEM; 316bdf5396bSKalle Valo 317bc07ddb2SKalle Valo /* read undelivered logs from firmware */ 318bc07ddb2SKalle Valo ath6kl_read_fwlogs(ar); 319bc07ddb2SKalle Valo 320bdf5396bSKalle Valo spin_lock_bh(&ar->debug.fwlog_lock); 321bdf5396bSKalle Valo 322bdf5396bSKalle Valo while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { 323bdf5396bSKalle Valo ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, 324bdf5396bSKalle Valo ATH6KL_FWLOG_SIZE); 325bdf5396bSKalle Valo 326bdf5396bSKalle Valo if ((size_t) ccnt > buf_len - len) 327bdf5396bSKalle Valo ccnt = buf_len - len; 328bdf5396bSKalle Valo 329bdf5396bSKalle Valo memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); 330bdf5396bSKalle Valo len += ccnt; 331bdf5396bSKalle Valo 332bdf5396bSKalle Valo fwlog->tail = (fwlog->tail + ccnt) & 333bdf5396bSKalle Valo (ATH6KL_FWLOG_SIZE - 1); 334bdf5396bSKalle Valo } 335bdf5396bSKalle Valo 336bdf5396bSKalle Valo spin_unlock_bh(&ar->debug.fwlog_lock); 337bdf5396bSKalle Valo 338bdf5396bSKalle Valo if (WARN_ON(len > buf_len)) 339bdf5396bSKalle Valo len = buf_len; 340bdf5396bSKalle Valo 341bdf5396bSKalle Valo ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 342bdf5396bSKalle Valo 343bdf5396bSKalle Valo vfree(buf); 344bdf5396bSKalle Valo 345bdf5396bSKalle Valo return ret_cnt; 346bdf5396bSKalle Valo } 347bdf5396bSKalle Valo 348bdf5396bSKalle Valo static const struct file_operations fops_fwlog = { 349bdf5396bSKalle Valo .open = ath6kl_debugfs_open, 350bdf5396bSKalle Valo .read = ath6kl_fwlog_read, 351bdf5396bSKalle Valo .owner = THIS_MODULE, 352bdf5396bSKalle Valo .llseek = default_llseek, 353bdf5396bSKalle Valo }; 354bdf5396bSKalle Valo 355939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, 356939f1cceSKalle Valo size_t count, loff_t *ppos) 357939f1cceSKalle Valo { 358939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 359939f1cceSKalle Valo char buf[16]; 360939f1cceSKalle Valo int len; 361939f1cceSKalle Valo 362939f1cceSKalle Valo len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); 363939f1cceSKalle Valo 364939f1cceSKalle Valo return simple_read_from_buffer(user_buf, count, ppos, buf, len); 365939f1cceSKalle Valo } 366939f1cceSKalle Valo 367939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_write(struct file *file, 368939f1cceSKalle Valo const char __user *user_buf, 369939f1cceSKalle Valo size_t count, loff_t *ppos) 370939f1cceSKalle Valo { 371939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 372939f1cceSKalle Valo int ret; 373939f1cceSKalle Valo 374939f1cceSKalle Valo ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); 375939f1cceSKalle Valo if (ret) 376939f1cceSKalle Valo return ret; 377939f1cceSKalle Valo 378939f1cceSKalle Valo ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, 379939f1cceSKalle Valo ATH6KL_FWLOG_VALID_MASK, 380939f1cceSKalle Valo ar->debug.fwlog_mask); 381939f1cceSKalle Valo if (ret) 382939f1cceSKalle Valo return ret; 383939f1cceSKalle Valo 384939f1cceSKalle Valo return count; 385939f1cceSKalle Valo } 386939f1cceSKalle Valo 387939f1cceSKalle Valo static const struct file_operations fops_fwlog_mask = { 388939f1cceSKalle Valo .open = ath6kl_debugfs_open, 389939f1cceSKalle Valo .read = ath6kl_fwlog_mask_read, 390939f1cceSKalle Valo .write = ath6kl_fwlog_mask_write, 391939f1cceSKalle Valo .owner = THIS_MODULE, 392939f1cceSKalle Valo .llseek = default_llseek, 393939f1cceSKalle Valo }; 394939f1cceSKalle Valo 39503f68a95SVasanthakumar Thiagarajan static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, 39603f68a95SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 39703f68a95SVasanthakumar Thiagarajan { 39803f68a95SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 39903f68a95SVasanthakumar Thiagarajan struct target_stats *tgt_stats = &ar->target_stats; 40003f68a95SVasanthakumar Thiagarajan char *buf; 40103f68a95SVasanthakumar Thiagarajan unsigned int len = 0, buf_len = 1500; 40203f68a95SVasanthakumar Thiagarajan int i; 40303f68a95SVasanthakumar Thiagarajan long left; 40403f68a95SVasanthakumar Thiagarajan ssize_t ret_cnt; 40503f68a95SVasanthakumar Thiagarajan 40603f68a95SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 40703f68a95SVasanthakumar Thiagarajan if (!buf) 40803f68a95SVasanthakumar Thiagarajan return -ENOMEM; 40903f68a95SVasanthakumar Thiagarajan 41003f68a95SVasanthakumar Thiagarajan if (down_interruptible(&ar->sem)) { 41103f68a95SVasanthakumar Thiagarajan kfree(buf); 41203f68a95SVasanthakumar Thiagarajan return -EBUSY; 41303f68a95SVasanthakumar Thiagarajan } 41403f68a95SVasanthakumar Thiagarajan 41503f68a95SVasanthakumar Thiagarajan set_bit(STATS_UPDATE_PEND, &ar->flag); 41603f68a95SVasanthakumar Thiagarajan 41703f68a95SVasanthakumar Thiagarajan if (ath6kl_wmi_get_stats_cmd(ar->wmi)) { 41803f68a95SVasanthakumar Thiagarajan up(&ar->sem); 41903f68a95SVasanthakumar Thiagarajan kfree(buf); 42003f68a95SVasanthakumar Thiagarajan return -EIO; 42103f68a95SVasanthakumar Thiagarajan } 42203f68a95SVasanthakumar Thiagarajan 42303f68a95SVasanthakumar Thiagarajan left = wait_event_interruptible_timeout(ar->event_wq, 42403f68a95SVasanthakumar Thiagarajan !test_bit(STATS_UPDATE_PEND, 42503f68a95SVasanthakumar Thiagarajan &ar->flag), WMI_TIMEOUT); 42603f68a95SVasanthakumar Thiagarajan 42703f68a95SVasanthakumar Thiagarajan up(&ar->sem); 42803f68a95SVasanthakumar Thiagarajan 42903f68a95SVasanthakumar Thiagarajan if (left <= 0) { 43003f68a95SVasanthakumar Thiagarajan kfree(buf); 43103f68a95SVasanthakumar Thiagarajan return -ETIMEDOUT; 43203f68a95SVasanthakumar Thiagarajan } 43303f68a95SVasanthakumar Thiagarajan 43403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "\n"); 43503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 43603f68a95SVasanthakumar Thiagarajan "Target Tx stats"); 43703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n\n", 43803f68a95SVasanthakumar Thiagarajan "================="); 43903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44003f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->tx_ucast_pkt); 44103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44203f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->tx_bcast_pkt); 44303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44403f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->tx_ucast_byte); 44503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44603f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->tx_bcast_byte); 44703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44803f68a95SVasanthakumar Thiagarajan "Rts success cnt", tgt_stats->tx_rts_success_cnt); 44903f68a95SVasanthakumar Thiagarajan for (i = 0; i < 4; i++) 45003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 45103f68a95SVasanthakumar Thiagarajan "%18s %d %10llu\n", "PER on ac", 45203f68a95SVasanthakumar Thiagarajan i, tgt_stats->tx_pkt_per_ac[i]); 45303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 45403f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->tx_err); 45503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 45603f68a95SVasanthakumar Thiagarajan "Fail count", tgt_stats->tx_fail_cnt); 45703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 45803f68a95SVasanthakumar Thiagarajan "Retry count", tgt_stats->tx_retry_cnt); 45903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 46003f68a95SVasanthakumar Thiagarajan "Multi retry cnt", tgt_stats->tx_mult_retry_cnt); 46103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 46203f68a95SVasanthakumar Thiagarajan "Rts fail cnt", tgt_stats->tx_rts_fail_cnt); 46303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n", 46403f68a95SVasanthakumar Thiagarajan "TKIP counter measure used", 46503f68a95SVasanthakumar Thiagarajan tgt_stats->tkip_cnter_measures_invoked); 46603f68a95SVasanthakumar Thiagarajan 46703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 46803f68a95SVasanthakumar Thiagarajan "Target Rx stats"); 46903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 47003f68a95SVasanthakumar Thiagarajan "================="); 47103f68a95SVasanthakumar Thiagarajan 47203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 47303f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->rx_ucast_pkt); 47403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 47503f68a95SVasanthakumar Thiagarajan "Ucast Rate", tgt_stats->rx_ucast_rate); 47603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 47703f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->rx_bcast_pkt); 47803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 47903f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->rx_ucast_byte); 48003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 48103f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->rx_bcast_byte); 48203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 48303f68a95SVasanthakumar Thiagarajan "Fragmented pkt", tgt_stats->rx_frgment_pkt); 48403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 48503f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->rx_err); 48603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 48703f68a95SVasanthakumar Thiagarajan "CRC Err", tgt_stats->rx_crc_err); 48803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 48903f68a95SVasanthakumar Thiagarajan "Key chache miss", tgt_stats->rx_key_cache_miss); 49003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 49103f68a95SVasanthakumar Thiagarajan "Decrypt Err", tgt_stats->rx_decrypt_err); 49203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 49303f68a95SVasanthakumar Thiagarajan "Duplicate frame", tgt_stats->rx_dupl_frame); 49403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 49503f68a95SVasanthakumar Thiagarajan "Tkip Mic failure", tgt_stats->tkip_local_mic_fail); 49603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 49703f68a95SVasanthakumar Thiagarajan "TKIP format err", tgt_stats->tkip_fmt_err); 49803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 49903f68a95SVasanthakumar Thiagarajan "CCMP format Err", tgt_stats->ccmp_fmt_err); 50003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n", 50103f68a95SVasanthakumar Thiagarajan "CCMP Replay Err", tgt_stats->ccmp_replays); 50203f68a95SVasanthakumar Thiagarajan 50303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 50403f68a95SVasanthakumar Thiagarajan "Misc Target stats"); 50503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 50603f68a95SVasanthakumar Thiagarajan "================="); 50703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 50803f68a95SVasanthakumar Thiagarajan "Beacon Miss count", tgt_stats->cs_bmiss_cnt); 50903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 51003f68a95SVasanthakumar Thiagarajan "Num Connects", tgt_stats->cs_connect_cnt); 51103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 51203f68a95SVasanthakumar Thiagarajan "Num disconnects", tgt_stats->cs_discon_cnt); 51303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 51403f68a95SVasanthakumar Thiagarajan "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); 51503f68a95SVasanthakumar Thiagarajan 51603f68a95SVasanthakumar Thiagarajan if (len > buf_len) 51703f68a95SVasanthakumar Thiagarajan len = buf_len; 51803f68a95SVasanthakumar Thiagarajan 51903f68a95SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 52003f68a95SVasanthakumar Thiagarajan 52103f68a95SVasanthakumar Thiagarajan kfree(buf); 52203f68a95SVasanthakumar Thiagarajan return ret_cnt; 52303f68a95SVasanthakumar Thiagarajan } 52403f68a95SVasanthakumar Thiagarajan 52503f68a95SVasanthakumar Thiagarajan static const struct file_operations fops_tgt_stats = { 52603f68a95SVasanthakumar Thiagarajan .read = read_file_tgt_stats, 52703f68a95SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 52803f68a95SVasanthakumar Thiagarajan .owner = THIS_MODULE, 52903f68a95SVasanthakumar Thiagarajan .llseek = default_llseek, 53003f68a95SVasanthakumar Thiagarajan }; 53103f68a95SVasanthakumar Thiagarajan 53278fc4856SVasanthakumar Thiagarajan #define print_credit_info(fmt_str, ep_list_field) \ 53378fc4856SVasanthakumar Thiagarajan (len += scnprintf(buf + len, buf_len - len, fmt_str, \ 53478fc4856SVasanthakumar Thiagarajan ep_list->ep_list_field)) 53578fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_DISPLAY_STRING_LEN 200 53678fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_LEN 128 53778fc4856SVasanthakumar Thiagarajan 53878fc4856SVasanthakumar Thiagarajan static ssize_t read_file_credit_dist_stats(struct file *file, 53978fc4856SVasanthakumar Thiagarajan char __user *user_buf, 54078fc4856SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 54178fc4856SVasanthakumar Thiagarajan { 54278fc4856SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 54378fc4856SVasanthakumar Thiagarajan struct htc_target *target = ar->htc_target; 54478fc4856SVasanthakumar Thiagarajan struct htc_endpoint_credit_dist *ep_list; 54578fc4856SVasanthakumar Thiagarajan char *buf; 54678fc4856SVasanthakumar Thiagarajan unsigned int buf_len, len = 0; 54778fc4856SVasanthakumar Thiagarajan ssize_t ret_cnt; 54878fc4856SVasanthakumar Thiagarajan 54978fc4856SVasanthakumar Thiagarajan buf_len = CREDIT_INFO_DISPLAY_STRING_LEN + 55078fc4856SVasanthakumar Thiagarajan get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN; 55178fc4856SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 55278fc4856SVasanthakumar Thiagarajan if (!buf) 55378fc4856SVasanthakumar Thiagarajan return -ENOMEM; 55478fc4856SVasanthakumar Thiagarajan 55578fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 55678fc4856SVasanthakumar Thiagarajan "Total Avail Credits: ", 55778fc4856SVasanthakumar Thiagarajan target->cred_dist_cntxt->total_avail_credits); 55878fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 55978fc4856SVasanthakumar Thiagarajan "Free credits :", 56078fc4856SVasanthakumar Thiagarajan target->cred_dist_cntxt->cur_free_credits); 56178fc4856SVasanthakumar Thiagarajan 56278fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 56378fc4856SVasanthakumar Thiagarajan " Epid Flags Cred_norm Cred_min Credits Cred_assngd" 56478fc4856SVasanthakumar Thiagarajan " Seek_cred Cred_sz Cred_per_msg Cred_to_dist" 56578fc4856SVasanthakumar Thiagarajan " qdepth\n"); 56678fc4856SVasanthakumar Thiagarajan 56778fc4856SVasanthakumar Thiagarajan list_for_each_entry(ep_list, &target->cred_dist_list, list) { 56878fc4856SVasanthakumar Thiagarajan print_credit_info(" %2d", endpoint); 56978fc4856SVasanthakumar Thiagarajan print_credit_info("%10x", dist_flags); 57078fc4856SVasanthakumar Thiagarajan print_credit_info("%8d", cred_norm); 57178fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_min); 57278fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", credits); 57378fc4856SVasanthakumar Thiagarajan print_credit_info("%10d", cred_assngd); 57478fc4856SVasanthakumar Thiagarajan print_credit_info("%13d", seek_cred); 57578fc4856SVasanthakumar Thiagarajan print_credit_info("%12d", cred_sz); 57678fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_per_msg); 57778fc4856SVasanthakumar Thiagarajan print_credit_info("%14d", cred_to_dist); 57878fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%12d\n", 57978fc4856SVasanthakumar Thiagarajan get_queue_depth(&((struct htc_endpoint *) 58078fc4856SVasanthakumar Thiagarajan ep_list->htc_rsvd)->txq)); 58178fc4856SVasanthakumar Thiagarajan } 58278fc4856SVasanthakumar Thiagarajan 58378fc4856SVasanthakumar Thiagarajan if (len > buf_len) 58478fc4856SVasanthakumar Thiagarajan len = buf_len; 58578fc4856SVasanthakumar Thiagarajan 58678fc4856SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 58778fc4856SVasanthakumar Thiagarajan kfree(buf); 58878fc4856SVasanthakumar Thiagarajan return ret_cnt; 58978fc4856SVasanthakumar Thiagarajan } 59078fc4856SVasanthakumar Thiagarajan 59178fc4856SVasanthakumar Thiagarajan static const struct file_operations fops_credit_dist_stats = { 59278fc4856SVasanthakumar Thiagarajan .read = read_file_credit_dist_stats, 59378fc4856SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 59478fc4856SVasanthakumar Thiagarajan .owner = THIS_MODULE, 59578fc4856SVasanthakumar Thiagarajan .llseek = default_llseek, 59678fc4856SVasanthakumar Thiagarajan }; 59778fc4856SVasanthakumar Thiagarajan 598*e8091281SJouni Malinen static unsigned int print_endpoint_stat(struct htc_target *target, char *buf, 599*e8091281SJouni Malinen unsigned int buf_len, unsigned int len, 600*e8091281SJouni Malinen int offset, const char *name) 601*e8091281SJouni Malinen { 602*e8091281SJouni Malinen int i; 603*e8091281SJouni Malinen struct htc_endpoint_stats *ep_st; 604*e8091281SJouni Malinen u32 *counter; 605*e8091281SJouni Malinen 606*e8091281SJouni Malinen len += scnprintf(buf + len, buf_len - len, "%s:", name); 607*e8091281SJouni Malinen for (i = 0; i < ENDPOINT_MAX; i++) { 608*e8091281SJouni Malinen ep_st = &target->endpoint[i].ep_st; 609*e8091281SJouni Malinen counter = ((u32 *) ep_st) + (offset / 4); 610*e8091281SJouni Malinen len += scnprintf(buf + len, buf_len - len, " %u", *counter); 611*e8091281SJouni Malinen } 612*e8091281SJouni Malinen len += scnprintf(buf + len, buf_len - len, "\n"); 613*e8091281SJouni Malinen 614*e8091281SJouni Malinen return len; 615*e8091281SJouni Malinen } 616*e8091281SJouni Malinen 617*e8091281SJouni Malinen static ssize_t ath6kl_endpoint_stats_read(struct file *file, 618*e8091281SJouni Malinen char __user *user_buf, 619*e8091281SJouni Malinen size_t count, loff_t *ppos) 620*e8091281SJouni Malinen { 621*e8091281SJouni Malinen struct ath6kl *ar = file->private_data; 622*e8091281SJouni Malinen struct htc_target *target = ar->htc_target; 623*e8091281SJouni Malinen char *buf; 624*e8091281SJouni Malinen unsigned int buf_len, len = 0; 625*e8091281SJouni Malinen ssize_t ret_cnt; 626*e8091281SJouni Malinen 627*e8091281SJouni Malinen buf_len = 1000 + ENDPOINT_MAX * 100; 628*e8091281SJouni Malinen buf = kzalloc(buf_len, GFP_KERNEL); 629*e8091281SJouni Malinen if (!buf) 630*e8091281SJouni Malinen return -ENOMEM; 631*e8091281SJouni Malinen 632*e8091281SJouni Malinen #define EPSTAT(name) \ 633*e8091281SJouni Malinen len = print_endpoint_stat(target, buf, buf_len, len, \ 634*e8091281SJouni Malinen offsetof(struct htc_endpoint_stats, name), \ 635*e8091281SJouni Malinen #name) 636*e8091281SJouni Malinen EPSTAT(cred_low_indicate); 637*e8091281SJouni Malinen EPSTAT(tx_issued); 638*e8091281SJouni Malinen EPSTAT(tx_pkt_bundled); 639*e8091281SJouni Malinen EPSTAT(tx_bundles); 640*e8091281SJouni Malinen EPSTAT(tx_dropped); 641*e8091281SJouni Malinen EPSTAT(tx_cred_rpt); 642*e8091281SJouni Malinen EPSTAT(cred_rpt_from_rx); 643*e8091281SJouni Malinen EPSTAT(cred_rpt_ep0); 644*e8091281SJouni Malinen EPSTAT(cred_from_rx); 645*e8091281SJouni Malinen EPSTAT(cred_from_other); 646*e8091281SJouni Malinen EPSTAT(cred_from_ep0); 647*e8091281SJouni Malinen EPSTAT(cred_cosumd); 648*e8091281SJouni Malinen EPSTAT(cred_retnd); 649*e8091281SJouni Malinen EPSTAT(rx_pkts); 650*e8091281SJouni Malinen EPSTAT(rx_lkahds); 651*e8091281SJouni Malinen EPSTAT(rx_bundl); 652*e8091281SJouni Malinen EPSTAT(rx_bundle_lkahd); 653*e8091281SJouni Malinen EPSTAT(rx_bundle_from_hdr); 654*e8091281SJouni Malinen EPSTAT(rx_alloc_thresh_hit); 655*e8091281SJouni Malinen EPSTAT(rxalloc_thresh_byte); 656*e8091281SJouni Malinen #undef EPSTAT 657*e8091281SJouni Malinen 658*e8091281SJouni Malinen if (len > buf_len) 659*e8091281SJouni Malinen len = buf_len; 660*e8091281SJouni Malinen 661*e8091281SJouni Malinen ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 662*e8091281SJouni Malinen kfree(buf); 663*e8091281SJouni Malinen return ret_cnt; 664*e8091281SJouni Malinen } 665*e8091281SJouni Malinen 666*e8091281SJouni Malinen static ssize_t ath6kl_endpoint_stats_write(struct file *file, 667*e8091281SJouni Malinen const char __user *user_buf, 668*e8091281SJouni Malinen size_t count, loff_t *ppos) 669*e8091281SJouni Malinen { 670*e8091281SJouni Malinen struct ath6kl *ar = file->private_data; 671*e8091281SJouni Malinen struct htc_target *target = ar->htc_target; 672*e8091281SJouni Malinen int ret, i; 673*e8091281SJouni Malinen u32 val; 674*e8091281SJouni Malinen struct htc_endpoint_stats *ep_st; 675*e8091281SJouni Malinen 676*e8091281SJouni Malinen ret = kstrtou32_from_user(user_buf, count, 0, &val); 677*e8091281SJouni Malinen if (ret) 678*e8091281SJouni Malinen return ret; 679*e8091281SJouni Malinen if (val == 0) { 680*e8091281SJouni Malinen for (i = 0; i < ENDPOINT_MAX; i++) { 681*e8091281SJouni Malinen ep_st = &target->endpoint[i].ep_st; 682*e8091281SJouni Malinen memset(ep_st, 0, sizeof(*ep_st)); 683*e8091281SJouni Malinen } 684*e8091281SJouni Malinen } 685*e8091281SJouni Malinen 686*e8091281SJouni Malinen return count; 687*e8091281SJouni Malinen } 688*e8091281SJouni Malinen 689*e8091281SJouni Malinen static const struct file_operations fops_endpoint_stats = { 690*e8091281SJouni Malinen .open = ath6kl_debugfs_open, 691*e8091281SJouni Malinen .read = ath6kl_endpoint_stats_read, 692*e8091281SJouni Malinen .write = ath6kl_endpoint_stats_write, 693*e8091281SJouni Malinen .owner = THIS_MODULE, 694*e8091281SJouni Malinen .llseek = default_llseek, 695*e8091281SJouni Malinen }; 696*e8091281SJouni Malinen 69791d57de5SVasanthakumar Thiagarajan static unsigned long ath6kl_get_num_reg(void) 69891d57de5SVasanthakumar Thiagarajan { 69991d57de5SVasanthakumar Thiagarajan int i; 70091d57de5SVasanthakumar Thiagarajan unsigned long n_reg = 0; 70191d57de5SVasanthakumar Thiagarajan 70291d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) 70391d57de5SVasanthakumar Thiagarajan n_reg = n_reg + 70491d57de5SVasanthakumar Thiagarajan (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1; 70591d57de5SVasanthakumar Thiagarajan 70691d57de5SVasanthakumar Thiagarajan return n_reg; 70791d57de5SVasanthakumar Thiagarajan } 70891d57de5SVasanthakumar Thiagarajan 70991d57de5SVasanthakumar Thiagarajan static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr) 71091d57de5SVasanthakumar Thiagarajan { 71191d57de5SVasanthakumar Thiagarajan int i; 71291d57de5SVasanthakumar Thiagarajan 71391d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { 71491d57de5SVasanthakumar Thiagarajan if (reg_addr >= diag_reg[i].reg_start && 71591d57de5SVasanthakumar Thiagarajan reg_addr <= diag_reg[i].reg_end) 71691d57de5SVasanthakumar Thiagarajan return true; 71791d57de5SVasanthakumar Thiagarajan } 71891d57de5SVasanthakumar Thiagarajan 71991d57de5SVasanthakumar Thiagarajan return false; 72091d57de5SVasanthakumar Thiagarajan } 72191d57de5SVasanthakumar Thiagarajan 72291d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf, 72391d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 72491d57de5SVasanthakumar Thiagarajan { 72591d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 72691d57de5SVasanthakumar Thiagarajan u8 buf[50]; 72791d57de5SVasanthakumar Thiagarajan unsigned int len = 0; 72891d57de5SVasanthakumar Thiagarajan 72991d57de5SVasanthakumar Thiagarajan if (ar->debug.dbgfs_diag_reg) 73091d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", 73191d57de5SVasanthakumar Thiagarajan ar->debug.dbgfs_diag_reg); 73291d57de5SVasanthakumar Thiagarajan else 73391d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, sizeof(buf) - len, 73491d57de5SVasanthakumar Thiagarajan "All diag registers\n"); 73591d57de5SVasanthakumar Thiagarajan 73691d57de5SVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 73791d57de5SVasanthakumar Thiagarajan } 73891d57de5SVasanthakumar Thiagarajan 73991d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regread_write(struct file *file, 74091d57de5SVasanthakumar Thiagarajan const char __user *user_buf, 74191d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 74291d57de5SVasanthakumar Thiagarajan { 74391d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 74491d57de5SVasanthakumar Thiagarajan u8 buf[50]; 74591d57de5SVasanthakumar Thiagarajan unsigned int len; 74691d57de5SVasanthakumar Thiagarajan unsigned long reg_addr; 74791d57de5SVasanthakumar Thiagarajan 74891d57de5SVasanthakumar Thiagarajan len = min(count, sizeof(buf) - 1); 74991d57de5SVasanthakumar Thiagarajan if (copy_from_user(buf, user_buf, len)) 75091d57de5SVasanthakumar Thiagarajan return -EFAULT; 75191d57de5SVasanthakumar Thiagarajan 75291d57de5SVasanthakumar Thiagarajan buf[len] = '\0'; 75391d57de5SVasanthakumar Thiagarajan 75491d57de5SVasanthakumar Thiagarajan if (strict_strtoul(buf, 0, ®_addr)) 75591d57de5SVasanthakumar Thiagarajan return -EINVAL; 75691d57de5SVasanthakumar Thiagarajan 75791d57de5SVasanthakumar Thiagarajan if ((reg_addr % 4) != 0) 75891d57de5SVasanthakumar Thiagarajan return -EINVAL; 75991d57de5SVasanthakumar Thiagarajan 76091d57de5SVasanthakumar Thiagarajan if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr)) 76191d57de5SVasanthakumar Thiagarajan return -EINVAL; 76291d57de5SVasanthakumar Thiagarajan 76391d57de5SVasanthakumar Thiagarajan ar->debug.dbgfs_diag_reg = reg_addr; 76491d57de5SVasanthakumar Thiagarajan 76591d57de5SVasanthakumar Thiagarajan return count; 76691d57de5SVasanthakumar Thiagarajan } 76791d57de5SVasanthakumar Thiagarajan 76891d57de5SVasanthakumar Thiagarajan static const struct file_operations fops_diag_reg_read = { 76991d57de5SVasanthakumar Thiagarajan .read = ath6kl_regread_read, 77091d57de5SVasanthakumar Thiagarajan .write = ath6kl_regread_write, 77191d57de5SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 77291d57de5SVasanthakumar Thiagarajan .owner = THIS_MODULE, 77391d57de5SVasanthakumar Thiagarajan .llseek = default_llseek, 77491d57de5SVasanthakumar Thiagarajan }; 77591d57de5SVasanthakumar Thiagarajan 77691d57de5SVasanthakumar Thiagarajan static int ath6kl_regdump_open(struct inode *inode, struct file *file) 77791d57de5SVasanthakumar Thiagarajan { 77891d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = inode->i_private; 77991d57de5SVasanthakumar Thiagarajan u8 *buf; 78091d57de5SVasanthakumar Thiagarajan unsigned long int reg_len; 78191d57de5SVasanthakumar Thiagarajan unsigned int len = 0, n_reg; 78291d57de5SVasanthakumar Thiagarajan u32 addr; 78391d57de5SVasanthakumar Thiagarajan __le32 reg_val; 78491d57de5SVasanthakumar Thiagarajan int i, status; 78591d57de5SVasanthakumar Thiagarajan 78691d57de5SVasanthakumar Thiagarajan /* Dump all the registers if no register is specified */ 78791d57de5SVasanthakumar Thiagarajan if (!ar->debug.dbgfs_diag_reg) 78891d57de5SVasanthakumar Thiagarajan n_reg = ath6kl_get_num_reg(); 78991d57de5SVasanthakumar Thiagarajan else 79091d57de5SVasanthakumar Thiagarajan n_reg = 1; 79191d57de5SVasanthakumar Thiagarajan 79291d57de5SVasanthakumar Thiagarajan reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE; 79391d57de5SVasanthakumar Thiagarajan if (n_reg > 1) 79491d57de5SVasanthakumar Thiagarajan reg_len += REGTYPE_STR_LEN; 79591d57de5SVasanthakumar Thiagarajan 79691d57de5SVasanthakumar Thiagarajan buf = vmalloc(reg_len); 79791d57de5SVasanthakumar Thiagarajan if (!buf) 79891d57de5SVasanthakumar Thiagarajan return -ENOMEM; 79991d57de5SVasanthakumar Thiagarajan 80091d57de5SVasanthakumar Thiagarajan if (n_reg == 1) { 80191d57de5SVasanthakumar Thiagarajan addr = ar->debug.dbgfs_diag_reg; 80291d57de5SVasanthakumar Thiagarajan 80391d57de5SVasanthakumar Thiagarajan status = ath6kl_diag_read32(ar, 80491d57de5SVasanthakumar Thiagarajan TARG_VTOP(ar->target_type, addr), 80591d57de5SVasanthakumar Thiagarajan (u32 *)®_val); 80691d57de5SVasanthakumar Thiagarajan if (status) 80791d57de5SVasanthakumar Thiagarajan goto fail_reg_read; 80891d57de5SVasanthakumar Thiagarajan 80991d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 81091d57de5SVasanthakumar Thiagarajan "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val)); 81191d57de5SVasanthakumar Thiagarajan goto done; 81291d57de5SVasanthakumar Thiagarajan } 81391d57de5SVasanthakumar Thiagarajan 81491d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { 81591d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 81691d57de5SVasanthakumar Thiagarajan "%s\n", diag_reg[i].reg_info); 81791d57de5SVasanthakumar Thiagarajan for (addr = diag_reg[i].reg_start; 81891d57de5SVasanthakumar Thiagarajan addr <= diag_reg[i].reg_end; addr += 4) { 81991d57de5SVasanthakumar Thiagarajan status = ath6kl_diag_read32(ar, 82091d57de5SVasanthakumar Thiagarajan TARG_VTOP(ar->target_type, addr), 82191d57de5SVasanthakumar Thiagarajan (u32 *)®_val); 82291d57de5SVasanthakumar Thiagarajan if (status) 82391d57de5SVasanthakumar Thiagarajan goto fail_reg_read; 82491d57de5SVasanthakumar Thiagarajan 82591d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 82691d57de5SVasanthakumar Thiagarajan "0x%06x 0x%08x\n", 82791d57de5SVasanthakumar Thiagarajan addr, le32_to_cpu(reg_val)); 82891d57de5SVasanthakumar Thiagarajan } 82991d57de5SVasanthakumar Thiagarajan } 83091d57de5SVasanthakumar Thiagarajan 83191d57de5SVasanthakumar Thiagarajan done: 83291d57de5SVasanthakumar Thiagarajan file->private_data = buf; 83391d57de5SVasanthakumar Thiagarajan return 0; 83491d57de5SVasanthakumar Thiagarajan 83591d57de5SVasanthakumar Thiagarajan fail_reg_read: 83691d57de5SVasanthakumar Thiagarajan ath6kl_warn("Unable to read memory:%u\n", addr); 83791d57de5SVasanthakumar Thiagarajan vfree(buf); 83891d57de5SVasanthakumar Thiagarajan return -EIO; 83991d57de5SVasanthakumar Thiagarajan } 84091d57de5SVasanthakumar Thiagarajan 84191d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf, 84291d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 84391d57de5SVasanthakumar Thiagarajan { 84491d57de5SVasanthakumar Thiagarajan u8 *buf = file->private_data; 84591d57de5SVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 84691d57de5SVasanthakumar Thiagarajan } 84791d57de5SVasanthakumar Thiagarajan 84891d57de5SVasanthakumar Thiagarajan static int ath6kl_regdump_release(struct inode *inode, struct file *file) 84991d57de5SVasanthakumar Thiagarajan { 85091d57de5SVasanthakumar Thiagarajan vfree(file->private_data); 85191d57de5SVasanthakumar Thiagarajan return 0; 85291d57de5SVasanthakumar Thiagarajan } 85391d57de5SVasanthakumar Thiagarajan 85491d57de5SVasanthakumar Thiagarajan static const struct file_operations fops_reg_dump = { 85591d57de5SVasanthakumar Thiagarajan .open = ath6kl_regdump_open, 85691d57de5SVasanthakumar Thiagarajan .read = ath6kl_regdump_read, 85791d57de5SVasanthakumar Thiagarajan .release = ath6kl_regdump_release, 85891d57de5SVasanthakumar Thiagarajan .owner = THIS_MODULE, 85991d57de5SVasanthakumar Thiagarajan .llseek = default_llseek, 86091d57de5SVasanthakumar Thiagarajan }; 86191d57de5SVasanthakumar Thiagarajan 862e5090444SVivek Natarajan static ssize_t ath6kl_lrssi_roam_write(struct file *file, 863e5090444SVivek Natarajan const char __user *user_buf, 864e5090444SVivek Natarajan size_t count, loff_t *ppos) 865e5090444SVivek Natarajan { 866e5090444SVivek Natarajan struct ath6kl *ar = file->private_data; 867e5090444SVivek Natarajan unsigned long lrssi_roam_threshold; 868e5090444SVivek Natarajan char buf[32]; 869e5090444SVivek Natarajan ssize_t len; 870e5090444SVivek Natarajan 871e5090444SVivek Natarajan len = min(count, sizeof(buf) - 1); 872e5090444SVivek Natarajan if (copy_from_user(buf, user_buf, len)) 873e5090444SVivek Natarajan return -EFAULT; 874e5090444SVivek Natarajan 875e5090444SVivek Natarajan buf[len] = '\0'; 876e5090444SVivek Natarajan if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) 877e5090444SVivek Natarajan return -EINVAL; 878e5090444SVivek Natarajan 879e5090444SVivek Natarajan ar->lrssi_roam_threshold = lrssi_roam_threshold; 880e5090444SVivek Natarajan 881e5090444SVivek Natarajan ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold); 882e5090444SVivek Natarajan 883e5090444SVivek Natarajan return count; 884e5090444SVivek Natarajan } 885e5090444SVivek Natarajan 886e5090444SVivek Natarajan static ssize_t ath6kl_lrssi_roam_read(struct file *file, 887e5090444SVivek Natarajan char __user *user_buf, 888e5090444SVivek Natarajan size_t count, loff_t *ppos) 889e5090444SVivek Natarajan { 890e5090444SVivek Natarajan struct ath6kl *ar = file->private_data; 891e5090444SVivek Natarajan char buf[32]; 892e5090444SVivek Natarajan unsigned int len; 893e5090444SVivek Natarajan 894e5090444SVivek Natarajan len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold); 895e5090444SVivek Natarajan 896e5090444SVivek Natarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 897e5090444SVivek Natarajan } 898e5090444SVivek Natarajan 899e5090444SVivek Natarajan static const struct file_operations fops_lrssi_roam_threshold = { 900e5090444SVivek Natarajan .read = ath6kl_lrssi_roam_read, 901e5090444SVivek Natarajan .write = ath6kl_lrssi_roam_write, 902e5090444SVivek Natarajan .open = ath6kl_debugfs_open, 903e5090444SVivek Natarajan .owner = THIS_MODULE, 904e5090444SVivek Natarajan .llseek = default_llseek, 905e5090444SVivek Natarajan }; 906e5090444SVivek Natarajan 907252c068bSVasanthakumar Thiagarajan static ssize_t ath6kl_regwrite_read(struct file *file, 908252c068bSVasanthakumar Thiagarajan char __user *user_buf, 909252c068bSVasanthakumar Thiagarajan size_t count, loff_t *ppos) 910252c068bSVasanthakumar Thiagarajan { 911252c068bSVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 912252c068bSVasanthakumar Thiagarajan u8 buf[32]; 913252c068bSVasanthakumar Thiagarajan unsigned int len = 0; 914252c068bSVasanthakumar Thiagarajan 915252c068bSVasanthakumar Thiagarajan len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n", 916252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr); 917252c068bSVasanthakumar Thiagarajan 918252c068bSVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 919252c068bSVasanthakumar Thiagarajan } 920252c068bSVasanthakumar Thiagarajan 921252c068bSVasanthakumar Thiagarajan static ssize_t ath6kl_regwrite_write(struct file *file, 922252c068bSVasanthakumar Thiagarajan const char __user *user_buf, 923252c068bSVasanthakumar Thiagarajan size_t count, loff_t *ppos) 924252c068bSVasanthakumar Thiagarajan { 925252c068bSVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 926252c068bSVasanthakumar Thiagarajan char buf[32]; 927252c068bSVasanthakumar Thiagarajan char *sptr, *token; 928252c068bSVasanthakumar Thiagarajan unsigned int len = 0; 929252c068bSVasanthakumar Thiagarajan u32 reg_addr, reg_val; 930252c068bSVasanthakumar Thiagarajan 931252c068bSVasanthakumar Thiagarajan len = min(count, sizeof(buf) - 1); 932252c068bSVasanthakumar Thiagarajan if (copy_from_user(buf, user_buf, len)) 933252c068bSVasanthakumar Thiagarajan return -EFAULT; 934252c068bSVasanthakumar Thiagarajan 935252c068bSVasanthakumar Thiagarajan buf[len] = '\0'; 936252c068bSVasanthakumar Thiagarajan sptr = buf; 937252c068bSVasanthakumar Thiagarajan 938252c068bSVasanthakumar Thiagarajan token = strsep(&sptr, "="); 939252c068bSVasanthakumar Thiagarajan if (!token) 940252c068bSVasanthakumar Thiagarajan return -EINVAL; 941252c068bSVasanthakumar Thiagarajan 942252c068bSVasanthakumar Thiagarajan if (kstrtou32(token, 0, ®_addr)) 943252c068bSVasanthakumar Thiagarajan return -EINVAL; 944252c068bSVasanthakumar Thiagarajan 945252c068bSVasanthakumar Thiagarajan if (!ath6kl_dbg_is_diag_reg_valid(reg_addr)) 946252c068bSVasanthakumar Thiagarajan return -EINVAL; 947252c068bSVasanthakumar Thiagarajan 948252c068bSVasanthakumar Thiagarajan if (kstrtou32(sptr, 0, ®_val)) 949252c068bSVasanthakumar Thiagarajan return -EINVAL; 950252c068bSVasanthakumar Thiagarajan 951252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_addr_wr = reg_addr; 952252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_val_wr = reg_val; 953252c068bSVasanthakumar Thiagarajan 954252c068bSVasanthakumar Thiagarajan if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr, 955252c068bSVasanthakumar Thiagarajan cpu_to_le32(ar->debug.diag_reg_val_wr))) 956252c068bSVasanthakumar Thiagarajan return -EIO; 957252c068bSVasanthakumar Thiagarajan 958252c068bSVasanthakumar Thiagarajan return count; 959252c068bSVasanthakumar Thiagarajan } 960252c068bSVasanthakumar Thiagarajan 961252c068bSVasanthakumar Thiagarajan static const struct file_operations fops_diag_reg_write = { 962252c068bSVasanthakumar Thiagarajan .read = ath6kl_regwrite_read, 963252c068bSVasanthakumar Thiagarajan .write = ath6kl_regwrite_write, 964252c068bSVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 965252c068bSVasanthakumar Thiagarajan .owner = THIS_MODULE, 966252c068bSVasanthakumar Thiagarajan .llseek = default_llseek, 967252c068bSVasanthakumar Thiagarajan }; 968252c068bSVasanthakumar Thiagarajan 969d999ba3eSVasanthakumar Thiagarajan int ath6kl_debug_init(struct ath6kl *ar) 970d999ba3eSVasanthakumar Thiagarajan { 971bdf5396bSKalle Valo ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); 972bdf5396bSKalle Valo if (ar->debug.fwlog_buf.buf == NULL) 973bdf5396bSKalle Valo return -ENOMEM; 974bdf5396bSKalle Valo 975bdf5396bSKalle Valo ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); 976bdf5396bSKalle Valo if (ar->debug.fwlog_tmp == NULL) { 977bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 978bdf5396bSKalle Valo return -ENOMEM; 979bdf5396bSKalle Valo } 980bdf5396bSKalle Valo 981bdf5396bSKalle Valo spin_lock_init(&ar->debug.fwlog_lock); 982bdf5396bSKalle Valo 983939f1cceSKalle Valo /* 984939f1cceSKalle Valo * Actually we are lying here but don't know how to read the mask 985939f1cceSKalle Valo * value from the firmware. 986939f1cceSKalle Valo */ 987939f1cceSKalle Valo ar->debug.fwlog_mask = 0; 988939f1cceSKalle Valo 989d999ba3eSVasanthakumar Thiagarajan ar->debugfs_phy = debugfs_create_dir("ath6kl", 990d999ba3eSVasanthakumar Thiagarajan ar->wdev->wiphy->debugfsdir); 991bdf5396bSKalle Valo if (!ar->debugfs_phy) { 992bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 993bdf5396bSKalle Valo kfree(ar->debug.fwlog_tmp); 994d999ba3eSVasanthakumar Thiagarajan return -ENOMEM; 995bdf5396bSKalle Valo } 996d999ba3eSVasanthakumar Thiagarajan 99703f68a95SVasanthakumar Thiagarajan debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, 99803f68a95SVasanthakumar Thiagarajan &fops_tgt_stats); 99903f68a95SVasanthakumar Thiagarajan 100078fc4856SVasanthakumar Thiagarajan debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar, 100178fc4856SVasanthakumar Thiagarajan &fops_credit_dist_stats); 100278fc4856SVasanthakumar Thiagarajan 1003*e8091281SJouni Malinen debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR, 1004*e8091281SJouni Malinen ar->debugfs_phy, ar, &fops_endpoint_stats); 1005*e8091281SJouni Malinen 1006bdf5396bSKalle Valo debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, 1007bdf5396bSKalle Valo &fops_fwlog); 1008bdf5396bSKalle Valo 1009939f1cceSKalle Valo debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, 1010939f1cceSKalle Valo ar, &fops_fwlog_mask); 1011939f1cceSKalle Valo 101291d57de5SVasanthakumar Thiagarajan debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, 101391d57de5SVasanthakumar Thiagarajan &fops_diag_reg_read); 101491d57de5SVasanthakumar Thiagarajan 101591d57de5SVasanthakumar Thiagarajan debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, 101691d57de5SVasanthakumar Thiagarajan &fops_reg_dump); 101791d57de5SVasanthakumar Thiagarajan 1018e5090444SVivek Natarajan debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, 1019e5090444SVivek Natarajan ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); 1020252c068bSVasanthakumar Thiagarajan 1021252c068bSVasanthakumar Thiagarajan debugfs_create_file("reg_write", S_IRUSR | S_IWUSR, 1022252c068bSVasanthakumar Thiagarajan ar->debugfs_phy, ar, &fops_diag_reg_write); 1023252c068bSVasanthakumar Thiagarajan 10249a730834SKalle Valo debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar, 10259a730834SKalle Valo &fops_war_stats); 10269a730834SKalle Valo 1027d999ba3eSVasanthakumar Thiagarajan return 0; 1028d999ba3eSVasanthakumar Thiagarajan } 1029bdf5396bSKalle Valo 1030bdf5396bSKalle Valo void ath6kl_debug_cleanup(struct ath6kl *ar) 1031bdf5396bSKalle Valo { 1032bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 1033bdf5396bSKalle Valo kfree(ar->debug.fwlog_tmp); 1034bdf5396bSKalle Valo } 1035bdf5396bSKalle Valo 1036bdcd8170SKalle Valo #endif 1037