12be7d22fSVladimir Kondratiev /* 2a351f2f5SLazar Alexei * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. 3e00243faSLior David * Copyright (c) 2018, The Linux Foundation. All rights reserved. 42be7d22fSVladimir Kondratiev * 52be7d22fSVladimir Kondratiev * Permission to use, copy, modify, and/or distribute this software for any 62be7d22fSVladimir Kondratiev * purpose with or without fee is hereby granted, provided that the above 72be7d22fSVladimir Kondratiev * copyright notice and this permission notice appear in all copies. 82be7d22fSVladimir Kondratiev * 92be7d22fSVladimir Kondratiev * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 102be7d22fSVladimir Kondratiev * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 112be7d22fSVladimir Kondratiev * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 122be7d22fSVladimir Kondratiev * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 132be7d22fSVladimir Kondratiev * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 142be7d22fSVladimir Kondratiev * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 152be7d22fSVladimir Kondratiev * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 162be7d22fSVladimir Kondratiev */ 172be7d22fSVladimir Kondratiev 182be7d22fSVladimir Kondratiev #include <linux/module.h> 192be7d22fSVladimir Kondratiev #include <linux/debugfs.h> 202be7d22fSVladimir Kondratiev #include <linux/seq_file.h> 212be7d22fSVladimir Kondratiev #include <linux/pci.h> 222be7d22fSVladimir Kondratiev #include <linux/rtnetlink.h> 2384bb29b7SVladimir Kondratiev #include <linux/power_supply.h> 242be7d22fSVladimir Kondratiev #include "wil6210.h" 2536345ac3SVladimir Kondratiev #include "wmi.h" 262be7d22fSVladimir Kondratiev #include "txrx.h" 27dc16427bSVladimir Kondratiev #include "pmc.h" 282be7d22fSVladimir Kondratiev 292be7d22fSVladimir Kondratiev /* Nasty hack. Better have per device instances */ 302be7d22fSVladimir Kondratiev static u32 mem_addr; 312be7d22fSVladimir Kondratiev static u32 dbg_txdesc_index; 32af31cb5aSVladimir Kondratiev static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ 332be7d22fSVladimir Kondratiev 34b7cde470SVladimir Kondratiev enum dbg_off_type { 35b7cde470SVladimir Kondratiev doff_u32 = 0, 36b7cde470SVladimir Kondratiev doff_x32 = 1, 37b7cde470SVladimir Kondratiev doff_ulong = 2, 38b7cde470SVladimir Kondratiev doff_io32 = 3, 3974997a53SLior David doff_u8 = 4 40b7cde470SVladimir Kondratiev }; 41b7cde470SVladimir Kondratiev 42b7cde470SVladimir Kondratiev /* offset to "wil" */ 43b7cde470SVladimir Kondratiev struct dbg_off { 44b7cde470SVladimir Kondratiev const char *name; 45b7cde470SVladimir Kondratiev umode_t mode; 46b7cde470SVladimir Kondratiev ulong off; 47b7cde470SVladimir Kondratiev enum dbg_off_type type; 48b7cde470SVladimir Kondratiev }; 49b7cde470SVladimir Kondratiev 502be7d22fSVladimir Kondratiev static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, 5159f7c0a9SVladimir Kondratiev const char *name, struct vring *vring, 5259f7c0a9SVladimir Kondratiev char _s, char _h) 532be7d22fSVladimir Kondratiev { 542be7d22fSVladimir Kondratiev void __iomem *x = wmi_addr(wil, vring->hwtail); 55995cdd0eSVladimir Kondratiev u32 v; 562be7d22fSVladimir Kondratiev 572be7d22fSVladimir Kondratiev seq_printf(s, "VRING %s = {\n", name); 5839c52ee8SVladimir Kondratiev seq_printf(s, " pa = %pad\n", &vring->pa); 592be7d22fSVladimir Kondratiev seq_printf(s, " va = 0x%p\n", vring->va); 602be7d22fSVladimir Kondratiev seq_printf(s, " size = %d\n", vring->size); 612be7d22fSVladimir Kondratiev seq_printf(s, " swtail = %d\n", vring->swtail); 622be7d22fSVladimir Kondratiev seq_printf(s, " swhead = %d\n", vring->swhead); 632be7d22fSVladimir Kondratiev seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); 64995cdd0eSVladimir Kondratiev if (x) { 65b9eeb512SVladimir Kondratiev v = readl(x); 66995cdd0eSVladimir Kondratiev seq_printf(s, "0x%08x = %d\n", v, v); 67995cdd0eSVladimir Kondratiev } else { 688fe59627SVladimir Kondratiev seq_puts(s, "???\n"); 69995cdd0eSVladimir Kondratiev } 702be7d22fSVladimir Kondratiev 71ee5dfe0dSHamad Kadmany if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { 722be7d22fSVladimir Kondratiev uint i; 738fe59627SVladimir Kondratiev 742be7d22fSVladimir Kondratiev for (i = 0; i < vring->size; i++) { 752be7d22fSVladimir Kondratiev volatile struct vring_tx_desc *d = &vring->va[i].tx; 768fe59627SVladimir Kondratiev 77ee5dfe0dSHamad Kadmany if ((i % 128) == 0 && (i != 0)) 788fe59627SVladimir Kondratiev seq_puts(s, "\n"); 7959f7c0a9SVladimir Kondratiev seq_printf(s, "%c", (d->dma.status & BIT(0)) ? 8059f7c0a9SVladimir Kondratiev _s : (vring->ctx[i].skb ? _h : 'h')); 812be7d22fSVladimir Kondratiev } 828fe59627SVladimir Kondratiev seq_puts(s, "\n"); 832be7d22fSVladimir Kondratiev } 848fe59627SVladimir Kondratiev seq_puts(s, "}\n"); 852be7d22fSVladimir Kondratiev } 862be7d22fSVladimir Kondratiev 872be7d22fSVladimir Kondratiev static int wil_vring_debugfs_show(struct seq_file *s, void *data) 882be7d22fSVladimir Kondratiev { 892be7d22fSVladimir Kondratiev uint i; 902be7d22fSVladimir Kondratiev struct wil6210_priv *wil = s->private; 912be7d22fSVladimir Kondratiev 9259f7c0a9SVladimir Kondratiev wil_print_vring(s, wil, "rx", &wil->vring_rx, 'S', '_'); 932be7d22fSVladimir Kondratiev 942be7d22fSVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) { 958fe59627SVladimir Kondratiev struct vring *vring = &wil->vring_tx[i]; 967c0acf86SVladimir Kondratiev struct vring_tx_data *txdata = &wil->vring_tx_data[i]; 977c0acf86SVladimir Kondratiev 982be7d22fSVladimir Kondratiev if (vring->va) { 993df2cd36SVladimir Kondratiev int cid = wil->vring2cid_tid[i][0]; 1003df2cd36SVladimir Kondratiev int tid = wil->vring2cid_tid[i][1]; 10167c3e1b4SVladimir Kondratiev u32 swhead = vring->swhead; 10267c3e1b4SVladimir Kondratiev u32 swtail = vring->swtail; 10367c3e1b4SVladimir Kondratiev int used = (vring->size + swhead - swtail) 10467c3e1b4SVladimir Kondratiev % vring->size; 10567c3e1b4SVladimir Kondratiev int avail = vring->size - used - 1; 1062be7d22fSVladimir Kondratiev char name[10]; 1078f55cbecSBoris Sorochkin char sidle[10]; 1087c0acf86SVladimir Kondratiev /* performance monitoring */ 1097c0acf86SVladimir Kondratiev cycles_t now = get_cycles(); 110c20e7789SChen Gang uint64_t idle = txdata->idle * 100; 111c20e7789SChen Gang uint64_t total = now - txdata->begin; 1127c0acf86SVladimir Kondratiev 1138f55cbecSBoris Sorochkin if (total != 0) { 114e48b1790SVladimir Kondratiev do_div(idle, total); 1158f55cbecSBoris Sorochkin snprintf(sidle, sizeof(sidle), "%3d%%", 1168f55cbecSBoris Sorochkin (int)idle); 1178f55cbecSBoris Sorochkin } else { 1188f55cbecSBoris Sorochkin snprintf(sidle, sizeof(sidle), "N/A"); 1198f55cbecSBoris Sorochkin } 1207c0acf86SVladimir Kondratiev txdata->begin = now; 1217c0acf86SVladimir Kondratiev txdata->idle = 0ULL; 1227c0acf86SVladimir Kondratiev 1232be7d22fSVladimir Kondratiev snprintf(name, sizeof(name), "tx_%2d", i); 1243df2cd36SVladimir Kondratiev 12541d6b093SVladimir Kondratiev if (cid < WIL6210_MAX_CID) 1263277213fSVladimir Kondratiev seq_printf(s, 127230d8442SVladimir Kondratiev "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", 1283277213fSVladimir Kondratiev wil->sta[cid].addr, cid, tid, 129230d8442SVladimir Kondratiev txdata->dot1x_open ? "+" : "-", 13041d6b093SVladimir Kondratiev txdata->agg_wsize, 13141d6b093SVladimir Kondratiev txdata->agg_timeout, 132cbcf5866SVladimir Kondratiev txdata->agg_amsdu ? "+" : "-", 1338f55cbecSBoris Sorochkin used, avail, sidle); 13441d6b093SVladimir Kondratiev else 13541d6b093SVladimir Kondratiev seq_printf(s, 136230d8442SVladimir Kondratiev "\nBroadcast 1x%s [%3d|%3d] idle %s\n", 137230d8442SVladimir Kondratiev txdata->dot1x_open ? "+" : "-", 13841d6b093SVladimir Kondratiev used, avail, sidle); 1397c0acf86SVladimir Kondratiev 14059f7c0a9SVladimir Kondratiev wil_print_vring(s, wil, name, vring, '_', 'H'); 1412be7d22fSVladimir Kondratiev } 1422be7d22fSVladimir Kondratiev } 1432be7d22fSVladimir Kondratiev 1442be7d22fSVladimir Kondratiev return 0; 1452be7d22fSVladimir Kondratiev } 1462be7d22fSVladimir Kondratiev 1472be7d22fSVladimir Kondratiev static int wil_vring_seq_open(struct inode *inode, struct file *file) 1482be7d22fSVladimir Kondratiev { 1492be7d22fSVladimir Kondratiev return single_open(file, wil_vring_debugfs_show, inode->i_private); 1502be7d22fSVladimir Kondratiev } 1512be7d22fSVladimir Kondratiev 1522be7d22fSVladimir Kondratiev static const struct file_operations fops_vring = { 1532be7d22fSVladimir Kondratiev .open = wil_vring_seq_open, 1542be7d22fSVladimir Kondratiev .release = single_release, 1552be7d22fSVladimir Kondratiev .read = seq_read, 1562be7d22fSVladimir Kondratiev .llseek = seq_lseek, 1572be7d22fSVladimir Kondratiev }; 1582be7d22fSVladimir Kondratiev 159a202fbbfSAndy Shevchenko static void wil_seq_hexdump(struct seq_file *s, void *p, int len, 160a202fbbfSAndy Shevchenko const char *prefix) 161a202fbbfSAndy Shevchenko { 162a202fbbfSAndy Shevchenko seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false); 163a202fbbfSAndy Shevchenko } 164a202fbbfSAndy Shevchenko 1652be7d22fSVladimir Kondratiev static void wil_print_ring(struct seq_file *s, const char *prefix, 1662be7d22fSVladimir Kondratiev void __iomem *off) 1672be7d22fSVladimir Kondratiev { 1682be7d22fSVladimir Kondratiev struct wil6210_priv *wil = s->private; 1692be7d22fSVladimir Kondratiev struct wil6210_mbox_ring r; 1702be7d22fSVladimir Kondratiev int rsize; 1712be7d22fSVladimir Kondratiev uint i; 1722be7d22fSVladimir Kondratiev 173349214c1SMaya Erez wil_halp_vote(wil); 174349214c1SMaya Erez 1752be7d22fSVladimir Kondratiev wil_memcpy_fromio_32(&r, off, sizeof(r)); 1762be7d22fSVladimir Kondratiev wil_mbox_ring_le2cpus(&r); 1772be7d22fSVladimir Kondratiev /* 1782be7d22fSVladimir Kondratiev * we just read memory block from NIC. This memory may be 1792be7d22fSVladimir Kondratiev * garbage. Check validity before using it. 1802be7d22fSVladimir Kondratiev */ 1812be7d22fSVladimir Kondratiev rsize = r.size / sizeof(struct wil6210_mbox_ring_desc); 1822be7d22fSVladimir Kondratiev 1832be7d22fSVladimir Kondratiev seq_printf(s, "ring %s = {\n", prefix); 1842be7d22fSVladimir Kondratiev seq_printf(s, " base = 0x%08x\n", r.base); 1852be7d22fSVladimir Kondratiev seq_printf(s, " size = 0x%04x bytes -> %d entries\n", r.size, rsize); 1862be7d22fSVladimir Kondratiev seq_printf(s, " tail = 0x%08x\n", r.tail); 1872be7d22fSVladimir Kondratiev seq_printf(s, " head = 0x%08x\n", r.head); 1882be7d22fSVladimir Kondratiev seq_printf(s, " entry size = %d\n", r.entry_size); 1892be7d22fSVladimir Kondratiev 1902be7d22fSVladimir Kondratiev if (r.size % sizeof(struct wil6210_mbox_ring_desc)) { 1912be7d22fSVladimir Kondratiev seq_printf(s, " ??? size is not multiple of %zd, garbage?\n", 1922be7d22fSVladimir Kondratiev sizeof(struct wil6210_mbox_ring_desc)); 1932be7d22fSVladimir Kondratiev goto out; 1942be7d22fSVladimir Kondratiev } 1952be7d22fSVladimir Kondratiev 1962be7d22fSVladimir Kondratiev if (!wmi_addr(wil, r.base) || 1972be7d22fSVladimir Kondratiev !wmi_addr(wil, r.tail) || 1982be7d22fSVladimir Kondratiev !wmi_addr(wil, r.head)) { 1998fe59627SVladimir Kondratiev seq_puts(s, " ??? pointers are garbage?\n"); 2002be7d22fSVladimir Kondratiev goto out; 2012be7d22fSVladimir Kondratiev } 2022be7d22fSVladimir Kondratiev 2032be7d22fSVladimir Kondratiev for (i = 0; i < rsize; i++) { 2042be7d22fSVladimir Kondratiev struct wil6210_mbox_ring_desc d; 2052be7d22fSVladimir Kondratiev struct wil6210_mbox_hdr hdr; 2062be7d22fSVladimir Kondratiev size_t delta = i * sizeof(d); 2072be7d22fSVladimir Kondratiev void __iomem *x = wil->csr + HOSTADDR(r.base) + delta; 2082be7d22fSVladimir Kondratiev 2092be7d22fSVladimir Kondratiev wil_memcpy_fromio_32(&d, x, sizeof(d)); 2102be7d22fSVladimir Kondratiev 2112be7d22fSVladimir Kondratiev seq_printf(s, " [%2x] %s %s%s 0x%08x", i, 2122be7d22fSVladimir Kondratiev d.sync ? "F" : "E", 2132be7d22fSVladimir Kondratiev (r.tail - r.base == delta) ? "t" : " ", 2142be7d22fSVladimir Kondratiev (r.head - r.base == delta) ? "h" : " ", 2152be7d22fSVladimir Kondratiev le32_to_cpu(d.addr)); 2162be7d22fSVladimir Kondratiev if (0 == wmi_read_hdr(wil, d.addr, &hdr)) { 2172be7d22fSVladimir Kondratiev u16 len = le16_to_cpu(hdr.len); 2188fe59627SVladimir Kondratiev 2192be7d22fSVladimir Kondratiev seq_printf(s, " -> %04x %04x %04x %02x\n", 2202be7d22fSVladimir Kondratiev le16_to_cpu(hdr.seq), len, 2212be7d22fSVladimir Kondratiev le16_to_cpu(hdr.type), hdr.flags); 2222be7d22fSVladimir Kondratiev if (len <= MAX_MBOXITEM_SIZE) { 2232be7d22fSVladimir Kondratiev unsigned char databuf[MAX_MBOXITEM_SIZE]; 2242be7d22fSVladimir Kondratiev void __iomem *src = wmi_buffer(wil, d.addr) + 2252be7d22fSVladimir Kondratiev sizeof(struct wil6210_mbox_hdr); 2262be7d22fSVladimir Kondratiev /* 2272be7d22fSVladimir Kondratiev * No need to check @src for validity - 2282be7d22fSVladimir Kondratiev * we already validated @d.addr while 2292be7d22fSVladimir Kondratiev * reading header 2302be7d22fSVladimir Kondratiev */ 2312be7d22fSVladimir Kondratiev wil_memcpy_fromio_32(databuf, src, len); 232a202fbbfSAndy Shevchenko wil_seq_hexdump(s, databuf, len, " : "); 2332be7d22fSVladimir Kondratiev } 2342be7d22fSVladimir Kondratiev } else { 2358fe59627SVladimir Kondratiev seq_puts(s, "\n"); 2362be7d22fSVladimir Kondratiev } 2372be7d22fSVladimir Kondratiev } 2382be7d22fSVladimir Kondratiev out: 2398fe59627SVladimir Kondratiev seq_puts(s, "}\n"); 240349214c1SMaya Erez wil_halp_unvote(wil); 2412be7d22fSVladimir Kondratiev } 2422be7d22fSVladimir Kondratiev 2432be7d22fSVladimir Kondratiev static int wil_mbox_debugfs_show(struct seq_file *s, void *data) 2442be7d22fSVladimir Kondratiev { 2452be7d22fSVladimir Kondratiev struct wil6210_priv *wil = s->private; 24694162666SLazar Alexei int ret; 24794162666SLazar Alexei 24894162666SLazar Alexei ret = wil_pm_runtime_get(wil); 24994162666SLazar Alexei if (ret < 0) 25094162666SLazar Alexei return ret; 2512be7d22fSVladimir Kondratiev 2522be7d22fSVladimir Kondratiev wil_print_ring(s, "tx", wil->csr + HOST_MBOX + 2532be7d22fSVladimir Kondratiev offsetof(struct wil6210_mbox_ctl, tx)); 2542be7d22fSVladimir Kondratiev wil_print_ring(s, "rx", wil->csr + HOST_MBOX + 2552be7d22fSVladimir Kondratiev offsetof(struct wil6210_mbox_ctl, rx)); 2562be7d22fSVladimir Kondratiev 25794162666SLazar Alexei wil_pm_runtime_put(wil); 25894162666SLazar Alexei 2592be7d22fSVladimir Kondratiev return 0; 2602be7d22fSVladimir Kondratiev } 2612be7d22fSVladimir Kondratiev 2622be7d22fSVladimir Kondratiev static int wil_mbox_seq_open(struct inode *inode, struct file *file) 2632be7d22fSVladimir Kondratiev { 2642be7d22fSVladimir Kondratiev return single_open(file, wil_mbox_debugfs_show, inode->i_private); 2652be7d22fSVladimir Kondratiev } 2662be7d22fSVladimir Kondratiev 2672be7d22fSVladimir Kondratiev static const struct file_operations fops_mbox = { 2682be7d22fSVladimir Kondratiev .open = wil_mbox_seq_open, 2692be7d22fSVladimir Kondratiev .release = single_release, 2702be7d22fSVladimir Kondratiev .read = seq_read, 2712be7d22fSVladimir Kondratiev .llseek = seq_lseek, 2722be7d22fSVladimir Kondratiev }; 2732be7d22fSVladimir Kondratiev 2742be7d22fSVladimir Kondratiev static int wil_debugfs_iomem_x32_set(void *data, u64 val) 2752be7d22fSVladimir Kondratiev { 27694162666SLazar Alexei struct wil_debugfs_iomem_data *d = (struct 27794162666SLazar Alexei wil_debugfs_iomem_data *)data; 27894162666SLazar Alexei struct wil6210_priv *wil = d->wil; 27994162666SLazar Alexei int ret; 28094162666SLazar Alexei 28194162666SLazar Alexei ret = wil_pm_runtime_get(wil); 28294162666SLazar Alexei if (ret < 0) 28394162666SLazar Alexei return ret; 28494162666SLazar Alexei 28594162666SLazar Alexei writel(val, (void __iomem *)d->offset); 2862be7d22fSVladimir Kondratiev wmb(); /* make sure write propagated to HW */ 2872be7d22fSVladimir Kondratiev 28894162666SLazar Alexei wil_pm_runtime_put(wil); 28994162666SLazar Alexei 2902be7d22fSVladimir Kondratiev return 0; 2912be7d22fSVladimir Kondratiev } 2922be7d22fSVladimir Kondratiev 2932be7d22fSVladimir Kondratiev static int wil_debugfs_iomem_x32_get(void *data, u64 *val) 2942be7d22fSVladimir Kondratiev { 29594162666SLazar Alexei struct wil_debugfs_iomem_data *d = (struct 29694162666SLazar Alexei wil_debugfs_iomem_data *)data; 29794162666SLazar Alexei struct wil6210_priv *wil = d->wil; 29894162666SLazar Alexei int ret; 29994162666SLazar Alexei 30094162666SLazar Alexei ret = wil_pm_runtime_get(wil); 30194162666SLazar Alexei if (ret < 0) 30294162666SLazar Alexei return ret; 30394162666SLazar Alexei 30494162666SLazar Alexei *val = readl((void __iomem *)d->offset); 30594162666SLazar Alexei 30694162666SLazar Alexei wil_pm_runtime_put(wil); 3072be7d22fSVladimir Kondratiev 3082be7d22fSVladimir Kondratiev return 0; 3092be7d22fSVladimir Kondratiev } 3102be7d22fSVladimir Kondratiev 3112be7d22fSVladimir Kondratiev DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, 3122be7d22fSVladimir Kondratiev wil_debugfs_iomem_x32_set, "0x%08llx\n"); 3132be7d22fSVladimir Kondratiev 3142be7d22fSVladimir Kondratiev static struct dentry *wil_debugfs_create_iomem_x32(const char *name, 3150ecc833bSAl Viro umode_t mode, 3162be7d22fSVladimir Kondratiev struct dentry *parent, 31794162666SLazar Alexei void *value, 31894162666SLazar Alexei struct wil6210_priv *wil) 3192be7d22fSVladimir Kondratiev { 32094162666SLazar Alexei struct dentry *file; 32194162666SLazar Alexei struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[ 32294162666SLazar Alexei wil->dbg_data.iomem_data_count]; 32394162666SLazar Alexei 32494162666SLazar Alexei data->wil = wil; 32594162666SLazar Alexei data->offset = value; 32694162666SLazar Alexei 32794162666SLazar Alexei file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32); 32894162666SLazar Alexei if (!IS_ERR_OR_NULL(file)) 32994162666SLazar Alexei wil->dbg_data.iomem_data_count++; 33094162666SLazar Alexei 33194162666SLazar Alexei return file; 3322be7d22fSVladimir Kondratiev } 3332be7d22fSVladimir Kondratiev 3343de6cf20SVladimir Kondratiev static int wil_debugfs_ulong_set(void *data, u64 val) 3353de6cf20SVladimir Kondratiev { 3363de6cf20SVladimir Kondratiev *(ulong *)data = val; 3373de6cf20SVladimir Kondratiev return 0; 3383de6cf20SVladimir Kondratiev } 3398fe59627SVladimir Kondratiev 3403de6cf20SVladimir Kondratiev static int wil_debugfs_ulong_get(void *data, u64 *val) 3413de6cf20SVladimir Kondratiev { 3423de6cf20SVladimir Kondratiev *val = *(ulong *)data; 3433de6cf20SVladimir Kondratiev return 0; 3443de6cf20SVladimir Kondratiev } 3458fe59627SVladimir Kondratiev 3463de6cf20SVladimir Kondratiev DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, 3478ea06188SVladimir Kondratiev wil_debugfs_ulong_set, "0x%llx\n"); 3483de6cf20SVladimir Kondratiev 3493de6cf20SVladimir Kondratiev static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, 3503de6cf20SVladimir Kondratiev struct dentry *parent, 3513de6cf20SVladimir Kondratiev ulong *value) 3523de6cf20SVladimir Kondratiev { 3533de6cf20SVladimir Kondratiev return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong); 3543de6cf20SVladimir Kondratiev } 3553de6cf20SVladimir Kondratiev 356b7cde470SVladimir Kondratiev /** 357b7cde470SVladimir Kondratiev * wil6210_debugfs_init_offset - create set of debugfs files 358b7cde470SVladimir Kondratiev * @wil - driver's context, used for printing 359b7cde470SVladimir Kondratiev * @dbg - directory on the debugfs, where files will be created 360b7cde470SVladimir Kondratiev * @base - base address used in address calculation 361b7cde470SVladimir Kondratiev * @tbl - table with file descriptions. Should be terminated with empty element. 362b7cde470SVladimir Kondratiev * 363b7cde470SVladimir Kondratiev * Creates files accordingly to the @tbl. 364b7cde470SVladimir Kondratiev */ 365b7cde470SVladimir Kondratiev static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, 366b7cde470SVladimir Kondratiev struct dentry *dbg, void *base, 367b7cde470SVladimir Kondratiev const struct dbg_off * const tbl) 368b7cde470SVladimir Kondratiev { 369b7cde470SVladimir Kondratiev int i; 370b7cde470SVladimir Kondratiev 371b7cde470SVladimir Kondratiev for (i = 0; tbl[i].name; i++) { 372867fa0d4SVladimir Kondratiev struct dentry *f; 373b7cde470SVladimir Kondratiev 374b7cde470SVladimir Kondratiev switch (tbl[i].type) { 375b7cde470SVladimir Kondratiev case doff_u32: 376b7cde470SVladimir Kondratiev f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, 377b7cde470SVladimir Kondratiev base + tbl[i].off); 378b7cde470SVladimir Kondratiev break; 379b7cde470SVladimir Kondratiev case doff_x32: 380b7cde470SVladimir Kondratiev f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, 381b7cde470SVladimir Kondratiev base + tbl[i].off); 382b7cde470SVladimir Kondratiev break; 383b7cde470SVladimir Kondratiev case doff_ulong: 384b7cde470SVladimir Kondratiev f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode, 385b7cde470SVladimir Kondratiev dbg, base + tbl[i].off); 386b7cde470SVladimir Kondratiev break; 387b7cde470SVladimir Kondratiev case doff_io32: 388b7cde470SVladimir Kondratiev f = wil_debugfs_create_iomem_x32(tbl[i].name, 389b7cde470SVladimir Kondratiev tbl[i].mode, dbg, 39094162666SLazar Alexei base + tbl[i].off, 39194162666SLazar Alexei wil); 392b7cde470SVladimir Kondratiev break; 39374997a53SLior David case doff_u8: 39474997a53SLior David f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, 39574997a53SLior David base + tbl[i].off); 39674997a53SLior David break; 397867fa0d4SVladimir Kondratiev default: 398867fa0d4SVladimir Kondratiev f = ERR_PTR(-EINVAL); 399b7cde470SVladimir Kondratiev } 400b7cde470SVladimir Kondratiev if (IS_ERR_OR_NULL(f)) 401b7cde470SVladimir Kondratiev wil_err(wil, "Create file \"%s\": err %ld\n", 402b7cde470SVladimir Kondratiev tbl[i].name, PTR_ERR(f)); 403b7cde470SVladimir Kondratiev } 404b7cde470SVladimir Kondratiev } 405b7cde470SVladimir Kondratiev 406b7cde470SVladimir Kondratiev static const struct dbg_off isr_off[] = { 40778484c44SMaya Erez {"ICC", 0644, offsetof(struct RGF_ICR, ICC), doff_io32}, 40878484c44SMaya Erez {"ICR", 0644, offsetof(struct RGF_ICR, ICR), doff_io32}, 40978484c44SMaya Erez {"ICM", 0644, offsetof(struct RGF_ICR, ICM), doff_io32}, 41078484c44SMaya Erez {"ICS", 0244, offsetof(struct RGF_ICR, ICS), doff_io32}, 41178484c44SMaya Erez {"IMV", 0644, offsetof(struct RGF_ICR, IMV), doff_io32}, 41278484c44SMaya Erez {"IMS", 0244, offsetof(struct RGF_ICR, IMS), doff_io32}, 41378484c44SMaya Erez {"IMC", 0244, offsetof(struct RGF_ICR, IMC), doff_io32}, 414b7cde470SVladimir Kondratiev {}, 415b7cde470SVladimir Kondratiev }; 4168fe59627SVladimir Kondratiev 4172be7d22fSVladimir Kondratiev static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, 4182be7d22fSVladimir Kondratiev const char *name, 4192be7d22fSVladimir Kondratiev struct dentry *parent, u32 off) 4202be7d22fSVladimir Kondratiev { 4212be7d22fSVladimir Kondratiev struct dentry *d = debugfs_create_dir(name, parent); 4222be7d22fSVladimir Kondratiev 4232be7d22fSVladimir Kondratiev if (IS_ERR_OR_NULL(d)) 4242be7d22fSVladimir Kondratiev return -ENODEV; 4252be7d22fSVladimir Kondratiev 426b7cde470SVladimir Kondratiev wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off, 427b7cde470SVladimir Kondratiev isr_off); 4282be7d22fSVladimir Kondratiev 4292be7d22fSVladimir Kondratiev return 0; 4302be7d22fSVladimir Kondratiev } 4312be7d22fSVladimir Kondratiev 432b7cde470SVladimir Kondratiev static const struct dbg_off pseudo_isr_off[] = { 43378484c44SMaya Erez {"CAUSE", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32}, 43478484c44SMaya Erez {"MASK_SW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32}, 43578484c44SMaya Erez {"MASK_FW", 0444, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32}, 436b7cde470SVladimir Kondratiev {}, 437b7cde470SVladimir Kondratiev }; 438b7cde470SVladimir Kondratiev 4392be7d22fSVladimir Kondratiev static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, 4402be7d22fSVladimir Kondratiev struct dentry *parent) 4412be7d22fSVladimir Kondratiev { 4422be7d22fSVladimir Kondratiev struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); 4432be7d22fSVladimir Kondratiev 4442be7d22fSVladimir Kondratiev if (IS_ERR_OR_NULL(d)) 4452be7d22fSVladimir Kondratiev return -ENODEV; 4462be7d22fSVladimir Kondratiev 447b7cde470SVladimir Kondratiev wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, 448b7cde470SVladimir Kondratiev pseudo_isr_off); 4492be7d22fSVladimir Kondratiev 4502be7d22fSVladimir Kondratiev return 0; 4512be7d22fSVladimir Kondratiev } 4522be7d22fSVladimir Kondratiev 45378366f69SVladimir Kondratiev static const struct dbg_off lgc_itr_cnt_off[] = { 45478484c44SMaya Erez {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32}, 45578484c44SMaya Erez {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32}, 45678484c44SMaya Erez {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32}, 457b7cde470SVladimir Kondratiev {}, 458b7cde470SVladimir Kondratiev }; 459b7cde470SVladimir Kondratiev 46078366f69SVladimir Kondratiev static const struct dbg_off tx_itr_cnt_off[] = { 46178484c44SMaya Erez {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH), 46278366f69SVladimir Kondratiev doff_io32}, 46378484c44SMaya Erez {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA), 46478366f69SVladimir Kondratiev doff_io32}, 46578484c44SMaya Erez {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL), 46678366f69SVladimir Kondratiev doff_io32}, 46778484c44SMaya Erez {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH), 46878366f69SVladimir Kondratiev doff_io32}, 46978484c44SMaya Erez {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA), 47078366f69SVladimir Kondratiev doff_io32}, 47178484c44SMaya Erez {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL), 47278366f69SVladimir Kondratiev doff_io32}, 47378366f69SVladimir Kondratiev {}, 47478366f69SVladimir Kondratiev }; 47578366f69SVladimir Kondratiev 47678366f69SVladimir Kondratiev static const struct dbg_off rx_itr_cnt_off[] = { 47778484c44SMaya Erez {"TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH), 47878366f69SVladimir Kondratiev doff_io32}, 47978484c44SMaya Erez {"DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA), 48078366f69SVladimir Kondratiev doff_io32}, 48178484c44SMaya Erez {"CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL), 48278366f69SVladimir Kondratiev doff_io32}, 48378484c44SMaya Erez {"IDL_TRSH", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH), 48478366f69SVladimir Kondratiev doff_io32}, 48578484c44SMaya Erez {"IDL_DATA", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA), 48678366f69SVladimir Kondratiev doff_io32}, 48778484c44SMaya Erez {"IDL_CTL", 0644, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL), 48878366f69SVladimir Kondratiev doff_io32}, 48978366f69SVladimir Kondratiev {}, 49078366f69SVladimir Kondratiev }; 49178366f69SVladimir Kondratiev 4922be7d22fSVladimir Kondratiev static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, 4932be7d22fSVladimir Kondratiev struct dentry *parent) 4942be7d22fSVladimir Kondratiev { 49578366f69SVladimir Kondratiev struct dentry *d, *dtx, *drx; 4962be7d22fSVladimir Kondratiev 49778366f69SVladimir Kondratiev d = debugfs_create_dir("ITR_CNT", parent); 4982be7d22fSVladimir Kondratiev if (IS_ERR_OR_NULL(d)) 4992be7d22fSVladimir Kondratiev return -ENODEV; 5002be7d22fSVladimir Kondratiev 50178366f69SVladimir Kondratiev dtx = debugfs_create_dir("TX", d); 50278366f69SVladimir Kondratiev drx = debugfs_create_dir("RX", d); 50378366f69SVladimir Kondratiev if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx)) 50478366f69SVladimir Kondratiev return -ENODEV; 5052be7d22fSVladimir Kondratiev 50678366f69SVladimir Kondratiev wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, 50778366f69SVladimir Kondratiev lgc_itr_cnt_off); 50878366f69SVladimir Kondratiev 50978366f69SVladimir Kondratiev wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr, 51078366f69SVladimir Kondratiev tx_itr_cnt_off); 51178366f69SVladimir Kondratiev 51278366f69SVladimir Kondratiev wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr, 51378366f69SVladimir Kondratiev rx_itr_cnt_off); 5142be7d22fSVladimir Kondratiev return 0; 5152be7d22fSVladimir Kondratiev } 5162be7d22fSVladimir Kondratiev 5172be7d22fSVladimir Kondratiev static int wil_memread_debugfs_show(struct seq_file *s, void *data) 5182be7d22fSVladimir Kondratiev { 5192be7d22fSVladimir Kondratiev struct wil6210_priv *wil = s->private; 52094162666SLazar Alexei void __iomem *a; 52194162666SLazar Alexei int ret; 52294162666SLazar Alexei 52394162666SLazar Alexei ret = wil_pm_runtime_get(wil); 52494162666SLazar Alexei if (ret < 0) 52594162666SLazar Alexei return ret; 52694162666SLazar Alexei 52794162666SLazar Alexei a = wmi_buffer(wil, cpu_to_le32(mem_addr)); 5282be7d22fSVladimir Kondratiev 5292be7d22fSVladimir Kondratiev if (a) 530b9eeb512SVladimir Kondratiev seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a)); 5312be7d22fSVladimir Kondratiev else 5322be7d22fSVladimir Kondratiev seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); 5332be7d22fSVladimir Kondratiev 53494162666SLazar Alexei wil_pm_runtime_put(wil); 53594162666SLazar Alexei 5362be7d22fSVladimir Kondratiev return 0; 5372be7d22fSVladimir Kondratiev } 5382be7d22fSVladimir Kondratiev 5392be7d22fSVladimir Kondratiev static int wil_memread_seq_open(struct inode *inode, struct file *file) 5402be7d22fSVladimir Kondratiev { 5412be7d22fSVladimir Kondratiev return single_open(file, wil_memread_debugfs_show, inode->i_private); 5422be7d22fSVladimir Kondratiev } 5432be7d22fSVladimir Kondratiev 5442be7d22fSVladimir Kondratiev static const struct file_operations fops_memread = { 5452be7d22fSVladimir Kondratiev .open = wil_memread_seq_open, 5462be7d22fSVladimir Kondratiev .release = single_release, 5472be7d22fSVladimir Kondratiev .read = seq_read, 5482be7d22fSVladimir Kondratiev .llseek = seq_lseek, 5492be7d22fSVladimir Kondratiev }; 5502be7d22fSVladimir Kondratiev 5512be7d22fSVladimir Kondratiev static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, 5522be7d22fSVladimir Kondratiev size_t count, loff_t *ppos) 5532be7d22fSVladimir Kondratiev { 5542be7d22fSVladimir Kondratiev enum { max_count = 4096 }; 555349214c1SMaya Erez struct wil_blob_wrapper *wil_blob = file->private_data; 55694162666SLazar Alexei struct wil6210_priv *wil = wil_blob->wil; 5572be7d22fSVladimir Kondratiev loff_t pos = *ppos; 558349214c1SMaya Erez size_t available = wil_blob->blob.size; 5592be7d22fSVladimir Kondratiev void *buf; 5602be7d22fSVladimir Kondratiev size_t ret; 56194162666SLazar Alexei int rc; 5622be7d22fSVladimir Kondratiev 563fe9ee51eSMaya Erez if (test_bit(wil_status_suspending, wil_blob->wil->status) || 564fe9ee51eSMaya Erez test_bit(wil_status_suspended, wil_blob->wil->status)) 565fe9ee51eSMaya Erez return 0; 566fe9ee51eSMaya Erez 5672be7d22fSVladimir Kondratiev if (pos < 0) 5682be7d22fSVladimir Kondratiev return -EINVAL; 5692be7d22fSVladimir Kondratiev 5702be7d22fSVladimir Kondratiev if (pos >= available || !count) 5712be7d22fSVladimir Kondratiev return 0; 5722be7d22fSVladimir Kondratiev 5732be7d22fSVladimir Kondratiev if (count > available - pos) 5742be7d22fSVladimir Kondratiev count = available - pos; 5752be7d22fSVladimir Kondratiev if (count > max_count) 5762be7d22fSVladimir Kondratiev count = max_count; 5772be7d22fSVladimir Kondratiev 5782be7d22fSVladimir Kondratiev buf = kmalloc(count, GFP_KERNEL); 5792be7d22fSVladimir Kondratiev if (!buf) 5802be7d22fSVladimir Kondratiev return -ENOMEM; 5812be7d22fSVladimir Kondratiev 58294162666SLazar Alexei rc = wil_pm_runtime_get(wil); 58394162666SLazar Alexei if (rc < 0) { 58494162666SLazar Alexei kfree(buf); 58594162666SLazar Alexei return rc; 58694162666SLazar Alexei } 58794162666SLazar Alexei 588bd50e268SMaya Erez wil_memcpy_fromio_32(buf, (const void __iomem *) 589349214c1SMaya Erez wil_blob->blob.data + pos, count); 5902be7d22fSVladimir Kondratiev 5912be7d22fSVladimir Kondratiev ret = copy_to_user(user_buf, buf, count); 59294162666SLazar Alexei 59394162666SLazar Alexei wil_pm_runtime_put(wil); 59494162666SLazar Alexei 5952be7d22fSVladimir Kondratiev kfree(buf); 5962be7d22fSVladimir Kondratiev if (ret == count) 5972be7d22fSVladimir Kondratiev return -EFAULT; 5982be7d22fSVladimir Kondratiev 5992be7d22fSVladimir Kondratiev count -= ret; 6002be7d22fSVladimir Kondratiev *ppos = pos + count; 6012be7d22fSVladimir Kondratiev 6022be7d22fSVladimir Kondratiev return count; 6032be7d22fSVladimir Kondratiev } 6042be7d22fSVladimir Kondratiev 6052be7d22fSVladimir Kondratiev static const struct file_operations fops_ioblob = { 6062be7d22fSVladimir Kondratiev .read = wil_read_file_ioblob, 60793ecbd64SWei Yongjun .open = simple_open, 6082be7d22fSVladimir Kondratiev .llseek = default_llseek, 6092be7d22fSVladimir Kondratiev }; 6102be7d22fSVladimir Kondratiev 6112be7d22fSVladimir Kondratiev static 6122be7d22fSVladimir Kondratiev struct dentry *wil_debugfs_create_ioblob(const char *name, 6130ecc833bSAl Viro umode_t mode, 6142be7d22fSVladimir Kondratiev struct dentry *parent, 615349214c1SMaya Erez struct wil_blob_wrapper *wil_blob) 6162be7d22fSVladimir Kondratiev { 617349214c1SMaya Erez return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob); 6182be7d22fSVladimir Kondratiev } 6198fe59627SVladimir Kondratiev 6202be7d22fSVladimir Kondratiev /*---reset---*/ 6212be7d22fSVladimir Kondratiev static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, 6222be7d22fSVladimir Kondratiev size_t len, loff_t *ppos) 6232be7d22fSVladimir Kondratiev { 6242be7d22fSVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 625e00243faSLior David struct net_device *ndev = wil->main_ndev; 6262be7d22fSVladimir Kondratiev 6272be7d22fSVladimir Kondratiev /** 6282be7d22fSVladimir Kondratiev * BUG: 6292be7d22fSVladimir Kondratiev * this code does NOT sync device state with the rest of system 6302be7d22fSVladimir Kondratiev * use with care, debug only!!! 6312be7d22fSVladimir Kondratiev */ 6322be7d22fSVladimir Kondratiev rtnl_lock(); 6332be7d22fSVladimir Kondratiev dev_close(ndev); 6342be7d22fSVladimir Kondratiev ndev->flags &= ~IFF_UP; 6352be7d22fSVladimir Kondratiev rtnl_unlock(); 6362cd0f021SVladimir Kondratiev wil_reset(wil, true); 6372be7d22fSVladimir Kondratiev 6382be7d22fSVladimir Kondratiev return len; 6392be7d22fSVladimir Kondratiev } 6402be7d22fSVladimir Kondratiev 6412be7d22fSVladimir Kondratiev static const struct file_operations fops_reset = { 6422be7d22fSVladimir Kondratiev .write = wil_write_file_reset, 64393ecbd64SWei Yongjun .open = simple_open, 6442be7d22fSVladimir Kondratiev }; 6458fe59627SVladimir Kondratiev 6460b39aaf2SVladimir Kondratiev /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ 6470b39aaf2SVladimir Kondratiev static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, 6480b39aaf2SVladimir Kondratiev size_t len, loff_t *ppos) 6490b39aaf2SVladimir Kondratiev { 6500b39aaf2SVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 6510b39aaf2SVladimir Kondratiev int rc; 6520b39aaf2SVladimir Kondratiev long channel; 6530b39aaf2SVladimir Kondratiev bool on; 6540b39aaf2SVladimir Kondratiev 65516e5c1fcSAl Viro char *kbuf = memdup_user_nul(buf, len); 6568fe59627SVladimir Kondratiev 65716e5c1fcSAl Viro if (IS_ERR(kbuf)) 65816e5c1fcSAl Viro return PTR_ERR(kbuf); 6590b39aaf2SVladimir Kondratiev rc = kstrtol(kbuf, 0, &channel); 6600b39aaf2SVladimir Kondratiev kfree(kbuf); 6610b39aaf2SVladimir Kondratiev if (rc) 6620b39aaf2SVladimir Kondratiev return rc; 6630b39aaf2SVladimir Kondratiev 6640b39aaf2SVladimir Kondratiev if ((channel < 0) || (channel > 4)) { 6650b39aaf2SVladimir Kondratiev wil_err(wil, "Invalid channel %ld\n", channel); 6660b39aaf2SVladimir Kondratiev return -EINVAL; 6670b39aaf2SVladimir Kondratiev } 6680b39aaf2SVladimir Kondratiev on = !!channel; 6690b39aaf2SVladimir Kondratiev 6700b39aaf2SVladimir Kondratiev if (on) { 6710b39aaf2SVladimir Kondratiev rc = wmi_set_channel(wil, (int)channel); 6720b39aaf2SVladimir Kondratiev if (rc) 6730b39aaf2SVladimir Kondratiev return rc; 6740b39aaf2SVladimir Kondratiev } 6750b39aaf2SVladimir Kondratiev 6760b39aaf2SVladimir Kondratiev rc = wmi_rxon(wil, on); 6770b39aaf2SVladimir Kondratiev if (rc) 6780b39aaf2SVladimir Kondratiev return rc; 6790b39aaf2SVladimir Kondratiev 6800b39aaf2SVladimir Kondratiev return len; 6810b39aaf2SVladimir Kondratiev } 6820b39aaf2SVladimir Kondratiev 6830b39aaf2SVladimir Kondratiev static const struct file_operations fops_rxon = { 6840b39aaf2SVladimir Kondratiev .write = wil_write_file_rxon, 6850b39aaf2SVladimir Kondratiev .open = simple_open, 6860b39aaf2SVladimir Kondratiev }; 6878fe59627SVladimir Kondratiev 68849cb5dfbSVladimir Kondratiev /* block ack control, write: 68949cb5dfbSVladimir Kondratiev * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA 69049cb5dfbSVladimir Kondratiev * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side 69149cb5dfbSVladimir Kondratiev * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side 6923277213fSVladimir Kondratiev */ 69349cb5dfbSVladimir Kondratiev static ssize_t wil_write_back(struct file *file, const char __user *buf, 6943277213fSVladimir Kondratiev size_t len, loff_t *ppos) 6953277213fSVladimir Kondratiev { 6963277213fSVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 6973277213fSVladimir Kondratiev int rc; 6983277213fSVladimir Kondratiev char *kbuf = kmalloc(len + 1, GFP_KERNEL); 6992a19f776SColin Ian King char cmd[9]; 70049cb5dfbSVladimir Kondratiev int p1, p2, p3; 7013277213fSVladimir Kondratiev 7023277213fSVladimir Kondratiev if (!kbuf) 7033277213fSVladimir Kondratiev return -ENOMEM; 7043277213fSVladimir Kondratiev 7053277213fSVladimir Kondratiev rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 7063277213fSVladimir Kondratiev if (rc != len) { 7073277213fSVladimir Kondratiev kfree(kbuf); 7083277213fSVladimir Kondratiev return rc >= 0 ? -EIO : rc; 7093277213fSVladimir Kondratiev } 7103277213fSVladimir Kondratiev 7113277213fSVladimir Kondratiev kbuf[len] = '\0'; 71249cb5dfbSVladimir Kondratiev rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3); 7133277213fSVladimir Kondratiev kfree(kbuf); 7143277213fSVladimir Kondratiev 71549cb5dfbSVladimir Kondratiev if (rc < 0) 7163277213fSVladimir Kondratiev return rc; 71749cb5dfbSVladimir Kondratiev if (rc < 2) 7183277213fSVladimir Kondratiev return -EINVAL; 7193277213fSVladimir Kondratiev 720e00243faSLior David if ((strcmp(cmd, "add") == 0) || 721e00243faSLior David (strcmp(cmd, "del_tx") == 0)) { 722e00243faSLior David struct vring_tx_data *txdata; 723e00243faSLior David 724e00243faSLior David if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) { 725e00243faSLior David wil_err(wil, "BACK: invalid ring id %d\n", p1); 726e00243faSLior David return -EINVAL; 727e00243faSLior David } 728e00243faSLior David txdata = &wil->vring_tx_data[p1]; 729e00243faSLior David if (strcmp(cmd, "add") == 0) { 73049cb5dfbSVladimir Kondratiev if (rc < 3) { 73149cb5dfbSVladimir Kondratiev wil_err(wil, "BACK: add require at least 2 params\n"); 73249cb5dfbSVladimir Kondratiev return -EINVAL; 73349cb5dfbSVladimir Kondratiev } 73449cb5dfbSVladimir Kondratiev if (rc < 4) 73549cb5dfbSVladimir Kondratiev p3 = 0; 736e00243faSLior David wmi_addba(wil, txdata->mid, p1, p2, p3); 737e00243faSLior David } else { 73849cb5dfbSVladimir Kondratiev if (rc < 3) 73949cb5dfbSVladimir Kondratiev p2 = WLAN_REASON_QSTA_LEAVE_QBSS; 740e00243faSLior David wmi_delba_tx(wil, txdata->mid, p1, p2); 741e00243faSLior David } 742e00243faSLior David } else if (strcmp(cmd, "del_rx") == 0) { 743e00243faSLior David struct wil_sta_info *sta; 744e00243faSLior David 74549cb5dfbSVladimir Kondratiev if (rc < 3) { 74649cb5dfbSVladimir Kondratiev wil_err(wil, 74749cb5dfbSVladimir Kondratiev "BACK: del_rx require at least 2 params\n"); 74849cb5dfbSVladimir Kondratiev return -EINVAL; 74949cb5dfbSVladimir Kondratiev } 750e00243faSLior David if (p1 < 0 || p1 >= WIL6210_MAX_CID) { 751e00243faSLior David wil_err(wil, "BACK: invalid CID %d\n", p1); 752e00243faSLior David return -EINVAL; 753e00243faSLior David } 75449cb5dfbSVladimir Kondratiev if (rc < 4) 75549cb5dfbSVladimir Kondratiev p3 = WLAN_REASON_QSTA_LEAVE_QBSS; 756e00243faSLior David sta = &wil->sta[p1]; 757e00243faSLior David wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3); 75849cb5dfbSVladimir Kondratiev } else { 75949cb5dfbSVladimir Kondratiev wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); 76049cb5dfbSVladimir Kondratiev return -EINVAL; 76149cb5dfbSVladimir Kondratiev } 7623277213fSVladimir Kondratiev 7633277213fSVladimir Kondratiev return len; 7643277213fSVladimir Kondratiev } 7653277213fSVladimir Kondratiev 76649cb5dfbSVladimir Kondratiev static ssize_t wil_read_back(struct file *file, char __user *user_buf, 76749cb5dfbSVladimir Kondratiev size_t count, loff_t *ppos) 76849cb5dfbSVladimir Kondratiev { 76949cb5dfbSVladimir Kondratiev static const char text[] = "block ack control, write:\n" 77049cb5dfbSVladimir Kondratiev " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n" 77149cb5dfbSVladimir Kondratiev "If missing, <timeout> defaults to 0\n" 77249cb5dfbSVladimir Kondratiev " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n" 77349cb5dfbSVladimir Kondratiev " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n" 77449cb5dfbSVladimir Kondratiev "If missing, <reason> set to \"STA_LEAVING\" (36)\n"; 77549cb5dfbSVladimir Kondratiev 77649cb5dfbSVladimir Kondratiev return simple_read_from_buffer(user_buf, count, ppos, text, 77749cb5dfbSVladimir Kondratiev sizeof(text)); 77849cb5dfbSVladimir Kondratiev } 77949cb5dfbSVladimir Kondratiev 78049cb5dfbSVladimir Kondratiev static const struct file_operations fops_back = { 78149cb5dfbSVladimir Kondratiev .read = wil_read_back, 78249cb5dfbSVladimir Kondratiev .write = wil_write_back, 7833277213fSVladimir Kondratiev .open = simple_open, 7843277213fSVladimir Kondratiev }; 7853277213fSVladimir Kondratiev 786dc16427bSVladimir Kondratiev /* pmc control, write: 787dc16427bSVladimir Kondratiev * - "alloc <num descriptors> <descriptor_size>" to allocate PMC 788dc16427bSVladimir Kondratiev * - "free" to release memory allocated for PMC 789dc16427bSVladimir Kondratiev */ 790dc16427bSVladimir Kondratiev static ssize_t wil_write_pmccfg(struct file *file, const char __user *buf, 791dc16427bSVladimir Kondratiev size_t len, loff_t *ppos) 792dc16427bSVladimir Kondratiev { 793dc16427bSVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 794dc16427bSVladimir Kondratiev int rc; 795dc16427bSVladimir Kondratiev char *kbuf = kmalloc(len + 1, GFP_KERNEL); 796dc16427bSVladimir Kondratiev char cmd[9]; 797dc16427bSVladimir Kondratiev int num_descs, desc_size; 798dc16427bSVladimir Kondratiev 799dc16427bSVladimir Kondratiev if (!kbuf) 800dc16427bSVladimir Kondratiev return -ENOMEM; 801dc16427bSVladimir Kondratiev 802dc16427bSVladimir Kondratiev rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 803dc16427bSVladimir Kondratiev if (rc != len) { 804dc16427bSVladimir Kondratiev kfree(kbuf); 805dc16427bSVladimir Kondratiev return rc >= 0 ? -EIO : rc; 806dc16427bSVladimir Kondratiev } 807dc16427bSVladimir Kondratiev 808dc16427bSVladimir Kondratiev kbuf[len] = '\0'; 809dc16427bSVladimir Kondratiev rc = sscanf(kbuf, "%8s %d %d", cmd, &num_descs, &desc_size); 810dc16427bSVladimir Kondratiev kfree(kbuf); 811dc16427bSVladimir Kondratiev 812dc16427bSVladimir Kondratiev if (rc < 0) 813dc16427bSVladimir Kondratiev return rc; 814dc16427bSVladimir Kondratiev 815dc16427bSVladimir Kondratiev if (rc < 1) { 816dc16427bSVladimir Kondratiev wil_err(wil, "pmccfg: no params given\n"); 817dc16427bSVladimir Kondratiev return -EINVAL; 818dc16427bSVladimir Kondratiev } 819dc16427bSVladimir Kondratiev 820dc16427bSVladimir Kondratiev if (0 == strcmp(cmd, "alloc")) { 821dc16427bSVladimir Kondratiev if (rc != 3) { 822dc16427bSVladimir Kondratiev wil_err(wil, "pmccfg: alloc requires 2 params\n"); 823dc16427bSVladimir Kondratiev return -EINVAL; 824dc16427bSVladimir Kondratiev } 825dc16427bSVladimir Kondratiev wil_pmc_alloc(wil, num_descs, desc_size); 826dc16427bSVladimir Kondratiev } else if (0 == strcmp(cmd, "free")) { 827dc16427bSVladimir Kondratiev if (rc != 1) { 828dc16427bSVladimir Kondratiev wil_err(wil, "pmccfg: free does not have any params\n"); 829dc16427bSVladimir Kondratiev return -EINVAL; 830dc16427bSVladimir Kondratiev } 831dc16427bSVladimir Kondratiev wil_pmc_free(wil, true); 832dc16427bSVladimir Kondratiev } else { 833dc16427bSVladimir Kondratiev wil_err(wil, "pmccfg: Unrecognized command \"%s\"\n", cmd); 834dc16427bSVladimir Kondratiev return -EINVAL; 835dc16427bSVladimir Kondratiev } 836dc16427bSVladimir Kondratiev 837dc16427bSVladimir Kondratiev return len; 838dc16427bSVladimir Kondratiev } 839dc16427bSVladimir Kondratiev 840dc16427bSVladimir Kondratiev static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf, 841dc16427bSVladimir Kondratiev size_t count, loff_t *ppos) 842dc16427bSVladimir Kondratiev { 843dc16427bSVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 844dc16427bSVladimir Kondratiev char text[256]; 845dc16427bSVladimir Kondratiev char help[] = "pmc control, write:\n" 846dc16427bSVladimir Kondratiev " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n" 847dc16427bSVladimir Kondratiev " - \"free\" to free memory allocated for pmc\n"; 848dc16427bSVladimir Kondratiev 849dc16427bSVladimir Kondratiev sprintf(text, "Last command status: %d\n\n%s", 850dc16427bSVladimir Kondratiev wil_pmc_last_cmd_status(wil), 851dc16427bSVladimir Kondratiev help); 852dc16427bSVladimir Kondratiev 853dc16427bSVladimir Kondratiev return simple_read_from_buffer(user_buf, count, ppos, text, 854dc16427bSVladimir Kondratiev strlen(text) + 1); 855dc16427bSVladimir Kondratiev } 856dc16427bSVladimir Kondratiev 857dc16427bSVladimir Kondratiev static const struct file_operations fops_pmccfg = { 858dc16427bSVladimir Kondratiev .read = wil_read_pmccfg, 859dc16427bSVladimir Kondratiev .write = wil_write_pmccfg, 860dc16427bSVladimir Kondratiev .open = simple_open, 861dc16427bSVladimir Kondratiev }; 862dc16427bSVladimir Kondratiev 863dc16427bSVladimir Kondratiev static const struct file_operations fops_pmcdata = { 864dc16427bSVladimir Kondratiev .open = simple_open, 865dc16427bSVladimir Kondratiev .read = wil_pmc_read, 866dc16427bSVladimir Kondratiev .llseek = wil_pmc_llseek, 867dc16427bSVladimir Kondratiev }; 868dc16427bSVladimir Kondratiev 8690b39aaf2SVladimir Kondratiev /*---tx_mgmt---*/ 8700b39aaf2SVladimir Kondratiev /* Write mgmt frame to this file to send it */ 8710b39aaf2SVladimir Kondratiev static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, 8720b39aaf2SVladimir Kondratiev size_t len, loff_t *ppos) 8730b39aaf2SVladimir Kondratiev { 8740b39aaf2SVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 8750b39aaf2SVladimir Kondratiev struct wiphy *wiphy = wil_to_wiphy(wil); 876e00243faSLior David struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; 8770b39aaf2SVladimir Kondratiev struct cfg80211_mgmt_tx_params params; 8780b39aaf2SVladimir Kondratiev int rc; 8799a492909SGeliang Tang void *frame; 8808fe59627SVladimir Kondratiev 8816641525cSHamad Kadmany if (!len) 8826641525cSHamad Kadmany return -EINVAL; 8836641525cSHamad Kadmany 8849a492909SGeliang Tang frame = memdup_user(buf, len); 8859a492909SGeliang Tang if (IS_ERR(frame)) 8869a492909SGeliang Tang return PTR_ERR(frame); 8870b39aaf2SVladimir Kondratiev 8880b39aaf2SVladimir Kondratiev params.buf = frame; 8890b39aaf2SVladimir Kondratiev params.len = len; 8900b39aaf2SVladimir Kondratiev 8910b39aaf2SVladimir Kondratiev rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); 8920b39aaf2SVladimir Kondratiev 8930b39aaf2SVladimir Kondratiev kfree(frame); 894af3db60aSLazar Alexei wil_info(wil, "-> %d\n", rc); 8950b39aaf2SVladimir Kondratiev 8960b39aaf2SVladimir Kondratiev return len; 8970b39aaf2SVladimir Kondratiev } 8980b39aaf2SVladimir Kondratiev 8990b39aaf2SVladimir Kondratiev static const struct file_operations fops_txmgmt = { 9000b39aaf2SVladimir Kondratiev .write = wil_write_file_txmgmt, 9010b39aaf2SVladimir Kondratiev .open = simple_open, 9020b39aaf2SVladimir Kondratiev }; 9032be7d22fSVladimir Kondratiev 904ff974e40SVladimir Kondratiev /* Write WMI command (w/o mbox header) to this file to send it 905ff974e40SVladimir Kondratiev * WMI starts from wil6210_mbox_hdr_wmi header 906ff974e40SVladimir Kondratiev */ 907ff974e40SVladimir Kondratiev static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, 908ff974e40SVladimir Kondratiev size_t len, loff_t *ppos) 909ff974e40SVladimir Kondratiev { 910ff974e40SVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 911e00243faSLior David struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 912b874ddecSLior David struct wmi_cmd_hdr *wmi; 913ff974e40SVladimir Kondratiev void *cmd; 914b874ddecSLior David int cmdlen = len - sizeof(struct wmi_cmd_hdr); 915ff974e40SVladimir Kondratiev u16 cmdid; 916ff974e40SVladimir Kondratiev int rc, rc1; 917ff974e40SVladimir Kondratiev 91869218a48SLior David if (cmdlen < 0) 919ff974e40SVladimir Kondratiev return -EINVAL; 920ff974e40SVladimir Kondratiev 921ff974e40SVladimir Kondratiev wmi = kmalloc(len, GFP_KERNEL); 922ff974e40SVladimir Kondratiev if (!wmi) 923ff974e40SVladimir Kondratiev return -ENOMEM; 924ff974e40SVladimir Kondratiev 925ff974e40SVladimir Kondratiev rc = simple_write_to_buffer(wmi, len, ppos, buf, len); 9268e09b7d2SLino Sanfilippo if (rc < 0) { 9278e09b7d2SLino Sanfilippo kfree(wmi); 928ff974e40SVladimir Kondratiev return rc; 9298e09b7d2SLino Sanfilippo } 930ff974e40SVladimir Kondratiev 93169218a48SLior David cmd = (cmdlen > 0) ? &wmi[1] : NULL; 932b874ddecSLior David cmdid = le16_to_cpu(wmi->command_id); 933ff974e40SVladimir Kondratiev 934e00243faSLior David rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen); 935ff974e40SVladimir Kondratiev kfree(wmi); 936ff974e40SVladimir Kondratiev 937af3db60aSLazar Alexei wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); 938ff974e40SVladimir Kondratiev 939ff974e40SVladimir Kondratiev return rc; 940ff974e40SVladimir Kondratiev } 941ff974e40SVladimir Kondratiev 942ff974e40SVladimir Kondratiev static const struct file_operations fops_wmi = { 943ff974e40SVladimir Kondratiev .write = wil_write_file_wmi, 944ff974e40SVladimir Kondratiev .open = simple_open, 945ff974e40SVladimir Kondratiev }; 946ff974e40SVladimir Kondratiev 947c236658fSVladimir Kondratiev static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) 948c236658fSVladimir Kondratiev { 949c236658fSVladimir Kondratiev int i = 0; 950c236658fSVladimir Kondratiev int len = skb_headlen(skb); 951c236658fSVladimir Kondratiev void *p = skb->data; 952c236658fSVladimir Kondratiev int nr_frags = skb_shinfo(skb)->nr_frags; 953c236658fSVladimir Kondratiev 954c236658fSVladimir Kondratiev seq_printf(s, " len = %d\n", len); 955c236658fSVladimir Kondratiev wil_seq_hexdump(s, p, len, " : "); 956c236658fSVladimir Kondratiev 957c236658fSVladimir Kondratiev if (nr_frags) { 958c236658fSVladimir Kondratiev seq_printf(s, " nr_frags = %d\n", nr_frags); 959c236658fSVladimir Kondratiev for (i = 0; i < nr_frags; i++) { 960c236658fSVladimir Kondratiev const struct skb_frag_struct *frag = 961c236658fSVladimir Kondratiev &skb_shinfo(skb)->frags[i]; 962c236658fSVladimir Kondratiev 963c236658fSVladimir Kondratiev len = skb_frag_size(frag); 964c236658fSVladimir Kondratiev p = skb_frag_address_safe(frag); 965c236658fSVladimir Kondratiev seq_printf(s, " [%2d] : len = %d\n", i, len); 966c236658fSVladimir Kondratiev wil_seq_hexdump(s, p, len, " : "); 967c236658fSVladimir Kondratiev } 968c236658fSVladimir Kondratiev } 969c236658fSVladimir Kondratiev } 970c236658fSVladimir Kondratiev 9713a85543eSVladimir Kondratiev /*---------Tx/Rx descriptor------------*/ 9722be7d22fSVladimir Kondratiev static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) 9732be7d22fSVladimir Kondratiev { 9742be7d22fSVladimir Kondratiev struct wil6210_priv *wil = s->private; 9753a85543eSVladimir Kondratiev struct vring *vring; 976af31cb5aSVladimir Kondratiev bool tx = (dbg_vring_index < WIL6210_MAX_TX_RINGS); 9778fe59627SVladimir Kondratiev 9788fe59627SVladimir Kondratiev vring = tx ? &wil->vring_tx[dbg_vring_index] : &wil->vring_rx; 9792be7d22fSVladimir Kondratiev 9802be7d22fSVladimir Kondratiev if (!vring->va) { 981af31cb5aSVladimir Kondratiev if (tx) 9823a85543eSVladimir Kondratiev seq_printf(s, "No Tx[%2d] VRING\n", dbg_vring_index); 9833a85543eSVladimir Kondratiev else 9843a85543eSVladimir Kondratiev seq_puts(s, "No Rx VRING\n"); 9852be7d22fSVladimir Kondratiev return 0; 9862be7d22fSVladimir Kondratiev } 9872be7d22fSVladimir Kondratiev 9882be7d22fSVladimir Kondratiev if (dbg_txdesc_index < vring->size) { 9893a85543eSVladimir Kondratiev /* use struct vring_tx_desc for Rx as well, 9903a85543eSVladimir Kondratiev * only field used, .dma.length, is the same 9913a85543eSVladimir Kondratiev */ 9922be7d22fSVladimir Kondratiev volatile struct vring_tx_desc *d = 9938fe59627SVladimir Kondratiev &vring->va[dbg_txdesc_index].tx; 9942be7d22fSVladimir Kondratiev volatile u32 *u = (volatile u32 *)d; 995f88f113aSVladimir Kondratiev struct sk_buff *skb = vring->ctx[dbg_txdesc_index].skb; 9962be7d22fSVladimir Kondratiev 997af31cb5aSVladimir Kondratiev if (tx) 9983a85543eSVladimir Kondratiev seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_vring_index, 9993a85543eSVladimir Kondratiev dbg_txdesc_index); 10003a85543eSVladimir Kondratiev else 10013a85543eSVladimir Kondratiev seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); 10022be7d22fSVladimir Kondratiev seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", 10032be7d22fSVladimir Kondratiev u[0], u[1], u[2], u[3]); 10042be7d22fSVladimir Kondratiev seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", 10052be7d22fSVladimir Kondratiev u[4], u[5], u[6], u[7]); 100639c52ee8SVladimir Kondratiev seq_printf(s, " SKB = 0x%p\n", skb); 10072be7d22fSVladimir Kondratiev 10082be7d22fSVladimir Kondratiev if (skb) { 1009c236658fSVladimir Kondratiev skb_get(skb); 1010c236658fSVladimir Kondratiev wil_seq_print_skb(s, skb); 1011c236658fSVladimir Kondratiev kfree_skb(skb); 10122be7d22fSVladimir Kondratiev } 10138fe59627SVladimir Kondratiev seq_puts(s, "}\n"); 10142be7d22fSVladimir Kondratiev } else { 1015af31cb5aSVladimir Kondratiev if (tx) 10163a85543eSVladimir Kondratiev seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", 10173a85543eSVladimir Kondratiev dbg_vring_index, dbg_txdesc_index, 10183a85543eSVladimir Kondratiev vring->size); 10193a85543eSVladimir Kondratiev else 10203a85543eSVladimir Kondratiev seq_printf(s, "RxDesc index (%d) >= size (%d)\n", 10212be7d22fSVladimir Kondratiev dbg_txdesc_index, vring->size); 10222be7d22fSVladimir Kondratiev } 10232be7d22fSVladimir Kondratiev 10242be7d22fSVladimir Kondratiev return 0; 10252be7d22fSVladimir Kondratiev } 10262be7d22fSVladimir Kondratiev 10272be7d22fSVladimir Kondratiev static int wil_txdesc_seq_open(struct inode *inode, struct file *file) 10282be7d22fSVladimir Kondratiev { 10292be7d22fSVladimir Kondratiev return single_open(file, wil_txdesc_debugfs_show, inode->i_private); 10302be7d22fSVladimir Kondratiev } 10312be7d22fSVladimir Kondratiev 10322be7d22fSVladimir Kondratiev static const struct file_operations fops_txdesc = { 10332be7d22fSVladimir Kondratiev .open = wil_txdesc_seq_open, 10342be7d22fSVladimir Kondratiev .release = single_release, 10352be7d22fSVladimir Kondratiev .read = seq_read, 10362be7d22fSVladimir Kondratiev .llseek = seq_lseek, 10372be7d22fSVladimir Kondratiev }; 10382be7d22fSVladimir Kondratiev 10392be7d22fSVladimir Kondratiev /*---------beamforming------------*/ 104036345ac3SVladimir Kondratiev static char *wil_bfstatus_str(u32 status) 104136345ac3SVladimir Kondratiev { 104236345ac3SVladimir Kondratiev switch (status) { 104336345ac3SVladimir Kondratiev case 0: 104436345ac3SVladimir Kondratiev return "Failed"; 104536345ac3SVladimir Kondratiev case 1: 104636345ac3SVladimir Kondratiev return "OK"; 104736345ac3SVladimir Kondratiev case 2: 104836345ac3SVladimir Kondratiev return "Retrying"; 104936345ac3SVladimir Kondratiev default: 105036345ac3SVladimir Kondratiev return "??"; 105136345ac3SVladimir Kondratiev } 105236345ac3SVladimir Kondratiev } 105336345ac3SVladimir Kondratiev 105436345ac3SVladimir Kondratiev static bool is_all_zeros(void * const x_, size_t sz) 105536345ac3SVladimir Kondratiev { 105636345ac3SVladimir Kondratiev /* if reply is all-0, ignore this CID */ 105736345ac3SVladimir Kondratiev u32 *x = x_; 105836345ac3SVladimir Kondratiev int n; 105936345ac3SVladimir Kondratiev 106036345ac3SVladimir Kondratiev for (n = 0; n < sz / sizeof(*x); n++) 106136345ac3SVladimir Kondratiev if (x[n]) 106236345ac3SVladimir Kondratiev return false; 106336345ac3SVladimir Kondratiev 106436345ac3SVladimir Kondratiev return true; 106536345ac3SVladimir Kondratiev } 106636345ac3SVladimir Kondratiev 10672be7d22fSVladimir Kondratiev static int wil_bf_debugfs_show(struct seq_file *s, void *data) 10682be7d22fSVladimir Kondratiev { 106936345ac3SVladimir Kondratiev int rc; 107036345ac3SVladimir Kondratiev int i; 10712be7d22fSVladimir Kondratiev struct wil6210_priv *wil = s->private; 1072e00243faSLior David struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 107336345ac3SVladimir Kondratiev struct wmi_notify_req_cmd cmd = { 107436345ac3SVladimir Kondratiev .interval_usec = 0, 107536345ac3SVladimir Kondratiev }; 107636345ac3SVladimir Kondratiev struct { 1077b874ddecSLior David struct wmi_cmd_hdr wmi; 107836345ac3SVladimir Kondratiev struct wmi_notify_req_done_event evt; 107936345ac3SVladimir Kondratiev } __packed reply; 108036345ac3SVladimir Kondratiev 108136345ac3SVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 108236345ac3SVladimir Kondratiev u32 status; 108336345ac3SVladimir Kondratiev 108436345ac3SVladimir Kondratiev cmd.cid = i; 1085e00243faSLior David rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, 1086e00243faSLior David &cmd, sizeof(cmd), 108736345ac3SVladimir Kondratiev WMI_NOTIFY_REQ_DONE_EVENTID, &reply, 108836345ac3SVladimir Kondratiev sizeof(reply), 20); 108936345ac3SVladimir Kondratiev /* if reply is all-0, ignore this CID */ 109036345ac3SVladimir Kondratiev if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt))) 109136345ac3SVladimir Kondratiev continue; 109236345ac3SVladimir Kondratiev 109336345ac3SVladimir Kondratiev status = le32_to_cpu(reply.evt.status); 109436345ac3SVladimir Kondratiev seq_printf(s, "CID %d {\n" 109536345ac3SVladimir Kondratiev " TSF = 0x%016llx\n" 109636345ac3SVladimir Kondratiev " TxMCS = %2d TxTpt = %4d\n" 109736345ac3SVladimir Kondratiev " SQI = %4d\n" 109830868f5dSDedy Lansky " RSSI = %4d\n" 109936345ac3SVladimir Kondratiev " Status = 0x%08x %s\n" 110036345ac3SVladimir Kondratiev " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" 110136345ac3SVladimir Kondratiev " Goodput(rx:tx) %4d:%4d\n" 110236345ac3SVladimir Kondratiev "}\n", 110336345ac3SVladimir Kondratiev i, 110436345ac3SVladimir Kondratiev le64_to_cpu(reply.evt.tsf), 110536345ac3SVladimir Kondratiev le16_to_cpu(reply.evt.bf_mcs), 110636345ac3SVladimir Kondratiev le32_to_cpu(reply.evt.tx_tpt), 110736345ac3SVladimir Kondratiev reply.evt.sqi, 110830868f5dSDedy Lansky reply.evt.rssi, 110936345ac3SVladimir Kondratiev status, wil_bfstatus_str(status), 111036345ac3SVladimir Kondratiev le16_to_cpu(reply.evt.my_rx_sector), 111136345ac3SVladimir Kondratiev le16_to_cpu(reply.evt.my_tx_sector), 111236345ac3SVladimir Kondratiev le16_to_cpu(reply.evt.other_rx_sector), 111336345ac3SVladimir Kondratiev le16_to_cpu(reply.evt.other_tx_sector), 111436345ac3SVladimir Kondratiev le32_to_cpu(reply.evt.rx_goodput), 111536345ac3SVladimir Kondratiev le32_to_cpu(reply.evt.tx_goodput)); 111636345ac3SVladimir Kondratiev } 11172be7d22fSVladimir Kondratiev return 0; 11182be7d22fSVladimir Kondratiev } 11192be7d22fSVladimir Kondratiev 11202be7d22fSVladimir Kondratiev static int wil_bf_seq_open(struct inode *inode, struct file *file) 11212be7d22fSVladimir Kondratiev { 11222be7d22fSVladimir Kondratiev return single_open(file, wil_bf_debugfs_show, inode->i_private); 11232be7d22fSVladimir Kondratiev } 11242be7d22fSVladimir Kondratiev 11252be7d22fSVladimir Kondratiev static const struct file_operations fops_bf = { 11262be7d22fSVladimir Kondratiev .open = wil_bf_seq_open, 11272be7d22fSVladimir Kondratiev .release = single_release, 11282be7d22fSVladimir Kondratiev .read = seq_read, 11292be7d22fSVladimir Kondratiev .llseek = seq_lseek, 11302be7d22fSVladimir Kondratiev }; 11318fe59627SVladimir Kondratiev 11321a2780e0SVladimir Kondratiev /*---------temp------------*/ 11331a2780e0SVladimir Kondratiev static void print_temp(struct seq_file *s, const char *prefix, u32 t) 11341a2780e0SVladimir Kondratiev { 11351a2780e0SVladimir Kondratiev switch (t) { 11361a2780e0SVladimir Kondratiev case 0: 11371a2780e0SVladimir Kondratiev case ~(u32)0: 11381a2780e0SVladimir Kondratiev seq_printf(s, "%s N/A\n", prefix); 11391a2780e0SVladimir Kondratiev break; 11401a2780e0SVladimir Kondratiev default: 11411a2780e0SVladimir Kondratiev seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000); 11421a2780e0SVladimir Kondratiev break; 11431a2780e0SVladimir Kondratiev } 11441a2780e0SVladimir Kondratiev } 11451a2780e0SVladimir Kondratiev 11461a2780e0SVladimir Kondratiev static int wil_temp_debugfs_show(struct seq_file *s, void *data) 11471a2780e0SVladimir Kondratiev { 11481a2780e0SVladimir Kondratiev struct wil6210_priv *wil = s->private; 11491a2780e0SVladimir Kondratiev u32 t_m, t_r; 11501a2780e0SVladimir Kondratiev int rc = wmi_get_temperature(wil, &t_m, &t_r); 11518fe59627SVladimir Kondratiev 11521a2780e0SVladimir Kondratiev if (rc) { 11538fe59627SVladimir Kondratiev seq_puts(s, "Failed\n"); 11541a2780e0SVladimir Kondratiev return 0; 11551a2780e0SVladimir Kondratiev } 11561a2780e0SVladimir Kondratiev 1157d45cff9fSVladimir Kondratiev print_temp(s, "T_mac =", t_m); 1158d45cff9fSVladimir Kondratiev print_temp(s, "T_radio =", t_r); 11591a2780e0SVladimir Kondratiev 11601a2780e0SVladimir Kondratiev return 0; 11611a2780e0SVladimir Kondratiev } 11621a2780e0SVladimir Kondratiev 11631a2780e0SVladimir Kondratiev static int wil_temp_seq_open(struct inode *inode, struct file *file) 11641a2780e0SVladimir Kondratiev { 11651a2780e0SVladimir Kondratiev return single_open(file, wil_temp_debugfs_show, inode->i_private); 11661a2780e0SVladimir Kondratiev } 11671a2780e0SVladimir Kondratiev 11681a2780e0SVladimir Kondratiev static const struct file_operations fops_temp = { 11691a2780e0SVladimir Kondratiev .open = wil_temp_seq_open, 11701a2780e0SVladimir Kondratiev .release = single_release, 11711a2780e0SVladimir Kondratiev .read = seq_read, 11721a2780e0SVladimir Kondratiev .llseek = seq_lseek, 11731a2780e0SVladimir Kondratiev }; 11741a2780e0SVladimir Kondratiev 11759eb82d43SVladimir Kondratiev /*---------freq------------*/ 11769eb82d43SVladimir Kondratiev static int wil_freq_debugfs_show(struct seq_file *s, void *data) 11779eb82d43SVladimir Kondratiev { 11789eb82d43SVladimir Kondratiev struct wil6210_priv *wil = s->private; 1179e00243faSLior David struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; 11809eb82d43SVladimir Kondratiev u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; 11819eb82d43SVladimir Kondratiev 11829eb82d43SVladimir Kondratiev seq_printf(s, "Freq = %d\n", freq); 11839eb82d43SVladimir Kondratiev 11849eb82d43SVladimir Kondratiev return 0; 11859eb82d43SVladimir Kondratiev } 11869eb82d43SVladimir Kondratiev 11879eb82d43SVladimir Kondratiev static int wil_freq_seq_open(struct inode *inode, struct file *file) 11889eb82d43SVladimir Kondratiev { 11899eb82d43SVladimir Kondratiev return single_open(file, wil_freq_debugfs_show, inode->i_private); 11909eb82d43SVladimir Kondratiev } 11919eb82d43SVladimir Kondratiev 11929eb82d43SVladimir Kondratiev static const struct file_operations fops_freq = { 11939eb82d43SVladimir Kondratiev .open = wil_freq_seq_open, 11949eb82d43SVladimir Kondratiev .release = single_release, 11959eb82d43SVladimir Kondratiev .read = seq_read, 11969eb82d43SVladimir Kondratiev .llseek = seq_lseek, 11979eb82d43SVladimir Kondratiev }; 11989eb82d43SVladimir Kondratiev 11999eb82d43SVladimir Kondratiev /*---------link------------*/ 12009eb82d43SVladimir Kondratiev static int wil_link_debugfs_show(struct seq_file *s, void *data) 12019eb82d43SVladimir Kondratiev { 12029eb82d43SVladimir Kondratiev struct wil6210_priv *wil = s->private; 1203*41bd3d58SToke Høiland-Jørgensen struct station_info *sinfo; 1204*41bd3d58SToke Høiland-Jørgensen int i, rc = 0; 1205*41bd3d58SToke Høiland-Jørgensen 1206*41bd3d58SToke Høiland-Jørgensen sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); 1207*41bd3d58SToke Høiland-Jørgensen if (!sinfo) 1208*41bd3d58SToke Høiland-Jørgensen return -ENOMEM; 12099eb82d43SVladimir Kondratiev 12109eb82d43SVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 12119eb82d43SVladimir Kondratiev struct wil_sta_info *p = &wil->sta[i]; 12129eb82d43SVladimir Kondratiev char *status = "unknown"; 12135bd60982SLior David struct wil6210_vif *vif; 12145bd60982SLior David u8 mid; 12158fe59627SVladimir Kondratiev 12169eb82d43SVladimir Kondratiev switch (p->status) { 12179eb82d43SVladimir Kondratiev case wil_sta_unused: 12189eb82d43SVladimir Kondratiev status = "unused "; 12199eb82d43SVladimir Kondratiev break; 12209eb82d43SVladimir Kondratiev case wil_sta_conn_pending: 12219eb82d43SVladimir Kondratiev status = "pending "; 12229eb82d43SVladimir Kondratiev break; 12239eb82d43SVladimir Kondratiev case wil_sta_connected: 12249eb82d43SVladimir Kondratiev status = "connected"; 12259eb82d43SVladimir Kondratiev break; 12269eb82d43SVladimir Kondratiev } 12275bd60982SLior David mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; 12285bd60982SLior David seq_printf(s, "[%d][MID %d] %pM %s\n", 12295bd60982SLior David i, mid, p->addr, status); 12309eb82d43SVladimir Kondratiev 12315bd60982SLior David if (p->status != wil_sta_connected) 12325bd60982SLior David continue; 12335bd60982SLior David 12345bd60982SLior David vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; 12355bd60982SLior David if (vif) { 1236*41bd3d58SToke Høiland-Jørgensen rc = wil_cid_fill_sinfo(vif, i, sinfo); 12379eb82d43SVladimir Kondratiev if (rc) 1238*41bd3d58SToke Høiland-Jørgensen goto out; 12399eb82d43SVladimir Kondratiev 1240*41bd3d58SToke Høiland-Jørgensen seq_printf(s, " Tx_mcs = %d\n", sinfo->txrate.mcs); 1241*41bd3d58SToke Høiland-Jørgensen seq_printf(s, " Rx_mcs = %d\n", sinfo->rxrate.mcs); 1242*41bd3d58SToke Høiland-Jørgensen seq_printf(s, " SQ = %d\n", sinfo->signal); 12435bd60982SLior David } else { 12445bd60982SLior David seq_puts(s, " INVALID MID\n"); 12459eb82d43SVladimir Kondratiev } 12469eb82d43SVladimir Kondratiev } 12479eb82d43SVladimir Kondratiev 1248*41bd3d58SToke Høiland-Jørgensen out: 1249*41bd3d58SToke Høiland-Jørgensen kfree(sinfo); 1250*41bd3d58SToke Høiland-Jørgensen return rc; 12519eb82d43SVladimir Kondratiev } 12529eb82d43SVladimir Kondratiev 12539eb82d43SVladimir Kondratiev static int wil_link_seq_open(struct inode *inode, struct file *file) 12549eb82d43SVladimir Kondratiev { 12559eb82d43SVladimir Kondratiev return single_open(file, wil_link_debugfs_show, inode->i_private); 12569eb82d43SVladimir Kondratiev } 12579eb82d43SVladimir Kondratiev 12589eb82d43SVladimir Kondratiev static const struct file_operations fops_link = { 12599eb82d43SVladimir Kondratiev .open = wil_link_seq_open, 12609eb82d43SVladimir Kondratiev .release = single_release, 12619eb82d43SVladimir Kondratiev .read = seq_read, 12629eb82d43SVladimir Kondratiev .llseek = seq_lseek, 12639eb82d43SVladimir Kondratiev }; 12649eb82d43SVladimir Kondratiev 126584bb29b7SVladimir Kondratiev /*---------info------------*/ 126684bb29b7SVladimir Kondratiev static int wil_info_debugfs_show(struct seq_file *s, void *data) 126784bb29b7SVladimir Kondratiev { 1268be299858SVladimir Kondratiev struct wil6210_priv *wil = s->private; 1269e00243faSLior David struct net_device *ndev = wil->main_ndev; 127084bb29b7SVladimir Kondratiev int is_ac = power_supply_is_system_supplied(); 1271be299858SVladimir Kondratiev int rx = atomic_xchg(&wil->isr_count_rx, 0); 1272be299858SVladimir Kondratiev int tx = atomic_xchg(&wil->isr_count_tx, 0); 1273be299858SVladimir Kondratiev static ulong rxf_old, txf_old; 1274be299858SVladimir Kondratiev ulong rxf = ndev->stats.rx_packets; 1275be299858SVladimir Kondratiev ulong txf = ndev->stats.tx_packets; 127655f8f680SVladimir Kondratiev unsigned int i; 127784bb29b7SVladimir Kondratiev 127884bb29b7SVladimir Kondratiev /* >0 : AC; 0 : battery; <0 : error */ 127984bb29b7SVladimir Kondratiev seq_printf(s, "AC powered : %d\n", is_ac); 1280be299858SVladimir Kondratiev seq_printf(s, "Rx irqs:packets : %8d : %8ld\n", rx, rxf - rxf_old); 1281be299858SVladimir Kondratiev seq_printf(s, "Tx irqs:packets : %8d : %8ld\n", tx, txf - txf_old); 1282be299858SVladimir Kondratiev rxf_old = rxf; 1283be299858SVladimir Kondratiev txf_old = txf; 128484bb29b7SVladimir Kondratiev 128555f8f680SVladimir Kondratiev #define CHECK_QSTATE(x) (state & BIT(__QUEUE_STATE_ ## x)) ? \ 128655f8f680SVladimir Kondratiev " " __stringify(x) : "" 128755f8f680SVladimir Kondratiev 128855f8f680SVladimir Kondratiev for (i = 0; i < ndev->num_tx_queues; i++) { 128955f8f680SVladimir Kondratiev struct netdev_queue *txq = netdev_get_tx_queue(ndev, i); 129055f8f680SVladimir Kondratiev unsigned long state = txq->state; 129155f8f680SVladimir Kondratiev 129255f8f680SVladimir Kondratiev seq_printf(s, "Tx queue[%i] state : 0x%lx%s%s%s\n", i, state, 129355f8f680SVladimir Kondratiev CHECK_QSTATE(DRV_XOFF), 129455f8f680SVladimir Kondratiev CHECK_QSTATE(STACK_XOFF), 129555f8f680SVladimir Kondratiev CHECK_QSTATE(FROZEN) 129655f8f680SVladimir Kondratiev ); 129755f8f680SVladimir Kondratiev } 129855f8f680SVladimir Kondratiev #undef CHECK_QSTATE 129984bb29b7SVladimir Kondratiev return 0; 130084bb29b7SVladimir Kondratiev } 130184bb29b7SVladimir Kondratiev 130284bb29b7SVladimir Kondratiev static int wil_info_seq_open(struct inode *inode, struct file *file) 130384bb29b7SVladimir Kondratiev { 130484bb29b7SVladimir Kondratiev return single_open(file, wil_info_debugfs_show, inode->i_private); 130584bb29b7SVladimir Kondratiev } 130684bb29b7SVladimir Kondratiev 130784bb29b7SVladimir Kondratiev static const struct file_operations fops_info = { 130884bb29b7SVladimir Kondratiev .open = wil_info_seq_open, 130984bb29b7SVladimir Kondratiev .release = single_release, 131084bb29b7SVladimir Kondratiev .read = seq_read, 131184bb29b7SVladimir Kondratiev .llseek = seq_lseek, 131284bb29b7SVladimir Kondratiev }; 131384bb29b7SVladimir Kondratiev 1314c33407a8SVladimir Kondratiev /*---------recovery------------*/ 1315c33407a8SVladimir Kondratiev /* mode = [manual|auto] 1316c33407a8SVladimir Kondratiev * state = [idle|pending|running] 1317c33407a8SVladimir Kondratiev */ 1318c33407a8SVladimir Kondratiev static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf, 1319c33407a8SVladimir Kondratiev size_t count, loff_t *ppos) 1320c33407a8SVladimir Kondratiev { 1321c33407a8SVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 1322c33407a8SVladimir Kondratiev char buf[80]; 1323c33407a8SVladimir Kondratiev int n; 1324c33407a8SVladimir Kondratiev static const char * const sstate[] = {"idle", "pending", "running"}; 1325c33407a8SVladimir Kondratiev 1326c33407a8SVladimir Kondratiev n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n", 1327c33407a8SVladimir Kondratiev no_fw_recovery ? "manual" : "auto", 1328c33407a8SVladimir Kondratiev sstate[wil->recovery_state]); 1329c33407a8SVladimir Kondratiev 1330c33407a8SVladimir Kondratiev n = min_t(int, n, sizeof(buf)); 1331c33407a8SVladimir Kondratiev 1332c33407a8SVladimir Kondratiev return simple_read_from_buffer(user_buf, count, ppos, 1333c33407a8SVladimir Kondratiev buf, n); 1334c33407a8SVladimir Kondratiev } 1335c33407a8SVladimir Kondratiev 1336c33407a8SVladimir Kondratiev static ssize_t wil_write_file_recovery(struct file *file, 1337c33407a8SVladimir Kondratiev const char __user *buf_, 1338c33407a8SVladimir Kondratiev size_t count, loff_t *ppos) 1339c33407a8SVladimir Kondratiev { 1340c33407a8SVladimir Kondratiev struct wil6210_priv *wil = file->private_data; 1341c33407a8SVladimir Kondratiev static const char run_command[] = "run"; 1342c33407a8SVladimir Kondratiev char buf[sizeof(run_command) + 1]; /* to detect "runx" */ 1343c33407a8SVladimir Kondratiev ssize_t rc; 1344c33407a8SVladimir Kondratiev 1345c33407a8SVladimir Kondratiev if (wil->recovery_state != fw_recovery_pending) { 1346c33407a8SVladimir Kondratiev wil_err(wil, "No recovery pending\n"); 1347c33407a8SVladimir Kondratiev return -EINVAL; 1348c33407a8SVladimir Kondratiev } 1349c33407a8SVladimir Kondratiev 1350c33407a8SVladimir Kondratiev if (*ppos != 0) { 1351c33407a8SVladimir Kondratiev wil_err(wil, "Offset [%d]\n", (int)*ppos); 1352c33407a8SVladimir Kondratiev return -EINVAL; 1353c33407a8SVladimir Kondratiev } 1354c33407a8SVladimir Kondratiev 1355c33407a8SVladimir Kondratiev if (count > sizeof(buf)) { 1356c33407a8SVladimir Kondratiev wil_err(wil, "Input too long, len = %d\n", (int)count); 1357c33407a8SVladimir Kondratiev return -EINVAL; 1358c33407a8SVladimir Kondratiev } 1359c33407a8SVladimir Kondratiev 1360c33407a8SVladimir Kondratiev rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count); 1361c33407a8SVladimir Kondratiev if (rc < 0) 1362c33407a8SVladimir Kondratiev return rc; 1363c33407a8SVladimir Kondratiev 1364c33407a8SVladimir Kondratiev buf[rc] = '\0'; 1365c33407a8SVladimir Kondratiev if (0 == strcmp(buf, run_command)) 1366c33407a8SVladimir Kondratiev wil_set_recovery_state(wil, fw_recovery_running); 1367c33407a8SVladimir Kondratiev else 1368c33407a8SVladimir Kondratiev wil_err(wil, "Bad recovery command \"%s\"\n", buf); 1369c33407a8SVladimir Kondratiev 1370c33407a8SVladimir Kondratiev return rc; 1371c33407a8SVladimir Kondratiev } 1372c33407a8SVladimir Kondratiev 1373c33407a8SVladimir Kondratiev static const struct file_operations fops_recovery = { 1374c33407a8SVladimir Kondratiev .read = wil_read_file_recovery, 1375c33407a8SVladimir Kondratiev .write = wil_write_file_recovery, 1376c33407a8SVladimir Kondratiev .open = simple_open, 1377c33407a8SVladimir Kondratiev }; 1378c33407a8SVladimir Kondratiev 13793df2cd36SVladimir Kondratiev /*---------Station matrix------------*/ 1380b4490f42SVladimir Kondratiev static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) 1381b4490f42SVladimir Kondratiev { 1382b4490f42SVladimir Kondratiev int i; 1383b4490f42SVladimir Kondratiev u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; 138491a8edccSVladimir Kondratiev unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old; 13858fe59627SVladimir Kondratiev 138656637e7bSVladimir Kondratiev seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, 138756637e7bSVladimir Kondratiev r->head_seq_num); 1388b4490f42SVladimir Kondratiev for (i = 0; i < r->buf_size; i++) { 1389b4490f42SVladimir Kondratiev if (i == index) 1390b4490f42SVladimir Kondratiev seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|'); 1391b4490f42SVladimir Kondratiev else 1392b4490f42SVladimir Kondratiev seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); 1393b4490f42SVladimir Kondratiev } 139491a8edccSVladimir Kondratiev seq_printf(s, 139591a8edccSVladimir Kondratiev "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n", 139691a8edccSVladimir Kondratiev r->total, drop_dup + drop_old, drop_dup, drop_old, 139791a8edccSVladimir Kondratiev r->ssn_last_drop); 1398b4490f42SVladimir Kondratiev } 13993df2cd36SVladimir Kondratiev 140058527421SVladimir Kondratiev static void wil_print_rxtid_crypto(struct seq_file *s, int tid, 140158527421SVladimir Kondratiev struct wil_tid_crypto_rx *c) 140258527421SVladimir Kondratiev { 140358527421SVladimir Kondratiev int i; 140458527421SVladimir Kondratiev 140558527421SVladimir Kondratiev for (i = 0; i < 4; i++) { 140658527421SVladimir Kondratiev struct wil_tid_crypto_rx_single *cc = &c->key_id[i]; 140758527421SVladimir Kondratiev 140858527421SVladimir Kondratiev if (cc->key_set) 140958527421SVladimir Kondratiev goto has_keys; 141058527421SVladimir Kondratiev } 141158527421SVladimir Kondratiev return; 141258527421SVladimir Kondratiev 141358527421SVladimir Kondratiev has_keys: 141458527421SVladimir Kondratiev if (tid < WIL_STA_TID_NUM) 141558527421SVladimir Kondratiev seq_printf(s, " [%2d] PN", tid); 141658527421SVladimir Kondratiev else 141758527421SVladimir Kondratiev seq_puts(s, " [GR] PN"); 141858527421SVladimir Kondratiev 141958527421SVladimir Kondratiev for (i = 0; i < 4; i++) { 142058527421SVladimir Kondratiev struct wil_tid_crypto_rx_single *cc = &c->key_id[i]; 142158527421SVladimir Kondratiev 142258527421SVladimir Kondratiev seq_printf(s, " [%i%s]%6phN", i, cc->key_set ? "+" : "-", 142358527421SVladimir Kondratiev cc->pn); 142458527421SVladimir Kondratiev } 142558527421SVladimir Kondratiev seq_puts(s, "\n"); 142658527421SVladimir Kondratiev } 142758527421SVladimir Kondratiev 14283df2cd36SVladimir Kondratiev static int wil_sta_debugfs_show(struct seq_file *s, void *data) 1429bd33273bSVladimir Kondratiev __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) 14303df2cd36SVladimir Kondratiev { 14313df2cd36SVladimir Kondratiev struct wil6210_priv *wil = s->private; 1432c4a110d8SVladimir Kondratiev int i, tid, mcs; 14333df2cd36SVladimir Kondratiev 14343df2cd36SVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 14353df2cd36SVladimir Kondratiev struct wil_sta_info *p = &wil->sta[i]; 14363df2cd36SVladimir Kondratiev char *status = "unknown"; 14379d865ee2SLior David u8 aid = 0; 14385bd60982SLior David u8 mid; 14398fe59627SVladimir Kondratiev 14403df2cd36SVladimir Kondratiev switch (p->status) { 14413df2cd36SVladimir Kondratiev case wil_sta_unused: 14423df2cd36SVladimir Kondratiev status = "unused "; 14433df2cd36SVladimir Kondratiev break; 14443df2cd36SVladimir Kondratiev case wil_sta_conn_pending: 14453df2cd36SVladimir Kondratiev status = "pending "; 14463df2cd36SVladimir Kondratiev break; 14473df2cd36SVladimir Kondratiev case wil_sta_connected: 14483df2cd36SVladimir Kondratiev status = "connected"; 14499d865ee2SLior David aid = p->aid; 14503df2cd36SVladimir Kondratiev break; 14513df2cd36SVladimir Kondratiev } 14525bd60982SLior David mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; 14535bd60982SLior David seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, 14545bd60982SLior David mid, aid); 1455b4490f42SVladimir Kondratiev 1456b4490f42SVladimir Kondratiev if (p->status == wil_sta_connected) { 1457bd33273bSVladimir Kondratiev spin_lock_bh(&p->tid_rx_lock); 1458b4490f42SVladimir Kondratiev for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { 1459b4490f42SVladimir Kondratiev struct wil_tid_ampdu_rx *r = p->tid_rx[tid]; 146058527421SVladimir Kondratiev struct wil_tid_crypto_rx *c = 146158527421SVladimir Kondratiev &p->tid_crypto_rx[tid]; 14628fe59627SVladimir Kondratiev 1463b4490f42SVladimir Kondratiev if (r) { 1464b4490f42SVladimir Kondratiev seq_printf(s, " [%2d] ", tid); 1465b4490f42SVladimir Kondratiev wil_print_rxtid(s, r); 1466b4490f42SVladimir Kondratiev } 146758527421SVladimir Kondratiev 146858527421SVladimir Kondratiev wil_print_rxtid_crypto(s, tid, c); 1469b4490f42SVladimir Kondratiev } 147058527421SVladimir Kondratiev wil_print_rxtid_crypto(s, WIL_STA_TID_NUM, 147158527421SVladimir Kondratiev &p->group_crypto_rx); 1472bd33273bSVladimir Kondratiev spin_unlock_bh(&p->tid_rx_lock); 14733b282bc6SVladimir Kondratiev seq_printf(s, 147458527421SVladimir Kondratiev "Rx invalid frame: non-data %lu, short %lu, large %lu, replay %lu\n", 14753b282bc6SVladimir Kondratiev p->stats.rx_non_data_frame, 14763b282bc6SVladimir Kondratiev p->stats.rx_short_frame, 147758527421SVladimir Kondratiev p->stats.rx_large_frame, 147858527421SVladimir Kondratiev p->stats.rx_replay); 14793b282bc6SVladimir Kondratiev 1480c4a110d8SVladimir Kondratiev seq_puts(s, "Rx/MCS:"); 1481c4a110d8SVladimir Kondratiev for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); 1482c4a110d8SVladimir Kondratiev mcs++) 1483c4a110d8SVladimir Kondratiev seq_printf(s, " %lld", 1484c4a110d8SVladimir Kondratiev p->stats.rx_per_mcs[mcs]); 1485c4a110d8SVladimir Kondratiev seq_puts(s, "\n"); 1486b4490f42SVladimir Kondratiev } 14873df2cd36SVladimir Kondratiev } 14883df2cd36SVladimir Kondratiev 14893df2cd36SVladimir Kondratiev return 0; 14903df2cd36SVladimir Kondratiev } 14913df2cd36SVladimir Kondratiev 14923df2cd36SVladimir Kondratiev static int wil_sta_seq_open(struct inode *inode, struct file *file) 14933df2cd36SVladimir Kondratiev { 14943df2cd36SVladimir Kondratiev return single_open(file, wil_sta_debugfs_show, inode->i_private); 14953df2cd36SVladimir Kondratiev } 14963df2cd36SVladimir Kondratiev 14973df2cd36SVladimir Kondratiev static const struct file_operations fops_sta = { 14983df2cd36SVladimir Kondratiev .open = wil_sta_seq_open, 14993df2cd36SVladimir Kondratiev .release = single_release, 15003df2cd36SVladimir Kondratiev .read = seq_read, 15013df2cd36SVladimir Kondratiev .llseek = seq_lseek, 15023df2cd36SVladimir Kondratiev }; 15033df2cd36SVladimir Kondratiev 15043a3b745fSLior David static int wil_mids_debugfs_show(struct seq_file *s, void *data) 15053a3b745fSLior David { 15063a3b745fSLior David struct wil6210_priv *wil = s->private; 15073a3b745fSLior David struct wil6210_vif *vif; 15083a3b745fSLior David struct net_device *ndev; 15093a3b745fSLior David int i; 15103a3b745fSLior David 15113a3b745fSLior David mutex_lock(&wil->vif_mutex); 15123a3b745fSLior David for (i = 0; i < wil->max_vifs; i++) { 15133a3b745fSLior David vif = wil->vifs[i]; 15143a3b745fSLior David 15153a3b745fSLior David if (vif) { 15163a3b745fSLior David ndev = vif_to_ndev(vif); 15173a3b745fSLior David seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr, 15183a3b745fSLior David ndev->name); 15193a3b745fSLior David } else { 15203a3b745fSLior David seq_printf(s, "[%d] unused\n", i); 15213a3b745fSLior David } 15223a3b745fSLior David } 15233a3b745fSLior David mutex_unlock(&wil->vif_mutex); 15243a3b745fSLior David 15253a3b745fSLior David return 0; 15263a3b745fSLior David } 15273a3b745fSLior David 15283a3b745fSLior David static int wil_mids_seq_open(struct inode *inode, struct file *file) 15293a3b745fSLior David { 15303a3b745fSLior David return single_open(file, wil_mids_debugfs_show, inode->i_private); 15313a3b745fSLior David } 15323a3b745fSLior David 15333a3b745fSLior David static const struct file_operations fops_mids = { 15343a3b745fSLior David .open = wil_mids_seq_open, 15353a3b745fSLior David .release = single_release, 15363a3b745fSLior David .read = seq_read, 15373a3b745fSLior David .llseek = seq_lseek, 15383a3b745fSLior David }; 15393a3b745fSLior David 154010d599adSMaya Erez static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, 154110d599adSMaya Erez size_t count, loff_t *ppos) 154210d599adSMaya Erez { 154310d599adSMaya Erez char buf[80]; 154410d599adSMaya Erez int n; 154510d599adSMaya Erez 154610d599adSMaya Erez n = snprintf(buf, sizeof(buf), 154710d599adSMaya Erez "led_id is set to %d, echo 1 to enable, 0 to disable\n", 154810d599adSMaya Erez led_id); 154910d599adSMaya Erez 155010d599adSMaya Erez n = min_t(int, n, sizeof(buf)); 155110d599adSMaya Erez 155210d599adSMaya Erez return simple_read_from_buffer(user_buf, count, ppos, 155310d599adSMaya Erez buf, n); 155410d599adSMaya Erez } 155510d599adSMaya Erez 155610d599adSMaya Erez static ssize_t wil_write_file_led_cfg(struct file *file, 155710d599adSMaya Erez const char __user *buf_, 155810d599adSMaya Erez size_t count, loff_t *ppos) 155910d599adSMaya Erez { 156010d599adSMaya Erez struct wil6210_priv *wil = file->private_data; 156110d599adSMaya Erez int val; 156210d599adSMaya Erez int rc; 156310d599adSMaya Erez 156410d599adSMaya Erez rc = kstrtoint_from_user(buf_, count, 0, &val); 156510d599adSMaya Erez if (rc) { 156610d599adSMaya Erez wil_err(wil, "Invalid argument\n"); 156710d599adSMaya Erez return rc; 156810d599adSMaya Erez } 156910d599adSMaya Erez 157010d599adSMaya Erez wil_info(wil, "%s led %d\n", val ? "Enabling" : "Disabling", led_id); 157110d599adSMaya Erez rc = wmi_led_cfg(wil, val); 157210d599adSMaya Erez if (rc) { 157310d599adSMaya Erez wil_info(wil, "%s led %d failed\n", 157410d599adSMaya Erez val ? "Enabling" : "Disabling", led_id); 157510d599adSMaya Erez return rc; 157610d599adSMaya Erez } 157710d599adSMaya Erez 157810d599adSMaya Erez return count; 157910d599adSMaya Erez } 158010d599adSMaya Erez 158110d599adSMaya Erez static const struct file_operations fops_led_cfg = { 158210d599adSMaya Erez .read = wil_read_file_led_cfg, 158310d599adSMaya Erez .write = wil_write_file_led_cfg, 158410d599adSMaya Erez .open = simple_open, 158510d599adSMaya Erez }; 158610d599adSMaya Erez 158710d599adSMaya Erez /* led_blink_time, write: 158810d599adSMaya Erez * "<blink_on_slow> <blink_off_slow> <blink_on_med> <blink_off_med> <blink_on_fast> <blink_off_fast> 158910d599adSMaya Erez */ 159010d599adSMaya Erez static ssize_t wil_write_led_blink_time(struct file *file, 159110d599adSMaya Erez const char __user *buf, 159210d599adSMaya Erez size_t len, loff_t *ppos) 159310d599adSMaya Erez { 159410d599adSMaya Erez int rc; 159510d599adSMaya Erez char *kbuf = kmalloc(len + 1, GFP_KERNEL); 159610d599adSMaya Erez 159710d599adSMaya Erez if (!kbuf) 159810d599adSMaya Erez return -ENOMEM; 159910d599adSMaya Erez 160010d599adSMaya Erez rc = simple_write_to_buffer(kbuf, len, ppos, buf, len); 160110d599adSMaya Erez if (rc != len) { 160210d599adSMaya Erez kfree(kbuf); 160310d599adSMaya Erez return rc >= 0 ? -EIO : rc; 160410d599adSMaya Erez } 160510d599adSMaya Erez 160610d599adSMaya Erez kbuf[len] = '\0'; 160710d599adSMaya Erez rc = sscanf(kbuf, "%d %d %d %d %d %d", 160810d599adSMaya Erez &led_blink_time[WIL_LED_TIME_SLOW].on_ms, 160910d599adSMaya Erez &led_blink_time[WIL_LED_TIME_SLOW].off_ms, 161010d599adSMaya Erez &led_blink_time[WIL_LED_TIME_MED].on_ms, 161110d599adSMaya Erez &led_blink_time[WIL_LED_TIME_MED].off_ms, 161210d599adSMaya Erez &led_blink_time[WIL_LED_TIME_FAST].on_ms, 161310d599adSMaya Erez &led_blink_time[WIL_LED_TIME_FAST].off_ms); 161410d599adSMaya Erez kfree(kbuf); 161510d599adSMaya Erez 161610d599adSMaya Erez if (rc < 0) 161710d599adSMaya Erez return rc; 161810d599adSMaya Erez if (rc < 6) 161910d599adSMaya Erez return -EINVAL; 162010d599adSMaya Erez 162110d599adSMaya Erez return len; 162210d599adSMaya Erez } 162310d599adSMaya Erez 162410d599adSMaya Erez static ssize_t wil_read_led_blink_time(struct file *file, char __user *user_buf, 162510d599adSMaya Erez size_t count, loff_t *ppos) 162610d599adSMaya Erez { 162710d599adSMaya Erez static char text[400]; 162810d599adSMaya Erez 162910d599adSMaya Erez snprintf(text, sizeof(text), 163010d599adSMaya Erez "To set led blink on/off time variables write:\n" 163110d599adSMaya Erez "<blink_on_slow> <blink_off_slow> <blink_on_med> " 163210d599adSMaya Erez "<blink_off_med> <blink_on_fast> <blink_off_fast>\n" 163310d599adSMaya Erez "The current values are:\n" 163410d599adSMaya Erez "%d %d %d %d %d %d\n", 163510d599adSMaya Erez led_blink_time[WIL_LED_TIME_SLOW].on_ms, 163610d599adSMaya Erez led_blink_time[WIL_LED_TIME_SLOW].off_ms, 163710d599adSMaya Erez led_blink_time[WIL_LED_TIME_MED].on_ms, 163810d599adSMaya Erez led_blink_time[WIL_LED_TIME_MED].off_ms, 163910d599adSMaya Erez led_blink_time[WIL_LED_TIME_FAST].on_ms, 164010d599adSMaya Erez led_blink_time[WIL_LED_TIME_FAST].off_ms); 164110d599adSMaya Erez 164210d599adSMaya Erez return simple_read_from_buffer(user_buf, count, ppos, text, 164310d599adSMaya Erez sizeof(text)); 164410d599adSMaya Erez } 164510d599adSMaya Erez 164610d599adSMaya Erez static const struct file_operations fops_led_blink_time = { 164710d599adSMaya Erez .read = wil_read_led_blink_time, 164810d599adSMaya Erez .write = wil_write_led_blink_time, 164910d599adSMaya Erez .open = simple_open, 165010d599adSMaya Erez }; 165110d599adSMaya Erez 165212bace75SLior David /*---------FW capabilities------------*/ 165312bace75SLior David static int wil_fw_capabilities_debugfs_show(struct seq_file *s, void *data) 165412bace75SLior David { 165512bace75SLior David struct wil6210_priv *wil = s->private; 165612bace75SLior David 165712bace75SLior David seq_printf(s, "fw_capabilities : %*pb\n", WMI_FW_CAPABILITY_MAX, 165812bace75SLior David wil->fw_capabilities); 165912bace75SLior David 166012bace75SLior David return 0; 166112bace75SLior David } 166212bace75SLior David 166312bace75SLior David static int wil_fw_capabilities_seq_open(struct inode *inode, struct file *file) 166412bace75SLior David { 166512bace75SLior David return single_open(file, wil_fw_capabilities_debugfs_show, 166612bace75SLior David inode->i_private); 166712bace75SLior David } 166812bace75SLior David 166912bace75SLior David static const struct file_operations fops_fw_capabilities = { 167012bace75SLior David .open = wil_fw_capabilities_seq_open, 167112bace75SLior David .release = single_release, 167212bace75SLior David .read = seq_read, 167312bace75SLior David .llseek = seq_lseek, 167412bace75SLior David }; 167512bace75SLior David 167613cd9f75SLior David /*---------FW version------------*/ 167713cd9f75SLior David static int wil_fw_version_debugfs_show(struct seq_file *s, void *data) 167813cd9f75SLior David { 167913cd9f75SLior David struct wil6210_priv *wil = s->private; 168013cd9f75SLior David 168113cd9f75SLior David if (wil->fw_version[0]) 168213cd9f75SLior David seq_printf(s, "%s\n", wil->fw_version); 168313cd9f75SLior David else 168413cd9f75SLior David seq_puts(s, "N/A\n"); 168513cd9f75SLior David 168613cd9f75SLior David return 0; 168713cd9f75SLior David } 168813cd9f75SLior David 168913cd9f75SLior David static int wil_fw_version_seq_open(struct inode *inode, struct file *file) 169013cd9f75SLior David { 169113cd9f75SLior David return single_open(file, wil_fw_version_debugfs_show, 169213cd9f75SLior David inode->i_private); 169313cd9f75SLior David } 169413cd9f75SLior David 169513cd9f75SLior David static const struct file_operations fops_fw_version = { 169613cd9f75SLior David .open = wil_fw_version_seq_open, 169713cd9f75SLior David .release = single_release, 169813cd9f75SLior David .read = seq_read, 169913cd9f75SLior David .llseek = seq_lseek, 170013cd9f75SLior David }; 170113cd9f75SLior David 1702fe9ee51eSMaya Erez /*---------suspend_stats---------*/ 1703fe9ee51eSMaya Erez static ssize_t wil_write_suspend_stats(struct file *file, 1704fe9ee51eSMaya Erez const char __user *buf, 1705fe9ee51eSMaya Erez size_t len, loff_t *ppos) 1706fe9ee51eSMaya Erez { 1707fe9ee51eSMaya Erez struct wil6210_priv *wil = file->private_data; 1708fe9ee51eSMaya Erez 1709fe9ee51eSMaya Erez memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); 1710fe9ee51eSMaya Erez 1711fe9ee51eSMaya Erez return len; 1712fe9ee51eSMaya Erez } 1713fe9ee51eSMaya Erez 1714fe9ee51eSMaya Erez static ssize_t wil_read_suspend_stats(struct file *file, 1715fe9ee51eSMaya Erez char __user *user_buf, 1716fe9ee51eSMaya Erez size_t count, loff_t *ppos) 1717fe9ee51eSMaya Erez { 1718fe9ee51eSMaya Erez struct wil6210_priv *wil = file->private_data; 1719bd8bdc6cSLazar Alexei char *text; 1720bd8bdc6cSLazar Alexei int n, ret, text_size = 500; 1721fe9ee51eSMaya Erez 1722bd8bdc6cSLazar Alexei text = kmalloc(text_size, GFP_KERNEL); 1723bd8bdc6cSLazar Alexei if (!text) 1724bd8bdc6cSLazar Alexei return -ENOMEM; 1725bd8bdc6cSLazar Alexei 1726bd8bdc6cSLazar Alexei n = snprintf(text, text_size, 1727bd8bdc6cSLazar Alexei "Radio on suspend statistics:\n" 1728fe9ee51eSMaya Erez "successful suspends:%ld failed suspends:%ld\n" 1729fe9ee51eSMaya Erez "successful resumes:%ld failed resumes:%ld\n" 1730bd8bdc6cSLazar Alexei "rejected by device:%ld\n" 1731bd8bdc6cSLazar Alexei "Radio off suspend statistics:\n" 1732bd8bdc6cSLazar Alexei "successful suspends:%ld failed suspends:%ld\n" 1733bd8bdc6cSLazar Alexei "successful resumes:%ld failed resumes:%ld\n" 1734bd8bdc6cSLazar Alexei "General statistics:\n" 1735bd8bdc6cSLazar Alexei "rejected by host:%ld\n", 1736bd8bdc6cSLazar Alexei wil->suspend_stats.r_on.successful_suspends, 1737bd8bdc6cSLazar Alexei wil->suspend_stats.r_on.failed_suspends, 1738bd8bdc6cSLazar Alexei wil->suspend_stats.r_on.successful_resumes, 1739bd8bdc6cSLazar Alexei wil->suspend_stats.r_on.failed_resumes, 1740bd8bdc6cSLazar Alexei wil->suspend_stats.rejected_by_device, 1741bd8bdc6cSLazar Alexei wil->suspend_stats.r_off.successful_suspends, 1742bd8bdc6cSLazar Alexei wil->suspend_stats.r_off.failed_suspends, 1743bd8bdc6cSLazar Alexei wil->suspend_stats.r_off.successful_resumes, 1744bd8bdc6cSLazar Alexei wil->suspend_stats.r_off.failed_resumes, 1745bd8bdc6cSLazar Alexei wil->suspend_stats.rejected_by_host); 1746fe9ee51eSMaya Erez 1747bd8bdc6cSLazar Alexei n = min_t(int, n, text_size); 1748fe9ee51eSMaya Erez 1749bd8bdc6cSLazar Alexei ret = simple_read_from_buffer(user_buf, count, ppos, text, n); 1750bd8bdc6cSLazar Alexei 1751bd8bdc6cSLazar Alexei kfree(text); 1752bd8bdc6cSLazar Alexei 1753bd8bdc6cSLazar Alexei return ret; 1754fe9ee51eSMaya Erez } 1755fe9ee51eSMaya Erez 1756fe9ee51eSMaya Erez static const struct file_operations fops_suspend_stats = { 1757fe9ee51eSMaya Erez .read = wil_read_suspend_stats, 1758fe9ee51eSMaya Erez .write = wil_write_suspend_stats, 1759fe9ee51eSMaya Erez .open = simple_open, 1760fe9ee51eSMaya Erez }; 1761fe9ee51eSMaya Erez 17622be7d22fSVladimir Kondratiev /*----------------*/ 1763b541d0a0SVladimir Kondratiev static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil, 1764b541d0a0SVladimir Kondratiev struct dentry *dbg) 1765b541d0a0SVladimir Kondratiev { 1766b541d0a0SVladimir Kondratiev int i; 1767b541d0a0SVladimir Kondratiev char name[32]; 1768b541d0a0SVladimir Kondratiev 1769b541d0a0SVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { 1770349214c1SMaya Erez struct wil_blob_wrapper *wil_blob = &wil->blobs[i]; 1771349214c1SMaya Erez struct debugfs_blob_wrapper *blob = &wil_blob->blob; 1772b541d0a0SVladimir Kondratiev const struct fw_map *map = &fw_mapping[i]; 1773b541d0a0SVladimir Kondratiev 1774b541d0a0SVladimir Kondratiev if (!map->name) 1775b541d0a0SVladimir Kondratiev continue; 1776b541d0a0SVladimir Kondratiev 1777349214c1SMaya Erez wil_blob->wil = wil; 1778b541d0a0SVladimir Kondratiev blob->data = (void * __force)wil->csr + HOSTADDR(map->host); 1779b541d0a0SVladimir Kondratiev blob->size = map->to - map->from; 1780b541d0a0SVladimir Kondratiev snprintf(name, sizeof(name), "blob_%s", map->name); 178178484c44SMaya Erez wil_debugfs_create_ioblob(name, 0444, dbg, wil_blob); 1782b541d0a0SVladimir Kondratiev } 1783b541d0a0SVladimir Kondratiev } 1784b541d0a0SVladimir Kondratiev 1785b7cde470SVladimir Kondratiev /* misc files */ 1786b7cde470SVladimir Kondratiev static const struct { 1787b7cde470SVladimir Kondratiev const char *name; 1788b7cde470SVladimir Kondratiev umode_t mode; 1789b7cde470SVladimir Kondratiev const struct file_operations *fops; 1790b7cde470SVladimir Kondratiev } dbg_files[] = { 179178484c44SMaya Erez {"mbox", 0444, &fops_mbox}, 179278484c44SMaya Erez {"vrings", 0444, &fops_vring}, 179378484c44SMaya Erez {"stations", 0444, &fops_sta}, 17943a3b745fSLior David {"mids", 0444, &fops_mids}, 179578484c44SMaya Erez {"desc", 0444, &fops_txdesc}, 179678484c44SMaya Erez {"bf", 0444, &fops_bf}, 179778484c44SMaya Erez {"mem_val", 0644, &fops_memread}, 179878484c44SMaya Erez {"reset", 0244, &fops_reset}, 179978484c44SMaya Erez {"rxon", 0244, &fops_rxon}, 180078484c44SMaya Erez {"tx_mgmt", 0244, &fops_txmgmt}, 180178484c44SMaya Erez {"wmi_send", 0244, &fops_wmi}, 180278484c44SMaya Erez {"back", 0644, &fops_back}, 180378484c44SMaya Erez {"pmccfg", 0644, &fops_pmccfg}, 180478484c44SMaya Erez {"pmcdata", 0444, &fops_pmcdata}, 180578484c44SMaya Erez {"temp", 0444, &fops_temp}, 180678484c44SMaya Erez {"freq", 0444, &fops_freq}, 180778484c44SMaya Erez {"link", 0444, &fops_link}, 180878484c44SMaya Erez {"info", 0444, &fops_info}, 180978484c44SMaya Erez {"recovery", 0644, &fops_recovery}, 181078484c44SMaya Erez {"led_cfg", 0644, &fops_led_cfg}, 181178484c44SMaya Erez {"led_blink_time", 0644, &fops_led_blink_time}, 181278484c44SMaya Erez {"fw_capabilities", 0444, &fops_fw_capabilities}, 181378484c44SMaya Erez {"fw_version", 0444, &fops_fw_version}, 1814fe9ee51eSMaya Erez {"suspend_stats", 0644, &fops_suspend_stats}, 1815b7cde470SVladimir Kondratiev }; 1816b7cde470SVladimir Kondratiev 1817b7cde470SVladimir Kondratiev static void wil6210_debugfs_init_files(struct wil6210_priv *wil, 1818b7cde470SVladimir Kondratiev struct dentry *dbg) 1819b7cde470SVladimir Kondratiev { 1820b7cde470SVladimir Kondratiev int i; 1821b7cde470SVladimir Kondratiev 1822b7cde470SVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(dbg_files); i++) 1823b7cde470SVladimir Kondratiev debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg, 1824b7cde470SVladimir Kondratiev wil, dbg_files[i].fops); 1825b7cde470SVladimir Kondratiev } 1826b7cde470SVladimir Kondratiev 1827b7cde470SVladimir Kondratiev /* interrupt control blocks */ 1828b7cde470SVladimir Kondratiev static const struct { 1829b7cde470SVladimir Kondratiev const char *name; 1830b7cde470SVladimir Kondratiev u32 icr_off; 1831b7cde470SVladimir Kondratiev } dbg_icr[] = { 1832b7cde470SVladimir Kondratiev {"USER_ICR", HOSTADDR(RGF_USER_USER_ICR)}, 1833b7cde470SVladimir Kondratiev {"DMA_EP_TX_ICR", HOSTADDR(RGF_DMA_EP_TX_ICR)}, 1834b7cde470SVladimir Kondratiev {"DMA_EP_RX_ICR", HOSTADDR(RGF_DMA_EP_RX_ICR)}, 1835b7cde470SVladimir Kondratiev {"DMA_EP_MISC_ICR", HOSTADDR(RGF_DMA_EP_MISC_ICR)}, 1836b7cde470SVladimir Kondratiev }; 1837b7cde470SVladimir Kondratiev 1838b7cde470SVladimir Kondratiev static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, 1839b7cde470SVladimir Kondratiev struct dentry *dbg) 1840b7cde470SVladimir Kondratiev { 1841b7cde470SVladimir Kondratiev int i; 1842b7cde470SVladimir Kondratiev 1843b7cde470SVladimir Kondratiev for (i = 0; i < ARRAY_SIZE(dbg_icr); i++) 1844b7cde470SVladimir Kondratiev wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg, 1845b7cde470SVladimir Kondratiev dbg_icr[i].icr_off); 1846b7cde470SVladimir Kondratiev } 1847b7cde470SVladimir Kondratiev 1848b7cde470SVladimir Kondratiev #define WIL_FIELD(name, mode, type) { __stringify(name), mode, \ 1849b7cde470SVladimir Kondratiev offsetof(struct wil6210_priv, name), type} 1850b7cde470SVladimir Kondratiev 1851b7cde470SVladimir Kondratiev /* fields in struct wil6210_priv */ 1852b7cde470SVladimir Kondratiev static const struct dbg_off dbg_wil_off[] = { 185378484c44SMaya Erez WIL_FIELD(status[0], 0644, doff_ulong), 185478484c44SMaya Erez WIL_FIELD(hw_version, 0444, doff_x32), 185578484c44SMaya Erez WIL_FIELD(recovery_count, 0444, doff_u32), 185678484c44SMaya Erez WIL_FIELD(discovery_mode, 0644, doff_u8), 185778484c44SMaya Erez WIL_FIELD(chip_revision, 0444, doff_u8), 185878484c44SMaya Erez WIL_FIELD(abft_len, 0644, doff_u8), 1859fe9ee51eSMaya Erez WIL_FIELD(wakeup_trigger, 0644, doff_u8), 186038d16ab2SGidon Studinski WIL_FIELD(vring_idle_trsh, 0644, doff_u32), 1861b7cde470SVladimir Kondratiev {}, 1862b7cde470SVladimir Kondratiev }; 1863b7cde470SVladimir Kondratiev 1864b7cde470SVladimir Kondratiev static const struct dbg_off dbg_wil_regs[] = { 186578484c44SMaya Erez {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0), 1866b7cde470SVladimir Kondratiev doff_io32}, 186778484c44SMaya Erez {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32}, 1868b7cde470SVladimir Kondratiev {}, 1869b7cde470SVladimir Kondratiev }; 1870b7cde470SVladimir Kondratiev 1871b7cde470SVladimir Kondratiev /* static parameters */ 1872b7cde470SVladimir Kondratiev static const struct dbg_off dbg_statics[] = { 187378484c44SMaya Erez {"desc_index", 0644, (ulong)&dbg_txdesc_index, doff_u32}, 187478484c44SMaya Erez {"vring_index", 0644, (ulong)&dbg_vring_index, doff_u32}, 187578484c44SMaya Erez {"mem_addr", 0644, (ulong)&mem_addr, doff_u32}, 187678484c44SMaya Erez {"led_polarity", 0644, (ulong)&led_polarity, doff_u8}, 1877b7cde470SVladimir Kondratiev {}, 1878b7cde470SVladimir Kondratiev }; 1879b7cde470SVladimir Kondratiev 188094162666SLazar Alexei static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) + 188194162666SLazar Alexei ARRAY_SIZE(dbg_wil_regs) - 1 + 188294162666SLazar Alexei ARRAY_SIZE(pseudo_isr_off) - 1 + 188394162666SLazar Alexei ARRAY_SIZE(lgc_itr_cnt_off) - 1 + 188494162666SLazar Alexei ARRAY_SIZE(tx_itr_cnt_off) - 1 + 188594162666SLazar Alexei ARRAY_SIZE(rx_itr_cnt_off) - 1; 188694162666SLazar Alexei 18872be7d22fSVladimir Kondratiev int wil6210_debugfs_init(struct wil6210_priv *wil) 18882be7d22fSVladimir Kondratiev { 18892be7d22fSVladimir Kondratiev struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, 18902be7d22fSVladimir Kondratiev wil_to_wiphy(wil)->debugfsdir); 18912be7d22fSVladimir Kondratiev if (IS_ERR_OR_NULL(dbg)) 18922be7d22fSVladimir Kondratiev return -ENODEV; 18932be7d22fSVladimir Kondratiev 189494162666SLazar Alexei wil->dbg_data.data_arr = kcalloc(dbg_off_count, 189594162666SLazar Alexei sizeof(struct wil_debugfs_iomem_data), 189694162666SLazar Alexei GFP_KERNEL); 189794162666SLazar Alexei if (!wil->dbg_data.data_arr) { 189894162666SLazar Alexei debugfs_remove_recursive(dbg); 189994162666SLazar Alexei wil->debug = NULL; 190094162666SLazar Alexei return -ENOMEM; 190194162666SLazar Alexei } 190294162666SLazar Alexei 190394162666SLazar Alexei wil->dbg_data.iomem_data_count = 0; 190494162666SLazar Alexei 1905dc16427bSVladimir Kondratiev wil_pmc_init(wil); 1906dc16427bSVladimir Kondratiev 1907b7cde470SVladimir Kondratiev wil6210_debugfs_init_files(wil, dbg); 1908b7cde470SVladimir Kondratiev wil6210_debugfs_init_isr(wil, dbg); 1909b541d0a0SVladimir Kondratiev wil6210_debugfs_init_blobs(wil, dbg); 1910b7cde470SVladimir Kondratiev wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off); 1911b7cde470SVladimir Kondratiev wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr, 1912b7cde470SVladimir Kondratiev dbg_wil_regs); 1913b7cde470SVladimir Kondratiev wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics); 1914b7cde470SVladimir Kondratiev 1915b7cde470SVladimir Kondratiev wil6210_debugfs_create_pseudo_ISR(wil, dbg); 1916b7cde470SVladimir Kondratiev 1917b7cde470SVladimir Kondratiev wil6210_debugfs_create_ITR_CNT(wil, dbg); 19182be7d22fSVladimir Kondratiev 19192be7d22fSVladimir Kondratiev return 0; 19202be7d22fSVladimir Kondratiev } 19212be7d22fSVladimir Kondratiev 19222be7d22fSVladimir Kondratiev void wil6210_debugfs_remove(struct wil6210_priv *wil) 19232be7d22fSVladimir Kondratiev { 19242be7d22fSVladimir Kondratiev debugfs_remove_recursive(wil->debug); 19252be7d22fSVladimir Kondratiev wil->debug = NULL; 1926dc16427bSVladimir Kondratiev 192794162666SLazar Alexei kfree(wil->dbg_data.data_arr); 192894162666SLazar Alexei 1929dc16427bSVladimir Kondratiev /* free pmc memory without sending command to fw, as it will 1930dc16427bSVladimir Kondratiev * be reset on the way down anyway 1931dc16427bSVladimir Kondratiev */ 1932dc16427bSVladimir Kondratiev wil_pmc_free(wil, false); 19332be7d22fSVladimir Kondratiev } 1934