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> 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) 36939f1cceSKalle 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 5791d57de5SVasanthakumar Thiagarajan 5891d57de5SVasanthakumar Thiagarajan #define REG_OUTPUT_LEN_PER_LINE 25 5991d57de5SVasanthakumar Thiagarajan #define REGTYPE_STR_LEN 100 6091d57de5SVasanthakumar Thiagarajan 6191d57de5SVasanthakumar Thiagarajan struct ath6kl_diag_reg_info { 6291d57de5SVasanthakumar Thiagarajan u32 reg_start; 6391d57de5SVasanthakumar Thiagarajan u32 reg_end; 6491d57de5SVasanthakumar Thiagarajan const char *reg_info; 6591d57de5SVasanthakumar Thiagarajan }; 6691d57de5SVasanthakumar Thiagarajan 6791d57de5SVasanthakumar Thiagarajan static const struct ath6kl_diag_reg_info diag_reg[] = { 6891d57de5SVasanthakumar Thiagarajan { 0x20000, 0x200fc, "General DMA and Rx registers" }, 6991d57de5SVasanthakumar Thiagarajan { 0x28000, 0x28900, "MAC PCU register & keycache" }, 7091d57de5SVasanthakumar Thiagarajan { 0x20800, 0x20a40, "QCU" }, 7191d57de5SVasanthakumar Thiagarajan { 0x21000, 0x212f0, "DCU" }, 7291d57de5SVasanthakumar Thiagarajan { 0x4000, 0x42e4, "RTC" }, 7391d57de5SVasanthakumar Thiagarajan { 0x540000, 0x540000 + (256 * 1024), "RAM" }, 7491d57de5SVasanthakumar Thiagarajan { 0x29800, 0x2B210, "Base Band" }, 7591d57de5SVasanthakumar Thiagarajan { 0x1C000, 0x1C748, "Analog" }, 7691d57de5SVasanthakumar Thiagarajan }; 7791d57de5SVasanthakumar Thiagarajan 78bdcd8170SKalle Valo void ath6kl_dump_registers(struct ath6kl_device *dev, 79bdcd8170SKalle Valo struct ath6kl_irq_proc_registers *irq_proc_reg, 80bdcd8170SKalle Valo struct ath6kl_irq_enable_reg *irq_enable_reg) 81bdcd8170SKalle Valo { 82bdcd8170SKalle Valo 83bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); 84bdcd8170SKalle Valo 85bdcd8170SKalle Valo if (irq_proc_reg != NULL) { 86bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 87bdcd8170SKalle Valo "Host Int status: 0x%x\n", 88bdcd8170SKalle Valo irq_proc_reg->host_int_status); 89bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 90bdcd8170SKalle Valo "CPU Int status: 0x%x\n", 91bdcd8170SKalle Valo irq_proc_reg->cpu_int_status); 92bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 93bdcd8170SKalle Valo "Error Int status: 0x%x\n", 94bdcd8170SKalle Valo irq_proc_reg->error_int_status); 95bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 96bdcd8170SKalle Valo "Counter Int status: 0x%x\n", 97bdcd8170SKalle Valo irq_proc_reg->counter_int_status); 98bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 99bdcd8170SKalle Valo "Mbox Frame: 0x%x\n", 100bdcd8170SKalle Valo irq_proc_reg->mbox_frame); 101bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 102bdcd8170SKalle Valo "Rx Lookahead Valid: 0x%x\n", 103bdcd8170SKalle Valo irq_proc_reg->rx_lkahd_valid); 104bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 105bdcd8170SKalle Valo "Rx Lookahead 0: 0x%x\n", 106bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[0]); 107bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 108bdcd8170SKalle Valo "Rx Lookahead 1: 0x%x\n", 109bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[1]); 110bdcd8170SKalle Valo 111bdcd8170SKalle Valo if (dev->ar->mbox_info.gmbox_addr != 0) { 112bdcd8170SKalle Valo /* 113bdcd8170SKalle Valo * If the target supports GMBOX hardware, dump some 114bdcd8170SKalle Valo * additional state. 115bdcd8170SKalle Valo */ 116bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 117bdcd8170SKalle Valo "GMBOX Host Int status 2: 0x%x\n", 118bdcd8170SKalle Valo irq_proc_reg->host_int_status2); 119bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 120bdcd8170SKalle Valo "GMBOX RX Avail: 0x%x\n", 121bdcd8170SKalle Valo irq_proc_reg->gmbox_rx_avail); 122bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 123bdcd8170SKalle Valo "GMBOX lookahead alias 0: 0x%x\n", 124bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[0]); 125bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 126bdcd8170SKalle Valo "GMBOX lookahead alias 1: 0x%x\n", 127bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[1]); 128bdcd8170SKalle Valo } 129bdcd8170SKalle Valo 130bdcd8170SKalle Valo } 131bdcd8170SKalle Valo 132bdcd8170SKalle Valo if (irq_enable_reg != NULL) { 133bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 134bdcd8170SKalle Valo "Int status Enable: 0x%x\n", 135bdcd8170SKalle Valo irq_enable_reg->int_status_en); 136bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", 137bdcd8170SKalle Valo irq_enable_reg->cntr_int_status_en); 138bdcd8170SKalle Valo } 139bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); 140bdcd8170SKalle Valo } 141bdcd8170SKalle Valo 142bdcd8170SKalle Valo static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) 143bdcd8170SKalle Valo { 144bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 145bdcd8170SKalle Valo "--- endpoint: %d svc_id: 0x%X ---\n", 146bdcd8170SKalle Valo ep_dist->endpoint, ep_dist->svc_id); 147bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n", 148bdcd8170SKalle Valo ep_dist->dist_flags); 149bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n", 150bdcd8170SKalle Valo ep_dist->cred_norm); 151bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n", 152bdcd8170SKalle Valo ep_dist->cred_min); 153bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n", 154bdcd8170SKalle Valo ep_dist->credits); 155bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n", 156bdcd8170SKalle Valo ep_dist->cred_assngd); 157bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n", 158bdcd8170SKalle Valo ep_dist->seek_cred); 159bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n", 160bdcd8170SKalle Valo ep_dist->cred_sz); 161bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n", 162bdcd8170SKalle Valo ep_dist->cred_per_msg); 163bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n", 164bdcd8170SKalle Valo ep_dist->cred_to_dist); 165bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n", 166bdcd8170SKalle Valo get_queue_depth(&((struct htc_endpoint *) 167bdcd8170SKalle Valo ep_dist->htc_rsvd)->txq)); 168bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_ANY, 169bdcd8170SKalle Valo "----------------------------------\n"); 170bdcd8170SKalle Valo } 171bdcd8170SKalle Valo 172bdcd8170SKalle Valo void dump_cred_dist_stats(struct htc_target *target) 173bdcd8170SKalle Valo { 174bdcd8170SKalle Valo struct htc_endpoint_credit_dist *ep_list; 175bdcd8170SKalle Valo 176bdcd8170SKalle Valo if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC)) 177bdcd8170SKalle Valo return; 178bdcd8170SKalle Valo 179bdcd8170SKalle Valo list_for_each_entry(ep_list, &target->cred_dist_list, list) 180bdcd8170SKalle Valo dump_cred_dist(ep_list); 181bdcd8170SKalle Valo 182bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n", 183bdcd8170SKalle Valo target->cred_dist_cntxt, NULL); 184bdcd8170SKalle Valo ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n", 185bdcd8170SKalle Valo target->cred_dist_cntxt->total_avail_credits, 186bdcd8170SKalle Valo target->cred_dist_cntxt->cur_free_credits); 187bdcd8170SKalle Valo } 188bdcd8170SKalle Valo 18903f68a95SVasanthakumar Thiagarajan static int ath6kl_debugfs_open(struct inode *inode, struct file *file) 19003f68a95SVasanthakumar Thiagarajan { 19103f68a95SVasanthakumar Thiagarajan file->private_data = inode->i_private; 19203f68a95SVasanthakumar Thiagarajan return 0; 19303f68a95SVasanthakumar Thiagarajan } 19403f68a95SVasanthakumar Thiagarajan 195bdf5396bSKalle Valo static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, 196bdf5396bSKalle Valo size_t buf_len) 197bdf5396bSKalle Valo { 198bdf5396bSKalle Valo struct circ_buf *fwlog = &ar->debug.fwlog_buf; 199bdf5396bSKalle Valo size_t space; 200bdf5396bSKalle Valo int i; 201bdf5396bSKalle Valo 202bdf5396bSKalle Valo /* entries must all be equal size */ 203bdf5396bSKalle Valo if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) 204bdf5396bSKalle Valo return; 205bdf5396bSKalle Valo 206bdf5396bSKalle Valo space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); 207bdf5396bSKalle Valo if (space < buf_len) 208bdf5396bSKalle Valo /* discard oldest slot */ 209bdf5396bSKalle Valo fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & 210bdf5396bSKalle Valo (ATH6KL_FWLOG_SIZE - 1); 211bdf5396bSKalle Valo 212bdf5396bSKalle Valo for (i = 0; i < buf_len; i += space) { 213bdf5396bSKalle Valo space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, 214bdf5396bSKalle Valo ATH6KL_FWLOG_SIZE); 215bdf5396bSKalle Valo 216bdf5396bSKalle Valo if ((size_t) space > buf_len - i) 217bdf5396bSKalle Valo space = buf_len - i; 218bdf5396bSKalle Valo 219bdf5396bSKalle Valo memcpy(&fwlog->buf[fwlog->head], buf, space); 220bdf5396bSKalle Valo fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); 221bdf5396bSKalle Valo } 222bdf5396bSKalle Valo 223bdf5396bSKalle Valo } 224bdf5396bSKalle Valo 225bdf5396bSKalle Valo void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) 226bdf5396bSKalle Valo { 227bdf5396bSKalle Valo struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; 228bdf5396bSKalle Valo size_t slot_len; 229bdf5396bSKalle Valo 230bdf5396bSKalle Valo if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) 231bdf5396bSKalle Valo return; 232bdf5396bSKalle Valo 233bdf5396bSKalle Valo spin_lock_bh(&ar->debug.fwlog_lock); 234bdf5396bSKalle Valo 235bdf5396bSKalle Valo slot->timestamp = cpu_to_le32(jiffies); 236bdf5396bSKalle Valo slot->length = cpu_to_le32(len); 237bdf5396bSKalle Valo memcpy(slot->payload, buf, len); 238bdf5396bSKalle Valo 239bdf5396bSKalle Valo slot_len = sizeof(*slot) + len; 240bdf5396bSKalle Valo 241bdf5396bSKalle Valo if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) 242bdf5396bSKalle Valo memset(slot->payload + len, 0, 243bdf5396bSKalle Valo ATH6KL_FWLOG_SLOT_SIZE - slot_len); 244bdf5396bSKalle Valo 245bdf5396bSKalle Valo ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); 246bdf5396bSKalle Valo 247bdf5396bSKalle Valo spin_unlock_bh(&ar->debug.fwlog_lock); 248bdf5396bSKalle Valo } 249bdf5396bSKalle Valo 250bdf5396bSKalle Valo static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) 251bdf5396bSKalle Valo { 252bdf5396bSKalle Valo return CIRC_CNT(ar->debug.fwlog_buf.head, 253bdf5396bSKalle Valo ar->debug.fwlog_buf.tail, 254bdf5396bSKalle Valo ATH6KL_FWLOG_SLOT_SIZE) == 0; 255bdf5396bSKalle Valo } 256bdf5396bSKalle Valo 257bdf5396bSKalle Valo static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, 258bdf5396bSKalle Valo size_t count, loff_t *ppos) 259bdf5396bSKalle Valo { 260bdf5396bSKalle Valo struct ath6kl *ar = file->private_data; 261bdf5396bSKalle Valo struct circ_buf *fwlog = &ar->debug.fwlog_buf; 262bdf5396bSKalle Valo size_t len = 0, buf_len = count; 263bdf5396bSKalle Valo ssize_t ret_cnt; 264bdf5396bSKalle Valo char *buf; 265bdf5396bSKalle Valo int ccnt; 266bdf5396bSKalle Valo 267bdf5396bSKalle Valo buf = vmalloc(buf_len); 268bdf5396bSKalle Valo if (!buf) 269bdf5396bSKalle Valo return -ENOMEM; 270bdf5396bSKalle Valo 271bc07ddb2SKalle Valo /* read undelivered logs from firmware */ 272bc07ddb2SKalle Valo ath6kl_read_fwlogs(ar); 273bc07ddb2SKalle Valo 274bdf5396bSKalle Valo spin_lock_bh(&ar->debug.fwlog_lock); 275bdf5396bSKalle Valo 276bdf5396bSKalle Valo while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { 277bdf5396bSKalle Valo ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, 278bdf5396bSKalle Valo ATH6KL_FWLOG_SIZE); 279bdf5396bSKalle Valo 280bdf5396bSKalle Valo if ((size_t) ccnt > buf_len - len) 281bdf5396bSKalle Valo ccnt = buf_len - len; 282bdf5396bSKalle Valo 283bdf5396bSKalle Valo memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); 284bdf5396bSKalle Valo len += ccnt; 285bdf5396bSKalle Valo 286bdf5396bSKalle Valo fwlog->tail = (fwlog->tail + ccnt) & 287bdf5396bSKalle Valo (ATH6KL_FWLOG_SIZE - 1); 288bdf5396bSKalle Valo } 289bdf5396bSKalle Valo 290bdf5396bSKalle Valo spin_unlock_bh(&ar->debug.fwlog_lock); 291bdf5396bSKalle Valo 292bdf5396bSKalle Valo if (WARN_ON(len > buf_len)) 293bdf5396bSKalle Valo len = buf_len; 294bdf5396bSKalle Valo 295bdf5396bSKalle Valo ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 296bdf5396bSKalle Valo 297bdf5396bSKalle Valo vfree(buf); 298bdf5396bSKalle Valo 299bdf5396bSKalle Valo return ret_cnt; 300bdf5396bSKalle Valo } 301bdf5396bSKalle Valo 302bdf5396bSKalle Valo static const struct file_operations fops_fwlog = { 303bdf5396bSKalle Valo .open = ath6kl_debugfs_open, 304bdf5396bSKalle Valo .read = ath6kl_fwlog_read, 305bdf5396bSKalle Valo .owner = THIS_MODULE, 306bdf5396bSKalle Valo .llseek = default_llseek, 307bdf5396bSKalle Valo }; 308bdf5396bSKalle Valo 309939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, 310939f1cceSKalle Valo size_t count, loff_t *ppos) 311939f1cceSKalle Valo { 312939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 313939f1cceSKalle Valo char buf[16]; 314939f1cceSKalle Valo int len; 315939f1cceSKalle Valo 316939f1cceSKalle Valo len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); 317939f1cceSKalle Valo 318939f1cceSKalle Valo return simple_read_from_buffer(user_buf, count, ppos, buf, len); 319939f1cceSKalle Valo } 320939f1cceSKalle Valo 321939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_write(struct file *file, 322939f1cceSKalle Valo const char __user *user_buf, 323939f1cceSKalle Valo size_t count, loff_t *ppos) 324939f1cceSKalle Valo { 325939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 326939f1cceSKalle Valo int ret; 327939f1cceSKalle Valo 328939f1cceSKalle Valo ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); 329939f1cceSKalle Valo if (ret) 330939f1cceSKalle Valo return ret; 331939f1cceSKalle Valo 332939f1cceSKalle Valo ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, 333939f1cceSKalle Valo ATH6KL_FWLOG_VALID_MASK, 334939f1cceSKalle Valo ar->debug.fwlog_mask); 335939f1cceSKalle Valo if (ret) 336939f1cceSKalle Valo return ret; 337939f1cceSKalle Valo 338939f1cceSKalle Valo return count; 339939f1cceSKalle Valo } 340939f1cceSKalle Valo 341939f1cceSKalle Valo static const struct file_operations fops_fwlog_mask = { 342939f1cceSKalle Valo .open = ath6kl_debugfs_open, 343939f1cceSKalle Valo .read = ath6kl_fwlog_mask_read, 344939f1cceSKalle Valo .write = ath6kl_fwlog_mask_write, 345939f1cceSKalle Valo .owner = THIS_MODULE, 346939f1cceSKalle Valo .llseek = default_llseek, 347939f1cceSKalle Valo }; 348939f1cceSKalle Valo 34903f68a95SVasanthakumar Thiagarajan static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, 35003f68a95SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 35103f68a95SVasanthakumar Thiagarajan { 35203f68a95SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 35303f68a95SVasanthakumar Thiagarajan struct target_stats *tgt_stats = &ar->target_stats; 35403f68a95SVasanthakumar Thiagarajan char *buf; 35503f68a95SVasanthakumar Thiagarajan unsigned int len = 0, buf_len = 1500; 35603f68a95SVasanthakumar Thiagarajan int i; 35703f68a95SVasanthakumar Thiagarajan long left; 35803f68a95SVasanthakumar Thiagarajan ssize_t ret_cnt; 35903f68a95SVasanthakumar Thiagarajan 36003f68a95SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 36103f68a95SVasanthakumar Thiagarajan if (!buf) 36203f68a95SVasanthakumar Thiagarajan return -ENOMEM; 36303f68a95SVasanthakumar Thiagarajan 36403f68a95SVasanthakumar Thiagarajan if (down_interruptible(&ar->sem)) { 36503f68a95SVasanthakumar Thiagarajan kfree(buf); 36603f68a95SVasanthakumar Thiagarajan return -EBUSY; 36703f68a95SVasanthakumar Thiagarajan } 36803f68a95SVasanthakumar Thiagarajan 36903f68a95SVasanthakumar Thiagarajan set_bit(STATS_UPDATE_PEND, &ar->flag); 37003f68a95SVasanthakumar Thiagarajan 37103f68a95SVasanthakumar Thiagarajan if (ath6kl_wmi_get_stats_cmd(ar->wmi)) { 37203f68a95SVasanthakumar Thiagarajan up(&ar->sem); 37303f68a95SVasanthakumar Thiagarajan kfree(buf); 37403f68a95SVasanthakumar Thiagarajan return -EIO; 37503f68a95SVasanthakumar Thiagarajan } 37603f68a95SVasanthakumar Thiagarajan 37703f68a95SVasanthakumar Thiagarajan left = wait_event_interruptible_timeout(ar->event_wq, 37803f68a95SVasanthakumar Thiagarajan !test_bit(STATS_UPDATE_PEND, 37903f68a95SVasanthakumar Thiagarajan &ar->flag), WMI_TIMEOUT); 38003f68a95SVasanthakumar Thiagarajan 38103f68a95SVasanthakumar Thiagarajan up(&ar->sem); 38203f68a95SVasanthakumar Thiagarajan 38303f68a95SVasanthakumar Thiagarajan if (left <= 0) { 38403f68a95SVasanthakumar Thiagarajan kfree(buf); 38503f68a95SVasanthakumar Thiagarajan return -ETIMEDOUT; 38603f68a95SVasanthakumar Thiagarajan } 38703f68a95SVasanthakumar Thiagarajan 38803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "\n"); 38903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 39003f68a95SVasanthakumar Thiagarajan "Target Tx stats"); 39103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n\n", 39203f68a95SVasanthakumar Thiagarajan "================="); 39303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 39403f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->tx_ucast_pkt); 39503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 39603f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->tx_bcast_pkt); 39703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 39803f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->tx_ucast_byte); 39903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 40003f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->tx_bcast_byte); 40103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 40203f68a95SVasanthakumar Thiagarajan "Rts success cnt", tgt_stats->tx_rts_success_cnt); 40303f68a95SVasanthakumar Thiagarajan for (i = 0; i < 4; i++) 40403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 40503f68a95SVasanthakumar Thiagarajan "%18s %d %10llu\n", "PER on ac", 40603f68a95SVasanthakumar Thiagarajan i, tgt_stats->tx_pkt_per_ac[i]); 40703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 40803f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->tx_err); 40903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41003f68a95SVasanthakumar Thiagarajan "Fail count", tgt_stats->tx_fail_cnt); 41103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41203f68a95SVasanthakumar Thiagarajan "Retry count", tgt_stats->tx_retry_cnt); 41303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41403f68a95SVasanthakumar Thiagarajan "Multi retry cnt", tgt_stats->tx_mult_retry_cnt); 41503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 41603f68a95SVasanthakumar Thiagarajan "Rts fail cnt", tgt_stats->tx_rts_fail_cnt); 41703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n", 41803f68a95SVasanthakumar Thiagarajan "TKIP counter measure used", 41903f68a95SVasanthakumar Thiagarajan tgt_stats->tkip_cnter_measures_invoked); 42003f68a95SVasanthakumar Thiagarajan 42103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 42203f68a95SVasanthakumar Thiagarajan "Target Rx stats"); 42303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 42403f68a95SVasanthakumar Thiagarajan "================="); 42503f68a95SVasanthakumar Thiagarajan 42603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 42703f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->rx_ucast_pkt); 42803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 42903f68a95SVasanthakumar Thiagarajan "Ucast Rate", tgt_stats->rx_ucast_rate); 43003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 43103f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->rx_bcast_pkt); 43203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 43303f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->rx_ucast_byte); 43403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 43503f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->rx_bcast_byte); 43603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 43703f68a95SVasanthakumar Thiagarajan "Fragmented pkt", tgt_stats->rx_frgment_pkt); 43803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 43903f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->rx_err); 44003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44103f68a95SVasanthakumar Thiagarajan "CRC Err", tgt_stats->rx_crc_err); 44203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44303f68a95SVasanthakumar Thiagarajan "Key chache miss", tgt_stats->rx_key_cache_miss); 44403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44503f68a95SVasanthakumar Thiagarajan "Decrypt Err", tgt_stats->rx_decrypt_err); 44603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44703f68a95SVasanthakumar Thiagarajan "Duplicate frame", tgt_stats->rx_dupl_frame); 44803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 44903f68a95SVasanthakumar Thiagarajan "Tkip Mic failure", tgt_stats->tkip_local_mic_fail); 45003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 45103f68a95SVasanthakumar Thiagarajan "TKIP format err", tgt_stats->tkip_fmt_err); 45203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 45303f68a95SVasanthakumar Thiagarajan "CCMP format Err", tgt_stats->ccmp_fmt_err); 45403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n", 45503f68a95SVasanthakumar Thiagarajan "CCMP Replay Err", tgt_stats->ccmp_replays); 45603f68a95SVasanthakumar Thiagarajan 45703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 45803f68a95SVasanthakumar Thiagarajan "Misc Target stats"); 45903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 46003f68a95SVasanthakumar Thiagarajan "================="); 46103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 46203f68a95SVasanthakumar Thiagarajan "Beacon Miss count", tgt_stats->cs_bmiss_cnt); 46303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 46403f68a95SVasanthakumar Thiagarajan "Num Connects", tgt_stats->cs_connect_cnt); 46503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 46603f68a95SVasanthakumar Thiagarajan "Num disconnects", tgt_stats->cs_discon_cnt); 46703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 46803f68a95SVasanthakumar Thiagarajan "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); 46903f68a95SVasanthakumar Thiagarajan 47003f68a95SVasanthakumar Thiagarajan if (len > buf_len) 47103f68a95SVasanthakumar Thiagarajan len = buf_len; 47203f68a95SVasanthakumar Thiagarajan 47303f68a95SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 47403f68a95SVasanthakumar Thiagarajan 47503f68a95SVasanthakumar Thiagarajan kfree(buf); 47603f68a95SVasanthakumar Thiagarajan return ret_cnt; 47703f68a95SVasanthakumar Thiagarajan } 47803f68a95SVasanthakumar Thiagarajan 47903f68a95SVasanthakumar Thiagarajan static const struct file_operations fops_tgt_stats = { 48003f68a95SVasanthakumar Thiagarajan .read = read_file_tgt_stats, 48103f68a95SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 48203f68a95SVasanthakumar Thiagarajan .owner = THIS_MODULE, 48303f68a95SVasanthakumar Thiagarajan .llseek = default_llseek, 48403f68a95SVasanthakumar Thiagarajan }; 48503f68a95SVasanthakumar Thiagarajan 48678fc4856SVasanthakumar Thiagarajan #define print_credit_info(fmt_str, ep_list_field) \ 48778fc4856SVasanthakumar Thiagarajan (len += scnprintf(buf + len, buf_len - len, fmt_str, \ 48878fc4856SVasanthakumar Thiagarajan ep_list->ep_list_field)) 48978fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_DISPLAY_STRING_LEN 200 49078fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_LEN 128 49178fc4856SVasanthakumar Thiagarajan 49278fc4856SVasanthakumar Thiagarajan static ssize_t read_file_credit_dist_stats(struct file *file, 49378fc4856SVasanthakumar Thiagarajan char __user *user_buf, 49478fc4856SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 49578fc4856SVasanthakumar Thiagarajan { 49678fc4856SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 49778fc4856SVasanthakumar Thiagarajan struct htc_target *target = ar->htc_target; 49878fc4856SVasanthakumar Thiagarajan struct htc_endpoint_credit_dist *ep_list; 49978fc4856SVasanthakumar Thiagarajan char *buf; 50078fc4856SVasanthakumar Thiagarajan unsigned int buf_len, len = 0; 50178fc4856SVasanthakumar Thiagarajan ssize_t ret_cnt; 50278fc4856SVasanthakumar Thiagarajan 50378fc4856SVasanthakumar Thiagarajan buf_len = CREDIT_INFO_DISPLAY_STRING_LEN + 50478fc4856SVasanthakumar Thiagarajan get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN; 50578fc4856SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 50678fc4856SVasanthakumar Thiagarajan if (!buf) 50778fc4856SVasanthakumar Thiagarajan return -ENOMEM; 50878fc4856SVasanthakumar Thiagarajan 50978fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 51078fc4856SVasanthakumar Thiagarajan "Total Avail Credits: ", 51178fc4856SVasanthakumar Thiagarajan target->cred_dist_cntxt->total_avail_credits); 51278fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 51378fc4856SVasanthakumar Thiagarajan "Free credits :", 51478fc4856SVasanthakumar Thiagarajan target->cred_dist_cntxt->cur_free_credits); 51578fc4856SVasanthakumar Thiagarajan 51678fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 51778fc4856SVasanthakumar Thiagarajan " Epid Flags Cred_norm Cred_min Credits Cred_assngd" 51878fc4856SVasanthakumar Thiagarajan " Seek_cred Cred_sz Cred_per_msg Cred_to_dist" 51978fc4856SVasanthakumar Thiagarajan " qdepth\n"); 52078fc4856SVasanthakumar Thiagarajan 52178fc4856SVasanthakumar Thiagarajan list_for_each_entry(ep_list, &target->cred_dist_list, list) { 52278fc4856SVasanthakumar Thiagarajan print_credit_info(" %2d", endpoint); 52378fc4856SVasanthakumar Thiagarajan print_credit_info("%10x", dist_flags); 52478fc4856SVasanthakumar Thiagarajan print_credit_info("%8d", cred_norm); 52578fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_min); 52678fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", credits); 52778fc4856SVasanthakumar Thiagarajan print_credit_info("%10d", cred_assngd); 52878fc4856SVasanthakumar Thiagarajan print_credit_info("%13d", seek_cred); 52978fc4856SVasanthakumar Thiagarajan print_credit_info("%12d", cred_sz); 53078fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_per_msg); 53178fc4856SVasanthakumar Thiagarajan print_credit_info("%14d", cred_to_dist); 53278fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%12d\n", 53378fc4856SVasanthakumar Thiagarajan get_queue_depth(&((struct htc_endpoint *) 53478fc4856SVasanthakumar Thiagarajan ep_list->htc_rsvd)->txq)); 53578fc4856SVasanthakumar Thiagarajan } 53678fc4856SVasanthakumar Thiagarajan 53778fc4856SVasanthakumar Thiagarajan if (len > buf_len) 53878fc4856SVasanthakumar Thiagarajan len = buf_len; 53978fc4856SVasanthakumar Thiagarajan 54078fc4856SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 54178fc4856SVasanthakumar Thiagarajan kfree(buf); 54278fc4856SVasanthakumar Thiagarajan return ret_cnt; 54378fc4856SVasanthakumar Thiagarajan } 54478fc4856SVasanthakumar Thiagarajan 54578fc4856SVasanthakumar Thiagarajan static const struct file_operations fops_credit_dist_stats = { 54678fc4856SVasanthakumar Thiagarajan .read = read_file_credit_dist_stats, 54778fc4856SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 54878fc4856SVasanthakumar Thiagarajan .owner = THIS_MODULE, 54978fc4856SVasanthakumar Thiagarajan .llseek = default_llseek, 55078fc4856SVasanthakumar Thiagarajan }; 55178fc4856SVasanthakumar Thiagarajan 55291d57de5SVasanthakumar Thiagarajan static unsigned long ath6kl_get_num_reg(void) 55391d57de5SVasanthakumar Thiagarajan { 55491d57de5SVasanthakumar Thiagarajan int i; 55591d57de5SVasanthakumar Thiagarajan unsigned long n_reg = 0; 55691d57de5SVasanthakumar Thiagarajan 55791d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) 55891d57de5SVasanthakumar Thiagarajan n_reg = n_reg + 55991d57de5SVasanthakumar Thiagarajan (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1; 56091d57de5SVasanthakumar Thiagarajan 56191d57de5SVasanthakumar Thiagarajan return n_reg; 56291d57de5SVasanthakumar Thiagarajan } 56391d57de5SVasanthakumar Thiagarajan 56491d57de5SVasanthakumar Thiagarajan static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr) 56591d57de5SVasanthakumar Thiagarajan { 56691d57de5SVasanthakumar Thiagarajan int i; 56791d57de5SVasanthakumar Thiagarajan 56891d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { 56991d57de5SVasanthakumar Thiagarajan if (reg_addr >= diag_reg[i].reg_start && 57091d57de5SVasanthakumar Thiagarajan reg_addr <= diag_reg[i].reg_end) 57191d57de5SVasanthakumar Thiagarajan return true; 57291d57de5SVasanthakumar Thiagarajan } 57391d57de5SVasanthakumar Thiagarajan 57491d57de5SVasanthakumar Thiagarajan return false; 57591d57de5SVasanthakumar Thiagarajan } 57691d57de5SVasanthakumar Thiagarajan 57791d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf, 57891d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 57991d57de5SVasanthakumar Thiagarajan { 58091d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 58191d57de5SVasanthakumar Thiagarajan u8 buf[50]; 58291d57de5SVasanthakumar Thiagarajan unsigned int len = 0; 58391d57de5SVasanthakumar Thiagarajan 58491d57de5SVasanthakumar Thiagarajan if (ar->debug.dbgfs_diag_reg) 58591d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", 58691d57de5SVasanthakumar Thiagarajan ar->debug.dbgfs_diag_reg); 58791d57de5SVasanthakumar Thiagarajan else 58891d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, sizeof(buf) - len, 58991d57de5SVasanthakumar Thiagarajan "All diag registers\n"); 59091d57de5SVasanthakumar Thiagarajan 59191d57de5SVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 59291d57de5SVasanthakumar Thiagarajan } 59391d57de5SVasanthakumar Thiagarajan 59491d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regread_write(struct file *file, 59591d57de5SVasanthakumar Thiagarajan const char __user *user_buf, 59691d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 59791d57de5SVasanthakumar Thiagarajan { 59891d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 59991d57de5SVasanthakumar Thiagarajan u8 buf[50]; 60091d57de5SVasanthakumar Thiagarajan unsigned int len; 60191d57de5SVasanthakumar Thiagarajan unsigned long reg_addr; 60291d57de5SVasanthakumar Thiagarajan 60391d57de5SVasanthakumar Thiagarajan len = min(count, sizeof(buf) - 1); 60491d57de5SVasanthakumar Thiagarajan if (copy_from_user(buf, user_buf, len)) 60591d57de5SVasanthakumar Thiagarajan return -EFAULT; 60691d57de5SVasanthakumar Thiagarajan 60791d57de5SVasanthakumar Thiagarajan buf[len] = '\0'; 60891d57de5SVasanthakumar Thiagarajan 60991d57de5SVasanthakumar Thiagarajan if (strict_strtoul(buf, 0, ®_addr)) 61091d57de5SVasanthakumar Thiagarajan return -EINVAL; 61191d57de5SVasanthakumar Thiagarajan 61291d57de5SVasanthakumar Thiagarajan if ((reg_addr % 4) != 0) 61391d57de5SVasanthakumar Thiagarajan return -EINVAL; 61491d57de5SVasanthakumar Thiagarajan 61591d57de5SVasanthakumar Thiagarajan if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr)) 61691d57de5SVasanthakumar Thiagarajan return -EINVAL; 61791d57de5SVasanthakumar Thiagarajan 61891d57de5SVasanthakumar Thiagarajan ar->debug.dbgfs_diag_reg = reg_addr; 61991d57de5SVasanthakumar Thiagarajan 62091d57de5SVasanthakumar Thiagarajan return count; 62191d57de5SVasanthakumar Thiagarajan } 62291d57de5SVasanthakumar Thiagarajan 62391d57de5SVasanthakumar Thiagarajan static const struct file_operations fops_diag_reg_read = { 62491d57de5SVasanthakumar Thiagarajan .read = ath6kl_regread_read, 62591d57de5SVasanthakumar Thiagarajan .write = ath6kl_regread_write, 62691d57de5SVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 62791d57de5SVasanthakumar Thiagarajan .owner = THIS_MODULE, 62891d57de5SVasanthakumar Thiagarajan .llseek = default_llseek, 62991d57de5SVasanthakumar Thiagarajan }; 63091d57de5SVasanthakumar Thiagarajan 63191d57de5SVasanthakumar Thiagarajan static int ath6kl_regdump_open(struct inode *inode, struct file *file) 63291d57de5SVasanthakumar Thiagarajan { 63391d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = inode->i_private; 63491d57de5SVasanthakumar Thiagarajan u8 *buf; 63591d57de5SVasanthakumar Thiagarajan unsigned long int reg_len; 63691d57de5SVasanthakumar Thiagarajan unsigned int len = 0, n_reg; 63791d57de5SVasanthakumar Thiagarajan u32 addr; 63891d57de5SVasanthakumar Thiagarajan __le32 reg_val; 63991d57de5SVasanthakumar Thiagarajan int i, status; 64091d57de5SVasanthakumar Thiagarajan 64191d57de5SVasanthakumar Thiagarajan /* Dump all the registers if no register is specified */ 64291d57de5SVasanthakumar Thiagarajan if (!ar->debug.dbgfs_diag_reg) 64391d57de5SVasanthakumar Thiagarajan n_reg = ath6kl_get_num_reg(); 64491d57de5SVasanthakumar Thiagarajan else 64591d57de5SVasanthakumar Thiagarajan n_reg = 1; 64691d57de5SVasanthakumar Thiagarajan 64791d57de5SVasanthakumar Thiagarajan reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE; 64891d57de5SVasanthakumar Thiagarajan if (n_reg > 1) 64991d57de5SVasanthakumar Thiagarajan reg_len += REGTYPE_STR_LEN; 65091d57de5SVasanthakumar Thiagarajan 65191d57de5SVasanthakumar Thiagarajan buf = vmalloc(reg_len); 65291d57de5SVasanthakumar Thiagarajan if (!buf) 65391d57de5SVasanthakumar Thiagarajan return -ENOMEM; 65491d57de5SVasanthakumar Thiagarajan 65591d57de5SVasanthakumar Thiagarajan if (n_reg == 1) { 65691d57de5SVasanthakumar Thiagarajan addr = ar->debug.dbgfs_diag_reg; 65791d57de5SVasanthakumar Thiagarajan 65891d57de5SVasanthakumar Thiagarajan status = ath6kl_diag_read32(ar, 65991d57de5SVasanthakumar Thiagarajan TARG_VTOP(ar->target_type, addr), 66091d57de5SVasanthakumar Thiagarajan (u32 *)®_val); 66191d57de5SVasanthakumar Thiagarajan if (status) 66291d57de5SVasanthakumar Thiagarajan goto fail_reg_read; 66391d57de5SVasanthakumar Thiagarajan 66491d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 66591d57de5SVasanthakumar Thiagarajan "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val)); 66691d57de5SVasanthakumar Thiagarajan goto done; 66791d57de5SVasanthakumar Thiagarajan } 66891d57de5SVasanthakumar Thiagarajan 66991d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { 67091d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 67191d57de5SVasanthakumar Thiagarajan "%s\n", diag_reg[i].reg_info); 67291d57de5SVasanthakumar Thiagarajan for (addr = diag_reg[i].reg_start; 67391d57de5SVasanthakumar Thiagarajan addr <= diag_reg[i].reg_end; addr += 4) { 67491d57de5SVasanthakumar Thiagarajan status = ath6kl_diag_read32(ar, 67591d57de5SVasanthakumar Thiagarajan TARG_VTOP(ar->target_type, addr), 67691d57de5SVasanthakumar Thiagarajan (u32 *)®_val); 67791d57de5SVasanthakumar Thiagarajan if (status) 67891d57de5SVasanthakumar Thiagarajan goto fail_reg_read; 67991d57de5SVasanthakumar Thiagarajan 68091d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 68191d57de5SVasanthakumar Thiagarajan "0x%06x 0x%08x\n", 68291d57de5SVasanthakumar Thiagarajan addr, le32_to_cpu(reg_val)); 68391d57de5SVasanthakumar Thiagarajan } 68491d57de5SVasanthakumar Thiagarajan } 68591d57de5SVasanthakumar Thiagarajan 68691d57de5SVasanthakumar Thiagarajan done: 68791d57de5SVasanthakumar Thiagarajan file->private_data = buf; 68891d57de5SVasanthakumar Thiagarajan return 0; 68991d57de5SVasanthakumar Thiagarajan 69091d57de5SVasanthakumar Thiagarajan fail_reg_read: 69191d57de5SVasanthakumar Thiagarajan ath6kl_warn("Unable to read memory:%u\n", addr); 69291d57de5SVasanthakumar Thiagarajan vfree(buf); 69391d57de5SVasanthakumar Thiagarajan return -EIO; 69491d57de5SVasanthakumar Thiagarajan } 69591d57de5SVasanthakumar Thiagarajan 69691d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf, 69791d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 69891d57de5SVasanthakumar Thiagarajan { 69991d57de5SVasanthakumar Thiagarajan u8 *buf = file->private_data; 70091d57de5SVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 70191d57de5SVasanthakumar Thiagarajan } 70291d57de5SVasanthakumar Thiagarajan 70391d57de5SVasanthakumar Thiagarajan static int ath6kl_regdump_release(struct inode *inode, struct file *file) 70491d57de5SVasanthakumar Thiagarajan { 70591d57de5SVasanthakumar Thiagarajan vfree(file->private_data); 70691d57de5SVasanthakumar Thiagarajan return 0; 70791d57de5SVasanthakumar Thiagarajan } 70891d57de5SVasanthakumar Thiagarajan 70991d57de5SVasanthakumar Thiagarajan static const struct file_operations fops_reg_dump = { 71091d57de5SVasanthakumar Thiagarajan .open = ath6kl_regdump_open, 71191d57de5SVasanthakumar Thiagarajan .read = ath6kl_regdump_read, 71291d57de5SVasanthakumar Thiagarajan .release = ath6kl_regdump_release, 71391d57de5SVasanthakumar Thiagarajan .owner = THIS_MODULE, 71491d57de5SVasanthakumar Thiagarajan .llseek = default_llseek, 71591d57de5SVasanthakumar Thiagarajan }; 71691d57de5SVasanthakumar Thiagarajan 717e5090444SVivek Natarajan static ssize_t ath6kl_lrssi_roam_write(struct file *file, 718e5090444SVivek Natarajan const char __user *user_buf, 719e5090444SVivek Natarajan size_t count, loff_t *ppos) 720e5090444SVivek Natarajan { 721e5090444SVivek Natarajan struct ath6kl *ar = file->private_data; 722e5090444SVivek Natarajan unsigned long lrssi_roam_threshold; 723e5090444SVivek Natarajan char buf[32]; 724e5090444SVivek Natarajan ssize_t len; 725e5090444SVivek Natarajan 726e5090444SVivek Natarajan len = min(count, sizeof(buf) - 1); 727e5090444SVivek Natarajan if (copy_from_user(buf, user_buf, len)) 728e5090444SVivek Natarajan return -EFAULT; 729e5090444SVivek Natarajan 730e5090444SVivek Natarajan buf[len] = '\0'; 731e5090444SVivek Natarajan if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) 732e5090444SVivek Natarajan return -EINVAL; 733e5090444SVivek Natarajan 734e5090444SVivek Natarajan ar->lrssi_roam_threshold = lrssi_roam_threshold; 735e5090444SVivek Natarajan 736e5090444SVivek Natarajan ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold); 737e5090444SVivek Natarajan 738e5090444SVivek Natarajan return count; 739e5090444SVivek Natarajan } 740e5090444SVivek Natarajan 741e5090444SVivek Natarajan static ssize_t ath6kl_lrssi_roam_read(struct file *file, 742e5090444SVivek Natarajan char __user *user_buf, 743e5090444SVivek Natarajan size_t count, loff_t *ppos) 744e5090444SVivek Natarajan { 745e5090444SVivek Natarajan struct ath6kl *ar = file->private_data; 746e5090444SVivek Natarajan char buf[32]; 747e5090444SVivek Natarajan unsigned int len; 748e5090444SVivek Natarajan 749e5090444SVivek Natarajan len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold); 750e5090444SVivek Natarajan 751e5090444SVivek Natarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 752e5090444SVivek Natarajan } 753e5090444SVivek Natarajan 754e5090444SVivek Natarajan static const struct file_operations fops_lrssi_roam_threshold = { 755e5090444SVivek Natarajan .read = ath6kl_lrssi_roam_read, 756e5090444SVivek Natarajan .write = ath6kl_lrssi_roam_write, 757e5090444SVivek Natarajan .open = ath6kl_debugfs_open, 758e5090444SVivek Natarajan .owner = THIS_MODULE, 759e5090444SVivek Natarajan .llseek = default_llseek, 760e5090444SVivek Natarajan }; 761e5090444SVivek Natarajan 762*252c068bSVasanthakumar Thiagarajan static ssize_t ath6kl_regwrite_read(struct file *file, 763*252c068bSVasanthakumar Thiagarajan char __user *user_buf, 764*252c068bSVasanthakumar Thiagarajan size_t count, loff_t *ppos) 765*252c068bSVasanthakumar Thiagarajan { 766*252c068bSVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 767*252c068bSVasanthakumar Thiagarajan u8 buf[32]; 768*252c068bSVasanthakumar Thiagarajan unsigned int len = 0; 769*252c068bSVasanthakumar Thiagarajan 770*252c068bSVasanthakumar Thiagarajan len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n", 771*252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr); 772*252c068bSVasanthakumar Thiagarajan 773*252c068bSVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 774*252c068bSVasanthakumar Thiagarajan } 775*252c068bSVasanthakumar Thiagarajan 776*252c068bSVasanthakumar Thiagarajan static ssize_t ath6kl_regwrite_write(struct file *file, 777*252c068bSVasanthakumar Thiagarajan const char __user *user_buf, 778*252c068bSVasanthakumar Thiagarajan size_t count, loff_t *ppos) 779*252c068bSVasanthakumar Thiagarajan { 780*252c068bSVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 781*252c068bSVasanthakumar Thiagarajan char buf[32]; 782*252c068bSVasanthakumar Thiagarajan char *sptr, *token; 783*252c068bSVasanthakumar Thiagarajan unsigned int len = 0; 784*252c068bSVasanthakumar Thiagarajan u32 reg_addr, reg_val; 785*252c068bSVasanthakumar Thiagarajan 786*252c068bSVasanthakumar Thiagarajan len = min(count, sizeof(buf) - 1); 787*252c068bSVasanthakumar Thiagarajan if (copy_from_user(buf, user_buf, len)) 788*252c068bSVasanthakumar Thiagarajan return -EFAULT; 789*252c068bSVasanthakumar Thiagarajan 790*252c068bSVasanthakumar Thiagarajan buf[len] = '\0'; 791*252c068bSVasanthakumar Thiagarajan sptr = buf; 792*252c068bSVasanthakumar Thiagarajan 793*252c068bSVasanthakumar Thiagarajan token = strsep(&sptr, "="); 794*252c068bSVasanthakumar Thiagarajan if (!token) 795*252c068bSVasanthakumar Thiagarajan return -EINVAL; 796*252c068bSVasanthakumar Thiagarajan 797*252c068bSVasanthakumar Thiagarajan if (kstrtou32(token, 0, ®_addr)) 798*252c068bSVasanthakumar Thiagarajan return -EINVAL; 799*252c068bSVasanthakumar Thiagarajan 800*252c068bSVasanthakumar Thiagarajan if (!ath6kl_dbg_is_diag_reg_valid(reg_addr)) 801*252c068bSVasanthakumar Thiagarajan return -EINVAL; 802*252c068bSVasanthakumar Thiagarajan 803*252c068bSVasanthakumar Thiagarajan if (kstrtou32(sptr, 0, ®_val)) 804*252c068bSVasanthakumar Thiagarajan return -EINVAL; 805*252c068bSVasanthakumar Thiagarajan 806*252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_addr_wr = reg_addr; 807*252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_val_wr = reg_val; 808*252c068bSVasanthakumar Thiagarajan 809*252c068bSVasanthakumar Thiagarajan if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr, 810*252c068bSVasanthakumar Thiagarajan cpu_to_le32(ar->debug.diag_reg_val_wr))) 811*252c068bSVasanthakumar Thiagarajan return -EIO; 812*252c068bSVasanthakumar Thiagarajan 813*252c068bSVasanthakumar Thiagarajan return count; 814*252c068bSVasanthakumar Thiagarajan } 815*252c068bSVasanthakumar Thiagarajan 816*252c068bSVasanthakumar Thiagarajan static const struct file_operations fops_diag_reg_write = { 817*252c068bSVasanthakumar Thiagarajan .read = ath6kl_regwrite_read, 818*252c068bSVasanthakumar Thiagarajan .write = ath6kl_regwrite_write, 819*252c068bSVasanthakumar Thiagarajan .open = ath6kl_debugfs_open, 820*252c068bSVasanthakumar Thiagarajan .owner = THIS_MODULE, 821*252c068bSVasanthakumar Thiagarajan .llseek = default_llseek, 822*252c068bSVasanthakumar Thiagarajan }; 823*252c068bSVasanthakumar Thiagarajan 824d999ba3eSVasanthakumar Thiagarajan int ath6kl_debug_init(struct ath6kl *ar) 825d999ba3eSVasanthakumar Thiagarajan { 826bdf5396bSKalle Valo ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); 827bdf5396bSKalle Valo if (ar->debug.fwlog_buf.buf == NULL) 828bdf5396bSKalle Valo return -ENOMEM; 829bdf5396bSKalle Valo 830bdf5396bSKalle Valo ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); 831bdf5396bSKalle Valo if (ar->debug.fwlog_tmp == NULL) { 832bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 833bdf5396bSKalle Valo return -ENOMEM; 834bdf5396bSKalle Valo } 835bdf5396bSKalle Valo 836bdf5396bSKalle Valo spin_lock_init(&ar->debug.fwlog_lock); 837bdf5396bSKalle Valo 838939f1cceSKalle Valo /* 839939f1cceSKalle Valo * Actually we are lying here but don't know how to read the mask 840939f1cceSKalle Valo * value from the firmware. 841939f1cceSKalle Valo */ 842939f1cceSKalle Valo ar->debug.fwlog_mask = 0; 843939f1cceSKalle Valo 844d999ba3eSVasanthakumar Thiagarajan ar->debugfs_phy = debugfs_create_dir("ath6kl", 845d999ba3eSVasanthakumar Thiagarajan ar->wdev->wiphy->debugfsdir); 846bdf5396bSKalle Valo if (!ar->debugfs_phy) { 847bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 848bdf5396bSKalle Valo kfree(ar->debug.fwlog_tmp); 849d999ba3eSVasanthakumar Thiagarajan return -ENOMEM; 850bdf5396bSKalle Valo } 851d999ba3eSVasanthakumar Thiagarajan 85203f68a95SVasanthakumar Thiagarajan debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, 85303f68a95SVasanthakumar Thiagarajan &fops_tgt_stats); 85403f68a95SVasanthakumar Thiagarajan 85578fc4856SVasanthakumar Thiagarajan debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar, 85678fc4856SVasanthakumar Thiagarajan &fops_credit_dist_stats); 85778fc4856SVasanthakumar Thiagarajan 858bdf5396bSKalle Valo debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, 859bdf5396bSKalle Valo &fops_fwlog); 860bdf5396bSKalle Valo 861939f1cceSKalle Valo debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, 862939f1cceSKalle Valo ar, &fops_fwlog_mask); 863939f1cceSKalle Valo 86491d57de5SVasanthakumar Thiagarajan debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, 86591d57de5SVasanthakumar Thiagarajan &fops_diag_reg_read); 86691d57de5SVasanthakumar Thiagarajan 86791d57de5SVasanthakumar Thiagarajan debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, 86891d57de5SVasanthakumar Thiagarajan &fops_reg_dump); 86991d57de5SVasanthakumar Thiagarajan 870e5090444SVivek Natarajan debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, 871e5090444SVivek Natarajan ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); 872*252c068bSVasanthakumar Thiagarajan 873*252c068bSVasanthakumar Thiagarajan debugfs_create_file("reg_write", S_IRUSR | S_IWUSR, 874*252c068bSVasanthakumar Thiagarajan ar->debugfs_phy, ar, &fops_diag_reg_write); 875*252c068bSVasanthakumar Thiagarajan 876d999ba3eSVasanthakumar Thiagarajan return 0; 877d999ba3eSVasanthakumar Thiagarajan } 878bdf5396bSKalle Valo 879bdf5396bSKalle Valo void ath6kl_debug_cleanup(struct ath6kl *ar) 880bdf5396bSKalle Valo { 881bdf5396bSKalle Valo vfree(ar->debug.fwlog_buf.buf); 882bdf5396bSKalle Valo kfree(ar->debug.fwlog_tmp); 883bdf5396bSKalle Valo } 884bdf5396bSKalle Valo 885bdcd8170SKalle Valo #endif 886