162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Atheros CARL9170 driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * debug(fs) probing 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> 762306a36Sopenharmony_ci * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1062306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1162306a36Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 1262306a36Sopenharmony_ci * (at your option) any later version. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, 1562306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1762306a36Sopenharmony_ci * GNU General Public License for more details. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 2062306a36Sopenharmony_ci * along with this program; see the file COPYING. If not, see 2162306a36Sopenharmony_ci * http://www.gnu.org/licenses/. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and 2462306a36Sopenharmony_ci * permission notice: 2562306a36Sopenharmony_ci * Copyright (c) 2008-2009 Atheros Communications, Inc. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 2862306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 2962306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 3262306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 3362306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 3462306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 3562306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 3662306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 3762306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <linux/slab.h> 4162306a36Sopenharmony_ci#include <linux/module.h> 4262306a36Sopenharmony_ci#include <linux/seq_file.h> 4362306a36Sopenharmony_ci#include <linux/vmalloc.h> 4462306a36Sopenharmony_ci#include "carl9170.h" 4562306a36Sopenharmony_ci#include "cmd.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define ADD(buf, off, max, fmt, args...) \ 4862306a36Sopenharmony_ci off += scnprintf(&buf[off], max - off, fmt, ##args) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct carl9170_debugfs_fops { 5262306a36Sopenharmony_ci unsigned int read_bufsize; 5362306a36Sopenharmony_ci umode_t attr; 5462306a36Sopenharmony_ci char *(*read)(struct ar9170 *ar, char *buf, size_t bufsize, 5562306a36Sopenharmony_ci ssize_t *len); 5662306a36Sopenharmony_ci ssize_t (*write)(struct ar9170 *aru, const char *buf, size_t size); 5762306a36Sopenharmony_ci const struct file_operations fops; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci enum carl9170_device_state req_dev_state; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic ssize_t carl9170_debugfs_read(struct file *file, char __user *userbuf, 6362306a36Sopenharmony_ci size_t count, loff_t *ppos) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct carl9170_debugfs_fops *dfops; 6662306a36Sopenharmony_ci struct ar9170 *ar; 6762306a36Sopenharmony_ci char *buf = NULL, *res_buf = NULL; 6862306a36Sopenharmony_ci ssize_t ret = 0; 6962306a36Sopenharmony_ci int err = 0; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (!count) 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci ar = file->private_data; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!ar) 7762306a36Sopenharmony_ci return -ENODEV; 7862306a36Sopenharmony_ci dfops = container_of(debugfs_real_fops(file), 7962306a36Sopenharmony_ci struct carl9170_debugfs_fops, fops); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!dfops->read) 8262306a36Sopenharmony_ci return -ENOSYS; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (dfops->read_bufsize) { 8562306a36Sopenharmony_ci buf = vmalloc(dfops->read_bufsize); 8662306a36Sopenharmony_ci if (!buf) 8762306a36Sopenharmony_ci return -ENOMEM; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci mutex_lock(&ar->mutex); 9162306a36Sopenharmony_ci if (!CHK_DEV_STATE(ar, dfops->req_dev_state)) { 9262306a36Sopenharmony_ci err = -ENODEV; 9362306a36Sopenharmony_ci res_buf = buf; 9462306a36Sopenharmony_ci goto out_free; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci res_buf = dfops->read(ar, buf, dfops->read_bufsize, &ret); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (ret > 0) 10062306a36Sopenharmony_ci err = simple_read_from_buffer(userbuf, count, ppos, 10162306a36Sopenharmony_ci res_buf, ret); 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci err = ret; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci WARN_ON_ONCE(dfops->read_bufsize && (res_buf != buf)); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciout_free: 10862306a36Sopenharmony_ci vfree(res_buf); 10962306a36Sopenharmony_ci mutex_unlock(&ar->mutex); 11062306a36Sopenharmony_ci return err; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic ssize_t carl9170_debugfs_write(struct file *file, 11462306a36Sopenharmony_ci const char __user *userbuf, size_t count, loff_t *ppos) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct carl9170_debugfs_fops *dfops; 11762306a36Sopenharmony_ci struct ar9170 *ar; 11862306a36Sopenharmony_ci char *buf = NULL; 11962306a36Sopenharmony_ci int err = 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (!count) 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (count > PAGE_SIZE) 12562306a36Sopenharmony_ci return -E2BIG; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci ar = file->private_data; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (!ar) 13062306a36Sopenharmony_ci return -ENODEV; 13162306a36Sopenharmony_ci dfops = container_of(debugfs_real_fops(file), 13262306a36Sopenharmony_ci struct carl9170_debugfs_fops, fops); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!dfops->write) 13562306a36Sopenharmony_ci return -ENOSYS; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci buf = vmalloc(count); 13862306a36Sopenharmony_ci if (!buf) 13962306a36Sopenharmony_ci return -ENOMEM; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (copy_from_user(buf, userbuf, count)) { 14262306a36Sopenharmony_ci err = -EFAULT; 14362306a36Sopenharmony_ci goto out_free; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (mutex_trylock(&ar->mutex) == 0) { 14762306a36Sopenharmony_ci err = -EAGAIN; 14862306a36Sopenharmony_ci goto out_free; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!CHK_DEV_STATE(ar, dfops->req_dev_state)) { 15262306a36Sopenharmony_ci err = -ENODEV; 15362306a36Sopenharmony_ci goto out_unlock; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci err = dfops->write(ar, buf, count); 15762306a36Sopenharmony_ci if (err) 15862306a36Sopenharmony_ci goto out_unlock; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciout_unlock: 16162306a36Sopenharmony_ci mutex_unlock(&ar->mutex); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciout_free: 16462306a36Sopenharmony_ci vfree(buf); 16562306a36Sopenharmony_ci return err; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci#define __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \ 16962306a36Sopenharmony_ci _attr, _dstate) \ 17062306a36Sopenharmony_cistatic const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\ 17162306a36Sopenharmony_ci .read_bufsize = _read_bufsize, \ 17262306a36Sopenharmony_ci .read = _read, \ 17362306a36Sopenharmony_ci .write = _write, \ 17462306a36Sopenharmony_ci .attr = _attr, \ 17562306a36Sopenharmony_ci .req_dev_state = _dstate, \ 17662306a36Sopenharmony_ci .fops = { \ 17762306a36Sopenharmony_ci .open = simple_open, \ 17862306a36Sopenharmony_ci .read = carl9170_debugfs_read, \ 17962306a36Sopenharmony_ci .write = carl9170_debugfs_write, \ 18062306a36Sopenharmony_ci .owner = THIS_MODULE \ 18162306a36Sopenharmony_ci }, \ 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, _attr) \ 18562306a36Sopenharmony_ci __DEBUGFS_DECLARE_FILE(name, _read, _write, _read_bufsize, \ 18662306a36Sopenharmony_ci _attr, CARL9170_STARTED) \ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \ 18962306a36Sopenharmony_ci DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ 19062306a36Sopenharmony_ci NULL, _read_bufsize, 0400) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define DEBUGFS_DECLARE_WO_FILE(name) \ 19362306a36Sopenharmony_ci DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\ 19462306a36Sopenharmony_ci 0, 0200) 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \ 19762306a36Sopenharmony_ci DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ 19862306a36Sopenharmony_ci carl9170_debugfs_##name ##_write, \ 19962306a36Sopenharmony_ci _read_bufsize, 0600) 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \ 20262306a36Sopenharmony_ci __DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ 20362306a36Sopenharmony_ci carl9170_debugfs_##name ##_write, \ 20462306a36Sopenharmony_ci _read_bufsize, 0600, _dstate) 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \ 20762306a36Sopenharmony_cistatic char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \ 20862306a36Sopenharmony_ci char *buf, size_t buf_size,\ 20962306a36Sopenharmony_ci ssize_t *len) \ 21062306a36Sopenharmony_ci{ \ 21162306a36Sopenharmony_ci ADD(buf, *len, buf_size, fmt "\n", ##value); \ 21262306a36Sopenharmony_ci return buf; \ 21362306a36Sopenharmony_ci} \ 21462306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic char *carl9170_debugfs_mem_usage_read(struct ar9170 *ar, char *buf, 21762306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci spin_lock_bh(&ar->mem_lock); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ADD(buf, *len, bufsize, "jar: [%*pb]\n", 22262306a36Sopenharmony_ci ar->fw.mem_blocks, ar->mem_bitmap); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ADD(buf, *len, bufsize, "cookies: used:%3d / total:%3d, allocs:%d\n", 22562306a36Sopenharmony_ci bitmap_weight(ar->mem_bitmap, ar->fw.mem_blocks), 22662306a36Sopenharmony_ci ar->fw.mem_blocks, atomic_read(&ar->mem_allocs)); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ADD(buf, *len, bufsize, "memory: free:%3d (%3d KiB) / total:%3d KiB)\n", 22962306a36Sopenharmony_ci atomic_read(&ar->mem_free_blocks), 23062306a36Sopenharmony_ci (atomic_read(&ar->mem_free_blocks) * ar->fw.mem_block_size) / 1024, 23162306a36Sopenharmony_ci (ar->fw.mem_blocks * ar->fw.mem_block_size) / 1024); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci spin_unlock_bh(&ar->mem_lock); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci return buf; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(mem_usage, 512); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic char *carl9170_debugfs_qos_stat_read(struct ar9170 *ar, char *buf, 24062306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci ADD(buf, *len, bufsize, "%s QoS AC\n", modparam_noht ? "Hardware" : 24362306a36Sopenharmony_ci "Software"); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ADD(buf, *len, bufsize, "[ VO VI " 24662306a36Sopenharmony_ci " BE BK ]\n"); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci spin_lock_bh(&ar->tx_stats_lock); 24962306a36Sopenharmony_ci ADD(buf, *len, bufsize, "[length/limit length/limit " 25062306a36Sopenharmony_ci "length/limit length/limit ]\n" 25162306a36Sopenharmony_ci "[ %3d/%3d %3d/%3d " 25262306a36Sopenharmony_ci " %3d/%3d %3d/%3d ]\n\n", 25362306a36Sopenharmony_ci ar->tx_stats[0].len, ar->tx_stats[0].limit, 25462306a36Sopenharmony_ci ar->tx_stats[1].len, ar->tx_stats[1].limit, 25562306a36Sopenharmony_ci ar->tx_stats[2].len, ar->tx_stats[2].limit, 25662306a36Sopenharmony_ci ar->tx_stats[3].len, ar->tx_stats[3].limit); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ADD(buf, *len, bufsize, "[ total total " 25962306a36Sopenharmony_ci " total total ]\n" 26062306a36Sopenharmony_ci "[%10d %10d %10d %10d ]\n\n", 26162306a36Sopenharmony_ci ar->tx_stats[0].count, ar->tx_stats[1].count, 26262306a36Sopenharmony_ci ar->tx_stats[2].count, ar->tx_stats[3].count); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci spin_unlock_bh(&ar->tx_stats_lock); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ADD(buf, *len, bufsize, "[ pend/waittx pend/waittx " 26762306a36Sopenharmony_ci " pend/waittx pend/waittx]\n" 26862306a36Sopenharmony_ci "[ %3d/%3d %3d/%3d " 26962306a36Sopenharmony_ci " %3d/%3d %3d/%3d ]\n\n", 27062306a36Sopenharmony_ci skb_queue_len(&ar->tx_pending[0]), 27162306a36Sopenharmony_ci skb_queue_len(&ar->tx_status[0]), 27262306a36Sopenharmony_ci skb_queue_len(&ar->tx_pending[1]), 27362306a36Sopenharmony_ci skb_queue_len(&ar->tx_status[1]), 27462306a36Sopenharmony_ci skb_queue_len(&ar->tx_pending[2]), 27562306a36Sopenharmony_ci skb_queue_len(&ar->tx_status[2]), 27662306a36Sopenharmony_ci skb_queue_len(&ar->tx_pending[3]), 27762306a36Sopenharmony_ci skb_queue_len(&ar->tx_status[3])); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return buf; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(qos_stat, 512); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void carl9170_debugfs_format_frame(struct ar9170 *ar, 28462306a36Sopenharmony_ci struct sk_buff *skb, const char *prefix, char *buf, 28562306a36Sopenharmony_ci ssize_t *off, ssize_t bufsize) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct _carl9170_tx_superframe *txc = (void *) skb->data; 28862306a36Sopenharmony_ci struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); 28962306a36Sopenharmony_ci struct carl9170_tx_info *arinfo = (void *) txinfo->rate_driver_data; 29062306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *) txc->frame_data; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ADD(buf, *off, bufsize, "%s %p, c:%2x, DA:%pM, sq:%4d, mc:%.4x, " 29362306a36Sopenharmony_ci "pc:%.8x, to:%d ms\n", prefix, skb, txc->s.cookie, 29462306a36Sopenharmony_ci ieee80211_get_DA(hdr), get_seq_h(hdr), 29562306a36Sopenharmony_ci le16_to_cpu(txc->f.mac_control), le32_to_cpu(txc->f.phy_control), 29662306a36Sopenharmony_ci jiffies_to_msecs(jiffies - arinfo->timeout)); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic char *carl9170_debugfs_ampdu_state_read(struct ar9170 *ar, char *buf, 30162306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct carl9170_sta_tid *iter; 30462306a36Sopenharmony_ci struct sk_buff *skb; 30562306a36Sopenharmony_ci int cnt = 0, fc; 30662306a36Sopenharmony_ci int offset; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci rcu_read_lock(); 30962306a36Sopenharmony_ci list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci spin_lock_bh(&iter->lock); 31262306a36Sopenharmony_ci ADD(buf, *len, bufsize, "Entry: #%2d TID:%1d, BSN:%4d, " 31362306a36Sopenharmony_ci "SNX:%4d, HSN:%4d, BAW:%2d, state:%1d, toggles:%d\n", 31462306a36Sopenharmony_ci cnt, iter->tid, iter->bsn, iter->snx, iter->hsn, 31562306a36Sopenharmony_ci iter->max, iter->state, iter->counter); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci ADD(buf, *len, bufsize, "\tWindow: [%*pb,W]\n", 31862306a36Sopenharmony_ci CARL9170_BAW_BITS, iter->bitmap); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci#define BM_STR_OFF(offset) \ 32162306a36Sopenharmony_ci ((CARL9170_BAW_BITS - (offset) - 1) / 4 + \ 32262306a36Sopenharmony_ci (CARL9170_BAW_BITS - (offset) - 1) / 32 + 1) 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci offset = BM_STR_OFF(0); 32562306a36Sopenharmony_ci ADD(buf, *len, bufsize, "\tBase Seq: %*s\n", offset, "T"); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci offset = BM_STR_OFF(SEQ_DIFF(iter->snx, iter->bsn)); 32862306a36Sopenharmony_ci ADD(buf, *len, bufsize, "\tNext Seq: %*s\n", offset, "W"); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci offset = BM_STR_OFF(((int)iter->hsn - (int)iter->bsn) % 33162306a36Sopenharmony_ci CARL9170_BAW_BITS); 33262306a36Sopenharmony_ci ADD(buf, *len, bufsize, "\tLast Seq: %*s\n", offset, "N"); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ADD(buf, *len, bufsize, "\tPre-Aggregation reorder buffer: " 33562306a36Sopenharmony_ci " currently queued:%d\n", skb_queue_len(&iter->queue)); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci fc = 0; 33862306a36Sopenharmony_ci skb_queue_walk(&iter->queue, skb) { 33962306a36Sopenharmony_ci char prefix[32]; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci snprintf(prefix, sizeof(prefix), "\t\t%3d :", fc); 34262306a36Sopenharmony_ci carl9170_debugfs_format_frame(ar, skb, prefix, buf, 34362306a36Sopenharmony_ci len, bufsize); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci fc++; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci spin_unlock_bh(&iter->lock); 34862306a36Sopenharmony_ci cnt++; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci rcu_read_unlock(); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return buf; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(ampdu_state, 8000); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void carl9170_debugfs_queue_dump(struct ar9170 *ar, char *buf, 35762306a36Sopenharmony_ci ssize_t *len, size_t bufsize, struct sk_buff_head *queue) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct sk_buff *skb; 36062306a36Sopenharmony_ci char prefix[16]; 36162306a36Sopenharmony_ci int fc = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci spin_lock_bh(&queue->lock); 36462306a36Sopenharmony_ci skb_queue_walk(queue, skb) { 36562306a36Sopenharmony_ci snprintf(prefix, sizeof(prefix), "%3d :", fc); 36662306a36Sopenharmony_ci carl9170_debugfs_format_frame(ar, skb, prefix, buf, 36762306a36Sopenharmony_ci len, bufsize); 36862306a36Sopenharmony_ci fc++; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci spin_unlock_bh(&queue->lock); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci#define DEBUGFS_QUEUE_DUMP(q, qi) \ 37462306a36Sopenharmony_cistatic char *carl9170_debugfs_##q ##_##qi ##_read(struct ar9170 *ar, \ 37562306a36Sopenharmony_ci char *buf, size_t bufsize, ssize_t *len) \ 37662306a36Sopenharmony_ci{ \ 37762306a36Sopenharmony_ci carl9170_debugfs_queue_dump(ar, buf, len, bufsize, &ar->q[qi]); \ 37862306a36Sopenharmony_ci return buf; \ 37962306a36Sopenharmony_ci} \ 38062306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(q##_##qi, 8000); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic char *carl9170_debugfs_sta_psm_read(struct ar9170 *ar, char *buf, 38362306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci ADD(buf, *len, bufsize, "psm state: %s\n", (ar->ps.off_override ? 38662306a36Sopenharmony_ci "FORCE CAM" : (ar->ps.state ? "PSM" : "CAM"))); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci ADD(buf, *len, bufsize, "sleep duration: %d ms.\n", ar->ps.sleep_ms); 38962306a36Sopenharmony_ci ADD(buf, *len, bufsize, "last power-state transition: %d ms ago.\n", 39062306a36Sopenharmony_ci jiffies_to_msecs(jiffies - ar->ps.last_action)); 39162306a36Sopenharmony_ci ADD(buf, *len, bufsize, "last CAM->PSM transition: %d ms ago.\n", 39262306a36Sopenharmony_ci jiffies_to_msecs(jiffies - ar->ps.last_slept)); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return buf; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(sta_psm, 160); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic char *carl9170_debugfs_tx_stuck_read(struct ar9170 *ar, char *buf, 39962306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci int i; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci for (i = 0; i < ar->hw->queues; i++) { 40462306a36Sopenharmony_ci ADD(buf, *len, bufsize, "TX queue [%d]: %10d max:%10d ms.\n", 40562306a36Sopenharmony_ci i, ieee80211_queue_stopped(ar->hw, i) ? 40662306a36Sopenharmony_ci jiffies_to_msecs(jiffies - ar->queue_stop_timeout[i]) : 0, 40762306a36Sopenharmony_ci jiffies_to_msecs(ar->max_queue_stop_timeout[i])); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ar->max_queue_stop_timeout[i] = 0; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return buf; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(tx_stuck, 180); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic char *carl9170_debugfs_phy_noise_read(struct ar9170 *ar, char *buf, 41762306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int err; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci err = carl9170_get_noisefloor(ar); 42262306a36Sopenharmony_ci if (err) { 42362306a36Sopenharmony_ci *len = err; 42462306a36Sopenharmony_ci return buf; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ADD(buf, *len, bufsize, "Chain 0: %10d dBm, ext. chan.:%10d dBm\n", 42862306a36Sopenharmony_ci ar->noise[0], ar->noise[2]); 42962306a36Sopenharmony_ci ADD(buf, *len, bufsize, "Chain 2: %10d dBm, ext. chan.:%10d dBm\n", 43062306a36Sopenharmony_ci ar->noise[1], ar->noise[3]); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return buf; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(phy_noise, 180); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic char *carl9170_debugfs_vif_dump_read(struct ar9170 *ar, char *buf, 43762306a36Sopenharmony_ci size_t bufsize, ssize_t *len) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct carl9170_vif_info *iter; 44062306a36Sopenharmony_ci int i = 0; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci ADD(buf, *len, bufsize, "registered VIFs:%d \\ %d\n", 44362306a36Sopenharmony_ci ar->vifs, ar->fw.vif_num); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ADD(buf, *len, bufsize, "VIF bitmap: [%*pb]\n", 44662306a36Sopenharmony_ci ar->fw.vif_num, &ar->vif_bitmap); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci rcu_read_lock(); 44962306a36Sopenharmony_ci list_for_each_entry_rcu(iter, &ar->vif_list, list) { 45062306a36Sopenharmony_ci struct ieee80211_vif *vif = carl9170_get_vif(iter); 45162306a36Sopenharmony_ci ADD(buf, *len, bufsize, "\t%d = [%s VIF, id:%d, type:%x " 45262306a36Sopenharmony_ci " mac:%pM %s]\n", i, (carl9170_get_main_vif(ar) == vif ? 45362306a36Sopenharmony_ci "Master" : " Slave"), iter->id, vif->type, vif->addr, 45462306a36Sopenharmony_ci iter->enable_beacon ? "beaconing " : ""); 45562306a36Sopenharmony_ci i++; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci rcu_read_unlock(); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return buf; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(vif_dump, 8000); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci#define UPDATE_COUNTER(ar, name) ({ \ 46462306a36Sopenharmony_ci u32 __tmp[ARRAY_SIZE(name##_regs)]; \ 46562306a36Sopenharmony_ci unsigned int __i, __err = -ENODEV; \ 46662306a36Sopenharmony_ci \ 46762306a36Sopenharmony_ci for (__i = 0; __i < ARRAY_SIZE(name##_regs); __i++) { \ 46862306a36Sopenharmony_ci __tmp[__i] = name##_regs[__i].reg; \ 46962306a36Sopenharmony_ci ar->debug.stats.name##_counter[__i] = 0; \ 47062306a36Sopenharmony_ci } \ 47162306a36Sopenharmony_ci \ 47262306a36Sopenharmony_ci if (IS_STARTED(ar)) \ 47362306a36Sopenharmony_ci __err = carl9170_read_mreg(ar, ARRAY_SIZE(name##_regs), \ 47462306a36Sopenharmony_ci __tmp, ar->debug.stats.name##_counter); \ 47562306a36Sopenharmony_ci (__err); }) 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci#define TALLY_SUM_UP(ar, name) do { \ 47862306a36Sopenharmony_ci unsigned int __i; \ 47962306a36Sopenharmony_ci \ 48062306a36Sopenharmony_ci for (__i = 0; __i < ARRAY_SIZE(name##_regs); __i++) { \ 48162306a36Sopenharmony_ci ar->debug.stats.name##_sum[__i] += \ 48262306a36Sopenharmony_ci ar->debug.stats.name##_counter[__i]; \ 48362306a36Sopenharmony_ci } \ 48462306a36Sopenharmony_ci} while (0) 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci#define DEBUGFS_HW_TALLY_FILE(name, f) \ 48762306a36Sopenharmony_cistatic char *carl9170_debugfs_##name ## _read(struct ar9170 *ar, \ 48862306a36Sopenharmony_ci char *dum, size_t bufsize, ssize_t *ret) \ 48962306a36Sopenharmony_ci{ \ 49062306a36Sopenharmony_ci char *buf; \ 49162306a36Sopenharmony_ci int i, max_len, err; \ 49262306a36Sopenharmony_ci \ 49362306a36Sopenharmony_ci max_len = ARRAY_SIZE(name##_regs) * 80; \ 49462306a36Sopenharmony_ci buf = vmalloc(max_len); \ 49562306a36Sopenharmony_ci if (!buf) \ 49662306a36Sopenharmony_ci return NULL; \ 49762306a36Sopenharmony_ci \ 49862306a36Sopenharmony_ci err = UPDATE_COUNTER(ar, name); \ 49962306a36Sopenharmony_ci if (err) { \ 50062306a36Sopenharmony_ci *ret = err; \ 50162306a36Sopenharmony_ci return buf; \ 50262306a36Sopenharmony_ci } \ 50362306a36Sopenharmony_ci \ 50462306a36Sopenharmony_ci TALLY_SUM_UP(ar, name); \ 50562306a36Sopenharmony_ci \ 50662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(name##_regs); i++) { \ 50762306a36Sopenharmony_ci ADD(buf, *ret, max_len, "%22s = %" f "[+%" f "]\n", \ 50862306a36Sopenharmony_ci name##_regs[i].nreg, ar->debug.stats.name ##_sum[i],\ 50962306a36Sopenharmony_ci ar->debug.stats.name ##_counter[i]); \ 51062306a36Sopenharmony_ci } \ 51162306a36Sopenharmony_ci \ 51262306a36Sopenharmony_ci return buf; \ 51362306a36Sopenharmony_ci} \ 51462306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(name, 0); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci#define DEBUGFS_HW_REG_FILE(name, f) \ 51762306a36Sopenharmony_cistatic char *carl9170_debugfs_##name ## _read(struct ar9170 *ar, \ 51862306a36Sopenharmony_ci char *dum, size_t bufsize, ssize_t *ret) \ 51962306a36Sopenharmony_ci{ \ 52062306a36Sopenharmony_ci char *buf; \ 52162306a36Sopenharmony_ci int i, max_len, err; \ 52262306a36Sopenharmony_ci \ 52362306a36Sopenharmony_ci max_len = ARRAY_SIZE(name##_regs) * 80; \ 52462306a36Sopenharmony_ci buf = vmalloc(max_len); \ 52562306a36Sopenharmony_ci if (!buf) \ 52662306a36Sopenharmony_ci return NULL; \ 52762306a36Sopenharmony_ci \ 52862306a36Sopenharmony_ci err = UPDATE_COUNTER(ar, name); \ 52962306a36Sopenharmony_ci if (err) { \ 53062306a36Sopenharmony_ci *ret = err; \ 53162306a36Sopenharmony_ci return buf; \ 53262306a36Sopenharmony_ci } \ 53362306a36Sopenharmony_ci \ 53462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(name##_regs); i++) { \ 53562306a36Sopenharmony_ci ADD(buf, *ret, max_len, "%22s = %" f "\n", \ 53662306a36Sopenharmony_ci name##_regs[i].nreg, \ 53762306a36Sopenharmony_ci ar->debug.stats.name##_counter[i]); \ 53862306a36Sopenharmony_ci } \ 53962306a36Sopenharmony_ci \ 54062306a36Sopenharmony_ci return buf; \ 54162306a36Sopenharmony_ci} \ 54262306a36Sopenharmony_ciDEBUGFS_DECLARE_RO_FILE(name, 0); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic ssize_t carl9170_debugfs_hw_ioread32_write(struct ar9170 *ar, 54562306a36Sopenharmony_ci const char *buf, size_t count) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci int err = 0, i, n = 0, max_len = 32, res; 54862306a36Sopenharmony_ci unsigned int reg, tmp; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!count) 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (count > max_len) 55462306a36Sopenharmony_ci return -E2BIG; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci res = sscanf(buf, "0x%X %d", ®, &n); 55762306a36Sopenharmony_ci if (res < 1) { 55862306a36Sopenharmony_ci err = -EINVAL; 55962306a36Sopenharmony_ci goto out; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (res == 1) 56362306a36Sopenharmony_ci n = 1; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (n > 15) { 56662306a36Sopenharmony_ci err = -EMSGSIZE; 56762306a36Sopenharmony_ci goto out; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if ((reg >= 0x280000) || ((reg + (n << 2)) >= 0x280000)) { 57162306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 57262306a36Sopenharmony_ci goto out; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (reg & 3) { 57662306a36Sopenharmony_ci err = -EINVAL; 57762306a36Sopenharmony_ci goto out; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci for (i = 0; i < n; i++) { 58162306a36Sopenharmony_ci err = carl9170_read_reg(ar, reg + (i << 2), &tmp); 58262306a36Sopenharmony_ci if (err) 58362306a36Sopenharmony_ci goto out; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci ar->debug.ring[ar->debug.ring_tail].reg = reg + (i << 2); 58662306a36Sopenharmony_ci ar->debug.ring[ar->debug.ring_tail].value = tmp; 58762306a36Sopenharmony_ci ar->debug.ring_tail++; 58862306a36Sopenharmony_ci ar->debug.ring_tail %= CARL9170_DEBUG_RING_SIZE; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ciout: 59262306a36Sopenharmony_ci return err ? err : count; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic char *carl9170_debugfs_hw_ioread32_read(struct ar9170 *ar, char *buf, 59662306a36Sopenharmony_ci size_t bufsize, ssize_t *ret) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci int i = 0; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci while (ar->debug.ring_head != ar->debug.ring_tail) { 60162306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "%.8x = %.8x\n", 60262306a36Sopenharmony_ci ar->debug.ring[ar->debug.ring_head].reg, 60362306a36Sopenharmony_ci ar->debug.ring[ar->debug.ring_head].value); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci ar->debug.ring_head++; 60662306a36Sopenharmony_ci ar->debug.ring_head %= CARL9170_DEBUG_RING_SIZE; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (i++ == 64) 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci ar->debug.ring_head = ar->debug.ring_tail; 61262306a36Sopenharmony_ci return buf; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ciDEBUGFS_DECLARE_RW_FILE(hw_ioread32, CARL9170_DEBUG_RING_SIZE * 40); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf, 61762306a36Sopenharmony_ci size_t count) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci int err; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (count < 1) 62262306a36Sopenharmony_ci return -EINVAL; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci switch (buf[0]) { 62562306a36Sopenharmony_ci case 'F': 62662306a36Sopenharmony_ci ar->needs_full_reset = true; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci case 'R': 63062306a36Sopenharmony_ci if (!IS_STARTED(ar)) { 63162306a36Sopenharmony_ci err = -EAGAIN; 63262306a36Sopenharmony_ci goto out; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ar->needs_full_reset = false; 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci case 'M': 63962306a36Sopenharmony_ci err = carl9170_mac_reset(ar); 64062306a36Sopenharmony_ci if (err < 0) 64162306a36Sopenharmony_ci count = err; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci goto out; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci case 'P': 64662306a36Sopenharmony_ci err = carl9170_set_channel(ar, ar->hw->conf.chandef.chan, 64762306a36Sopenharmony_ci cfg80211_get_chandef_type(&ar->hw->conf.chandef)); 64862306a36Sopenharmony_ci if (err < 0) 64962306a36Sopenharmony_ci count = err; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci goto out; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci default: 65462306a36Sopenharmony_ci return -EINVAL; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci carl9170_restart(ar, CARL9170_RR_USER_REQUEST); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ciout: 66062306a36Sopenharmony_ci return count; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic char *carl9170_debugfs_bug_read(struct ar9170 *ar, char *buf, 66462306a36Sopenharmony_ci size_t bufsize, ssize_t *ret) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "[P]hy reinit, [R]estart, [F]ull usb reset, " 66762306a36Sopenharmony_ci "[M]ac reset\n"); 66862306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "firmware restarts:%d, last reason:%d\n", 66962306a36Sopenharmony_ci ar->restart_counter, ar->last_reason); 67062306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "phy reinit errors:%d (%d)\n", 67162306a36Sopenharmony_ci ar->total_chan_fail, ar->chan_fail); 67262306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "reported firmware errors:%d\n", 67362306a36Sopenharmony_ci ar->fw.err_counter); 67462306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "reported firmware BUGs:%d\n", 67562306a36Sopenharmony_ci ar->fw.bug_counter); 67662306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "pending restart requests:%d\n", 67762306a36Sopenharmony_ci atomic_read(&ar->pending_restarts)); 67862306a36Sopenharmony_ci return buf; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci__DEBUGFS_DECLARE_RW_FILE(bug, 400, CARL9170_STOPPED); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic const char *const erp_modes[] = { 68362306a36Sopenharmony_ci [CARL9170_ERP_INVALID] = "INVALID", 68462306a36Sopenharmony_ci [CARL9170_ERP_AUTO] = "Automatic", 68562306a36Sopenharmony_ci [CARL9170_ERP_MAC80211] = "Set by MAC80211", 68662306a36Sopenharmony_ci [CARL9170_ERP_OFF] = "Force Off", 68762306a36Sopenharmony_ci [CARL9170_ERP_RTS] = "Force RTS", 68862306a36Sopenharmony_ci [CARL9170_ERP_CTS] = "Force CTS" 68962306a36Sopenharmony_ci}; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic char *carl9170_debugfs_erp_read(struct ar9170 *ar, char *buf, 69262306a36Sopenharmony_ci size_t bufsize, ssize_t *ret) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci ADD(buf, *ret, bufsize, "ERP Setting: (%d) -> %s\n", ar->erp_mode, 69562306a36Sopenharmony_ci erp_modes[ar->erp_mode]); 69662306a36Sopenharmony_ci return buf; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic ssize_t carl9170_debugfs_erp_write(struct ar9170 *ar, const char *buf, 70062306a36Sopenharmony_ci size_t count) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci int res, val; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (count < 1) 70562306a36Sopenharmony_ci return -EINVAL; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci res = sscanf(buf, "%d", &val); 70862306a36Sopenharmony_ci if (res != 1) 70962306a36Sopenharmony_ci return -EINVAL; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (!((val > CARL9170_ERP_INVALID) && 71262306a36Sopenharmony_ci (val < __CARL9170_ERP_NUM))) 71362306a36Sopenharmony_ci return -EINVAL; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci ar->erp_mode = val; 71662306a36Sopenharmony_ci return count; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ciDEBUGFS_DECLARE_RW_FILE(erp, 80); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic ssize_t carl9170_debugfs_hw_iowrite32_write(struct ar9170 *ar, 72262306a36Sopenharmony_ci const char *buf, size_t count) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci int err = 0, max_len = 22, res; 72562306a36Sopenharmony_ci u32 reg, val; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (!count) 72862306a36Sopenharmony_ci return 0; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (count > max_len) 73162306a36Sopenharmony_ci return -E2BIG; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X", ®, &val); 73462306a36Sopenharmony_ci if (res != 2) { 73562306a36Sopenharmony_ci err = -EINVAL; 73662306a36Sopenharmony_ci goto out; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (reg <= 0x100000 || reg >= 0x280000) { 74062306a36Sopenharmony_ci err = -EADDRNOTAVAIL; 74162306a36Sopenharmony_ci goto out; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (reg & 3) { 74562306a36Sopenharmony_ci err = -EINVAL; 74662306a36Sopenharmony_ci goto out; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci err = carl9170_write_reg(ar, reg, val); 75062306a36Sopenharmony_ci if (err) 75162306a36Sopenharmony_ci goto out; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ciout: 75462306a36Sopenharmony_ci return err ? err : count; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ciDEBUGFS_DECLARE_WO_FILE(hw_iowrite32); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ciDEBUGFS_HW_TALLY_FILE(hw_tx_tally, "u"); 75962306a36Sopenharmony_ciDEBUGFS_HW_TALLY_FILE(hw_rx_tally, "u"); 76062306a36Sopenharmony_ciDEBUGFS_HW_TALLY_FILE(hw_phy_errors, "u"); 76162306a36Sopenharmony_ciDEBUGFS_HW_REG_FILE(hw_wlan_queue, ".8x"); 76262306a36Sopenharmony_ciDEBUGFS_HW_REG_FILE(hw_pta_queue, ".8x"); 76362306a36Sopenharmony_ciDEBUGFS_HW_REG_FILE(hw_ampdu_info, ".8x"); 76462306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_status, 0); 76562306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_status, 1); 76662306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_status, 2); 76762306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_status, 3); 76862306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_pending, 0); 76962306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_pending, 1); 77062306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_pending, 2); 77162306a36Sopenharmony_ciDEBUGFS_QUEUE_DUMP(tx_pending, 3); 77262306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(usb_tx_anch_urbs, 20, "%d", 77362306a36Sopenharmony_ci atomic_read(&ar->tx_anch_urbs)); 77462306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(usb_rx_anch_urbs, 20, "%d", 77562306a36Sopenharmony_ci atomic_read(&ar->rx_anch_urbs)); 77662306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(usb_rx_work_urbs, 20, "%d", 77762306a36Sopenharmony_ci atomic_read(&ar->rx_work_urbs)); 77862306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(usb_rx_pool_urbs, 20, "%d", 77962306a36Sopenharmony_ci atomic_read(&ar->rx_pool_urbs)); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_total_queued, 20, "%d", 78262306a36Sopenharmony_ci atomic_read(&ar->tx_total_queued)); 78362306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_ampdu_scheduler, 20, "%d", 78462306a36Sopenharmony_ci atomic_read(&ar->tx_ampdu_scheduler)); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_total_pending, 20, "%d", 78762306a36Sopenharmony_ci atomic_read(&ar->tx_total_pending)); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_ampdu_list_len, 20, "%d", 79062306a36Sopenharmony_ci ar->tx_ampdu_list_len); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_ampdu_upload, 20, "%d", 79362306a36Sopenharmony_ci atomic_read(&ar->tx_ampdu_upload)); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_janitor_last_run, 64, "last run:%d ms ago", 79662306a36Sopenharmony_ci jiffies_to_msecs(jiffies - ar->tx_janitor_last_run)); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(tx_dropped, 20, "%d", ar->tx_dropped); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(rx_dropped, 20, "%d", ar->rx_dropped); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(sniffer_enabled, 20, "%d", ar->sniffer_enabled); 80362306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(rx_software_decryption, 20, "%d", 80462306a36Sopenharmony_ci ar->rx_software_decryption); 80562306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(ampdu_factor, 20, "%d", 80662306a36Sopenharmony_ci ar->current_factor); 80762306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(ampdu_density, 20, "%d", 80862306a36Sopenharmony_ci ar->current_density); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(beacon_int, 20, "%d TU", ar->global_beacon_int); 81162306a36Sopenharmony_ciDEBUGFS_READONLY_FILE(pretbtt, 20, "%d TU", ar->global_pretbtt); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_civoid carl9170_debugfs_register(struct ar9170 *ar) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci ar->debug_dir = debugfs_create_dir(KBUILD_MODNAME, 81662306a36Sopenharmony_ci ar->hw->wiphy->debugfsdir); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci#define DEBUGFS_ADD(name) \ 81962306a36Sopenharmony_ci debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \ 82062306a36Sopenharmony_ci ar->debug_dir, ar, \ 82162306a36Sopenharmony_ci &carl_debugfs_##name ## _ops.fops) 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci DEBUGFS_ADD(usb_tx_anch_urbs); 82462306a36Sopenharmony_ci DEBUGFS_ADD(usb_rx_pool_urbs); 82562306a36Sopenharmony_ci DEBUGFS_ADD(usb_rx_anch_urbs); 82662306a36Sopenharmony_ci DEBUGFS_ADD(usb_rx_work_urbs); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci DEBUGFS_ADD(tx_total_queued); 82962306a36Sopenharmony_ci DEBUGFS_ADD(tx_total_pending); 83062306a36Sopenharmony_ci DEBUGFS_ADD(tx_dropped); 83162306a36Sopenharmony_ci DEBUGFS_ADD(tx_stuck); 83262306a36Sopenharmony_ci DEBUGFS_ADD(tx_ampdu_upload); 83362306a36Sopenharmony_ci DEBUGFS_ADD(tx_ampdu_scheduler); 83462306a36Sopenharmony_ci DEBUGFS_ADD(tx_ampdu_list_len); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci DEBUGFS_ADD(rx_dropped); 83762306a36Sopenharmony_ci DEBUGFS_ADD(sniffer_enabled); 83862306a36Sopenharmony_ci DEBUGFS_ADD(rx_software_decryption); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci DEBUGFS_ADD(mem_usage); 84162306a36Sopenharmony_ci DEBUGFS_ADD(qos_stat); 84262306a36Sopenharmony_ci DEBUGFS_ADD(sta_psm); 84362306a36Sopenharmony_ci DEBUGFS_ADD(ampdu_state); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci DEBUGFS_ADD(hw_tx_tally); 84662306a36Sopenharmony_ci DEBUGFS_ADD(hw_rx_tally); 84762306a36Sopenharmony_ci DEBUGFS_ADD(hw_phy_errors); 84862306a36Sopenharmony_ci DEBUGFS_ADD(phy_noise); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci DEBUGFS_ADD(hw_wlan_queue); 85162306a36Sopenharmony_ci DEBUGFS_ADD(hw_pta_queue); 85262306a36Sopenharmony_ci DEBUGFS_ADD(hw_ampdu_info); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci DEBUGFS_ADD(ampdu_density); 85562306a36Sopenharmony_ci DEBUGFS_ADD(ampdu_factor); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci DEBUGFS_ADD(tx_janitor_last_run); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci DEBUGFS_ADD(tx_status_0); 86062306a36Sopenharmony_ci DEBUGFS_ADD(tx_status_1); 86162306a36Sopenharmony_ci DEBUGFS_ADD(tx_status_2); 86262306a36Sopenharmony_ci DEBUGFS_ADD(tx_status_3); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci DEBUGFS_ADD(tx_pending_0); 86562306a36Sopenharmony_ci DEBUGFS_ADD(tx_pending_1); 86662306a36Sopenharmony_ci DEBUGFS_ADD(tx_pending_2); 86762306a36Sopenharmony_ci DEBUGFS_ADD(tx_pending_3); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci DEBUGFS_ADD(hw_ioread32); 87062306a36Sopenharmony_ci DEBUGFS_ADD(hw_iowrite32); 87162306a36Sopenharmony_ci DEBUGFS_ADD(bug); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci DEBUGFS_ADD(erp); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci DEBUGFS_ADD(vif_dump); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci DEBUGFS_ADD(beacon_int); 87862306a36Sopenharmony_ci DEBUGFS_ADD(pretbtt); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci#undef DEBUGFS_ADD 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_civoid carl9170_debugfs_unregister(struct ar9170 *ar) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci debugfs_remove_recursive(ar->debug_dir); 88662306a36Sopenharmony_ci} 887