PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/net/wireless/b43legacy/debugfs.c

https://bitbucket.org/EaglesBlood_Development/eb_grouper
C | 506 lines | 401 code | 73 blank | 32 comment | 54 complexity | 22565695e9c42fa64a3ca64033211720 MD5 | raw file
  1. /*
  2. Broadcom B43legacy wireless driver
  3. debugfs driver debugging code
  4. Copyright (c) 2005-2007 Michael Buesch <m@bues.ch>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; see the file COPYING. If not, write to
  15. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  16. Boston, MA 02110-1301, USA.
  17. */
  18. #include <linux/fs.h>
  19. #include <linux/debugfs.h>
  20. #include <linux/slab.h>
  21. #include <linux/netdevice.h>
  22. #include <linux/pci.h>
  23. #include <linux/mutex.h>
  24. #include "b43legacy.h"
  25. #include "main.h"
  26. #include "debugfs.h"
  27. #include "dma.h"
  28. #include "pio.h"
  29. #include "xmit.h"
  30. /* The root directory. */
  31. static struct dentry *rootdir;
  32. struct b43legacy_debugfs_fops {
  33. ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize);
  34. int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count);
  35. struct file_operations fops;
  36. /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */
  37. size_t file_struct_offset;
  38. /* Take wl->irq_lock before calling read/write? */
  39. bool take_irqlock;
  40. };
  41. static inline
  42. struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev,
  43. const struct b43legacy_debugfs_fops *dfops)
  44. {
  45. void *p;
  46. p = dev->dfsentry;
  47. p += dfops->file_struct_offset;
  48. return p;
  49. }
  50. #define fappend(fmt, x...) \
  51. do { \
  52. if (bufsize - count) \
  53. count += snprintf(buf + count, \
  54. bufsize - count, \
  55. fmt , ##x); \
  56. else \
  57. printk(KERN_ERR "b43legacy: fappend overflow\n"); \
  58. } while (0)
  59. /* wl->irq_lock is locked */
  60. static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
  61. {
  62. ssize_t count = 0;
  63. u64 tsf;
  64. b43legacy_tsf_read(dev, &tsf);
  65. fappend("0x%08x%08x\n",
  66. (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
  67. (unsigned int)(tsf & 0xFFFFFFFFULL));
  68. return count;
  69. }
  70. /* wl->irq_lock is locked */
  71. static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
  72. {
  73. u64 tsf;
  74. if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
  75. return -EINVAL;
  76. b43legacy_tsf_write(dev, tsf);
  77. return 0;
  78. }
  79. /* wl->irq_lock is locked */
  80. static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
  81. {
  82. ssize_t count = 0;
  83. int i;
  84. for (i = 0; i < 64; i++) {
  85. fappend("r%d = 0x%04x\n", i,
  86. b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i));
  87. }
  88. return count;
  89. }
  90. /* wl->irq_lock is locked */
  91. static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
  92. {
  93. ssize_t count = 0;
  94. int i;
  95. u16 tmp;
  96. __le16 *le16buf = (__le16 *)buf;
  97. for (i = 0; i < 0x1000; i++) {
  98. if (bufsize < sizeof(tmp))
  99. break;
  100. tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
  101. le16buf[i] = cpu_to_le16(tmp);
  102. count += sizeof(tmp);
  103. bufsize -= sizeof(tmp);
  104. }
  105. return count;
  106. }
  107. static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
  108. {
  109. struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog;
  110. ssize_t count = 0;
  111. unsigned long flags;
  112. int i, idx;
  113. struct b43legacy_txstatus *stat;
  114. spin_lock_irqsave(&log->lock, flags);
  115. if (log->end < 0) {
  116. fappend("Nothing transmitted, yet\n");
  117. goto out_unlock;
  118. }
  119. fappend("b43legacy TX status reports:\n\n"
  120. "index | cookie | seq | phy_stat | frame_count | "
  121. "rts_count | supp_reason | pm_indicated | "
  122. "intermediate | for_ampdu | acked\n" "---\n");
  123. i = log->end + 1;
  124. idx = 0;
  125. while (1) {
  126. if (i == B43legacy_NR_LOGGED_TXSTATUS)
  127. i = 0;
  128. stat = &(log->log[i]);
  129. if (stat->cookie) {
  130. fappend("%03d | "
  131. "0x%04X | 0x%04X | 0x%02X | "
  132. "0x%X | 0x%X | "
  133. "%u | %u | "
  134. "%u | %u | %u\n",
  135. idx,
  136. stat->cookie, stat->seq, stat->phy_stat,
  137. stat->frame_count, stat->rts_count,
  138. stat->supp_reason, stat->pm_indicated,
  139. stat->intermediate, stat->for_ampdu,
  140. stat->acked);
  141. idx++;
  142. }
  143. if (i == log->end)
  144. break;
  145. i++;
  146. }
  147. out_unlock:
  148. spin_unlock_irqrestore(&log->lock, flags);
  149. return count;
  150. }
  151. /* wl->irq_lock is locked */
  152. static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
  153. {
  154. int err = 0;
  155. if (count > 0 && buf[0] == '1') {
  156. b43legacy_controller_restart(dev, "manually restarted");
  157. } else
  158. err = -EINVAL;
  159. return err;
  160. }
  161. #undef fappend
  162. static int b43legacy_debugfs_open(struct inode *inode, struct file *file)
  163. {
  164. file->private_data = inode->i_private;
  165. return 0;
  166. }
  167. static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
  168. size_t count, loff_t *ppos)
  169. {
  170. struct b43legacy_wldev *dev;
  171. struct b43legacy_debugfs_fops *dfops;
  172. struct b43legacy_dfs_file *dfile;
  173. ssize_t uninitialized_var(ret);
  174. char *buf;
  175. const size_t bufsize = 1024 * 16; /* 16 KiB buffer */
  176. const size_t buforder = get_order(bufsize);
  177. int err = 0;
  178. if (!count)
  179. return 0;
  180. dev = file->private_data;
  181. if (!dev)
  182. return -ENODEV;
  183. mutex_lock(&dev->wl->mutex);
  184. if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
  185. err = -ENODEV;
  186. goto out_unlock;
  187. }
  188. dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
  189. if (!dfops->read) {
  190. err = -ENOSYS;
  191. goto out_unlock;
  192. }
  193. dfile = fops_to_dfs_file(dev, dfops);
  194. if (!dfile->buffer) {
  195. buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
  196. if (!buf) {
  197. err = -ENOMEM;
  198. goto out_unlock;
  199. }
  200. memset(buf, 0, bufsize);
  201. if (dfops->take_irqlock) {
  202. spin_lock_irq(&dev->wl->irq_lock);
  203. ret = dfops->read(dev, buf, bufsize);
  204. spin_unlock_irq(&dev->wl->irq_lock);
  205. } else
  206. ret = dfops->read(dev, buf, bufsize);
  207. if (ret <= 0) {
  208. free_pages((unsigned long)buf, buforder);
  209. err = ret;
  210. goto out_unlock;
  211. }
  212. dfile->data_len = ret;
  213. dfile->buffer = buf;
  214. }
  215. ret = simple_read_from_buffer(userbuf, count, ppos,
  216. dfile->buffer,
  217. dfile->data_len);
  218. if (*ppos >= dfile->data_len) {
  219. free_pages((unsigned long)dfile->buffer, buforder);
  220. dfile->buffer = NULL;
  221. dfile->data_len = 0;
  222. }
  223. out_unlock:
  224. mutex_unlock(&dev->wl->mutex);
  225. return err ? err : ret;
  226. }
  227. static ssize_t b43legacy_debugfs_write(struct file *file,
  228. const char __user *userbuf,
  229. size_t count, loff_t *ppos)
  230. {
  231. struct b43legacy_wldev *dev;
  232. struct b43legacy_debugfs_fops *dfops;
  233. char *buf;
  234. int err = 0;
  235. if (!count)
  236. return 0;
  237. if (count > PAGE_SIZE)
  238. return -E2BIG;
  239. dev = file->private_data;
  240. if (!dev)
  241. return -ENODEV;
  242. mutex_lock(&dev->wl->mutex);
  243. if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
  244. err = -ENODEV;
  245. goto out_unlock;
  246. }
  247. dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
  248. if (!dfops->write) {
  249. err = -ENOSYS;
  250. goto out_unlock;
  251. }
  252. buf = (char *)get_zeroed_page(GFP_KERNEL);
  253. if (!buf) {
  254. err = -ENOMEM;
  255. goto out_unlock;
  256. }
  257. if (copy_from_user(buf, userbuf, count)) {
  258. err = -EFAULT;
  259. goto out_freepage;
  260. }
  261. if (dfops->take_irqlock) {
  262. spin_lock_irq(&dev->wl->irq_lock);
  263. err = dfops->write(dev, buf, count);
  264. spin_unlock_irq(&dev->wl->irq_lock);
  265. } else
  266. err = dfops->write(dev, buf, count);
  267. if (err)
  268. goto out_freepage;
  269. out_freepage:
  270. free_page((unsigned long)buf);
  271. out_unlock:
  272. mutex_unlock(&dev->wl->mutex);
  273. return err ? err : count;
  274. }
  275. #define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
  276. static struct b43legacy_debugfs_fops fops_##name = { \
  277. .read = _read, \
  278. .write = _write, \
  279. .fops = { \
  280. .open = b43legacy_debugfs_open, \
  281. .read = b43legacy_debugfs_read, \
  282. .write = b43legacy_debugfs_write, \
  283. .llseek = generic_file_llseek, \
  284. }, \
  285. .file_struct_offset = offsetof(struct b43legacy_dfsentry, \
  286. file_##name), \
  287. .take_irqlock = _take_irqlock, \
  288. }
  289. B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
  290. B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
  291. B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
  292. B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
  293. B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
  294. int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
  295. {
  296. return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
  297. }
  298. static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
  299. {
  300. struct b43legacy_dfsentry *e = dev->dfsentry;
  301. int i;
  302. for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
  303. debugfs_remove(e->dyn_debug_dentries[i]);
  304. }
  305. static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
  306. {
  307. struct b43legacy_dfsentry *e = dev->dfsentry;
  308. struct dentry *d;
  309. #define add_dyn_dbg(name, id, initstate) do { \
  310. e->dyn_debug[id] = (initstate); \
  311. d = debugfs_create_bool(name, 0600, e->subdir, \
  312. &(e->dyn_debug[id])); \
  313. if (!IS_ERR(d)) \
  314. e->dyn_debug_dentries[id] = d; \
  315. } while (0)
  316. add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0);
  317. add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0);
  318. add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0);
  319. add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0);
  320. add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0);
  321. #undef add_dyn_dbg
  322. }
  323. void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
  324. {
  325. struct b43legacy_dfsentry *e;
  326. struct b43legacy_txstatus_log *log;
  327. char devdir[16];
  328. B43legacy_WARN_ON(!dev);
  329. e = kzalloc(sizeof(*e), GFP_KERNEL);
  330. if (!e) {
  331. b43legacyerr(dev->wl, "debugfs: add device OOM\n");
  332. return;
  333. }
  334. e->dev = dev;
  335. log = &e->txstatlog;
  336. log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS,
  337. sizeof(struct b43legacy_txstatus), GFP_KERNEL);
  338. if (!log->log) {
  339. b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n");
  340. kfree(e);
  341. return;
  342. }
  343. log->end = -1;
  344. spin_lock_init(&log->lock);
  345. dev->dfsentry = e;
  346. snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
  347. e->subdir = debugfs_create_dir(devdir, rootdir);
  348. if (!e->subdir || IS_ERR(e->subdir)) {
  349. if (e->subdir == ERR_PTR(-ENODEV)) {
  350. b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
  351. "enabled in kernel config\n");
  352. } else {
  353. b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n",
  354. devdir);
  355. }
  356. dev->dfsentry = NULL;
  357. kfree(log->log);
  358. kfree(e);
  359. return;
  360. }
  361. #define ADD_FILE(name, mode) \
  362. do { \
  363. struct dentry *d; \
  364. d = debugfs_create_file(__stringify(name), \
  365. mode, e->subdir, dev, \
  366. &fops_##name.fops); \
  367. e->file_##name.dentry = NULL; \
  368. if (!IS_ERR(d)) \
  369. e->file_##name.dentry = d; \
  370. } while (0)
  371. ADD_FILE(tsf, 0600);
  372. ADD_FILE(ucode_regs, 0400);
  373. ADD_FILE(shm, 0400);
  374. ADD_FILE(txstat, 0400);
  375. ADD_FILE(restart, 0200);
  376. #undef ADD_FILE
  377. b43legacy_add_dynamic_debug(dev);
  378. }
  379. void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
  380. {
  381. struct b43legacy_dfsentry *e;
  382. if (!dev)
  383. return;
  384. e = dev->dfsentry;
  385. if (!e)
  386. return;
  387. b43legacy_remove_dynamic_debug(dev);
  388. debugfs_remove(e->file_tsf.dentry);
  389. debugfs_remove(e->file_ucode_regs.dentry);
  390. debugfs_remove(e->file_shm.dentry);
  391. debugfs_remove(e->file_txstat.dentry);
  392. debugfs_remove(e->file_restart.dentry);
  393. debugfs_remove(e->subdir);
  394. kfree(e->txstatlog.log);
  395. kfree(e);
  396. }
  397. void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
  398. const struct b43legacy_txstatus *status)
  399. {
  400. struct b43legacy_dfsentry *e = dev->dfsentry;
  401. struct b43legacy_txstatus_log *log;
  402. struct b43legacy_txstatus *cur;
  403. int i;
  404. if (!e)
  405. return;
  406. log = &e->txstatlog;
  407. B43legacy_WARN_ON(!irqs_disabled());
  408. spin_lock(&log->lock);
  409. i = log->end + 1;
  410. if (i == B43legacy_NR_LOGGED_TXSTATUS)
  411. i = 0;
  412. log->end = i;
  413. cur = &(log->log[i]);
  414. memcpy(cur, status, sizeof(*cur));
  415. spin_unlock(&log->lock);
  416. }
  417. void b43legacy_debugfs_init(void)
  418. {
  419. rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
  420. if (IS_ERR(rootdir))
  421. rootdir = NULL;
  422. }
  423. void b43legacy_debugfs_exit(void)
  424. {
  425. debugfs_remove(rootdir);
  426. }