1bdcd8170SKalle Valo /* 2bdcd8170SKalle Valo * Copyright (c) 2004-2011 Atheros Communications Inc. 31b2df407SVasanthakumar Thiagarajan * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. 4bdcd8170SKalle Valo * 5bdcd8170SKalle Valo * Permission to use, copy, modify, and/or distribute this software for any 6bdcd8170SKalle Valo * purpose with or without fee is hereby granted, provided that the above 7bdcd8170SKalle Valo * copyright notice and this permission notice appear in all copies. 8bdcd8170SKalle Valo * 9bdcd8170SKalle Valo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10bdcd8170SKalle Valo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11bdcd8170SKalle Valo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12bdcd8170SKalle Valo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13bdcd8170SKalle Valo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14bdcd8170SKalle Valo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15bdcd8170SKalle Valo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16bdcd8170SKalle Valo */ 17bdcd8170SKalle Valo 18bdcd8170SKalle Valo #include "core.h" 19bdf5396bSKalle Valo 209b9a4f2aSKalle Valo #include <linux/skbuff.h> 21939f1cceSKalle Valo #include <linux/fs.h> 2262c83ac4SKalle Valo #include <linux/vmalloc.h> 23ee40fa06SPaul Gortmaker #include <linux/export.h> 24bdf5396bSKalle Valo 25bdcd8170SKalle Valo #include "debug.h" 26bdf5396bSKalle Valo #include "target.h" 27bdf5396bSKalle Valo 28bdf5396bSKalle Valo struct ath6kl_fwlog_slot { 29bdf5396bSKalle Valo __le32 timestamp; 30bdf5396bSKalle Valo __le32 length; 31bdf5396bSKalle Valo 32bdf5396bSKalle Valo /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ 33bdf5396bSKalle Valo u8 payload[0]; 34bdf5396bSKalle Valo }; 35bdf5396bSKalle Valo 369b9a4f2aSKalle Valo #define ATH6KL_FWLOG_MAX_ENTRIES 20 379b9a4f2aSKalle Valo 38939f1cceSKalle Valo #define ATH6KL_FWLOG_VALID_MASK 0x1ffff 39bdcd8170SKalle Valo 40bdcd8170SKalle Valo int ath6kl_printk(const char *level, const char *fmt, ...) 41bdcd8170SKalle Valo { 42bdcd8170SKalle Valo struct va_format vaf; 43bdcd8170SKalle Valo va_list args; 44bdcd8170SKalle Valo int rtn; 45bdcd8170SKalle Valo 46bdcd8170SKalle Valo va_start(args, fmt); 47bdcd8170SKalle Valo 48bdcd8170SKalle Valo vaf.fmt = fmt; 49bdcd8170SKalle Valo vaf.va = &args; 50bdcd8170SKalle Valo 51bdcd8170SKalle Valo rtn = printk("%sath6kl: %pV", level, &vaf); 52bdcd8170SKalle Valo 53bdcd8170SKalle Valo va_end(args); 54bdcd8170SKalle Valo 55bdcd8170SKalle Valo return rtn; 56bdcd8170SKalle Valo } 57d6a434d6SKalle Valo EXPORT_SYMBOL(ath6kl_printk); 58bdcd8170SKalle Valo 59d470b4bcSKalle Valo int ath6kl_info(const char *fmt, ...) 60d470b4bcSKalle Valo { 61d470b4bcSKalle Valo struct va_format vaf = { 62d470b4bcSKalle Valo .fmt = fmt, 63d470b4bcSKalle Valo }; 64d470b4bcSKalle Valo va_list args; 65d470b4bcSKalle Valo int ret; 66d470b4bcSKalle Valo 67d470b4bcSKalle Valo va_start(args, fmt); 68d470b4bcSKalle Valo vaf.va = &args; 69d470b4bcSKalle Valo ret = ath6kl_printk(KERN_INFO, "%pV", &vaf); 70da01d53cSKalle Valo trace_ath6kl_log_info(&vaf); 71d470b4bcSKalle Valo va_end(args); 72d470b4bcSKalle Valo 73d470b4bcSKalle Valo return ret; 74d470b4bcSKalle Valo } 75d470b4bcSKalle Valo EXPORT_SYMBOL(ath6kl_info); 76d470b4bcSKalle Valo 77d470b4bcSKalle Valo int ath6kl_err(const char *fmt, ...) 78d470b4bcSKalle Valo { 79d470b4bcSKalle Valo struct va_format vaf = { 80d470b4bcSKalle Valo .fmt = fmt, 81d470b4bcSKalle Valo }; 82d470b4bcSKalle Valo va_list args; 83d470b4bcSKalle Valo int ret; 84d470b4bcSKalle Valo 85d470b4bcSKalle Valo va_start(args, fmt); 86d470b4bcSKalle Valo vaf.va = &args; 87d470b4bcSKalle Valo ret = ath6kl_printk(KERN_ERR, "%pV", &vaf); 88da01d53cSKalle Valo trace_ath6kl_log_err(&vaf); 89d470b4bcSKalle Valo va_end(args); 90d470b4bcSKalle Valo 91d470b4bcSKalle Valo return ret; 92d470b4bcSKalle Valo } 93d470b4bcSKalle Valo EXPORT_SYMBOL(ath6kl_err); 94d470b4bcSKalle Valo 95d470b4bcSKalle Valo int ath6kl_warn(const char *fmt, ...) 96d470b4bcSKalle Valo { 97d470b4bcSKalle Valo struct va_format vaf = { 98d470b4bcSKalle Valo .fmt = fmt, 99d470b4bcSKalle Valo }; 100d470b4bcSKalle Valo va_list args; 101d470b4bcSKalle Valo int ret; 102d470b4bcSKalle Valo 103d470b4bcSKalle Valo va_start(args, fmt); 104d470b4bcSKalle Valo vaf.va = &args; 105d470b4bcSKalle Valo ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf); 106da01d53cSKalle Valo trace_ath6kl_log_warn(&vaf); 107d470b4bcSKalle Valo va_end(args); 108d470b4bcSKalle Valo 109d470b4bcSKalle Valo return ret; 110d470b4bcSKalle Valo } 111d470b4bcSKalle Valo EXPORT_SYMBOL(ath6kl_warn); 112d470b4bcSKalle Valo 113bdcd8170SKalle Valo #ifdef CONFIG_ATH6KL_DEBUG 11491d57de5SVasanthakumar Thiagarajan 1153b1b7d09SKalle Valo void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...) 1163b1b7d09SKalle Valo { 1173b1b7d09SKalle Valo struct va_format vaf; 1183b1b7d09SKalle Valo va_list args; 1193b1b7d09SKalle Valo 1203b1b7d09SKalle Valo va_start(args, fmt); 1213b1b7d09SKalle Valo 1223b1b7d09SKalle Valo vaf.fmt = fmt; 1233b1b7d09SKalle Valo vaf.va = &args; 1243b1b7d09SKalle Valo 125aa8705fcSKalle Valo if (debug_mask & mask) 1263b1b7d09SKalle Valo ath6kl_printk(KERN_DEBUG, "%pV", &vaf); 1273b1b7d09SKalle Valo 128aa8705fcSKalle Valo trace_ath6kl_log_dbg(mask, &vaf); 129aa8705fcSKalle Valo 1303b1b7d09SKalle Valo va_end(args); 1313b1b7d09SKalle Valo } 132d6a434d6SKalle Valo EXPORT_SYMBOL(ath6kl_dbg); 1333b1b7d09SKalle Valo 1343b1b7d09SKalle Valo void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, 1353b1b7d09SKalle Valo const char *msg, const char *prefix, 1363b1b7d09SKalle Valo const void *buf, size_t len) 1373b1b7d09SKalle Valo { 1383b1b7d09SKalle Valo if (debug_mask & mask) { 1393b1b7d09SKalle Valo if (msg) 1403b1b7d09SKalle Valo ath6kl_dbg(mask, "%s\n", msg); 1413b1b7d09SKalle Valo 1423b1b7d09SKalle Valo print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); 1433b1b7d09SKalle Valo } 144aa8705fcSKalle Valo 145aa8705fcSKalle Valo /* tracing code doesn't like null strings :/ */ 146aa8705fcSKalle Valo trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "", 147aa8705fcSKalle Valo buf, len); 1483b1b7d09SKalle Valo } 149d6a434d6SKalle Valo EXPORT_SYMBOL(ath6kl_dbg_dump); 1503b1b7d09SKalle Valo 15191d57de5SVasanthakumar Thiagarajan #define REG_OUTPUT_LEN_PER_LINE 25 15291d57de5SVasanthakumar Thiagarajan #define REGTYPE_STR_LEN 100 15391d57de5SVasanthakumar Thiagarajan 15491d57de5SVasanthakumar Thiagarajan struct ath6kl_diag_reg_info { 15591d57de5SVasanthakumar Thiagarajan u32 reg_start; 15691d57de5SVasanthakumar Thiagarajan u32 reg_end; 15791d57de5SVasanthakumar Thiagarajan const char *reg_info; 15891d57de5SVasanthakumar Thiagarajan }; 15991d57de5SVasanthakumar Thiagarajan 16091d57de5SVasanthakumar Thiagarajan static const struct ath6kl_diag_reg_info diag_reg[] = { 16191d57de5SVasanthakumar Thiagarajan { 0x20000, 0x200fc, "General DMA and Rx registers" }, 16291d57de5SVasanthakumar Thiagarajan { 0x28000, 0x28900, "MAC PCU register & keycache" }, 16391d57de5SVasanthakumar Thiagarajan { 0x20800, 0x20a40, "QCU" }, 16491d57de5SVasanthakumar Thiagarajan { 0x21000, 0x212f0, "DCU" }, 16591d57de5SVasanthakumar Thiagarajan { 0x4000, 0x42e4, "RTC" }, 16691d57de5SVasanthakumar Thiagarajan { 0x540000, 0x540000 + (256 * 1024), "RAM" }, 16791d57de5SVasanthakumar Thiagarajan { 0x29800, 0x2B210, "Base Band" }, 16891d57de5SVasanthakumar Thiagarajan { 0x1C000, 0x1C748, "Analog" }, 16991d57de5SVasanthakumar Thiagarajan }; 17091d57de5SVasanthakumar Thiagarajan 171bdcd8170SKalle Valo void ath6kl_dump_registers(struct ath6kl_device *dev, 172bdcd8170SKalle Valo struct ath6kl_irq_proc_registers *irq_proc_reg, 173bdcd8170SKalle Valo struct ath6kl_irq_enable_reg *irq_enable_reg) 174bdcd8170SKalle Valo { 175bdcd8170SKalle Valo 1765afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, ("<------- Register Table -------->\n")); 177bdcd8170SKalle Valo 178bdcd8170SKalle Valo if (irq_proc_reg != NULL) { 1795afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 180bdcd8170SKalle Valo "Host Int status: 0x%x\n", 181bdcd8170SKalle Valo irq_proc_reg->host_int_status); 1825afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 183bdcd8170SKalle Valo "CPU Int status: 0x%x\n", 184bdcd8170SKalle Valo irq_proc_reg->cpu_int_status); 1855afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 186bdcd8170SKalle Valo "Error Int status: 0x%x\n", 187bdcd8170SKalle Valo irq_proc_reg->error_int_status); 1885afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 189bdcd8170SKalle Valo "Counter Int status: 0x%x\n", 190bdcd8170SKalle Valo irq_proc_reg->counter_int_status); 1915afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 192bdcd8170SKalle Valo "Mbox Frame: 0x%x\n", 193bdcd8170SKalle Valo irq_proc_reg->mbox_frame); 1945afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 195bdcd8170SKalle Valo "Rx Lookahead Valid: 0x%x\n", 196bdcd8170SKalle Valo irq_proc_reg->rx_lkahd_valid); 1975afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 198bdcd8170SKalle Valo "Rx Lookahead 0: 0x%x\n", 199bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[0]); 2005afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 201bdcd8170SKalle Valo "Rx Lookahead 1: 0x%x\n", 202bdcd8170SKalle Valo irq_proc_reg->rx_lkahd[1]); 203bdcd8170SKalle Valo 204bdcd8170SKalle Valo if (dev->ar->mbox_info.gmbox_addr != 0) { 205bdcd8170SKalle Valo /* 206bdcd8170SKalle Valo * If the target supports GMBOX hardware, dump some 207bdcd8170SKalle Valo * additional state. 208bdcd8170SKalle Valo */ 2095afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 210bdcd8170SKalle Valo "GMBOX Host Int status 2: 0x%x\n", 211bdcd8170SKalle Valo irq_proc_reg->host_int_status2); 2125afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 213bdcd8170SKalle Valo "GMBOX RX Avail: 0x%x\n", 214bdcd8170SKalle Valo irq_proc_reg->gmbox_rx_avail); 2155afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 216bdcd8170SKalle Valo "GMBOX lookahead alias 0: 0x%x\n", 217bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[0]); 2185afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 219bdcd8170SKalle Valo "GMBOX lookahead alias 1: 0x%x\n", 220bdcd8170SKalle Valo irq_proc_reg->rx_gmbox_lkahd_alias[1]); 221bdcd8170SKalle Valo } 222bdcd8170SKalle Valo 223bdcd8170SKalle Valo } 224bdcd8170SKalle Valo 225bdcd8170SKalle Valo if (irq_enable_reg != NULL) { 2265afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, 227bdcd8170SKalle Valo "Int status Enable: 0x%x\n", 228bdcd8170SKalle Valo irq_enable_reg->int_status_en); 2295afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, "Counter Int status Enable: 0x%x\n", 230bdcd8170SKalle Valo irq_enable_reg->cntr_int_status_en); 231bdcd8170SKalle Valo } 2325afa5aa7SKalle Valo ath6kl_dbg(ATH6KL_DBG_IRQ, "<------------------------------->\n"); 233bdcd8170SKalle Valo } 234bdcd8170SKalle Valo 235bdcd8170SKalle Valo static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) 236bdcd8170SKalle Valo { 23702f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, 238bdcd8170SKalle Valo "--- endpoint: %d svc_id: 0x%X ---\n", 239bdcd8170SKalle Valo ep_dist->endpoint, ep_dist->svc_id); 24002f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " dist_flags : 0x%X\n", 241bdcd8170SKalle Valo ep_dist->dist_flags); 24202f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_norm : %d\n", 243bdcd8170SKalle Valo ep_dist->cred_norm); 24402f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_min : %d\n", 245bdcd8170SKalle Valo ep_dist->cred_min); 24602f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " credits : %d\n", 247bdcd8170SKalle Valo ep_dist->credits); 24802f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_assngd : %d\n", 249bdcd8170SKalle Valo ep_dist->cred_assngd); 25002f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " seek_cred : %d\n", 251bdcd8170SKalle Valo ep_dist->seek_cred); 25202f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_sz : %d\n", 253bdcd8170SKalle Valo ep_dist->cred_sz); 25402f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_per_msg : %d\n", 255bdcd8170SKalle Valo ep_dist->cred_per_msg); 25602f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " cred_to_dist : %d\n", 257bdcd8170SKalle Valo ep_dist->cred_to_dist); 25802f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, " txq_depth : %d\n", 259e8c39790SKalle Valo get_queue_depth(&ep_dist->htc_ep->txq)); 26002f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, 261bdcd8170SKalle Valo "----------------------------------\n"); 262bdcd8170SKalle Valo } 263bdcd8170SKalle Valo 26402f0d6fcSKalle Valo /* FIXME: move to htc.c */ 265bdcd8170SKalle Valo void dump_cred_dist_stats(struct htc_target *target) 266bdcd8170SKalle Valo { 267bdcd8170SKalle Valo struct htc_endpoint_credit_dist *ep_list; 268bdcd8170SKalle Valo 269bdcd8170SKalle Valo list_for_each_entry(ep_list, &target->cred_dist_list, list) 270bdcd8170SKalle Valo dump_cred_dist(ep_list); 271bdcd8170SKalle Valo 27202f0d6fcSKalle Valo ath6kl_dbg(ATH6KL_DBG_CREDIT, 27302f0d6fcSKalle Valo "credit distribution total %d free %d\n", 2743c370398SKalle Valo target->credit_info->total_avail_credits, 2753c370398SKalle Valo target->credit_info->cur_free_credits); 276bdcd8170SKalle Valo } 277bdcd8170SKalle Valo 2789a730834SKalle Valo void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) 2799a730834SKalle Valo { 2809a730834SKalle Valo switch (war) { 2819a730834SKalle Valo case ATH6KL_WAR_INVALID_RATE: 2829a730834SKalle Valo ar->debug.war_stats.invalid_rate++; 2839a730834SKalle Valo break; 2849a730834SKalle Valo } 2859a730834SKalle Valo } 2869a730834SKalle Valo 2879a730834SKalle Valo static ssize_t read_file_war_stats(struct file *file, char __user *user_buf, 2889a730834SKalle Valo size_t count, loff_t *ppos) 2899a730834SKalle Valo { 2909a730834SKalle Valo struct ath6kl *ar = file->private_data; 2919a730834SKalle Valo char *buf; 2929a730834SKalle Valo unsigned int len = 0, buf_len = 1500; 2939a730834SKalle Valo ssize_t ret_cnt; 2949a730834SKalle Valo 2959a730834SKalle Valo buf = kzalloc(buf_len, GFP_KERNEL); 2969a730834SKalle Valo if (!buf) 2979a730834SKalle Valo return -ENOMEM; 2989a730834SKalle Valo 2999a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "\n"); 3009a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "%25s\n", 3019a730834SKalle Valo "Workaround stats"); 3029a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "%25s\n\n", 3039a730834SKalle Valo "================="); 3049a730834SKalle Valo len += scnprintf(buf + len, buf_len - len, "%20s %10u\n", 3059a730834SKalle Valo "Invalid rates", ar->debug.war_stats.invalid_rate); 3069a730834SKalle Valo 3079a730834SKalle Valo if (WARN_ON(len > buf_len)) 3089a730834SKalle Valo len = buf_len; 3099a730834SKalle Valo 3109a730834SKalle Valo ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 3119a730834SKalle Valo 3129a730834SKalle Valo kfree(buf); 3139a730834SKalle Valo return ret_cnt; 3149a730834SKalle Valo } 3159a730834SKalle Valo 3169a730834SKalle Valo static const struct file_operations fops_war_stats = { 3179a730834SKalle Valo .read = read_file_war_stats, 318234e3405SStephen Boyd .open = simple_open, 3199a730834SKalle Valo .owner = THIS_MODULE, 3209a730834SKalle Valo .llseek = default_llseek, 3219a730834SKalle Valo }; 3229a730834SKalle Valo 323bdf5396bSKalle Valo void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) 324bdf5396bSKalle Valo { 3259b9a4f2aSKalle Valo struct ath6kl_fwlog_slot *slot; 3269b9a4f2aSKalle Valo struct sk_buff *skb; 327bdf5396bSKalle Valo size_t slot_len; 328bdf5396bSKalle Valo 329bdf5396bSKalle Valo if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) 330bdf5396bSKalle Valo return; 331bdf5396bSKalle Valo 3327504a3e1SEtay Luz slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; 333bdf5396bSKalle Valo 3349b9a4f2aSKalle Valo skb = alloc_skb(slot_len, GFP_KERNEL); 3359b9a4f2aSKalle Valo if (!skb) 3369b9a4f2aSKalle Valo return; 3379b9a4f2aSKalle Valo 3389b9a4f2aSKalle Valo slot = (struct ath6kl_fwlog_slot *) skb_put(skb, slot_len); 339bdf5396bSKalle Valo slot->timestamp = cpu_to_le32(jiffies); 340bdf5396bSKalle Valo slot->length = cpu_to_le32(len); 341bdf5396bSKalle Valo memcpy(slot->payload, buf, len); 342bdf5396bSKalle Valo 3437504a3e1SEtay Luz /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ 3447504a3e1SEtay Luz memset(slot->payload + len, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - len); 3457504a3e1SEtay Luz 3469b9a4f2aSKalle Valo spin_lock(&ar->debug.fwlog_queue.lock); 347bdf5396bSKalle Valo 3489b9a4f2aSKalle Valo __skb_queue_tail(&ar->debug.fwlog_queue, skb); 349c807b30dSKalle Valo complete(&ar->debug.fwlog_completion); 350bdf5396bSKalle Valo 3519b9a4f2aSKalle Valo /* drop oldest entries */ 3529b9a4f2aSKalle Valo while (skb_queue_len(&ar->debug.fwlog_queue) > 3539b9a4f2aSKalle Valo ATH6KL_FWLOG_MAX_ENTRIES) { 3549b9a4f2aSKalle Valo skb = __skb_dequeue(&ar->debug.fwlog_queue); 3559b9a4f2aSKalle Valo kfree_skb(skb); 356bdf5396bSKalle Valo } 357bdf5396bSKalle Valo 3589b9a4f2aSKalle Valo spin_unlock(&ar->debug.fwlog_queue.lock); 3599b9a4f2aSKalle Valo 3609b9a4f2aSKalle Valo return; 361bdf5396bSKalle Valo } 362bdf5396bSKalle Valo 363c807b30dSKalle Valo static int ath6kl_fwlog_open(struct inode *inode, struct file *file) 364c807b30dSKalle Valo { 365c807b30dSKalle Valo struct ath6kl *ar = inode->i_private; 366c807b30dSKalle Valo 367c807b30dSKalle Valo if (ar->debug.fwlog_open) 368c807b30dSKalle Valo return -EBUSY; 369c807b30dSKalle Valo 370c807b30dSKalle Valo ar->debug.fwlog_open = true; 371c807b30dSKalle Valo 372c807b30dSKalle Valo file->private_data = inode->i_private; 373c807b30dSKalle Valo return 0; 374c807b30dSKalle Valo } 375c807b30dSKalle Valo 376c807b30dSKalle Valo static int ath6kl_fwlog_release(struct inode *inode, struct file *file) 377c807b30dSKalle Valo { 378c807b30dSKalle Valo struct ath6kl *ar = inode->i_private; 379c807b30dSKalle Valo 380c807b30dSKalle Valo ar->debug.fwlog_open = false; 381c807b30dSKalle Valo 382c807b30dSKalle Valo return 0; 383c807b30dSKalle Valo } 384c807b30dSKalle Valo 385bdf5396bSKalle Valo static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, 386bdf5396bSKalle Valo size_t count, loff_t *ppos) 387bdf5396bSKalle Valo { 388bdf5396bSKalle Valo struct ath6kl *ar = file->private_data; 3899b9a4f2aSKalle Valo struct sk_buff *skb; 390bdf5396bSKalle Valo ssize_t ret_cnt; 3919b9a4f2aSKalle Valo size_t len = 0; 392bdf5396bSKalle Valo char *buf; 393bdf5396bSKalle Valo 3949b9a4f2aSKalle Valo buf = vmalloc(count); 395bdf5396bSKalle Valo if (!buf) 396bdf5396bSKalle Valo return -ENOMEM; 397bdf5396bSKalle Valo 398bc07ddb2SKalle Valo /* read undelivered logs from firmware */ 399bc07ddb2SKalle Valo ath6kl_read_fwlogs(ar); 400bc07ddb2SKalle Valo 4019b9a4f2aSKalle Valo spin_lock(&ar->debug.fwlog_queue.lock); 402bdf5396bSKalle Valo 4039b9a4f2aSKalle Valo while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { 4049b9a4f2aSKalle Valo if (skb->len > count - len) { 4059b9a4f2aSKalle Valo /* not enough space, put skb back and leave */ 4069b9a4f2aSKalle Valo __skb_queue_head(&ar->debug.fwlog_queue, skb); 4079b9a4f2aSKalle Valo break; 408bdf5396bSKalle Valo } 409bdf5396bSKalle Valo 410bdf5396bSKalle Valo 4119b9a4f2aSKalle Valo memcpy(buf + len, skb->data, skb->len); 4129b9a4f2aSKalle Valo len += skb->len; 4139b9a4f2aSKalle Valo 4149b9a4f2aSKalle Valo kfree_skb(skb); 4159b9a4f2aSKalle Valo } 4169b9a4f2aSKalle Valo 4179b9a4f2aSKalle Valo spin_unlock(&ar->debug.fwlog_queue.lock); 4189b9a4f2aSKalle Valo 4199b9a4f2aSKalle Valo /* FIXME: what to do if len == 0? */ 420bdf5396bSKalle Valo 421bdf5396bSKalle Valo ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 422bdf5396bSKalle Valo 423bdf5396bSKalle Valo vfree(buf); 424bdf5396bSKalle Valo 425bdf5396bSKalle Valo return ret_cnt; 426bdf5396bSKalle Valo } 427bdf5396bSKalle Valo 428bdf5396bSKalle Valo static const struct file_operations fops_fwlog = { 429c807b30dSKalle Valo .open = ath6kl_fwlog_open, 430c807b30dSKalle Valo .release = ath6kl_fwlog_release, 431bdf5396bSKalle Valo .read = ath6kl_fwlog_read, 432bdf5396bSKalle Valo .owner = THIS_MODULE, 433bdf5396bSKalle Valo .llseek = default_llseek, 434bdf5396bSKalle Valo }; 435bdf5396bSKalle Valo 436c807b30dSKalle Valo static ssize_t ath6kl_fwlog_block_read(struct file *file, 437c807b30dSKalle Valo char __user *user_buf, 438c807b30dSKalle Valo size_t count, 439c807b30dSKalle Valo loff_t *ppos) 440c807b30dSKalle Valo { 441c807b30dSKalle Valo struct ath6kl *ar = file->private_data; 442c807b30dSKalle Valo struct sk_buff *skb; 443c807b30dSKalle Valo ssize_t ret_cnt; 444c807b30dSKalle Valo size_t len = 0, not_copied; 445c807b30dSKalle Valo char *buf; 446c807b30dSKalle Valo int ret; 447c807b30dSKalle Valo 448c807b30dSKalle Valo buf = vmalloc(count); 449c807b30dSKalle Valo if (!buf) 450c807b30dSKalle Valo return -ENOMEM; 451c807b30dSKalle Valo 452c807b30dSKalle Valo spin_lock(&ar->debug.fwlog_queue.lock); 453c807b30dSKalle Valo 454c807b30dSKalle Valo if (skb_queue_len(&ar->debug.fwlog_queue) == 0) { 455c807b30dSKalle Valo /* we must init under queue lock */ 456c807b30dSKalle Valo init_completion(&ar->debug.fwlog_completion); 457c807b30dSKalle Valo 458c807b30dSKalle Valo spin_unlock(&ar->debug.fwlog_queue.lock); 459c807b30dSKalle Valo 460c807b30dSKalle Valo ret = wait_for_completion_interruptible( 461c807b30dSKalle Valo &ar->debug.fwlog_completion); 462ae9a3405SJesper Juhl if (ret == -ERESTARTSYS) { 463ae9a3405SJesper Juhl vfree(buf); 464c807b30dSKalle Valo return ret; 465ae9a3405SJesper Juhl } 466c807b30dSKalle Valo 467c807b30dSKalle Valo spin_lock(&ar->debug.fwlog_queue.lock); 468c807b30dSKalle Valo } 469c807b30dSKalle Valo 470c807b30dSKalle Valo while ((skb = __skb_dequeue(&ar->debug.fwlog_queue))) { 471c807b30dSKalle Valo if (skb->len > count - len) { 472c807b30dSKalle Valo /* not enough space, put skb back and leave */ 473c807b30dSKalle Valo __skb_queue_head(&ar->debug.fwlog_queue, skb); 474c807b30dSKalle Valo break; 475c807b30dSKalle Valo } 476c807b30dSKalle Valo 477c807b30dSKalle Valo 478c807b30dSKalle Valo memcpy(buf + len, skb->data, skb->len); 479c807b30dSKalle Valo len += skb->len; 480c807b30dSKalle Valo 481c807b30dSKalle Valo kfree_skb(skb); 482c807b30dSKalle Valo } 483c807b30dSKalle Valo 484c807b30dSKalle Valo spin_unlock(&ar->debug.fwlog_queue.lock); 485c807b30dSKalle Valo 486c807b30dSKalle Valo /* FIXME: what to do if len == 0? */ 487c807b30dSKalle Valo 488c807b30dSKalle Valo not_copied = copy_to_user(user_buf, buf, len); 489c807b30dSKalle Valo if (not_copied != 0) { 490c807b30dSKalle Valo ret_cnt = -EFAULT; 491c807b30dSKalle Valo goto out; 492c807b30dSKalle Valo } 493c807b30dSKalle Valo 494c807b30dSKalle Valo *ppos = *ppos + len; 495c807b30dSKalle Valo 496c807b30dSKalle Valo ret_cnt = len; 497c807b30dSKalle Valo 498c807b30dSKalle Valo out: 499c807b30dSKalle Valo vfree(buf); 500c807b30dSKalle Valo 501c807b30dSKalle Valo return ret_cnt; 502c807b30dSKalle Valo } 503c807b30dSKalle Valo 504c807b30dSKalle Valo static const struct file_operations fops_fwlog_block = { 505c807b30dSKalle Valo .open = ath6kl_fwlog_open, 506c807b30dSKalle Valo .release = ath6kl_fwlog_release, 507c807b30dSKalle Valo .read = ath6kl_fwlog_block_read, 508c807b30dSKalle Valo .owner = THIS_MODULE, 509c807b30dSKalle Valo .llseek = default_llseek, 510c807b30dSKalle Valo }; 511c807b30dSKalle Valo 512939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, 513939f1cceSKalle Valo size_t count, loff_t *ppos) 514939f1cceSKalle Valo { 515939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 516939f1cceSKalle Valo char buf[16]; 517939f1cceSKalle Valo int len; 518939f1cceSKalle Valo 519939f1cceSKalle Valo len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); 520939f1cceSKalle Valo 521939f1cceSKalle Valo return simple_read_from_buffer(user_buf, count, ppos, buf, len); 522939f1cceSKalle Valo } 523939f1cceSKalle Valo 524939f1cceSKalle Valo static ssize_t ath6kl_fwlog_mask_write(struct file *file, 525939f1cceSKalle Valo const char __user *user_buf, 526939f1cceSKalle Valo size_t count, loff_t *ppos) 527939f1cceSKalle Valo { 528939f1cceSKalle Valo struct ath6kl *ar = file->private_data; 529939f1cceSKalle Valo int ret; 530939f1cceSKalle Valo 531939f1cceSKalle Valo ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); 532939f1cceSKalle Valo if (ret) 533939f1cceSKalle Valo return ret; 534939f1cceSKalle Valo 535939f1cceSKalle Valo ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, 536939f1cceSKalle Valo ATH6KL_FWLOG_VALID_MASK, 537939f1cceSKalle Valo ar->debug.fwlog_mask); 538939f1cceSKalle Valo if (ret) 539939f1cceSKalle Valo return ret; 540939f1cceSKalle Valo 541939f1cceSKalle Valo return count; 542939f1cceSKalle Valo } 543939f1cceSKalle Valo 544939f1cceSKalle Valo static const struct file_operations fops_fwlog_mask = { 545234e3405SStephen Boyd .open = simple_open, 546939f1cceSKalle Valo .read = ath6kl_fwlog_mask_read, 547939f1cceSKalle Valo .write = ath6kl_fwlog_mask_write, 548939f1cceSKalle Valo .owner = THIS_MODULE, 549939f1cceSKalle Valo .llseek = default_llseek, 550939f1cceSKalle Valo }; 551939f1cceSKalle Valo 55203f68a95SVasanthakumar Thiagarajan static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, 55303f68a95SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 55403f68a95SVasanthakumar Thiagarajan { 55503f68a95SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 556990bd915SVasanthakumar Thiagarajan struct ath6kl_vif *vif; 557990bd915SVasanthakumar Thiagarajan struct target_stats *tgt_stats; 55803f68a95SVasanthakumar Thiagarajan char *buf; 55903f68a95SVasanthakumar Thiagarajan unsigned int len = 0, buf_len = 1500; 56003f68a95SVasanthakumar Thiagarajan int i; 56103f68a95SVasanthakumar Thiagarajan long left; 56203f68a95SVasanthakumar Thiagarajan ssize_t ret_cnt; 56303f68a95SVasanthakumar Thiagarajan 564990bd915SVasanthakumar Thiagarajan vif = ath6kl_vif_first(ar); 565990bd915SVasanthakumar Thiagarajan if (!vif) 566990bd915SVasanthakumar Thiagarajan return -EIO; 567990bd915SVasanthakumar Thiagarajan 568990bd915SVasanthakumar Thiagarajan tgt_stats = &vif->target_stats; 569990bd915SVasanthakumar Thiagarajan 57003f68a95SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 57103f68a95SVasanthakumar Thiagarajan if (!buf) 57203f68a95SVasanthakumar Thiagarajan return -ENOMEM; 57303f68a95SVasanthakumar Thiagarajan 57403f68a95SVasanthakumar Thiagarajan if (down_interruptible(&ar->sem)) { 57503f68a95SVasanthakumar Thiagarajan kfree(buf); 57603f68a95SVasanthakumar Thiagarajan return -EBUSY; 57703f68a95SVasanthakumar Thiagarajan } 57803f68a95SVasanthakumar Thiagarajan 579b95907a7SVasanthakumar Thiagarajan set_bit(STATS_UPDATE_PEND, &vif->flags); 58003f68a95SVasanthakumar Thiagarajan 581334234b5SVasanthakumar Thiagarajan if (ath6kl_wmi_get_stats_cmd(ar->wmi, 0)) { 58203f68a95SVasanthakumar Thiagarajan up(&ar->sem); 58303f68a95SVasanthakumar Thiagarajan kfree(buf); 58403f68a95SVasanthakumar Thiagarajan return -EIO; 58503f68a95SVasanthakumar Thiagarajan } 58603f68a95SVasanthakumar Thiagarajan 58703f68a95SVasanthakumar Thiagarajan left = wait_event_interruptible_timeout(ar->event_wq, 58803f68a95SVasanthakumar Thiagarajan !test_bit(STATS_UPDATE_PEND, 589b95907a7SVasanthakumar Thiagarajan &vif->flags), WMI_TIMEOUT); 59003f68a95SVasanthakumar Thiagarajan 59103f68a95SVasanthakumar Thiagarajan up(&ar->sem); 59203f68a95SVasanthakumar Thiagarajan 59303f68a95SVasanthakumar Thiagarajan if (left <= 0) { 59403f68a95SVasanthakumar Thiagarajan kfree(buf); 59503f68a95SVasanthakumar Thiagarajan return -ETIMEDOUT; 59603f68a95SVasanthakumar Thiagarajan } 59703f68a95SVasanthakumar Thiagarajan 59803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "\n"); 59903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 60003f68a95SVasanthakumar Thiagarajan "Target Tx stats"); 60103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n\n", 60203f68a95SVasanthakumar Thiagarajan "================="); 60303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 60403f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->tx_ucast_pkt); 60503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 60603f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->tx_bcast_pkt); 60703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 60803f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->tx_ucast_byte); 60903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 61003f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->tx_bcast_byte); 61103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 61203f68a95SVasanthakumar Thiagarajan "Rts success cnt", tgt_stats->tx_rts_success_cnt); 61303f68a95SVasanthakumar Thiagarajan for (i = 0; i < 4; i++) 61403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 61503f68a95SVasanthakumar Thiagarajan "%18s %d %10llu\n", "PER on ac", 61603f68a95SVasanthakumar Thiagarajan i, tgt_stats->tx_pkt_per_ac[i]); 61703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 61803f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->tx_err); 61903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 62003f68a95SVasanthakumar Thiagarajan "Fail count", tgt_stats->tx_fail_cnt); 62103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 62203f68a95SVasanthakumar Thiagarajan "Retry count", tgt_stats->tx_retry_cnt); 62303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 62403f68a95SVasanthakumar Thiagarajan "Multi retry cnt", tgt_stats->tx_mult_retry_cnt); 62503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 62603f68a95SVasanthakumar Thiagarajan "Rts fail cnt", tgt_stats->tx_rts_fail_cnt); 62703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n", 62803f68a95SVasanthakumar Thiagarajan "TKIP counter measure used", 62903f68a95SVasanthakumar Thiagarajan tgt_stats->tkip_cnter_measures_invoked); 63003f68a95SVasanthakumar Thiagarajan 63103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 63203f68a95SVasanthakumar Thiagarajan "Target Rx stats"); 63303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 63403f68a95SVasanthakumar Thiagarajan "================="); 63503f68a95SVasanthakumar Thiagarajan 63603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 63703f68a95SVasanthakumar Thiagarajan "Ucast packets", tgt_stats->rx_ucast_pkt); 63803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 63903f68a95SVasanthakumar Thiagarajan "Ucast Rate", tgt_stats->rx_ucast_rate); 64003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 64103f68a95SVasanthakumar Thiagarajan "Bcast packets", tgt_stats->rx_bcast_pkt); 64203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 64303f68a95SVasanthakumar Thiagarajan "Ucast byte", tgt_stats->rx_ucast_byte); 64403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 64503f68a95SVasanthakumar Thiagarajan "Bcast byte", tgt_stats->rx_bcast_byte); 64603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 64703f68a95SVasanthakumar Thiagarajan "Fragmented pkt", tgt_stats->rx_frgment_pkt); 64803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 64903f68a95SVasanthakumar Thiagarajan "Error", tgt_stats->rx_err); 65003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 65103f68a95SVasanthakumar Thiagarajan "CRC Err", tgt_stats->rx_crc_err); 65203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 65303f68a95SVasanthakumar Thiagarajan "Key chache miss", tgt_stats->rx_key_cache_miss); 65403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 65503f68a95SVasanthakumar Thiagarajan "Decrypt Err", tgt_stats->rx_decrypt_err); 65603f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 65703f68a95SVasanthakumar Thiagarajan "Duplicate frame", tgt_stats->rx_dupl_frame); 65803f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 65903f68a95SVasanthakumar Thiagarajan "Tkip Mic failure", tgt_stats->tkip_local_mic_fail); 66003f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 66103f68a95SVasanthakumar Thiagarajan "TKIP format err", tgt_stats->tkip_fmt_err); 66203f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 66303f68a95SVasanthakumar Thiagarajan "CCMP format Err", tgt_stats->ccmp_fmt_err); 66403f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n", 66503f68a95SVasanthakumar Thiagarajan "CCMP Replay Err", tgt_stats->ccmp_replays); 66603f68a95SVasanthakumar Thiagarajan 66703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 66803f68a95SVasanthakumar Thiagarajan "Misc Target stats"); 66903f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s\n", 67003f68a95SVasanthakumar Thiagarajan "================="); 67103f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 67203f68a95SVasanthakumar Thiagarajan "Beacon Miss count", tgt_stats->cs_bmiss_cnt); 67303f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 67403f68a95SVasanthakumar Thiagarajan "Num Connects", tgt_stats->cs_connect_cnt); 67503f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", 67603f68a95SVasanthakumar Thiagarajan "Num disconnects", tgt_stats->cs_discon_cnt); 67703f68a95SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 67803f68a95SVasanthakumar Thiagarajan "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); 679f0446ea9SRaja Mani len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 680f0446ea9SRaja Mani "ARP pkt received", tgt_stats->arp_received); 681f0446ea9SRaja Mani len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 682f0446ea9SRaja Mani "ARP pkt matched", tgt_stats->arp_matched); 683f0446ea9SRaja Mani len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", 684f0446ea9SRaja Mani "ARP pkt replied", tgt_stats->arp_replied); 68503f68a95SVasanthakumar Thiagarajan 68603f68a95SVasanthakumar Thiagarajan if (len > buf_len) 68703f68a95SVasanthakumar Thiagarajan len = buf_len; 68803f68a95SVasanthakumar Thiagarajan 68903f68a95SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 69003f68a95SVasanthakumar Thiagarajan 69103f68a95SVasanthakumar Thiagarajan kfree(buf); 69203f68a95SVasanthakumar Thiagarajan return ret_cnt; 69303f68a95SVasanthakumar Thiagarajan } 69403f68a95SVasanthakumar Thiagarajan 69503f68a95SVasanthakumar Thiagarajan static const struct file_operations fops_tgt_stats = { 69603f68a95SVasanthakumar Thiagarajan .read = read_file_tgt_stats, 697234e3405SStephen Boyd .open = simple_open, 69803f68a95SVasanthakumar Thiagarajan .owner = THIS_MODULE, 69903f68a95SVasanthakumar Thiagarajan .llseek = default_llseek, 70003f68a95SVasanthakumar Thiagarajan }; 70103f68a95SVasanthakumar Thiagarajan 70278fc4856SVasanthakumar Thiagarajan #define print_credit_info(fmt_str, ep_list_field) \ 70378fc4856SVasanthakumar Thiagarajan (len += scnprintf(buf + len, buf_len - len, fmt_str, \ 70478fc4856SVasanthakumar Thiagarajan ep_list->ep_list_field)) 70578fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_DISPLAY_STRING_LEN 200 70678fc4856SVasanthakumar Thiagarajan #define CREDIT_INFO_LEN 128 70778fc4856SVasanthakumar Thiagarajan 70878fc4856SVasanthakumar Thiagarajan static ssize_t read_file_credit_dist_stats(struct file *file, 70978fc4856SVasanthakumar Thiagarajan char __user *user_buf, 71078fc4856SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 71178fc4856SVasanthakumar Thiagarajan { 71278fc4856SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 71378fc4856SVasanthakumar Thiagarajan struct htc_target *target = ar->htc_target; 71478fc4856SVasanthakumar Thiagarajan struct htc_endpoint_credit_dist *ep_list; 71578fc4856SVasanthakumar Thiagarajan char *buf; 71678fc4856SVasanthakumar Thiagarajan unsigned int buf_len, len = 0; 71778fc4856SVasanthakumar Thiagarajan ssize_t ret_cnt; 71878fc4856SVasanthakumar Thiagarajan 71978fc4856SVasanthakumar Thiagarajan buf_len = CREDIT_INFO_DISPLAY_STRING_LEN + 72078fc4856SVasanthakumar Thiagarajan get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN; 72178fc4856SVasanthakumar Thiagarajan buf = kzalloc(buf_len, GFP_KERNEL); 72278fc4856SVasanthakumar Thiagarajan if (!buf) 72378fc4856SVasanthakumar Thiagarajan return -ENOMEM; 72478fc4856SVasanthakumar Thiagarajan 72578fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 72678fc4856SVasanthakumar Thiagarajan "Total Avail Credits: ", 7273c370398SKalle Valo target->credit_info->total_avail_credits); 72878fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", 72978fc4856SVasanthakumar Thiagarajan "Free credits :", 7303c370398SKalle Valo target->credit_info->cur_free_credits); 73178fc4856SVasanthakumar Thiagarajan 73278fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, 73378fc4856SVasanthakumar Thiagarajan " Epid Flags Cred_norm Cred_min Credits Cred_assngd" 73478fc4856SVasanthakumar Thiagarajan " Seek_cred Cred_sz Cred_per_msg Cred_to_dist" 73578fc4856SVasanthakumar Thiagarajan " qdepth\n"); 73678fc4856SVasanthakumar Thiagarajan 73778fc4856SVasanthakumar Thiagarajan list_for_each_entry(ep_list, &target->cred_dist_list, list) { 73878fc4856SVasanthakumar Thiagarajan print_credit_info(" %2d", endpoint); 73978fc4856SVasanthakumar Thiagarajan print_credit_info("%10x", dist_flags); 74078fc4856SVasanthakumar Thiagarajan print_credit_info("%8d", cred_norm); 74178fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_min); 74278fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", credits); 74378fc4856SVasanthakumar Thiagarajan print_credit_info("%10d", cred_assngd); 74478fc4856SVasanthakumar Thiagarajan print_credit_info("%13d", seek_cred); 74578fc4856SVasanthakumar Thiagarajan print_credit_info("%12d", cred_sz); 74678fc4856SVasanthakumar Thiagarajan print_credit_info("%9d", cred_per_msg); 74778fc4856SVasanthakumar Thiagarajan print_credit_info("%14d", cred_to_dist); 74878fc4856SVasanthakumar Thiagarajan len += scnprintf(buf + len, buf_len - len, "%12d\n", 749e8c39790SKalle Valo get_queue_depth(&ep_list->htc_ep->txq)); 75078fc4856SVasanthakumar Thiagarajan } 75178fc4856SVasanthakumar Thiagarajan 75278fc4856SVasanthakumar Thiagarajan if (len > buf_len) 75378fc4856SVasanthakumar Thiagarajan len = buf_len; 75478fc4856SVasanthakumar Thiagarajan 75578fc4856SVasanthakumar Thiagarajan ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 75678fc4856SVasanthakumar Thiagarajan kfree(buf); 75778fc4856SVasanthakumar Thiagarajan return ret_cnt; 75878fc4856SVasanthakumar Thiagarajan } 75978fc4856SVasanthakumar Thiagarajan 76078fc4856SVasanthakumar Thiagarajan static const struct file_operations fops_credit_dist_stats = { 76178fc4856SVasanthakumar Thiagarajan .read = read_file_credit_dist_stats, 762234e3405SStephen Boyd .open = simple_open, 76378fc4856SVasanthakumar Thiagarajan .owner = THIS_MODULE, 76478fc4856SVasanthakumar Thiagarajan .llseek = default_llseek, 76578fc4856SVasanthakumar Thiagarajan }; 76678fc4856SVasanthakumar Thiagarajan 767e8091281SJouni Malinen static unsigned int print_endpoint_stat(struct htc_target *target, char *buf, 768e8091281SJouni Malinen unsigned int buf_len, unsigned int len, 769e8091281SJouni Malinen int offset, const char *name) 770e8091281SJouni Malinen { 771e8091281SJouni Malinen int i; 772e8091281SJouni Malinen struct htc_endpoint_stats *ep_st; 773e8091281SJouni Malinen u32 *counter; 774e8091281SJouni Malinen 775e8091281SJouni Malinen len += scnprintf(buf + len, buf_len - len, "%s:", name); 776e8091281SJouni Malinen for (i = 0; i < ENDPOINT_MAX; i++) { 777e8091281SJouni Malinen ep_st = &target->endpoint[i].ep_st; 778e8091281SJouni Malinen counter = ((u32 *) ep_st) + (offset / 4); 779e8091281SJouni Malinen len += scnprintf(buf + len, buf_len - len, " %u", *counter); 780e8091281SJouni Malinen } 781e8091281SJouni Malinen len += scnprintf(buf + len, buf_len - len, "\n"); 782e8091281SJouni Malinen 783e8091281SJouni Malinen return len; 784e8091281SJouni Malinen } 785e8091281SJouni Malinen 786e8091281SJouni Malinen static ssize_t ath6kl_endpoint_stats_read(struct file *file, 787e8091281SJouni Malinen char __user *user_buf, 788e8091281SJouni Malinen size_t count, loff_t *ppos) 789e8091281SJouni Malinen { 790e8091281SJouni Malinen struct ath6kl *ar = file->private_data; 791e8091281SJouni Malinen struct htc_target *target = ar->htc_target; 792e8091281SJouni Malinen char *buf; 793e8091281SJouni Malinen unsigned int buf_len, len = 0; 794e8091281SJouni Malinen ssize_t ret_cnt; 795e8091281SJouni Malinen 79617169329SJouni Malinen buf_len = sizeof(struct htc_endpoint_stats) / sizeof(u32) * 79717169329SJouni Malinen (25 + ENDPOINT_MAX * 11); 79817169329SJouni Malinen buf = kmalloc(buf_len, GFP_KERNEL); 799e8091281SJouni Malinen if (!buf) 800e8091281SJouni Malinen return -ENOMEM; 801e8091281SJouni Malinen 802e8091281SJouni Malinen #define EPSTAT(name) \ 803c650538fSKalle Valo do { \ 804e8091281SJouni Malinen len = print_endpoint_stat(target, buf, buf_len, len, \ 805c650538fSKalle Valo offsetof(struct htc_endpoint_stats, \ 806c650538fSKalle Valo name), \ 807c650538fSKalle Valo #name); \ 808c650538fSKalle Valo } while (0) 809c650538fSKalle Valo 810e8091281SJouni Malinen EPSTAT(cred_low_indicate); 811e8091281SJouni Malinen EPSTAT(tx_issued); 812e8091281SJouni Malinen EPSTAT(tx_pkt_bundled); 813e8091281SJouni Malinen EPSTAT(tx_bundles); 814e8091281SJouni Malinen EPSTAT(tx_dropped); 815e8091281SJouni Malinen EPSTAT(tx_cred_rpt); 816e8091281SJouni Malinen EPSTAT(cred_rpt_from_rx); 81717169329SJouni Malinen EPSTAT(cred_rpt_from_other); 818e8091281SJouni Malinen EPSTAT(cred_rpt_ep0); 819e8091281SJouni Malinen EPSTAT(cred_from_rx); 820e8091281SJouni Malinen EPSTAT(cred_from_other); 821e8091281SJouni Malinen EPSTAT(cred_from_ep0); 822e8091281SJouni Malinen EPSTAT(cred_cosumd); 823e8091281SJouni Malinen EPSTAT(cred_retnd); 824e8091281SJouni Malinen EPSTAT(rx_pkts); 825e8091281SJouni Malinen EPSTAT(rx_lkahds); 826e8091281SJouni Malinen EPSTAT(rx_bundl); 827e8091281SJouni Malinen EPSTAT(rx_bundle_lkahd); 828e8091281SJouni Malinen EPSTAT(rx_bundle_from_hdr); 829e8091281SJouni Malinen EPSTAT(rx_alloc_thresh_hit); 830e8091281SJouni Malinen EPSTAT(rxalloc_thresh_byte); 831e8091281SJouni Malinen #undef EPSTAT 832e8091281SJouni Malinen 833e8091281SJouni Malinen if (len > buf_len) 834e8091281SJouni Malinen len = buf_len; 835e8091281SJouni Malinen 836e8091281SJouni Malinen ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 837e8091281SJouni Malinen kfree(buf); 838e8091281SJouni Malinen return ret_cnt; 839e8091281SJouni Malinen } 840e8091281SJouni Malinen 841e8091281SJouni Malinen static ssize_t ath6kl_endpoint_stats_write(struct file *file, 842e8091281SJouni Malinen const char __user *user_buf, 843e8091281SJouni Malinen size_t count, loff_t *ppos) 844e8091281SJouni Malinen { 845e8091281SJouni Malinen struct ath6kl *ar = file->private_data; 846e8091281SJouni Malinen struct htc_target *target = ar->htc_target; 847e8091281SJouni Malinen int ret, i; 848e8091281SJouni Malinen u32 val; 849e8091281SJouni Malinen struct htc_endpoint_stats *ep_st; 850e8091281SJouni Malinen 851e8091281SJouni Malinen ret = kstrtou32_from_user(user_buf, count, 0, &val); 852e8091281SJouni Malinen if (ret) 853e8091281SJouni Malinen return ret; 854e8091281SJouni Malinen if (val == 0) { 855e8091281SJouni Malinen for (i = 0; i < ENDPOINT_MAX; i++) { 856e8091281SJouni Malinen ep_st = &target->endpoint[i].ep_st; 857e8091281SJouni Malinen memset(ep_st, 0, sizeof(*ep_st)); 858e8091281SJouni Malinen } 859e8091281SJouni Malinen } 860e8091281SJouni Malinen 861e8091281SJouni Malinen return count; 862e8091281SJouni Malinen } 863e8091281SJouni Malinen 864e8091281SJouni Malinen static const struct file_operations fops_endpoint_stats = { 865234e3405SStephen Boyd .open = simple_open, 866e8091281SJouni Malinen .read = ath6kl_endpoint_stats_read, 867e8091281SJouni Malinen .write = ath6kl_endpoint_stats_write, 868e8091281SJouni Malinen .owner = THIS_MODULE, 869e8091281SJouni Malinen .llseek = default_llseek, 870e8091281SJouni Malinen }; 871e8091281SJouni Malinen 87291d57de5SVasanthakumar Thiagarajan static unsigned long ath6kl_get_num_reg(void) 87391d57de5SVasanthakumar Thiagarajan { 87491d57de5SVasanthakumar Thiagarajan int i; 87591d57de5SVasanthakumar Thiagarajan unsigned long n_reg = 0; 87691d57de5SVasanthakumar Thiagarajan 87791d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) 87891d57de5SVasanthakumar Thiagarajan n_reg = n_reg + 87991d57de5SVasanthakumar Thiagarajan (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1; 88091d57de5SVasanthakumar Thiagarajan 88191d57de5SVasanthakumar Thiagarajan return n_reg; 88291d57de5SVasanthakumar Thiagarajan } 88391d57de5SVasanthakumar Thiagarajan 88491d57de5SVasanthakumar Thiagarajan static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr) 88591d57de5SVasanthakumar Thiagarajan { 88691d57de5SVasanthakumar Thiagarajan int i; 88791d57de5SVasanthakumar Thiagarajan 88891d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { 88991d57de5SVasanthakumar Thiagarajan if (reg_addr >= diag_reg[i].reg_start && 89091d57de5SVasanthakumar Thiagarajan reg_addr <= diag_reg[i].reg_end) 89191d57de5SVasanthakumar Thiagarajan return true; 89291d57de5SVasanthakumar Thiagarajan } 89391d57de5SVasanthakumar Thiagarajan 89491d57de5SVasanthakumar Thiagarajan return false; 89591d57de5SVasanthakumar Thiagarajan } 89691d57de5SVasanthakumar Thiagarajan 89791d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf, 89891d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 89991d57de5SVasanthakumar Thiagarajan { 90091d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 90191d57de5SVasanthakumar Thiagarajan u8 buf[50]; 90291d57de5SVasanthakumar Thiagarajan unsigned int len = 0; 90391d57de5SVasanthakumar Thiagarajan 90491d57de5SVasanthakumar Thiagarajan if (ar->debug.dbgfs_diag_reg) 90591d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", 90691d57de5SVasanthakumar Thiagarajan ar->debug.dbgfs_diag_reg); 90791d57de5SVasanthakumar Thiagarajan else 90891d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, sizeof(buf) - len, 90991d57de5SVasanthakumar Thiagarajan "All diag registers\n"); 91091d57de5SVasanthakumar Thiagarajan 91191d57de5SVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 91291d57de5SVasanthakumar Thiagarajan } 91391d57de5SVasanthakumar Thiagarajan 91491d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regread_write(struct file *file, 91591d57de5SVasanthakumar Thiagarajan const char __user *user_buf, 91691d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 91791d57de5SVasanthakumar Thiagarajan { 91891d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 91991d57de5SVasanthakumar Thiagarajan unsigned long reg_addr; 92091d57de5SVasanthakumar Thiagarajan 92106f33f13SKalle Valo if (kstrtoul_from_user(user_buf, count, 0, ®_addr)) 92291d57de5SVasanthakumar Thiagarajan return -EINVAL; 92391d57de5SVasanthakumar Thiagarajan 92491d57de5SVasanthakumar Thiagarajan if ((reg_addr % 4) != 0) 92591d57de5SVasanthakumar Thiagarajan return -EINVAL; 92691d57de5SVasanthakumar Thiagarajan 92791d57de5SVasanthakumar Thiagarajan if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr)) 92891d57de5SVasanthakumar Thiagarajan return -EINVAL; 92991d57de5SVasanthakumar Thiagarajan 93091d57de5SVasanthakumar Thiagarajan ar->debug.dbgfs_diag_reg = reg_addr; 93191d57de5SVasanthakumar Thiagarajan 93291d57de5SVasanthakumar Thiagarajan return count; 93391d57de5SVasanthakumar Thiagarajan } 93491d57de5SVasanthakumar Thiagarajan 93591d57de5SVasanthakumar Thiagarajan static const struct file_operations fops_diag_reg_read = { 93691d57de5SVasanthakumar Thiagarajan .read = ath6kl_regread_read, 93791d57de5SVasanthakumar Thiagarajan .write = ath6kl_regread_write, 938234e3405SStephen Boyd .open = simple_open, 93991d57de5SVasanthakumar Thiagarajan .owner = THIS_MODULE, 94091d57de5SVasanthakumar Thiagarajan .llseek = default_llseek, 94191d57de5SVasanthakumar Thiagarajan }; 94291d57de5SVasanthakumar Thiagarajan 94391d57de5SVasanthakumar Thiagarajan static int ath6kl_regdump_open(struct inode *inode, struct file *file) 94491d57de5SVasanthakumar Thiagarajan { 94591d57de5SVasanthakumar Thiagarajan struct ath6kl *ar = inode->i_private; 94691d57de5SVasanthakumar Thiagarajan u8 *buf; 94791d57de5SVasanthakumar Thiagarajan unsigned long int reg_len; 94891d57de5SVasanthakumar Thiagarajan unsigned int len = 0, n_reg; 94991d57de5SVasanthakumar Thiagarajan u32 addr; 95091d57de5SVasanthakumar Thiagarajan __le32 reg_val; 95191d57de5SVasanthakumar Thiagarajan int i, status; 95291d57de5SVasanthakumar Thiagarajan 95391d57de5SVasanthakumar Thiagarajan /* Dump all the registers if no register is specified */ 95491d57de5SVasanthakumar Thiagarajan if (!ar->debug.dbgfs_diag_reg) 95591d57de5SVasanthakumar Thiagarajan n_reg = ath6kl_get_num_reg(); 95691d57de5SVasanthakumar Thiagarajan else 95791d57de5SVasanthakumar Thiagarajan n_reg = 1; 95891d57de5SVasanthakumar Thiagarajan 95991d57de5SVasanthakumar Thiagarajan reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE; 96091d57de5SVasanthakumar Thiagarajan if (n_reg > 1) 96191d57de5SVasanthakumar Thiagarajan reg_len += REGTYPE_STR_LEN; 96291d57de5SVasanthakumar Thiagarajan 96391d57de5SVasanthakumar Thiagarajan buf = vmalloc(reg_len); 96491d57de5SVasanthakumar Thiagarajan if (!buf) 96591d57de5SVasanthakumar Thiagarajan return -ENOMEM; 96691d57de5SVasanthakumar Thiagarajan 96791d57de5SVasanthakumar Thiagarajan if (n_reg == 1) { 96891d57de5SVasanthakumar Thiagarajan addr = ar->debug.dbgfs_diag_reg; 96991d57de5SVasanthakumar Thiagarajan 97091d57de5SVasanthakumar Thiagarajan status = ath6kl_diag_read32(ar, 97191d57de5SVasanthakumar Thiagarajan TARG_VTOP(ar->target_type, addr), 97291d57de5SVasanthakumar Thiagarajan (u32 *)®_val); 97391d57de5SVasanthakumar Thiagarajan if (status) 97491d57de5SVasanthakumar Thiagarajan goto fail_reg_read; 97591d57de5SVasanthakumar Thiagarajan 97691d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 97791d57de5SVasanthakumar Thiagarajan "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val)); 97891d57de5SVasanthakumar Thiagarajan goto done; 97991d57de5SVasanthakumar Thiagarajan } 98091d57de5SVasanthakumar Thiagarajan 98191d57de5SVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { 98291d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 98391d57de5SVasanthakumar Thiagarajan "%s\n", diag_reg[i].reg_info); 98491d57de5SVasanthakumar Thiagarajan for (addr = diag_reg[i].reg_start; 98591d57de5SVasanthakumar Thiagarajan addr <= diag_reg[i].reg_end; addr += 4) { 98691d57de5SVasanthakumar Thiagarajan status = ath6kl_diag_read32(ar, 98791d57de5SVasanthakumar Thiagarajan TARG_VTOP(ar->target_type, addr), 98891d57de5SVasanthakumar Thiagarajan (u32 *)®_val); 98991d57de5SVasanthakumar Thiagarajan if (status) 99091d57de5SVasanthakumar Thiagarajan goto fail_reg_read; 99191d57de5SVasanthakumar Thiagarajan 99291d57de5SVasanthakumar Thiagarajan len += scnprintf(buf + len, reg_len - len, 99391d57de5SVasanthakumar Thiagarajan "0x%06x 0x%08x\n", 99491d57de5SVasanthakumar Thiagarajan addr, le32_to_cpu(reg_val)); 99591d57de5SVasanthakumar Thiagarajan } 99691d57de5SVasanthakumar Thiagarajan } 99791d57de5SVasanthakumar Thiagarajan 99891d57de5SVasanthakumar Thiagarajan done: 99991d57de5SVasanthakumar Thiagarajan file->private_data = buf; 100091d57de5SVasanthakumar Thiagarajan return 0; 100191d57de5SVasanthakumar Thiagarajan 100291d57de5SVasanthakumar Thiagarajan fail_reg_read: 100391d57de5SVasanthakumar Thiagarajan ath6kl_warn("Unable to read memory:%u\n", addr); 100491d57de5SVasanthakumar Thiagarajan vfree(buf); 100591d57de5SVasanthakumar Thiagarajan return -EIO; 100691d57de5SVasanthakumar Thiagarajan } 100791d57de5SVasanthakumar Thiagarajan 100891d57de5SVasanthakumar Thiagarajan static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf, 100991d57de5SVasanthakumar Thiagarajan size_t count, loff_t *ppos) 101091d57de5SVasanthakumar Thiagarajan { 101191d57de5SVasanthakumar Thiagarajan u8 *buf = file->private_data; 101291d57de5SVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); 101391d57de5SVasanthakumar Thiagarajan } 101491d57de5SVasanthakumar Thiagarajan 101591d57de5SVasanthakumar Thiagarajan static int ath6kl_regdump_release(struct inode *inode, struct file *file) 101691d57de5SVasanthakumar Thiagarajan { 101791d57de5SVasanthakumar Thiagarajan vfree(file->private_data); 101891d57de5SVasanthakumar Thiagarajan return 0; 101991d57de5SVasanthakumar Thiagarajan } 102091d57de5SVasanthakumar Thiagarajan 102191d57de5SVasanthakumar Thiagarajan static const struct file_operations fops_reg_dump = { 102291d57de5SVasanthakumar Thiagarajan .open = ath6kl_regdump_open, 102391d57de5SVasanthakumar Thiagarajan .read = ath6kl_regdump_read, 102491d57de5SVasanthakumar Thiagarajan .release = ath6kl_regdump_release, 102591d57de5SVasanthakumar Thiagarajan .owner = THIS_MODULE, 102691d57de5SVasanthakumar Thiagarajan .llseek = default_llseek, 102791d57de5SVasanthakumar Thiagarajan }; 102891d57de5SVasanthakumar Thiagarajan 1029e5090444SVivek Natarajan static ssize_t ath6kl_lrssi_roam_write(struct file *file, 1030e5090444SVivek Natarajan const char __user *user_buf, 1031e5090444SVivek Natarajan size_t count, loff_t *ppos) 1032e5090444SVivek Natarajan { 1033e5090444SVivek Natarajan struct ath6kl *ar = file->private_data; 1034e5090444SVivek Natarajan unsigned long lrssi_roam_threshold; 1035e5090444SVivek Natarajan 103606f33f13SKalle Valo if (kstrtoul_from_user(user_buf, count, 0, &lrssi_roam_threshold)) 1037e5090444SVivek Natarajan return -EINVAL; 1038e5090444SVivek Natarajan 1039e5090444SVivek Natarajan ar->lrssi_roam_threshold = lrssi_roam_threshold; 1040e5090444SVivek Natarajan 1041e5090444SVivek Natarajan ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold); 1042e5090444SVivek Natarajan 1043e5090444SVivek Natarajan return count; 1044e5090444SVivek Natarajan } 1045e5090444SVivek Natarajan 1046e5090444SVivek Natarajan static ssize_t ath6kl_lrssi_roam_read(struct file *file, 1047e5090444SVivek Natarajan char __user *user_buf, 1048e5090444SVivek Natarajan size_t count, loff_t *ppos) 1049e5090444SVivek Natarajan { 1050e5090444SVivek Natarajan struct ath6kl *ar = file->private_data; 1051e5090444SVivek Natarajan char buf[32]; 1052e5090444SVivek Natarajan unsigned int len; 1053e5090444SVivek Natarajan 1054e5090444SVivek Natarajan len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold); 1055e5090444SVivek Natarajan 1056e5090444SVivek Natarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1057e5090444SVivek Natarajan } 1058e5090444SVivek Natarajan 1059e5090444SVivek Natarajan static const struct file_operations fops_lrssi_roam_threshold = { 1060e5090444SVivek Natarajan .read = ath6kl_lrssi_roam_read, 1061e5090444SVivek Natarajan .write = ath6kl_lrssi_roam_write, 1062234e3405SStephen Boyd .open = simple_open, 1063e5090444SVivek Natarajan .owner = THIS_MODULE, 1064e5090444SVivek Natarajan .llseek = default_llseek, 1065e5090444SVivek Natarajan }; 1066e5090444SVivek Natarajan 1067252c068bSVasanthakumar Thiagarajan static ssize_t ath6kl_regwrite_read(struct file *file, 1068252c068bSVasanthakumar Thiagarajan char __user *user_buf, 1069252c068bSVasanthakumar Thiagarajan size_t count, loff_t *ppos) 1070252c068bSVasanthakumar Thiagarajan { 1071252c068bSVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 1072252c068bSVasanthakumar Thiagarajan u8 buf[32]; 1073252c068bSVasanthakumar Thiagarajan unsigned int len = 0; 1074252c068bSVasanthakumar Thiagarajan 1075252c068bSVasanthakumar Thiagarajan len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n", 1076252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr); 1077252c068bSVasanthakumar Thiagarajan 1078252c068bSVasanthakumar Thiagarajan return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1079252c068bSVasanthakumar Thiagarajan } 1080252c068bSVasanthakumar Thiagarajan 1081252c068bSVasanthakumar Thiagarajan static ssize_t ath6kl_regwrite_write(struct file *file, 1082252c068bSVasanthakumar Thiagarajan const char __user *user_buf, 1083252c068bSVasanthakumar Thiagarajan size_t count, loff_t *ppos) 1084252c068bSVasanthakumar Thiagarajan { 1085252c068bSVasanthakumar Thiagarajan struct ath6kl *ar = file->private_data; 1086252c068bSVasanthakumar Thiagarajan char buf[32]; 1087252c068bSVasanthakumar Thiagarajan char *sptr, *token; 1088252c068bSVasanthakumar Thiagarajan unsigned int len = 0; 1089252c068bSVasanthakumar Thiagarajan u32 reg_addr, reg_val; 1090252c068bSVasanthakumar Thiagarajan 1091252c068bSVasanthakumar Thiagarajan len = min(count, sizeof(buf) - 1); 1092252c068bSVasanthakumar Thiagarajan if (copy_from_user(buf, user_buf, len)) 1093252c068bSVasanthakumar Thiagarajan return -EFAULT; 1094252c068bSVasanthakumar Thiagarajan 1095252c068bSVasanthakumar Thiagarajan buf[len] = '\0'; 1096252c068bSVasanthakumar Thiagarajan sptr = buf; 1097252c068bSVasanthakumar Thiagarajan 1098252c068bSVasanthakumar Thiagarajan token = strsep(&sptr, "="); 1099252c068bSVasanthakumar Thiagarajan if (!token) 1100252c068bSVasanthakumar Thiagarajan return -EINVAL; 1101252c068bSVasanthakumar Thiagarajan 1102252c068bSVasanthakumar Thiagarajan if (kstrtou32(token, 0, ®_addr)) 1103252c068bSVasanthakumar Thiagarajan return -EINVAL; 1104252c068bSVasanthakumar Thiagarajan 1105252c068bSVasanthakumar Thiagarajan if (!ath6kl_dbg_is_diag_reg_valid(reg_addr)) 1106252c068bSVasanthakumar Thiagarajan return -EINVAL; 1107252c068bSVasanthakumar Thiagarajan 1108252c068bSVasanthakumar Thiagarajan if (kstrtou32(sptr, 0, ®_val)) 1109252c068bSVasanthakumar Thiagarajan return -EINVAL; 1110252c068bSVasanthakumar Thiagarajan 1111252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_addr_wr = reg_addr; 1112252c068bSVasanthakumar Thiagarajan ar->debug.diag_reg_val_wr = reg_val; 1113252c068bSVasanthakumar Thiagarajan 1114252c068bSVasanthakumar Thiagarajan if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr, 1115252c068bSVasanthakumar Thiagarajan cpu_to_le32(ar->debug.diag_reg_val_wr))) 1116252c068bSVasanthakumar Thiagarajan return -EIO; 1117252c068bSVasanthakumar Thiagarajan 1118252c068bSVasanthakumar Thiagarajan return count; 1119252c068bSVasanthakumar Thiagarajan } 1120252c068bSVasanthakumar Thiagarajan 1121252c068bSVasanthakumar Thiagarajan static const struct file_operations fops_diag_reg_write = { 1122252c068bSVasanthakumar Thiagarajan .read = ath6kl_regwrite_read, 1123252c068bSVasanthakumar Thiagarajan .write = ath6kl_regwrite_write, 1124234e3405SStephen Boyd .open = simple_open, 1125252c068bSVasanthakumar Thiagarajan .owner = THIS_MODULE, 1126252c068bSVasanthakumar Thiagarajan .llseek = default_llseek, 1127252c068bSVasanthakumar Thiagarajan }; 1128252c068bSVasanthakumar Thiagarajan 11294b28a80dSJouni Malinen int ath6kl_debug_roam_tbl_event(struct ath6kl *ar, const void *buf, 11304b28a80dSJouni Malinen size_t len) 11314b28a80dSJouni Malinen { 11324b28a80dSJouni Malinen const struct wmi_target_roam_tbl *tbl; 11334b28a80dSJouni Malinen u16 num_entries; 11344b28a80dSJouni Malinen 11354b28a80dSJouni Malinen if (len < sizeof(*tbl)) 11364b28a80dSJouni Malinen return -EINVAL; 11374b28a80dSJouni Malinen 11384b28a80dSJouni Malinen tbl = (const struct wmi_target_roam_tbl *) buf; 11394b28a80dSJouni Malinen num_entries = le16_to_cpu(tbl->num_entries); 11404b28a80dSJouni Malinen if (sizeof(*tbl) + num_entries * sizeof(struct wmi_bss_roam_info) > 11414b28a80dSJouni Malinen len) 11424b28a80dSJouni Malinen return -EINVAL; 11434b28a80dSJouni Malinen 11444b28a80dSJouni Malinen if (ar->debug.roam_tbl == NULL || 11454b28a80dSJouni Malinen ar->debug.roam_tbl_len < (unsigned int) len) { 11464b28a80dSJouni Malinen kfree(ar->debug.roam_tbl); 11474b28a80dSJouni Malinen ar->debug.roam_tbl = kmalloc(len, GFP_ATOMIC); 11484b28a80dSJouni Malinen if (ar->debug.roam_tbl == NULL) 11494b28a80dSJouni Malinen return -ENOMEM; 11504b28a80dSJouni Malinen } 11514b28a80dSJouni Malinen 11524b28a80dSJouni Malinen memcpy(ar->debug.roam_tbl, buf, len); 11534b28a80dSJouni Malinen ar->debug.roam_tbl_len = len; 11544b28a80dSJouni Malinen 11554b28a80dSJouni Malinen if (test_bit(ROAM_TBL_PEND, &ar->flag)) { 11564b28a80dSJouni Malinen clear_bit(ROAM_TBL_PEND, &ar->flag); 11574b28a80dSJouni Malinen wake_up(&ar->event_wq); 11584b28a80dSJouni Malinen } 11594b28a80dSJouni Malinen 11604b28a80dSJouni Malinen return 0; 11614b28a80dSJouni Malinen } 11624b28a80dSJouni Malinen 11634b28a80dSJouni Malinen static ssize_t ath6kl_roam_table_read(struct file *file, char __user *user_buf, 11644b28a80dSJouni Malinen size_t count, loff_t *ppos) 11654b28a80dSJouni Malinen { 11664b28a80dSJouni Malinen struct ath6kl *ar = file->private_data; 11674b28a80dSJouni Malinen int ret; 11684b28a80dSJouni Malinen long left; 11694b28a80dSJouni Malinen struct wmi_target_roam_tbl *tbl; 11704b28a80dSJouni Malinen u16 num_entries, i; 11714b28a80dSJouni Malinen char *buf; 11724b28a80dSJouni Malinen unsigned int len, buf_len; 11734b28a80dSJouni Malinen ssize_t ret_cnt; 11744b28a80dSJouni Malinen 11754b28a80dSJouni Malinen if (down_interruptible(&ar->sem)) 11764b28a80dSJouni Malinen return -EBUSY; 11774b28a80dSJouni Malinen 11784b28a80dSJouni Malinen set_bit(ROAM_TBL_PEND, &ar->flag); 11794b28a80dSJouni Malinen 11804b28a80dSJouni Malinen ret = ath6kl_wmi_get_roam_tbl_cmd(ar->wmi); 11814b28a80dSJouni Malinen if (ret) { 11824b28a80dSJouni Malinen up(&ar->sem); 11834b28a80dSJouni Malinen return ret; 11844b28a80dSJouni Malinen } 11854b28a80dSJouni Malinen 11864b28a80dSJouni Malinen left = wait_event_interruptible_timeout( 11874b28a80dSJouni Malinen ar->event_wq, !test_bit(ROAM_TBL_PEND, &ar->flag), WMI_TIMEOUT); 11884b28a80dSJouni Malinen up(&ar->sem); 11894b28a80dSJouni Malinen 11904b28a80dSJouni Malinen if (left <= 0) 11914b28a80dSJouni Malinen return -ETIMEDOUT; 11924b28a80dSJouni Malinen 11934b28a80dSJouni Malinen if (ar->debug.roam_tbl == NULL) 11944b28a80dSJouni Malinen return -ENOMEM; 11954b28a80dSJouni Malinen 11964b28a80dSJouni Malinen tbl = (struct wmi_target_roam_tbl *) ar->debug.roam_tbl; 11974b28a80dSJouni Malinen num_entries = le16_to_cpu(tbl->num_entries); 11984b28a80dSJouni Malinen 11994b28a80dSJouni Malinen buf_len = 100 + num_entries * 100; 12004b28a80dSJouni Malinen buf = kzalloc(buf_len, GFP_KERNEL); 12014b28a80dSJouni Malinen if (buf == NULL) 12024b28a80dSJouni Malinen return -ENOMEM; 12034b28a80dSJouni Malinen len = 0; 12044b28a80dSJouni Malinen len += scnprintf(buf + len, buf_len - len, 12054b28a80dSJouni Malinen "roam_mode=%u\n\n" 12064b28a80dSJouni Malinen "# roam_util bssid rssi rssidt last_rssi util bias\n", 12074b28a80dSJouni Malinen le16_to_cpu(tbl->roam_mode)); 12084b28a80dSJouni Malinen 12094b28a80dSJouni Malinen for (i = 0; i < num_entries; i++) { 12104b28a80dSJouni Malinen struct wmi_bss_roam_info *info = &tbl->info[i]; 12114b28a80dSJouni Malinen len += scnprintf(buf + len, buf_len - len, 12124b28a80dSJouni Malinen "%d %pM %d %d %d %d %d\n", 12134b28a80dSJouni Malinen a_sle32_to_cpu(info->roam_util), info->bssid, 12144b28a80dSJouni Malinen info->rssi, info->rssidt, info->last_rssi, 12154b28a80dSJouni Malinen info->util, info->bias); 12164b28a80dSJouni Malinen } 12174b28a80dSJouni Malinen 12184b28a80dSJouni Malinen if (len > buf_len) 12194b28a80dSJouni Malinen len = buf_len; 12204b28a80dSJouni Malinen 12214b28a80dSJouni Malinen ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); 12224b28a80dSJouni Malinen 12234b28a80dSJouni Malinen kfree(buf); 12244b28a80dSJouni Malinen return ret_cnt; 12254b28a80dSJouni Malinen } 12264b28a80dSJouni Malinen 12274b28a80dSJouni Malinen static const struct file_operations fops_roam_table = { 12284b28a80dSJouni Malinen .read = ath6kl_roam_table_read, 1229234e3405SStephen Boyd .open = simple_open, 12304b28a80dSJouni Malinen .owner = THIS_MODULE, 12314b28a80dSJouni Malinen .llseek = default_llseek, 12324b28a80dSJouni Malinen }; 12334b28a80dSJouni Malinen 12341261875fSJouni Malinen static ssize_t ath6kl_force_roam_write(struct file *file, 12351261875fSJouni Malinen const char __user *user_buf, 12361261875fSJouni Malinen size_t count, loff_t *ppos) 12371261875fSJouni Malinen { 12381261875fSJouni Malinen struct ath6kl *ar = file->private_data; 12391261875fSJouni Malinen int ret; 12401261875fSJouni Malinen char buf[20]; 12411261875fSJouni Malinen size_t len; 12421261875fSJouni Malinen u8 bssid[ETH_ALEN]; 12431261875fSJouni Malinen int i; 12441261875fSJouni Malinen int addr[ETH_ALEN]; 12451261875fSJouni Malinen 12461261875fSJouni Malinen len = min(count, sizeof(buf) - 1); 12471261875fSJouni Malinen if (copy_from_user(buf, user_buf, len)) 12481261875fSJouni Malinen return -EFAULT; 12491261875fSJouni Malinen buf[len] = '\0'; 12501261875fSJouni Malinen 12511261875fSJouni Malinen if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", 12521261875fSJouni Malinen &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) 12531261875fSJouni Malinen != ETH_ALEN) 12541261875fSJouni Malinen return -EINVAL; 12551261875fSJouni Malinen for (i = 0; i < ETH_ALEN; i++) 12561261875fSJouni Malinen bssid[i] = addr[i]; 12571261875fSJouni Malinen 12581261875fSJouni Malinen ret = ath6kl_wmi_force_roam_cmd(ar->wmi, bssid); 12591261875fSJouni Malinen if (ret) 12601261875fSJouni Malinen return ret; 12611261875fSJouni Malinen 12621261875fSJouni Malinen return count; 12631261875fSJouni Malinen } 12641261875fSJouni Malinen 12651261875fSJouni Malinen static const struct file_operations fops_force_roam = { 12661261875fSJouni Malinen .write = ath6kl_force_roam_write, 1267234e3405SStephen Boyd .open = simple_open, 12681261875fSJouni Malinen .owner = THIS_MODULE, 12691261875fSJouni Malinen .llseek = default_llseek, 12701261875fSJouni Malinen }; 12711261875fSJouni Malinen 12721261875fSJouni Malinen static ssize_t ath6kl_roam_mode_write(struct file *file, 12731261875fSJouni Malinen const char __user *user_buf, 12741261875fSJouni Malinen size_t count, loff_t *ppos) 12751261875fSJouni Malinen { 12761261875fSJouni Malinen struct ath6kl *ar = file->private_data; 12771261875fSJouni Malinen int ret; 12781261875fSJouni Malinen char buf[20]; 12791261875fSJouni Malinen size_t len; 12801261875fSJouni Malinen enum wmi_roam_mode mode; 12811261875fSJouni Malinen 12821261875fSJouni Malinen len = min(count, sizeof(buf) - 1); 12831261875fSJouni Malinen if (copy_from_user(buf, user_buf, len)) 12841261875fSJouni Malinen return -EFAULT; 12851261875fSJouni Malinen buf[len] = '\0'; 12861261875fSJouni Malinen if (len > 0 && buf[len - 1] == '\n') 12871261875fSJouni Malinen buf[len - 1] = '\0'; 12881261875fSJouni Malinen 12891261875fSJouni Malinen if (strcasecmp(buf, "default") == 0) 12901261875fSJouni Malinen mode = WMI_DEFAULT_ROAM_MODE; 12911261875fSJouni Malinen else if (strcasecmp(buf, "bssbias") == 0) 12921261875fSJouni Malinen mode = WMI_HOST_BIAS_ROAM_MODE; 12931261875fSJouni Malinen else if (strcasecmp(buf, "lock") == 0) 12941261875fSJouni Malinen mode = WMI_LOCK_BSS_MODE; 12951261875fSJouni Malinen else 12961261875fSJouni Malinen return -EINVAL; 12971261875fSJouni Malinen 12981261875fSJouni Malinen ret = ath6kl_wmi_set_roam_mode_cmd(ar->wmi, mode); 12991261875fSJouni Malinen if (ret) 13001261875fSJouni Malinen return ret; 13011261875fSJouni Malinen 13021261875fSJouni Malinen return count; 13031261875fSJouni Malinen } 13041261875fSJouni Malinen 13051261875fSJouni Malinen static const struct file_operations fops_roam_mode = { 13061261875fSJouni Malinen .write = ath6kl_roam_mode_write, 1307234e3405SStephen Boyd .open = simple_open, 13081261875fSJouni Malinen .owner = THIS_MODULE, 13091261875fSJouni Malinen .llseek = default_llseek, 13101261875fSJouni Malinen }; 13111261875fSJouni Malinen 1312ff0b0075SJouni Malinen void ath6kl_debug_set_keepalive(struct ath6kl *ar, u8 keepalive) 1313ff0b0075SJouni Malinen { 1314ff0b0075SJouni Malinen ar->debug.keepalive = keepalive; 1315ff0b0075SJouni Malinen } 1316ff0b0075SJouni Malinen 1317ff0b0075SJouni Malinen static ssize_t ath6kl_keepalive_read(struct file *file, char __user *user_buf, 1318ff0b0075SJouni Malinen size_t count, loff_t *ppos) 1319ff0b0075SJouni Malinen { 1320ff0b0075SJouni Malinen struct ath6kl *ar = file->private_data; 1321ff0b0075SJouni Malinen char buf[16]; 1322ff0b0075SJouni Malinen int len; 1323ff0b0075SJouni Malinen 1324ff0b0075SJouni Malinen len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.keepalive); 1325ff0b0075SJouni Malinen 1326ff0b0075SJouni Malinen return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1327ff0b0075SJouni Malinen } 1328ff0b0075SJouni Malinen 1329ff0b0075SJouni Malinen static ssize_t ath6kl_keepalive_write(struct file *file, 1330ff0b0075SJouni Malinen const char __user *user_buf, 1331ff0b0075SJouni Malinen size_t count, loff_t *ppos) 1332ff0b0075SJouni Malinen { 1333ff0b0075SJouni Malinen struct ath6kl *ar = file->private_data; 1334ff0b0075SJouni Malinen int ret; 1335ff0b0075SJouni Malinen u8 val; 1336ff0b0075SJouni Malinen 1337ff0b0075SJouni Malinen ret = kstrtou8_from_user(user_buf, count, 0, &val); 1338ff0b0075SJouni Malinen if (ret) 1339ff0b0075SJouni Malinen return ret; 1340ff0b0075SJouni Malinen 13410ce59445SVasanthakumar Thiagarajan ret = ath6kl_wmi_set_keepalive_cmd(ar->wmi, 0, val); 1342ff0b0075SJouni Malinen if (ret) 1343ff0b0075SJouni Malinen return ret; 1344ff0b0075SJouni Malinen 1345ff0b0075SJouni Malinen return count; 1346ff0b0075SJouni Malinen } 1347ff0b0075SJouni Malinen 1348ff0b0075SJouni Malinen static const struct file_operations fops_keepalive = { 1349234e3405SStephen Boyd .open = simple_open, 1350ff0b0075SJouni Malinen .read = ath6kl_keepalive_read, 1351ff0b0075SJouni Malinen .write = ath6kl_keepalive_write, 1352ff0b0075SJouni Malinen .owner = THIS_MODULE, 1353ff0b0075SJouni Malinen .llseek = default_llseek, 1354ff0b0075SJouni Malinen }; 1355ff0b0075SJouni Malinen 1356ff0b0075SJouni Malinen void ath6kl_debug_set_disconnect_timeout(struct ath6kl *ar, u8 timeout) 1357ff0b0075SJouni Malinen { 1358ff0b0075SJouni Malinen ar->debug.disc_timeout = timeout; 1359ff0b0075SJouni Malinen } 1360ff0b0075SJouni Malinen 1361ff0b0075SJouni Malinen static ssize_t ath6kl_disconnect_timeout_read(struct file *file, 1362ff0b0075SJouni Malinen char __user *user_buf, 1363ff0b0075SJouni Malinen size_t count, loff_t *ppos) 1364ff0b0075SJouni Malinen { 1365ff0b0075SJouni Malinen struct ath6kl *ar = file->private_data; 1366ff0b0075SJouni Malinen char buf[16]; 1367ff0b0075SJouni Malinen int len; 1368ff0b0075SJouni Malinen 1369ff0b0075SJouni Malinen len = snprintf(buf, sizeof(buf), "%u\n", ar->debug.disc_timeout); 1370ff0b0075SJouni Malinen 1371ff0b0075SJouni Malinen return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1372ff0b0075SJouni Malinen } 1373ff0b0075SJouni Malinen 1374ff0b0075SJouni Malinen static ssize_t ath6kl_disconnect_timeout_write(struct file *file, 1375ff0b0075SJouni Malinen const char __user *user_buf, 1376ff0b0075SJouni Malinen size_t count, loff_t *ppos) 1377ff0b0075SJouni Malinen { 1378ff0b0075SJouni Malinen struct ath6kl *ar = file->private_data; 1379ff0b0075SJouni Malinen int ret; 1380ff0b0075SJouni Malinen u8 val; 1381ff0b0075SJouni Malinen 1382ff0b0075SJouni Malinen ret = kstrtou8_from_user(user_buf, count, 0, &val); 1383ff0b0075SJouni Malinen if (ret) 1384ff0b0075SJouni Malinen return ret; 1385ff0b0075SJouni Malinen 13860ce59445SVasanthakumar Thiagarajan ret = ath6kl_wmi_disctimeout_cmd(ar->wmi, 0, val); 1387ff0b0075SJouni Malinen if (ret) 1388ff0b0075SJouni Malinen return ret; 1389ff0b0075SJouni Malinen 1390ff0b0075SJouni Malinen return count; 1391ff0b0075SJouni Malinen } 1392ff0b0075SJouni Malinen 1393ff0b0075SJouni Malinen static const struct file_operations fops_disconnect_timeout = { 1394234e3405SStephen Boyd .open = simple_open, 1395ff0b0075SJouni Malinen .read = ath6kl_disconnect_timeout_read, 1396ff0b0075SJouni Malinen .write = ath6kl_disconnect_timeout_write, 1397ff0b0075SJouni Malinen .owner = THIS_MODULE, 1398ff0b0075SJouni Malinen .llseek = default_llseek, 1399ff0b0075SJouni Malinen }; 1400ff0b0075SJouni Malinen 14018fffd9e5SRishi Panjwani static ssize_t ath6kl_create_qos_write(struct file *file, 14028fffd9e5SRishi Panjwani const char __user *user_buf, 14038fffd9e5SRishi Panjwani size_t count, loff_t *ppos) 14048fffd9e5SRishi Panjwani { 14058fffd9e5SRishi Panjwani 14068fffd9e5SRishi Panjwani struct ath6kl *ar = file->private_data; 1407990bd915SVasanthakumar Thiagarajan struct ath6kl_vif *vif; 14088cb6d991SVasanthakumar Thiagarajan char buf[200]; 14098fffd9e5SRishi Panjwani ssize_t len; 14108fffd9e5SRishi Panjwani char *sptr, *token; 14118fffd9e5SRishi Panjwani struct wmi_create_pstream_cmd pstream; 14128fffd9e5SRishi Panjwani u32 val32; 14138fffd9e5SRishi Panjwani u16 val16; 14148fffd9e5SRishi Panjwani 1415990bd915SVasanthakumar Thiagarajan vif = ath6kl_vif_first(ar); 1416990bd915SVasanthakumar Thiagarajan if (!vif) 1417990bd915SVasanthakumar Thiagarajan return -EIO; 1418990bd915SVasanthakumar Thiagarajan 14198fffd9e5SRishi Panjwani len = min(count, sizeof(buf) - 1); 14208fffd9e5SRishi Panjwani if (copy_from_user(buf, user_buf, len)) 14218fffd9e5SRishi Panjwani return -EFAULT; 14228fffd9e5SRishi Panjwani buf[len] = '\0'; 14238fffd9e5SRishi Panjwani sptr = buf; 14248fffd9e5SRishi Panjwani 14258fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14268fffd9e5SRishi Panjwani if (!token) 14278fffd9e5SRishi Panjwani return -EINVAL; 14288fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &pstream.user_pri)) 14298fffd9e5SRishi Panjwani return -EINVAL; 14308fffd9e5SRishi Panjwani 14318fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14328fffd9e5SRishi Panjwani if (!token) 14338fffd9e5SRishi Panjwani return -EINVAL; 14348fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &pstream.traffic_direc)) 14358fffd9e5SRishi Panjwani return -EINVAL; 14368fffd9e5SRishi Panjwani 14378fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14388fffd9e5SRishi Panjwani if (!token) 14398fffd9e5SRishi Panjwani return -EINVAL; 14408fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &pstream.traffic_class)) 14418fffd9e5SRishi Panjwani return -EINVAL; 14428fffd9e5SRishi Panjwani 14438fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14448fffd9e5SRishi Panjwani if (!token) 14458fffd9e5SRishi Panjwani return -EINVAL; 14468fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &pstream.traffic_type)) 14478fffd9e5SRishi Panjwani return -EINVAL; 14488fffd9e5SRishi Panjwani 14498fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14508fffd9e5SRishi Panjwani if (!token) 14518fffd9e5SRishi Panjwani return -EINVAL; 14528fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &pstream.voice_psc_cap)) 14538fffd9e5SRishi Panjwani return -EINVAL; 14548fffd9e5SRishi Panjwani 14558fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14568fffd9e5SRishi Panjwani if (!token) 14578fffd9e5SRishi Panjwani return -EINVAL; 14588fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 14598fffd9e5SRishi Panjwani return -EINVAL; 14608fffd9e5SRishi Panjwani pstream.min_service_int = cpu_to_le32(val32); 14618fffd9e5SRishi Panjwani 14628fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14638fffd9e5SRishi Panjwani if (!token) 14648fffd9e5SRishi Panjwani return -EINVAL; 14658fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 14668fffd9e5SRishi Panjwani return -EINVAL; 14678fffd9e5SRishi Panjwani pstream.max_service_int = cpu_to_le32(val32); 14688fffd9e5SRishi Panjwani 14698fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14708fffd9e5SRishi Panjwani if (!token) 14718fffd9e5SRishi Panjwani return -EINVAL; 14728fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 14738fffd9e5SRishi Panjwani return -EINVAL; 14748fffd9e5SRishi Panjwani pstream.inactivity_int = cpu_to_le32(val32); 14758fffd9e5SRishi Panjwani 14768fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14778fffd9e5SRishi Panjwani if (!token) 14788fffd9e5SRishi Panjwani return -EINVAL; 14798fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 14808fffd9e5SRishi Panjwani return -EINVAL; 14818fffd9e5SRishi Panjwani pstream.suspension_int = cpu_to_le32(val32); 14828fffd9e5SRishi Panjwani 14838fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14848fffd9e5SRishi Panjwani if (!token) 14858fffd9e5SRishi Panjwani return -EINVAL; 14868fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 14878fffd9e5SRishi Panjwani return -EINVAL; 14888fffd9e5SRishi Panjwani pstream.service_start_time = cpu_to_le32(val32); 14898fffd9e5SRishi Panjwani 14908fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14918fffd9e5SRishi Panjwani if (!token) 14928fffd9e5SRishi Panjwani return -EINVAL; 14938fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &pstream.tsid)) 14948fffd9e5SRishi Panjwani return -EINVAL; 14958fffd9e5SRishi Panjwani 14968fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 14978fffd9e5SRishi Panjwani if (!token) 14988fffd9e5SRishi Panjwani return -EINVAL; 14998fffd9e5SRishi Panjwani if (kstrtou16(token, 0, &val16)) 15008fffd9e5SRishi Panjwani return -EINVAL; 15018fffd9e5SRishi Panjwani pstream.nominal_msdu = cpu_to_le16(val16); 15028fffd9e5SRishi Panjwani 15038fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15048fffd9e5SRishi Panjwani if (!token) 15058fffd9e5SRishi Panjwani return -EINVAL; 15068fffd9e5SRishi Panjwani if (kstrtou16(token, 0, &val16)) 15078fffd9e5SRishi Panjwani return -EINVAL; 15088fffd9e5SRishi Panjwani pstream.max_msdu = cpu_to_le16(val16); 15098fffd9e5SRishi Panjwani 15108fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15118fffd9e5SRishi Panjwani if (!token) 15128fffd9e5SRishi Panjwani return -EINVAL; 15138fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15148fffd9e5SRishi Panjwani return -EINVAL; 15158fffd9e5SRishi Panjwani pstream.min_data_rate = cpu_to_le32(val32); 15168fffd9e5SRishi Panjwani 15178fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15188fffd9e5SRishi Panjwani if (!token) 15198fffd9e5SRishi Panjwani return -EINVAL; 15208fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15218fffd9e5SRishi Panjwani return -EINVAL; 15228fffd9e5SRishi Panjwani pstream.mean_data_rate = cpu_to_le32(val32); 15238fffd9e5SRishi Panjwani 15248fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15258fffd9e5SRishi Panjwani if (!token) 15268fffd9e5SRishi Panjwani return -EINVAL; 15278fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15288fffd9e5SRishi Panjwani return -EINVAL; 15298fffd9e5SRishi Panjwani pstream.peak_data_rate = cpu_to_le32(val32); 15308fffd9e5SRishi Panjwani 15318fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15328fffd9e5SRishi Panjwani if (!token) 15338fffd9e5SRishi Panjwani return -EINVAL; 15348fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15358fffd9e5SRishi Panjwani return -EINVAL; 15368fffd9e5SRishi Panjwani pstream.max_burst_size = cpu_to_le32(val32); 15378fffd9e5SRishi Panjwani 15388fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15398fffd9e5SRishi Panjwani if (!token) 15408fffd9e5SRishi Panjwani return -EINVAL; 15418fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15428fffd9e5SRishi Panjwani return -EINVAL; 15438fffd9e5SRishi Panjwani pstream.delay_bound = cpu_to_le32(val32); 15448fffd9e5SRishi Panjwani 15458fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15468fffd9e5SRishi Panjwani if (!token) 15478fffd9e5SRishi Panjwani return -EINVAL; 15488fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15498fffd9e5SRishi Panjwani return -EINVAL; 15508fffd9e5SRishi Panjwani pstream.min_phy_rate = cpu_to_le32(val32); 15518fffd9e5SRishi Panjwani 15528fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15538fffd9e5SRishi Panjwani if (!token) 15548fffd9e5SRishi Panjwani return -EINVAL; 15558fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15568fffd9e5SRishi Panjwani return -EINVAL; 15578fffd9e5SRishi Panjwani pstream.sba = cpu_to_le32(val32); 15588fffd9e5SRishi Panjwani 15598fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 15608fffd9e5SRishi Panjwani if (!token) 15618fffd9e5SRishi Panjwani return -EINVAL; 15628fffd9e5SRishi Panjwani if (kstrtou32(token, 0, &val32)) 15638fffd9e5SRishi Panjwani return -EINVAL; 15648fffd9e5SRishi Panjwani pstream.medium_time = cpu_to_le32(val32); 15658fffd9e5SRishi Panjwani 15665fbea5dcSChilam Ng pstream.nominal_phy = le32_to_cpu(pstream.min_phy_rate) / 1000000; 15675fbea5dcSChilam Ng 1568240d2799SVasanthakumar Thiagarajan ath6kl_wmi_create_pstream_cmd(ar->wmi, vif->fw_vif_idx, &pstream); 15698fffd9e5SRishi Panjwani 15708fffd9e5SRishi Panjwani return count; 15718fffd9e5SRishi Panjwani } 15728fffd9e5SRishi Panjwani 15738fffd9e5SRishi Panjwani static const struct file_operations fops_create_qos = { 15748fffd9e5SRishi Panjwani .write = ath6kl_create_qos_write, 1575234e3405SStephen Boyd .open = simple_open, 15768fffd9e5SRishi Panjwani .owner = THIS_MODULE, 15778fffd9e5SRishi Panjwani .llseek = default_llseek, 15788fffd9e5SRishi Panjwani }; 15798fffd9e5SRishi Panjwani 15808fffd9e5SRishi Panjwani static ssize_t ath6kl_delete_qos_write(struct file *file, 15818fffd9e5SRishi Panjwani const char __user *user_buf, 15828fffd9e5SRishi Panjwani size_t count, loff_t *ppos) 15838fffd9e5SRishi Panjwani { 15848fffd9e5SRishi Panjwani 15858fffd9e5SRishi Panjwani struct ath6kl *ar = file->private_data; 1586990bd915SVasanthakumar Thiagarajan struct ath6kl_vif *vif; 15878fffd9e5SRishi Panjwani char buf[100]; 15888fffd9e5SRishi Panjwani ssize_t len; 15898fffd9e5SRishi Panjwani char *sptr, *token; 15908fffd9e5SRishi Panjwani u8 traffic_class; 15918fffd9e5SRishi Panjwani u8 tsid; 15928fffd9e5SRishi Panjwani 1593990bd915SVasanthakumar Thiagarajan vif = ath6kl_vif_first(ar); 1594990bd915SVasanthakumar Thiagarajan if (!vif) 1595990bd915SVasanthakumar Thiagarajan return -EIO; 1596990bd915SVasanthakumar Thiagarajan 15978fffd9e5SRishi Panjwani len = min(count, sizeof(buf) - 1); 15988fffd9e5SRishi Panjwani if (copy_from_user(buf, user_buf, len)) 15998fffd9e5SRishi Panjwani return -EFAULT; 16008fffd9e5SRishi Panjwani buf[len] = '\0'; 16018fffd9e5SRishi Panjwani sptr = buf; 16028fffd9e5SRishi Panjwani 16038fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 16048fffd9e5SRishi Panjwani if (!token) 16058fffd9e5SRishi Panjwani return -EINVAL; 16068fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &traffic_class)) 16078fffd9e5SRishi Panjwani return -EINVAL; 16088fffd9e5SRishi Panjwani 16098fffd9e5SRishi Panjwani token = strsep(&sptr, " "); 16108fffd9e5SRishi Panjwani if (!token) 16118fffd9e5SRishi Panjwani return -EINVAL; 16128fffd9e5SRishi Panjwani if (kstrtou8(token, 0, &tsid)) 16138fffd9e5SRishi Panjwani return -EINVAL; 16148fffd9e5SRishi Panjwani 1615240d2799SVasanthakumar Thiagarajan ath6kl_wmi_delete_pstream_cmd(ar->wmi, vif->fw_vif_idx, 1616240d2799SVasanthakumar Thiagarajan traffic_class, tsid); 16178fffd9e5SRishi Panjwani 16188fffd9e5SRishi Panjwani return count; 16198fffd9e5SRishi Panjwani } 16208fffd9e5SRishi Panjwani 16218fffd9e5SRishi Panjwani static const struct file_operations fops_delete_qos = { 16228fffd9e5SRishi Panjwani .write = ath6kl_delete_qos_write, 1623234e3405SStephen Boyd .open = simple_open, 16248fffd9e5SRishi Panjwani .owner = THIS_MODULE, 16258fffd9e5SRishi Panjwani .llseek = default_llseek, 16268fffd9e5SRishi Panjwani }; 16278fffd9e5SRishi Panjwani 1628116b3a2eSRishi Panjwani static ssize_t ath6kl_bgscan_int_write(struct file *file, 1629116b3a2eSRishi Panjwani const char __user *user_buf, 1630116b3a2eSRishi Panjwani size_t count, loff_t *ppos) 1631116b3a2eSRishi Panjwani { 1632116b3a2eSRishi Panjwani struct ath6kl *ar = file->private_data; 1633eb38987eSRaja Mani struct ath6kl_vif *vif; 1634116b3a2eSRishi Panjwani u16 bgscan_int; 1635116b3a2eSRishi Panjwani char buf[32]; 1636116b3a2eSRishi Panjwani ssize_t len; 1637116b3a2eSRishi Panjwani 1638eb38987eSRaja Mani vif = ath6kl_vif_first(ar); 1639eb38987eSRaja Mani if (!vif) 1640eb38987eSRaja Mani return -EIO; 1641eb38987eSRaja Mani 1642116b3a2eSRishi Panjwani len = min(count, sizeof(buf) - 1); 1643116b3a2eSRishi Panjwani if (copy_from_user(buf, user_buf, len)) 1644116b3a2eSRishi Panjwani return -EFAULT; 1645116b3a2eSRishi Panjwani 1646116b3a2eSRishi Panjwani buf[len] = '\0'; 1647116b3a2eSRishi Panjwani if (kstrtou16(buf, 0, &bgscan_int)) 1648116b3a2eSRishi Panjwani return -EINVAL; 1649116b3a2eSRishi Panjwani 1650116b3a2eSRishi Panjwani if (bgscan_int == 0) 1651116b3a2eSRishi Panjwani bgscan_int = 0xffff; 1652116b3a2eSRishi Panjwani 1653eb38987eSRaja Mani vif->bg_scan_period = bgscan_int; 1654eb38987eSRaja Mani 1655334234b5SVasanthakumar Thiagarajan ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3, 1656116b3a2eSRishi Panjwani 0, 0, 0); 1657116b3a2eSRishi Panjwani 1658116b3a2eSRishi Panjwani return count; 1659116b3a2eSRishi Panjwani } 1660116b3a2eSRishi Panjwani 1661116b3a2eSRishi Panjwani static const struct file_operations fops_bgscan_int = { 1662116b3a2eSRishi Panjwani .write = ath6kl_bgscan_int_write, 1663234e3405SStephen Boyd .open = simple_open, 1664116b3a2eSRishi Panjwani .owner = THIS_MODULE, 1665116b3a2eSRishi Panjwani .llseek = default_llseek, 1666116b3a2eSRishi Panjwani }; 1667116b3a2eSRishi Panjwani 1668ef8f0ebaSRishi Panjwani static ssize_t ath6kl_listen_int_write(struct file *file, 1669ef8f0ebaSRishi Panjwani const char __user *user_buf, 1670ef8f0ebaSRishi Panjwani size_t count, loff_t *ppos) 1671ef8f0ebaSRishi Panjwani { 1672ef8f0ebaSRishi Panjwani struct ath6kl *ar = file->private_data; 16738232736dSSujith Manoharan struct ath6kl_vif *vif; 16748232736dSSujith Manoharan u16 listen_interval; 1675ef8f0ebaSRishi Panjwani char buf[32]; 1676ef8f0ebaSRishi Panjwani ssize_t len; 1677ef8f0ebaSRishi Panjwani 16788232736dSSujith Manoharan vif = ath6kl_vif_first(ar); 16798232736dSSujith Manoharan if (!vif) 16808232736dSSujith Manoharan return -EIO; 16818232736dSSujith Manoharan 1682ef8f0ebaSRishi Panjwani len = min(count, sizeof(buf) - 1); 1683ef8f0ebaSRishi Panjwani if (copy_from_user(buf, user_buf, len)) 1684ef8f0ebaSRishi Panjwani return -EFAULT; 1685ef8f0ebaSRishi Panjwani 1686ef8f0ebaSRishi Panjwani buf[len] = '\0'; 16878232736dSSujith Manoharan if (kstrtou16(buf, 0, &listen_interval)) 1688ef8f0ebaSRishi Panjwani return -EINVAL; 1689ef8f0ebaSRishi Panjwani 16908f46fccdSRaja Mani if ((listen_interval < 15) || (listen_interval > 3000)) 1691ef8f0ebaSRishi Panjwani return -EINVAL; 1692ef8f0ebaSRishi Panjwani 16938f46fccdSRaja Mani vif->listen_intvl_t = listen_interval; 16948f46fccdSRaja Mani ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 16958f46fccdSRaja Mani vif->listen_intvl_t, 0); 1696ef8f0ebaSRishi Panjwani 1697ef8f0ebaSRishi Panjwani return count; 1698ef8f0ebaSRishi Panjwani } 1699ef8f0ebaSRishi Panjwani 1700ef8f0ebaSRishi Panjwani static ssize_t ath6kl_listen_int_read(struct file *file, 1701ef8f0ebaSRishi Panjwani char __user *user_buf, 1702ef8f0ebaSRishi Panjwani size_t count, loff_t *ppos) 1703ef8f0ebaSRishi Panjwani { 1704ef8f0ebaSRishi Panjwani struct ath6kl *ar = file->private_data; 17058f46fccdSRaja Mani struct ath6kl_vif *vif; 170650553c2cSDan Carpenter char buf[32]; 1707ef8f0ebaSRishi Panjwani int len; 1708ef8f0ebaSRishi Panjwani 17098f46fccdSRaja Mani vif = ath6kl_vif_first(ar); 17108f46fccdSRaja Mani if (!vif) 17118f46fccdSRaja Mani return -EIO; 17128f46fccdSRaja Mani 17138f46fccdSRaja Mani len = scnprintf(buf, sizeof(buf), "%u\n", vif->listen_intvl_t); 1714ef8f0ebaSRishi Panjwani 1715ef8f0ebaSRishi Panjwani return simple_read_from_buffer(user_buf, count, ppos, buf, len); 1716ef8f0ebaSRishi Panjwani } 1717ef8f0ebaSRishi Panjwani 1718ef8f0ebaSRishi Panjwani static const struct file_operations fops_listen_int = { 1719ef8f0ebaSRishi Panjwani .read = ath6kl_listen_int_read, 1720ef8f0ebaSRishi Panjwani .write = ath6kl_listen_int_write, 1721234e3405SStephen Boyd .open = simple_open, 1722ef8f0ebaSRishi Panjwani .owner = THIS_MODULE, 1723ef8f0ebaSRishi Panjwani .llseek = default_llseek, 1724ef8f0ebaSRishi Panjwani }; 1725ef8f0ebaSRishi Panjwani 1726a24fc7c3SRishi Panjwani static ssize_t ath6kl_power_params_write(struct file *file, 1727a24fc7c3SRishi Panjwani const char __user *user_buf, 1728a24fc7c3SRishi Panjwani size_t count, loff_t *ppos) 1729a24fc7c3SRishi Panjwani { 1730a24fc7c3SRishi Panjwani struct ath6kl *ar = file->private_data; 1731a24fc7c3SRishi Panjwani u8 buf[100]; 1732a24fc7c3SRishi Panjwani unsigned int len = 0; 1733a24fc7c3SRishi Panjwani char *sptr, *token; 1734a24fc7c3SRishi Panjwani u16 idle_period, ps_poll_num, dtim, 1735a24fc7c3SRishi Panjwani tx_wakeup, num_tx; 1736a24fc7c3SRishi Panjwani 1737a24fc7c3SRishi Panjwani len = min(count, sizeof(buf) - 1); 1738a24fc7c3SRishi Panjwani if (copy_from_user(buf, user_buf, len)) 1739a24fc7c3SRishi Panjwani return -EFAULT; 1740a24fc7c3SRishi Panjwani buf[len] = '\0'; 1741a24fc7c3SRishi Panjwani sptr = buf; 1742a24fc7c3SRishi Panjwani 1743a24fc7c3SRishi Panjwani token = strsep(&sptr, " "); 1744a24fc7c3SRishi Panjwani if (!token) 1745a24fc7c3SRishi Panjwani return -EINVAL; 1746a24fc7c3SRishi Panjwani if (kstrtou16(token, 0, &idle_period)) 1747a24fc7c3SRishi Panjwani return -EINVAL; 1748a24fc7c3SRishi Panjwani 1749a24fc7c3SRishi Panjwani token = strsep(&sptr, " "); 1750a24fc7c3SRishi Panjwani if (!token) 1751a24fc7c3SRishi Panjwani return -EINVAL; 1752a24fc7c3SRishi Panjwani if (kstrtou16(token, 0, &ps_poll_num)) 1753a24fc7c3SRishi Panjwani return -EINVAL; 1754a24fc7c3SRishi Panjwani 1755a24fc7c3SRishi Panjwani token = strsep(&sptr, " "); 1756a24fc7c3SRishi Panjwani if (!token) 1757a24fc7c3SRishi Panjwani return -EINVAL; 1758a24fc7c3SRishi Panjwani if (kstrtou16(token, 0, &dtim)) 1759a24fc7c3SRishi Panjwani return -EINVAL; 1760a24fc7c3SRishi Panjwani 1761a24fc7c3SRishi Panjwani token = strsep(&sptr, " "); 1762a24fc7c3SRishi Panjwani if (!token) 1763a24fc7c3SRishi Panjwani return -EINVAL; 1764a24fc7c3SRishi Panjwani if (kstrtou16(token, 0, &tx_wakeup)) 1765a24fc7c3SRishi Panjwani return -EINVAL; 1766a24fc7c3SRishi Panjwani 1767a24fc7c3SRishi Panjwani token = strsep(&sptr, " "); 1768a24fc7c3SRishi Panjwani if (!token) 1769a24fc7c3SRishi Panjwani return -EINVAL; 1770a24fc7c3SRishi Panjwani if (kstrtou16(token, 0, &num_tx)) 1771a24fc7c3SRishi Panjwani return -EINVAL; 1772a24fc7c3SRishi Panjwani 1773a24fc7c3SRishi Panjwani ath6kl_wmi_pmparams_cmd(ar->wmi, 0, idle_period, ps_poll_num, 1774a24fc7c3SRishi Panjwani dtim, tx_wakeup, num_tx, 0); 1775a24fc7c3SRishi Panjwani 1776a24fc7c3SRishi Panjwani return count; 1777a24fc7c3SRishi Panjwani } 1778a24fc7c3SRishi Panjwani 1779a24fc7c3SRishi Panjwani static const struct file_operations fops_power_params = { 1780a24fc7c3SRishi Panjwani .write = ath6kl_power_params_write, 1781234e3405SStephen Boyd .open = simple_open, 1782a24fc7c3SRishi Panjwani .owner = THIS_MODULE, 1783a24fc7c3SRishi Panjwani .llseek = default_llseek, 1784a24fc7c3SRishi Panjwani }; 1785a24fc7c3SRishi Panjwani 1786068a4633SVasanthakumar Thiagarajan void ath6kl_debug_init(struct ath6kl *ar) 1787d999ba3eSVasanthakumar Thiagarajan { 17889b9a4f2aSKalle Valo skb_queue_head_init(&ar->debug.fwlog_queue); 1789c807b30dSKalle Valo init_completion(&ar->debug.fwlog_completion); 1790bdf5396bSKalle Valo 1791939f1cceSKalle Valo /* 1792939f1cceSKalle Valo * Actually we are lying here but don't know how to read the mask 1793939f1cceSKalle Valo * value from the firmware. 1794939f1cceSKalle Valo */ 1795939f1cceSKalle Valo ar->debug.fwlog_mask = 0; 1796068a4633SVasanthakumar Thiagarajan } 1797939f1cceSKalle Valo 1798068a4633SVasanthakumar Thiagarajan /* 1799068a4633SVasanthakumar Thiagarajan * Initialisation needs to happen in two stages as fwlog events can come 1800068a4633SVasanthakumar Thiagarajan * before cfg80211 is initialised, and debugfs depends on cfg80211 1801068a4633SVasanthakumar Thiagarajan * initialisation. 1802068a4633SVasanthakumar Thiagarajan */ 1803068a4633SVasanthakumar Thiagarajan int ath6kl_debug_init_fs(struct ath6kl *ar) 1804068a4633SVasanthakumar Thiagarajan { 1805d999ba3eSVasanthakumar Thiagarajan ar->debugfs_phy = debugfs_create_dir("ath6kl", 1806be98e3a4SVasanthakumar Thiagarajan ar->wiphy->debugfsdir); 18079b9a4f2aSKalle Valo if (!ar->debugfs_phy) 1808d999ba3eSVasanthakumar Thiagarajan return -ENOMEM; 1809d999ba3eSVasanthakumar Thiagarajan 181003f68a95SVasanthakumar Thiagarajan debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, 181103f68a95SVasanthakumar Thiagarajan &fops_tgt_stats); 181203f68a95SVasanthakumar Thiagarajan 1813*243c0280SMohammed Shafi Shajakhan if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO) 1814*243c0280SMohammed Shafi Shajakhan debugfs_create_file("credit_dist_stats", S_IRUSR, 1815*243c0280SMohammed Shafi Shajakhan ar->debugfs_phy, ar, 181678fc4856SVasanthakumar Thiagarajan &fops_credit_dist_stats); 181778fc4856SVasanthakumar Thiagarajan 1818e8091281SJouni Malinen debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR, 1819e8091281SJouni Malinen ar->debugfs_phy, ar, &fops_endpoint_stats); 1820e8091281SJouni Malinen 1821bdf5396bSKalle Valo debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, 1822bdf5396bSKalle Valo &fops_fwlog); 1823bdf5396bSKalle Valo 1824c807b30dSKalle Valo debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar, 1825c807b30dSKalle Valo &fops_fwlog_block); 1826c807b30dSKalle Valo 1827939f1cceSKalle Valo debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, 1828939f1cceSKalle Valo ar, &fops_fwlog_mask); 1829939f1cceSKalle Valo 183091d57de5SVasanthakumar Thiagarajan debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, 183191d57de5SVasanthakumar Thiagarajan &fops_diag_reg_read); 183291d57de5SVasanthakumar Thiagarajan 183391d57de5SVasanthakumar Thiagarajan debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, 183491d57de5SVasanthakumar Thiagarajan &fops_reg_dump); 183591d57de5SVasanthakumar Thiagarajan 1836e5090444SVivek Natarajan debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, 1837e5090444SVivek Natarajan ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); 1838252c068bSVasanthakumar Thiagarajan 1839252c068bSVasanthakumar Thiagarajan debugfs_create_file("reg_write", S_IRUSR | S_IWUSR, 1840252c068bSVasanthakumar Thiagarajan ar->debugfs_phy, ar, &fops_diag_reg_write); 1841252c068bSVasanthakumar Thiagarajan 18429a730834SKalle Valo debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar, 18439a730834SKalle Valo &fops_war_stats); 18449a730834SKalle Valo 18454b28a80dSJouni Malinen debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar, 18464b28a80dSJouni Malinen &fops_roam_table); 18474b28a80dSJouni Malinen 18481261875fSJouni Malinen debugfs_create_file("force_roam", S_IWUSR, ar->debugfs_phy, ar, 18491261875fSJouni Malinen &fops_force_roam); 18501261875fSJouni Malinen 18511261875fSJouni Malinen debugfs_create_file("roam_mode", S_IWUSR, ar->debugfs_phy, ar, 18521261875fSJouni Malinen &fops_roam_mode); 18531261875fSJouni Malinen 1854ff0b0075SJouni Malinen debugfs_create_file("keepalive", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, 1855ff0b0075SJouni Malinen &fops_keepalive); 1856ff0b0075SJouni Malinen 1857ff0b0075SJouni Malinen debugfs_create_file("disconnect_timeout", S_IRUSR | S_IWUSR, 1858ff0b0075SJouni Malinen ar->debugfs_phy, ar, &fops_disconnect_timeout); 1859ff0b0075SJouni Malinen 18608fffd9e5SRishi Panjwani debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, 18618fffd9e5SRishi Panjwani &fops_create_qos); 18628fffd9e5SRishi Panjwani 18638fffd9e5SRishi Panjwani debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, 18648fffd9e5SRishi Panjwani &fops_delete_qos); 18658fffd9e5SRishi Panjwani 1866116b3a2eSRishi Panjwani debugfs_create_file("bgscan_interval", S_IWUSR, 1867116b3a2eSRishi Panjwani ar->debugfs_phy, ar, &fops_bgscan_int); 1868116b3a2eSRishi Panjwani 18698232736dSSujith Manoharan debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, 18708232736dSSujith Manoharan ar->debugfs_phy, ar, &fops_listen_int); 18718232736dSSujith Manoharan 1872a24fc7c3SRishi Panjwani debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, 1873a24fc7c3SRishi Panjwani &fops_power_params); 1874a24fc7c3SRishi Panjwani 1875d999ba3eSVasanthakumar Thiagarajan return 0; 1876d999ba3eSVasanthakumar Thiagarajan } 1877bdf5396bSKalle Valo 1878bdf5396bSKalle Valo void ath6kl_debug_cleanup(struct ath6kl *ar) 1879bdf5396bSKalle Valo { 18809b9a4f2aSKalle Valo skb_queue_purge(&ar->debug.fwlog_queue); 188192ada046SThomas Pedersen complete(&ar->debug.fwlog_completion); 18824b28a80dSJouni Malinen kfree(ar->debug.roam_tbl); 1883bdf5396bSKalle Valo } 1884bdf5396bSKalle Valo 1885bdcd8170SKalle Valo #endif 1886