18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci Broadcom B43 wireless driver 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci debugfs driver debugging code 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci*/ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/fs.h> 148c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "b43.h" 218c2ecf20Sopenharmony_ci#include "main.h" 228c2ecf20Sopenharmony_ci#include "debugfs.h" 238c2ecf20Sopenharmony_ci#include "dma.h" 248c2ecf20Sopenharmony_ci#include "xmit.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* The root directory. */ 288c2ecf20Sopenharmony_cistatic struct dentry *rootdir; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct b43_debugfs_fops { 318c2ecf20Sopenharmony_ci ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize); 328c2ecf20Sopenharmony_ci int (*write)(struct b43_wldev *dev, const char *buf, size_t count); 338c2ecf20Sopenharmony_ci struct file_operations fops; 348c2ecf20Sopenharmony_ci /* Offset of struct b43_dfs_file in struct b43_dfsentry */ 358c2ecf20Sopenharmony_ci size_t file_struct_offset; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline 398c2ecf20Sopenharmony_cistruct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev, 408c2ecf20Sopenharmony_ci const struct b43_debugfs_fops *dfops) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci void *p; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci p = dev->dfsentry; 458c2ecf20Sopenharmony_ci p += dfops->file_struct_offset; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return p; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define fappend(fmt, x...) \ 528c2ecf20Sopenharmony_ci do { \ 538c2ecf20Sopenharmony_ci if (bufsize - count) \ 548c2ecf20Sopenharmony_ci count += scnprintf(buf + count, \ 558c2ecf20Sopenharmony_ci bufsize - count, \ 568c2ecf20Sopenharmony_ci fmt , ##x); \ 578c2ecf20Sopenharmony_ci else \ 588c2ecf20Sopenharmony_ci printk(KERN_ERR "b43: fappend overflow\n"); \ 598c2ecf20Sopenharmony_ci } while (0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* The biggest address values for SHM access from the debugfs files. */ 638c2ecf20Sopenharmony_ci#define B43_MAX_SHM_ROUTING 4 648c2ecf20Sopenharmony_ci#define B43_MAX_SHM_ADDR 0xFFFF 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic ssize_t shm16read__read_file(struct b43_wldev *dev, 678c2ecf20Sopenharmony_ci char *buf, size_t bufsize) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci ssize_t count = 0; 708c2ecf20Sopenharmony_ci unsigned int routing, addr; 718c2ecf20Sopenharmony_ci u16 val; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci routing = dev->dfsentry->shm16read_routing_next; 748c2ecf20Sopenharmony_ci addr = dev->dfsentry->shm16read_addr_next; 758c2ecf20Sopenharmony_ci if ((routing > B43_MAX_SHM_ROUTING) || 768c2ecf20Sopenharmony_ci (addr > B43_MAX_SHM_ADDR)) 778c2ecf20Sopenharmony_ci return -EDESTADDRREQ; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci val = b43_shm_read16(dev, routing, addr); 808c2ecf20Sopenharmony_ci fappend("0x%04X\n", val); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return count; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int shm16read__write_file(struct b43_wldev *dev, 868c2ecf20Sopenharmony_ci const char *buf, size_t count) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci unsigned int routing, addr; 898c2ecf20Sopenharmony_ci int res; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X", &routing, &addr); 928c2ecf20Sopenharmony_ci if (res != 2) 938c2ecf20Sopenharmony_ci return -EINVAL; 948c2ecf20Sopenharmony_ci if (routing > B43_MAX_SHM_ROUTING) 958c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 968c2ecf20Sopenharmony_ci if (addr > B43_MAX_SHM_ADDR) 978c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 988c2ecf20Sopenharmony_ci if (routing == B43_SHM_SHARED) { 998c2ecf20Sopenharmony_ci if ((addr % 2) != 0) 1008c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci dev->dfsentry->shm16read_routing_next = routing; 1048c2ecf20Sopenharmony_ci dev->dfsentry->shm16read_addr_next = addr; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int shm16write__write_file(struct b43_wldev *dev, 1108c2ecf20Sopenharmony_ci const char *buf, size_t count) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci unsigned int routing, addr, mask, set; 1138c2ecf20Sopenharmony_ci u16 val; 1148c2ecf20Sopenharmony_ci int res; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", 1178c2ecf20Sopenharmony_ci &routing, &addr, &mask, &set); 1188c2ecf20Sopenharmony_ci if (res != 4) 1198c2ecf20Sopenharmony_ci return -EINVAL; 1208c2ecf20Sopenharmony_ci if (routing > B43_MAX_SHM_ROUTING) 1218c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1228c2ecf20Sopenharmony_ci if (addr > B43_MAX_SHM_ADDR) 1238c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1248c2ecf20Sopenharmony_ci if (routing == B43_SHM_SHARED) { 1258c2ecf20Sopenharmony_ci if ((addr % 2) != 0) 1268c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci if ((mask > 0xFFFF) || (set > 0xFFFF)) 1298c2ecf20Sopenharmony_ci return -E2BIG; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (mask == 0) 1328c2ecf20Sopenharmony_ci val = 0; 1338c2ecf20Sopenharmony_ci else 1348c2ecf20Sopenharmony_ci val = b43_shm_read16(dev, routing, addr); 1358c2ecf20Sopenharmony_ci val &= mask; 1368c2ecf20Sopenharmony_ci val |= set; 1378c2ecf20Sopenharmony_ci b43_shm_write16(dev, routing, addr, val); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic ssize_t shm32read__read_file(struct b43_wldev *dev, 1438c2ecf20Sopenharmony_ci char *buf, size_t bufsize) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci ssize_t count = 0; 1468c2ecf20Sopenharmony_ci unsigned int routing, addr; 1478c2ecf20Sopenharmony_ci u32 val; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci routing = dev->dfsentry->shm32read_routing_next; 1508c2ecf20Sopenharmony_ci addr = dev->dfsentry->shm32read_addr_next; 1518c2ecf20Sopenharmony_ci if ((routing > B43_MAX_SHM_ROUTING) || 1528c2ecf20Sopenharmony_ci (addr > B43_MAX_SHM_ADDR)) 1538c2ecf20Sopenharmony_ci return -EDESTADDRREQ; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci val = b43_shm_read32(dev, routing, addr); 1568c2ecf20Sopenharmony_ci fappend("0x%08X\n", val); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return count; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int shm32read__write_file(struct b43_wldev *dev, 1628c2ecf20Sopenharmony_ci const char *buf, size_t count) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci unsigned int routing, addr; 1658c2ecf20Sopenharmony_ci int res; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X", &routing, &addr); 1688c2ecf20Sopenharmony_ci if (res != 2) 1698c2ecf20Sopenharmony_ci return -EINVAL; 1708c2ecf20Sopenharmony_ci if (routing > B43_MAX_SHM_ROUTING) 1718c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1728c2ecf20Sopenharmony_ci if (addr > B43_MAX_SHM_ADDR) 1738c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1748c2ecf20Sopenharmony_ci if (routing == B43_SHM_SHARED) { 1758c2ecf20Sopenharmony_ci if ((addr % 2) != 0) 1768c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci dev->dfsentry->shm32read_routing_next = routing; 1808c2ecf20Sopenharmony_ci dev->dfsentry->shm32read_addr_next = addr; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int shm32write__write_file(struct b43_wldev *dev, 1868c2ecf20Sopenharmony_ci const char *buf, size_t count) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci unsigned int routing, addr, mask, set; 1898c2ecf20Sopenharmony_ci u32 val; 1908c2ecf20Sopenharmony_ci int res; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X", 1938c2ecf20Sopenharmony_ci &routing, &addr, &mask, &set); 1948c2ecf20Sopenharmony_ci if (res != 4) 1958c2ecf20Sopenharmony_ci return -EINVAL; 1968c2ecf20Sopenharmony_ci if (routing > B43_MAX_SHM_ROUTING) 1978c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 1988c2ecf20Sopenharmony_ci if (addr > B43_MAX_SHM_ADDR) 1998c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 2008c2ecf20Sopenharmony_ci if (routing == B43_SHM_SHARED) { 2018c2ecf20Sopenharmony_ci if ((addr % 2) != 0) 2028c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) 2058c2ecf20Sopenharmony_ci return -E2BIG; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (mask == 0) 2088c2ecf20Sopenharmony_ci val = 0; 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci val = b43_shm_read32(dev, routing, addr); 2118c2ecf20Sopenharmony_ci val &= mask; 2128c2ecf20Sopenharmony_ci val |= set; 2138c2ecf20Sopenharmony_ci b43_shm_write32(dev, routing, addr, val); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* The biggest MMIO address that we allow access to from the debugfs files. */ 2198c2ecf20Sopenharmony_ci#define B43_MAX_MMIO_ACCESS (0xF00 - 1) 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic ssize_t mmio16read__read_file(struct b43_wldev *dev, 2228c2ecf20Sopenharmony_ci char *buf, size_t bufsize) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci ssize_t count = 0; 2258c2ecf20Sopenharmony_ci unsigned int addr; 2268c2ecf20Sopenharmony_ci u16 val; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci addr = dev->dfsentry->mmio16read_next; 2298c2ecf20Sopenharmony_ci if (addr > B43_MAX_MMIO_ACCESS) 2308c2ecf20Sopenharmony_ci return -EDESTADDRREQ; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci val = b43_read16(dev, addr); 2338c2ecf20Sopenharmony_ci fappend("0x%04X\n", val); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return count; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int mmio16read__write_file(struct b43_wldev *dev, 2398c2ecf20Sopenharmony_ci const char *buf, size_t count) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci unsigned int addr; 2428c2ecf20Sopenharmony_ci int res; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X", &addr); 2458c2ecf20Sopenharmony_ci if (res != 1) 2468c2ecf20Sopenharmony_ci return -EINVAL; 2478c2ecf20Sopenharmony_ci if (addr > B43_MAX_MMIO_ACCESS) 2488c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 2498c2ecf20Sopenharmony_ci if ((addr % 2) != 0) 2508c2ecf20Sopenharmony_ci return -EINVAL; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dev->dfsentry->mmio16read_next = addr; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic int mmio16write__write_file(struct b43_wldev *dev, 2588c2ecf20Sopenharmony_ci const char *buf, size_t count) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci unsigned int addr, mask, set; 2618c2ecf20Sopenharmony_ci int res; 2628c2ecf20Sopenharmony_ci u16 val; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set); 2658c2ecf20Sopenharmony_ci if (res != 3) 2668c2ecf20Sopenharmony_ci return -EINVAL; 2678c2ecf20Sopenharmony_ci if (addr > B43_MAX_MMIO_ACCESS) 2688c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 2698c2ecf20Sopenharmony_ci if ((mask > 0xFFFF) || (set > 0xFFFF)) 2708c2ecf20Sopenharmony_ci return -E2BIG; 2718c2ecf20Sopenharmony_ci if ((addr % 2) != 0) 2728c2ecf20Sopenharmony_ci return -EINVAL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (mask == 0) 2758c2ecf20Sopenharmony_ci val = 0; 2768c2ecf20Sopenharmony_ci else 2778c2ecf20Sopenharmony_ci val = b43_read16(dev, addr); 2788c2ecf20Sopenharmony_ci val &= mask; 2798c2ecf20Sopenharmony_ci val |= set; 2808c2ecf20Sopenharmony_ci b43_write16(dev, addr, val); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic ssize_t mmio32read__read_file(struct b43_wldev *dev, 2868c2ecf20Sopenharmony_ci char *buf, size_t bufsize) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci ssize_t count = 0; 2898c2ecf20Sopenharmony_ci unsigned int addr; 2908c2ecf20Sopenharmony_ci u32 val; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci addr = dev->dfsentry->mmio32read_next; 2938c2ecf20Sopenharmony_ci if (addr > B43_MAX_MMIO_ACCESS) 2948c2ecf20Sopenharmony_ci return -EDESTADDRREQ; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci val = b43_read32(dev, addr); 2978c2ecf20Sopenharmony_ci fappend("0x%08X\n", val); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return count; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int mmio32read__write_file(struct b43_wldev *dev, 3038c2ecf20Sopenharmony_ci const char *buf, size_t count) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci unsigned int addr; 3068c2ecf20Sopenharmony_ci int res; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X", &addr); 3098c2ecf20Sopenharmony_ci if (res != 1) 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci if (addr > B43_MAX_MMIO_ACCESS) 3128c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 3138c2ecf20Sopenharmony_ci if ((addr % 4) != 0) 3148c2ecf20Sopenharmony_ci return -EINVAL; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci dev->dfsentry->mmio32read_next = addr; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int mmio32write__write_file(struct b43_wldev *dev, 3228c2ecf20Sopenharmony_ci const char *buf, size_t count) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci unsigned int addr, mask, set; 3258c2ecf20Sopenharmony_ci int res; 3268c2ecf20Sopenharmony_ci u32 val; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set); 3298c2ecf20Sopenharmony_ci if (res != 3) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci if (addr > B43_MAX_MMIO_ACCESS) 3328c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 3338c2ecf20Sopenharmony_ci if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF)) 3348c2ecf20Sopenharmony_ci return -E2BIG; 3358c2ecf20Sopenharmony_ci if ((addr % 4) != 0) 3368c2ecf20Sopenharmony_ci return -EINVAL; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (mask == 0) 3398c2ecf20Sopenharmony_ci val = 0; 3408c2ecf20Sopenharmony_ci else 3418c2ecf20Sopenharmony_ci val = b43_read32(dev, addr); 3428c2ecf20Sopenharmony_ci val &= mask; 3438c2ecf20Sopenharmony_ci val |= set; 3448c2ecf20Sopenharmony_ci b43_write32(dev, addr, val); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic ssize_t txstat_read_file(struct b43_wldev *dev, 3508c2ecf20Sopenharmony_ci char *buf, size_t bufsize) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct b43_txstatus_log *log = &dev->dfsentry->txstatlog; 3538c2ecf20Sopenharmony_ci ssize_t count = 0; 3548c2ecf20Sopenharmony_ci int i, idx; 3558c2ecf20Sopenharmony_ci struct b43_txstatus *stat; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (log->end < 0) { 3588c2ecf20Sopenharmony_ci fappend("Nothing transmitted, yet\n"); 3598c2ecf20Sopenharmony_ci goto out; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci fappend("b43 TX status reports:\n\n" 3628c2ecf20Sopenharmony_ci "index | cookie | seq | phy_stat | frame_count | " 3638c2ecf20Sopenharmony_ci "rts_count | supp_reason | pm_indicated | " 3648c2ecf20Sopenharmony_ci "intermediate | for_ampdu | acked\n" "---\n"); 3658c2ecf20Sopenharmony_ci i = log->end + 1; 3668c2ecf20Sopenharmony_ci idx = 0; 3678c2ecf20Sopenharmony_ci while (1) { 3688c2ecf20Sopenharmony_ci if (i == B43_NR_LOGGED_TXSTATUS) 3698c2ecf20Sopenharmony_ci i = 0; 3708c2ecf20Sopenharmony_ci stat = &(log->log[i]); 3718c2ecf20Sopenharmony_ci if (stat->cookie) { 3728c2ecf20Sopenharmony_ci fappend("%03d | " 3738c2ecf20Sopenharmony_ci "0x%04X | 0x%04X | 0x%02X | " 3748c2ecf20Sopenharmony_ci "0x%X | 0x%X | " 3758c2ecf20Sopenharmony_ci "%u | %u | " 3768c2ecf20Sopenharmony_ci "%u | %u | %u\n", 3778c2ecf20Sopenharmony_ci idx, 3788c2ecf20Sopenharmony_ci stat->cookie, stat->seq, stat->phy_stat, 3798c2ecf20Sopenharmony_ci stat->frame_count, stat->rts_count, 3808c2ecf20Sopenharmony_ci stat->supp_reason, stat->pm_indicated, 3818c2ecf20Sopenharmony_ci stat->intermediate, stat->for_ampdu, 3828c2ecf20Sopenharmony_ci stat->acked); 3838c2ecf20Sopenharmony_ci idx++; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci if (i == log->end) 3868c2ecf20Sopenharmony_ci break; 3878c2ecf20Sopenharmony_ci i++; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ciout: 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return count; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int restart_write_file(struct b43_wldev *dev, 3958c2ecf20Sopenharmony_ci const char *buf, size_t count) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci int err = 0; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (count > 0 && buf[0] == '1') { 4008c2ecf20Sopenharmony_ci b43_controller_restart(dev, "manually restarted"); 4018c2ecf20Sopenharmony_ci } else 4028c2ecf20Sopenharmony_ci err = -EINVAL; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return err; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic unsigned long calc_expire_secs(unsigned long now, 4088c2ecf20Sopenharmony_ci unsigned long time, 4098c2ecf20Sopenharmony_ci unsigned long expire) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci expire = time + expire; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (time_after(now, expire)) 4148c2ecf20Sopenharmony_ci return 0; /* expired */ 4158c2ecf20Sopenharmony_ci if (expire < now) { 4168c2ecf20Sopenharmony_ci /* jiffies wrapped */ 4178c2ecf20Sopenharmony_ci expire -= MAX_JIFFY_OFFSET; 4188c2ecf20Sopenharmony_ci now -= MAX_JIFFY_OFFSET; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci B43_WARN_ON(expire < now); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return (expire - now) / HZ; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic ssize_t loctls_read_file(struct b43_wldev *dev, 4268c2ecf20Sopenharmony_ci char *buf, size_t bufsize) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci ssize_t count = 0; 4298c2ecf20Sopenharmony_ci struct b43_txpower_lo_control *lo; 4308c2ecf20Sopenharmony_ci int i, err = 0; 4318c2ecf20Sopenharmony_ci struct b43_lo_calib *cal; 4328c2ecf20Sopenharmony_ci unsigned long now = jiffies; 4338c2ecf20Sopenharmony_ci struct b43_phy *phy = &dev->phy; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (phy->type != B43_PHYTYPE_G) { 4368c2ecf20Sopenharmony_ci fappend("Device is not a G-PHY\n"); 4378c2ecf20Sopenharmony_ci err = -ENODEV; 4388c2ecf20Sopenharmony_ci goto out; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci lo = phy->g->lo_control; 4418c2ecf20Sopenharmony_ci fappend("-- Local Oscillator calibration data --\n\n"); 4428c2ecf20Sopenharmony_ci fappend("HW-power-control enabled: %d\n", 4438c2ecf20Sopenharmony_ci dev->phy.hardware_power_control); 4448c2ecf20Sopenharmony_ci fappend("TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec)\n", 4458c2ecf20Sopenharmony_ci lo->tx_bias, lo->tx_magn, 4468c2ecf20Sopenharmony_ci calc_expire_secs(now, lo->txctl_measured_time, 4478c2ecf20Sopenharmony_ci B43_LO_TXCTL_EXPIRE)); 4488c2ecf20Sopenharmony_ci fappend("Power Vector: 0x%08X%08X (expires in %lu sec)\n", 4498c2ecf20Sopenharmony_ci (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32), 4508c2ecf20Sopenharmony_ci (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL), 4518c2ecf20Sopenharmony_ci calc_expire_secs(now, lo->pwr_vec_read_time, 4528c2ecf20Sopenharmony_ci B43_LO_PWRVEC_EXPIRE)); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci fappend("\nCalibrated settings:\n"); 4558c2ecf20Sopenharmony_ci list_for_each_entry(cal, &lo->calib_list, list) { 4568c2ecf20Sopenharmony_ci bool active; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) && 4598c2ecf20Sopenharmony_ci b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt)); 4608c2ecf20Sopenharmony_ci fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " 4618c2ecf20Sopenharmony_ci "(expires in %lu sec)%s\n", 4628c2ecf20Sopenharmony_ci cal->bbatt.att, 4638c2ecf20Sopenharmony_ci cal->rfatt.att, cal->rfatt.with_padmix, 4648c2ecf20Sopenharmony_ci cal->ctl.i, cal->ctl.q, 4658c2ecf20Sopenharmony_ci calc_expire_secs(now, cal->calib_time, 4668c2ecf20Sopenharmony_ci B43_LO_CALIB_EXPIRE), 4678c2ecf20Sopenharmony_ci active ? " ACTIVE" : ""); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n"); 4718c2ecf20Sopenharmony_ci for (i = 0; i < lo->rfatt_list.len; i++) { 4728c2ecf20Sopenharmony_ci fappend("%u(%d), ", 4738c2ecf20Sopenharmony_ci lo->rfatt_list.list[i].att, 4748c2ecf20Sopenharmony_ci lo->rfatt_list.list[i].with_padmix); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci fappend("\n"); 4778c2ecf20Sopenharmony_ci fappend("\nUsed Baseband attenuation values:\n"); 4788c2ecf20Sopenharmony_ci for (i = 0; i < lo->bbatt_list.len; i++) { 4798c2ecf20Sopenharmony_ci fappend("%u, ", 4808c2ecf20Sopenharmony_ci lo->bbatt_list.list[i].att); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci fappend("\n"); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ciout: 4858c2ecf20Sopenharmony_ci return err ? err : count; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci#undef fappend 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, 4918c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct b43_wldev *dev; 4948c2ecf20Sopenharmony_ci struct b43_debugfs_fops *dfops; 4958c2ecf20Sopenharmony_ci struct b43_dfs_file *dfile; 4968c2ecf20Sopenharmony_ci ssize_t ret; 4978c2ecf20Sopenharmony_ci char *buf; 4988c2ecf20Sopenharmony_ci const size_t bufsize = 1024 * 16; /* 16 kiB buffer */ 4998c2ecf20Sopenharmony_ci const size_t buforder = get_order(bufsize); 5008c2ecf20Sopenharmony_ci int err = 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (!count) 5038c2ecf20Sopenharmony_ci return 0; 5048c2ecf20Sopenharmony_ci dev = file->private_data; 5058c2ecf20Sopenharmony_ci if (!dev) 5068c2ecf20Sopenharmony_ci return -ENODEV; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci mutex_lock(&dev->wl->mutex); 5098c2ecf20Sopenharmony_ci if (b43_status(dev) < B43_STAT_INITIALIZED) { 5108c2ecf20Sopenharmony_ci err = -ENODEV; 5118c2ecf20Sopenharmony_ci goto out_unlock; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci dfops = container_of(debugfs_real_fops(file), 5158c2ecf20Sopenharmony_ci struct b43_debugfs_fops, fops); 5168c2ecf20Sopenharmony_ci if (!dfops->read) { 5178c2ecf20Sopenharmony_ci err = -ENOSYS; 5188c2ecf20Sopenharmony_ci goto out_unlock; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci dfile = fops_to_dfs_file(dev, dfops); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (!dfile->buffer) { 5238c2ecf20Sopenharmony_ci buf = (char *)__get_free_pages(GFP_KERNEL, buforder); 5248c2ecf20Sopenharmony_ci if (!buf) { 5258c2ecf20Sopenharmony_ci err = -ENOMEM; 5268c2ecf20Sopenharmony_ci goto out_unlock; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci memset(buf, 0, bufsize); 5298c2ecf20Sopenharmony_ci ret = dfops->read(dev, buf, bufsize); 5308c2ecf20Sopenharmony_ci if (ret <= 0) { 5318c2ecf20Sopenharmony_ci free_pages((unsigned long)buf, buforder); 5328c2ecf20Sopenharmony_ci err = ret; 5338c2ecf20Sopenharmony_ci goto out_unlock; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci dfile->data_len = ret; 5368c2ecf20Sopenharmony_ci dfile->buffer = buf; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, 5408c2ecf20Sopenharmony_ci dfile->buffer, 5418c2ecf20Sopenharmony_ci dfile->data_len); 5428c2ecf20Sopenharmony_ci if (*ppos >= dfile->data_len) { 5438c2ecf20Sopenharmony_ci free_pages((unsigned long)dfile->buffer, buforder); 5448c2ecf20Sopenharmony_ci dfile->buffer = NULL; 5458c2ecf20Sopenharmony_ci dfile->data_len = 0; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ciout_unlock: 5488c2ecf20Sopenharmony_ci mutex_unlock(&dev->wl->mutex); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return err ? err : ret; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic ssize_t b43_debugfs_write(struct file *file, 5548c2ecf20Sopenharmony_ci const char __user *userbuf, 5558c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct b43_wldev *dev; 5588c2ecf20Sopenharmony_ci struct b43_debugfs_fops *dfops; 5598c2ecf20Sopenharmony_ci char *buf; 5608c2ecf20Sopenharmony_ci int err = 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (!count) 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci if (count > PAGE_SIZE) 5658c2ecf20Sopenharmony_ci return -E2BIG; 5668c2ecf20Sopenharmony_ci dev = file->private_data; 5678c2ecf20Sopenharmony_ci if (!dev) 5688c2ecf20Sopenharmony_ci return -ENODEV; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci mutex_lock(&dev->wl->mutex); 5718c2ecf20Sopenharmony_ci if (b43_status(dev) < B43_STAT_INITIALIZED) { 5728c2ecf20Sopenharmony_ci err = -ENODEV; 5738c2ecf20Sopenharmony_ci goto out_unlock; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci dfops = container_of(debugfs_real_fops(file), 5778c2ecf20Sopenharmony_ci struct b43_debugfs_fops, fops); 5788c2ecf20Sopenharmony_ci if (!dfops->write) { 5798c2ecf20Sopenharmony_ci err = -ENOSYS; 5808c2ecf20Sopenharmony_ci goto out_unlock; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci buf = (char *)get_zeroed_page(GFP_KERNEL); 5848c2ecf20Sopenharmony_ci if (!buf) { 5858c2ecf20Sopenharmony_ci err = -ENOMEM; 5868c2ecf20Sopenharmony_ci goto out_unlock; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci if (copy_from_user(buf, userbuf, count)) { 5898c2ecf20Sopenharmony_ci err = -EFAULT; 5908c2ecf20Sopenharmony_ci goto out_freepage; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci err = dfops->write(dev, buf, count); 5938c2ecf20Sopenharmony_ci if (err) 5948c2ecf20Sopenharmony_ci goto out_freepage; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ciout_freepage: 5978c2ecf20Sopenharmony_ci free_page((unsigned long)buf); 5988c2ecf20Sopenharmony_ciout_unlock: 5998c2ecf20Sopenharmony_ci mutex_unlock(&dev->wl->mutex); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return err ? err : count; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci#define B43_DEBUGFS_FOPS(name, _read, _write) \ 6068c2ecf20Sopenharmony_ci static struct b43_debugfs_fops fops_##name = { \ 6078c2ecf20Sopenharmony_ci .read = _read, \ 6088c2ecf20Sopenharmony_ci .write = _write, \ 6098c2ecf20Sopenharmony_ci .fops = { \ 6108c2ecf20Sopenharmony_ci .open = simple_open, \ 6118c2ecf20Sopenharmony_ci .read = b43_debugfs_read, \ 6128c2ecf20Sopenharmony_ci .write = b43_debugfs_write, \ 6138c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, \ 6148c2ecf20Sopenharmony_ci }, \ 6158c2ecf20Sopenharmony_ci .file_struct_offset = offsetof(struct b43_dfsentry, \ 6168c2ecf20Sopenharmony_ci file_##name), \ 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file); 6208c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file); 6218c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file); 6228c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file); 6238c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file); 6248c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file); 6258c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file); 6268c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file); 6278c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL); 6288c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(restart, NULL, restart_write_file); 6298c2ecf20Sopenharmony_ciB43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_cibool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci bool enabled; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci enabled = (dev->dfsentry && dev->dfsentry->dyn_debug[feature]); 6378c2ecf20Sopenharmony_ci if (unlikely(enabled)) { 6388c2ecf20Sopenharmony_ci /* Force full debugging messages, if the user enabled 6398c2ecf20Sopenharmony_ci * some dynamic debugging feature. */ 6408c2ecf20Sopenharmony_ci b43_modparam_verbose = B43_VERBOSITY_MAX; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return enabled; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic void b43_remove_dynamic_debug(struct b43_wldev *dev) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct b43_dfsentry *e = dev->dfsentry; 6498c2ecf20Sopenharmony_ci int i; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci for (i = 0; i < __B43_NR_DYNDBG; i++) 6528c2ecf20Sopenharmony_ci debugfs_remove(e->dyn_debug_dentries[i]); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic void b43_add_dynamic_debug(struct b43_wldev *dev) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct b43_dfsentry *e = dev->dfsentry; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci#define add_dyn_dbg(name, id, initstate) do { \ 6608c2ecf20Sopenharmony_ci e->dyn_debug[id] = (initstate); \ 6618c2ecf20Sopenharmony_ci e->dyn_debug_dentries[id] = \ 6628c2ecf20Sopenharmony_ci debugfs_create_bool(name, 0600, e->subdir, \ 6638c2ecf20Sopenharmony_ci &(e->dyn_debug[id])); \ 6648c2ecf20Sopenharmony_ci } while (0) 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, false); 6678c2ecf20Sopenharmony_ci add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, false); 6688c2ecf20Sopenharmony_ci add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, false); 6698c2ecf20Sopenharmony_ci add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, false); 6708c2ecf20Sopenharmony_ci add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, false); 6718c2ecf20Sopenharmony_ci add_dyn_dbg("debug_lo", B43_DBG_LO, false); 6728c2ecf20Sopenharmony_ci add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, false); 6738c2ecf20Sopenharmony_ci add_dyn_dbg("debug_keys", B43_DBG_KEYS, false); 6748c2ecf20Sopenharmony_ci add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, false); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci#undef add_dyn_dbg 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_civoid b43_debugfs_add_device(struct b43_wldev *dev) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct b43_dfsentry *e; 6828c2ecf20Sopenharmony_ci struct b43_txstatus_log *log; 6838c2ecf20Sopenharmony_ci char devdir[16]; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci B43_WARN_ON(!dev); 6868c2ecf20Sopenharmony_ci e = kzalloc(sizeof(*e), GFP_KERNEL); 6878c2ecf20Sopenharmony_ci if (!e) { 6888c2ecf20Sopenharmony_ci b43err(dev->wl, "debugfs: add device OOM\n"); 6898c2ecf20Sopenharmony_ci return; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci e->dev = dev; 6928c2ecf20Sopenharmony_ci log = &e->txstatlog; 6938c2ecf20Sopenharmony_ci log->log = kcalloc(B43_NR_LOGGED_TXSTATUS, 6948c2ecf20Sopenharmony_ci sizeof(struct b43_txstatus), GFP_KERNEL); 6958c2ecf20Sopenharmony_ci if (!log->log) { 6968c2ecf20Sopenharmony_ci b43err(dev->wl, "debugfs: add device txstatus OOM\n"); 6978c2ecf20Sopenharmony_ci kfree(e); 6988c2ecf20Sopenharmony_ci return; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci log->end = -1; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci dev->dfsentry = e; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy)); 7058c2ecf20Sopenharmony_ci e->subdir = debugfs_create_dir(devdir, rootdir); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci e->mmio16read_next = 0xFFFF; /* invalid address */ 7088c2ecf20Sopenharmony_ci e->mmio32read_next = 0xFFFF; /* invalid address */ 7098c2ecf20Sopenharmony_ci e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */ 7108c2ecf20Sopenharmony_ci e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */ 7118c2ecf20Sopenharmony_ci e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */ 7128c2ecf20Sopenharmony_ci e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */ 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci#define ADD_FILE(name, mode) \ 7158c2ecf20Sopenharmony_ci do { \ 7168c2ecf20Sopenharmony_ci e->file_##name.dentry = \ 7178c2ecf20Sopenharmony_ci debugfs_create_file(__stringify(name), \ 7188c2ecf20Sopenharmony_ci mode, e->subdir, dev, \ 7198c2ecf20Sopenharmony_ci &fops_##name.fops); \ 7208c2ecf20Sopenharmony_ci } while (0) 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ADD_FILE(shm16read, 0600); 7248c2ecf20Sopenharmony_ci ADD_FILE(shm16write, 0200); 7258c2ecf20Sopenharmony_ci ADD_FILE(shm32read, 0600); 7268c2ecf20Sopenharmony_ci ADD_FILE(shm32write, 0200); 7278c2ecf20Sopenharmony_ci ADD_FILE(mmio16read, 0600); 7288c2ecf20Sopenharmony_ci ADD_FILE(mmio16write, 0200); 7298c2ecf20Sopenharmony_ci ADD_FILE(mmio32read, 0600); 7308c2ecf20Sopenharmony_ci ADD_FILE(mmio32write, 0200); 7318c2ecf20Sopenharmony_ci ADD_FILE(txstat, 0400); 7328c2ecf20Sopenharmony_ci ADD_FILE(restart, 0200); 7338c2ecf20Sopenharmony_ci ADD_FILE(loctls, 0400); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci#undef ADD_FILE 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci b43_add_dynamic_debug(dev); 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_civoid b43_debugfs_remove_device(struct b43_wldev *dev) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct b43_dfsentry *e; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (!dev) 7458c2ecf20Sopenharmony_ci return; 7468c2ecf20Sopenharmony_ci e = dev->dfsentry; 7478c2ecf20Sopenharmony_ci if (!e) 7488c2ecf20Sopenharmony_ci return; 7498c2ecf20Sopenharmony_ci b43_remove_dynamic_debug(dev); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci debugfs_remove(e->file_shm16read.dentry); 7528c2ecf20Sopenharmony_ci debugfs_remove(e->file_shm16write.dentry); 7538c2ecf20Sopenharmony_ci debugfs_remove(e->file_shm32read.dentry); 7548c2ecf20Sopenharmony_ci debugfs_remove(e->file_shm32write.dentry); 7558c2ecf20Sopenharmony_ci debugfs_remove(e->file_mmio16read.dentry); 7568c2ecf20Sopenharmony_ci debugfs_remove(e->file_mmio16write.dentry); 7578c2ecf20Sopenharmony_ci debugfs_remove(e->file_mmio32read.dentry); 7588c2ecf20Sopenharmony_ci debugfs_remove(e->file_mmio32write.dentry); 7598c2ecf20Sopenharmony_ci debugfs_remove(e->file_txstat.dentry); 7608c2ecf20Sopenharmony_ci debugfs_remove(e->file_restart.dentry); 7618c2ecf20Sopenharmony_ci debugfs_remove(e->file_loctls.dentry); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci debugfs_remove(e->subdir); 7648c2ecf20Sopenharmony_ci kfree(e->txstatlog.log); 7658c2ecf20Sopenharmony_ci kfree(e); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_civoid b43_debugfs_log_txstat(struct b43_wldev *dev, 7698c2ecf20Sopenharmony_ci const struct b43_txstatus *status) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct b43_dfsentry *e = dev->dfsentry; 7728c2ecf20Sopenharmony_ci struct b43_txstatus_log *log; 7738c2ecf20Sopenharmony_ci struct b43_txstatus *cur; 7748c2ecf20Sopenharmony_ci int i; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (!e) 7778c2ecf20Sopenharmony_ci return; 7788c2ecf20Sopenharmony_ci log = &e->txstatlog; 7798c2ecf20Sopenharmony_ci i = log->end + 1; 7808c2ecf20Sopenharmony_ci if (i == B43_NR_LOGGED_TXSTATUS) 7818c2ecf20Sopenharmony_ci i = 0; 7828c2ecf20Sopenharmony_ci log->end = i; 7838c2ecf20Sopenharmony_ci cur = &(log->log[i]); 7848c2ecf20Sopenharmony_ci memcpy(cur, status, sizeof(*cur)); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_civoid b43_debugfs_init(void) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_civoid b43_debugfs_exit(void) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci debugfs_remove(rootdir); 7958c2ecf20Sopenharmony_ci} 796