diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210/debugfs.c')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/debugfs.c | 361 |
1 files changed, 325 insertions, 36 deletions
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 8d4bc4bfb664..8f66186adb8c 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -19,6 +19,7 @@ #include <linux/seq_file.h> #include <linux/pci.h> #include <linux/rtnetlink.h> +#include <linux/power_supply.h> #include "wil6210.h" #include "txrx.h" @@ -69,14 +70,32 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { struct vring *vring = &(wil->vring_tx[i]); + struct vring_tx_data *txdata = &wil->vring_tx_data[i]; + if (vring->va) { int cid = wil->vring2cid_tid[i][0]; int tid = wil->vring2cid_tid[i][1]; + u32 swhead = vring->swhead; + u32 swtail = vring->swtail; + int used = (vring->size + swhead - swtail) + % vring->size; + int avail = vring->size - used - 1; char name[10]; + /* performance monitoring */ + cycles_t now = get_cycles(); + cycles_t idle = txdata->idle * 100; + cycles_t total = now - txdata->begin; + + do_div(idle, total); + txdata->begin = now; + txdata->idle = 0ULL; + snprintf(name, sizeof(name), "tx_%2d", i); - seq_printf(s, "\n%pM CID %d TID %d\n", - wil->sta[cid].addr, cid, tid); + seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n", + wil->sta[cid].addr, cid, tid, used, avail, + (int)idle); + wil_print_vring(s, wil, name, vring, '_', 'H'); } } @@ -231,6 +250,26 @@ static struct dentry *wil_debugfs_create_iomem_x32(const char *name, &fops_iomem_x32); } +static int wil_debugfs_ulong_set(void *data, u64 val) +{ + *(ulong *)data = val; + return 0; +} +static int wil_debugfs_ulong_get(void *data, u64 *val) +{ + *val = *(ulong *)data; + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, + wil_debugfs_ulong_set, "%llu\n"); + +static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, + struct dentry *parent, + ulong *value) +{ + return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); +} + static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, const char *name, struct dentry *parent, u32 off) @@ -284,11 +323,11 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, if (IS_ERR_OR_NULL(d)) return -ENODEV; - wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr + + wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); - wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr + + wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_DATA)); - wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr + + wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); return 0; @@ -397,6 +436,126 @@ static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; +/*---write channel 1..4 to rxon for it, 0 to rxoff---*/ +static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + int rc; + long channel; + bool on; + + char *kbuf = kmalloc(len + 1, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + if (copy_from_user(kbuf, buf, len)) { + kfree(kbuf); + return -EIO; + } + + kbuf[len] = '\0'; + rc = kstrtol(kbuf, 0, &channel); + kfree(kbuf); + if (rc) + return rc; + + if ((channel < 0) || (channel > 4)) { + wil_err(wil, "Invalid channel %ld\n", channel); + return -EINVAL; + } + on = !!channel; + + if (on) { + rc = wmi_set_channel(wil, (int)channel); + if (rc) + return rc; + } + + rc = wmi_rxon(wil, on); + if (rc) + return rc; + + return len; +} + +static const struct file_operations fops_rxon = { + .write = wil_write_file_rxon, + .open = simple_open, +}; +/*---tx_mgmt---*/ +/* Write mgmt frame to this file to send it */ +static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + struct wiphy *wiphy = wil_to_wiphy(wil); + struct wireless_dev *wdev = wil_to_wdev(wil); + struct cfg80211_mgmt_tx_params params; + int rc; + + void *frame = kmalloc(len, GFP_KERNEL); + if (!frame) + return -ENOMEM; + + if (copy_from_user(frame, buf, len)) + return -EIO; + + params.buf = frame; + params.len = len; + params.chan = wdev->preset_chandef.chan; + + rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); + + kfree(frame); + wil_info(wil, "%s() -> %d\n", __func__, rc); + + return len; +} + +static const struct file_operations fops_txmgmt = { + .write = wil_write_file_txmgmt, + .open = simple_open, +}; + +/* Write WMI command (w/o mbox header) to this file to send it + * WMI starts from wil6210_mbox_hdr_wmi header + */ +static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + struct wil6210_mbox_hdr_wmi *wmi; + void *cmd; + int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi); + u16 cmdid; + int rc, rc1; + + if (cmdlen <= 0) + return -EINVAL; + + wmi = kmalloc(len, GFP_KERNEL); + if (!wmi) + return -ENOMEM; + + rc = simple_write_to_buffer(wmi, len, ppos, buf, len); + if (rc < 0) + return rc; + + cmd = &wmi[1]; + cmdid = le16_to_cpu(wmi->id); + + rc1 = wmi_send(wil, cmdid, cmd, cmdlen); + kfree(wmi); + + wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1); + + return rc; +} + +static const struct file_operations fops_wmi = { + .write = wil_write_file_wmi, + .open = simple_open, +}; static void wil_seq_hexdump(struct seq_file *s, void *p, int len, const char *prefix) @@ -600,8 +759,8 @@ static int wil_temp_debugfs_show(struct seq_file *s, void *data) return 0; } - print_temp(s, "MAC temperature :", t_m); - print_temp(s, "Radio temperature :", t_r); + print_temp(s, "T_mac =", t_m); + print_temp(s, "T_radio =", t_r); return 0; } @@ -618,6 +777,130 @@ static const struct file_operations fops_temp = { .llseek = seq_lseek, }; +/*---------freq------------*/ +static int wil_freq_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct wireless_dev *wdev = wil_to_wdev(wil); + u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; + + seq_printf(s, "Freq = %d\n", freq); + + return 0; +} + +static int wil_freq_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_freq_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_freq = { + .open = wil_freq_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + +/*---------link------------*/ +static int wil_link_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct station_info sinfo; + int i, rc; + + for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { + struct wil_sta_info *p = &wil->sta[i]; + char *status = "unknown"; + switch (p->status) { + case wil_sta_unused: + status = "unused "; + break; + case wil_sta_conn_pending: + status = "pending "; + break; + case wil_sta_connected: + status = "connected"; + break; + } + seq_printf(s, "[%d] %pM %s%s\n", i, p->addr, status, + (p->data_port_open ? " data_port_open" : "")); + + if (p->status == wil_sta_connected) { + rc = wil_cid_fill_sinfo(wil, i, &sinfo); + if (rc) + return rc; + + seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); + seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); + seq_printf(s, " SQ = %d\n", sinfo.signal); + } + } + + return 0; +} + +static int wil_link_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_link_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_link = { + .open = wil_link_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + +/*---------info------------*/ +static int wil_info_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct net_device *ndev = wil_to_ndev(wil); + int is_ac = power_supply_is_system_supplied(); + int rx = atomic_xchg(&wil->isr_count_rx, 0); + int tx = atomic_xchg(&wil->isr_count_tx, 0); + static ulong rxf_old, txf_old; + ulong rxf = ndev->stats.rx_packets; + ulong txf = ndev->stats.tx_packets; + unsigned int i; + + /* >0 : AC; 0 : battery; <0 : error */ + seq_printf(s, "AC powered : %d\n", is_ac); + seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); + seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); + rxf_old = rxf; + txf_old = txf; + + +#define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ + " " __stringify(x) : "" + + for (i = 0; i < ndev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); + unsigned long state = txq->state; + + seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, + CHECK_QSTATE(DRV_XOFF), + CHECK_QSTATE(STACK_XOFF), + CHECK_QSTATE(FROZEN) + ); + } +#undef CHECK_QSTATE + return 0; +} + +static int wil_info_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_info_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_info = { + .open = wil_info_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*---------Station matrix------------*/ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { @@ -630,7 +913,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } - seq_puts(s, "]\n"); + seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) @@ -682,6 +965,26 @@ static const struct file_operations fops_sta = { }; /*----------------*/ +static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, + struct dentry *dbg) +{ + int i; + char name[32]; + + for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { + struct debugfs_blob_wrapper *blob = &wil->blobs[i]; + const struct fw_map *map = &fw_mapping[i]; + + if (!map->name) + continue; + + blob->data = (void * __force)wil->csr + HOSTADDR(map->host); + blob->size = map->to - map->from; + snprintf(name, sizeof(name), "blob_%s", map->name); + wil_debugfs_create_ioblob(name, S_IRUGO, dbg, blob); + } +} + int wil6210_debugfs_init(struct wil6210_priv *wil) { struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, @@ -703,6 +1006,10 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid); debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg, &wil->secure_pcp); + wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg, + &wil->status); + debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version); + debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version); wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg, HOSTADDR(RGF_USER_USER_ICR)); @@ -715,40 +1022,22 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) wil6210_debugfs_create_pseudo_ISR(wil, dbg); wil6210_debugfs_create_ITR_CNT(wil, dbg); + wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg, + wil->csr + + HOSTADDR(RGF_USER_USAGE_1)); debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr); debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread); debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset); + debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon); + debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt); + debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi); debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp); + debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq); + debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link); + debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info); - wil->rgf_blob.data = (void * __force)wil->csr + 0; - wil->rgf_blob.size = 0xa000; - wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob); - - wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000; - wil->fw_code_blob.size = 0x40000; - wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg, - &wil->fw_code_blob); - - wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000; - wil->fw_data_blob.size = 0x8000; - wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg, - &wil->fw_data_blob); - - wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000; - wil->fw_peri_blob.size = 0x18000; - wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg, - &wil->fw_peri_blob); - - wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000; - wil->uc_code_blob.size = 0x10000; - wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg, - &wil->uc_code_blob); - - wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000; - wil->uc_data_blob.size = 0x4000; - wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg, - &wil->uc_data_blob); + wil6210_debugfs_init_blobs(wil, dbg); return 0; } |