debugfs.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. /*
  2. Broadcom B43 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 "b43.h"
  25. #include "main.h"
  26. #include "debugfs.h"
  27. #include "dma.h"
  28. #include "xmit.h"
  29. /* The root directory. */
  30. static struct dentry *rootdir;
  31. struct b43_debugfs_fops {
  32. ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
  33. int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
  34. struct file_operations fops;
  35. /* Offset of struct b43_dfs_file in struct b43_dfsentry */
  36. size_t file_struct_offset;
  37. };
  38. static inline
  39. struct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev,
  40. const struct b43_debugfs_fops *dfops)
  41. {
  42. void *p;
  43. p = dev->dfsentry;
  44. p += dfops->file_struct_offset;
  45. return p;
  46. }
  47. #define fappend(fmt, x...) \
  48. do { \
  49. if (bufsize - count) \
  50. count += snprintf(buf + count, \
  51. bufsize - count, \
  52. fmt , ##x); \
  53. else \
  54. printk(KERN_ERR "b43: fappend overflow\n"); \
  55. } while (0)
  56. /* The biggest address values for SHM access from the debugfs files. */
  57. #define B43_MAX_SHM_ROUTING 4
  58. #define B43_MAX_SHM_ADDR 0xFFFF
  59. static ssize_t shm16read__read_file(struct b43_wldev *dev,
  60. char *buf, size_t bufsize)
  61. {
  62. ssize_t count = 0;
  63. unsigned int routing, addr;
  64. u16 val;
  65. routing = dev->dfsentry->shm16read_routing_next;
  66. addr = dev->dfsentry->shm16read_addr_next;
  67. if ((routing > B43_MAX_SHM_ROUTING) ||
  68. (addr > B43_MAX_SHM_ADDR))
  69. return -EDESTADDRREQ;
  70. val = b43_shm_read16(dev, routing, addr);
  71. fappend("0x%04X\n", val);
  72. return count;
  73. }
  74. static int shm16read__write_file(struct b43_wldev *dev,
  75. const char *buf, size_t count)
  76. {
  77. unsigned int routing, addr;
  78. int res;
  79. res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
  80. if (res != 2)
  81. return -EINVAL;
  82. if (routing > B43_MAX_SHM_ROUTING)
  83. return -EADDRNOTAVAIL;
  84. if (addr > B43_MAX_SHM_ADDR)
  85. return -EADDRNOTAVAIL;
  86. if (routing == B43_SHM_SHARED) {
  87. if ((addr % 2) != 0)
  88. return -EADDRNOTAVAIL;
  89. }
  90. dev->dfsentry->shm16read_routing_next = routing;
  91. dev->dfsentry->shm16read_addr_next = addr;
  92. return 0;
  93. }
  94. static int shm16write__write_file(struct b43_wldev *dev,
  95. const char *buf, size_t count)
  96. {
  97. unsigned int routing, addr, mask, set;
  98. u16 val;
  99. int res;
  100. res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
  101. &routing, &addr, &mask, &set);
  102. if (res != 4)
  103. return -EINVAL;
  104. if (routing > B43_MAX_SHM_ROUTING)
  105. return -EADDRNOTAVAIL;
  106. if (addr > B43_MAX_SHM_ADDR)
  107. return -EADDRNOTAVAIL;
  108. if (routing == B43_SHM_SHARED) {
  109. if ((addr % 2) != 0)
  110. return -EADDRNOTAVAIL;
  111. }
  112. if ((mask > 0xFFFF) || (set > 0xFFFF))
  113. return -E2BIG;
  114. if (mask == 0)
  115. val = 0;
  116. else
  117. val = b43_shm_read16(dev, routing, addr);
  118. val &= mask;
  119. val |= set;
  120. b43_shm_write16(dev, routing, addr, val);
  121. return 0;
  122. }
  123. static ssize_t shm32read__read_file(struct b43_wldev *dev,
  124. char *buf, size_t bufsize)
  125. {
  126. ssize_t count = 0;
  127. unsigned int routing, addr;
  128. u32 val;
  129. routing = dev->dfsentry->shm32read_routing_next;
  130. addr = dev->dfsentry->shm32read_addr_next;
  131. if ((routing > B43_MAX_SHM_ROUTING) ||
  132. (addr > B43_MAX_SHM_ADDR))
  133. return -EDESTADDRREQ;
  134. val = b43_shm_read32(dev, routing, addr);
  135. fappend("0x%08X\n", val);
  136. return count;
  137. }
  138. static int shm32read__write_file(struct b43_wldev *dev,
  139. const char *buf, size_t count)
  140. {
  141. unsigned int routing, addr;
  142. int res;
  143. res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
  144. if (res != 2)
  145. return -EINVAL;
  146. if (routing > B43_MAX_SHM_ROUTING)
  147. return -EADDRNOTAVAIL;
  148. if (addr > B43_MAX_SHM_ADDR)
  149. return -EADDRNOTAVAIL;
  150. if (routing == B43_SHM_SHARED) {
  151. if ((addr % 2) != 0)
  152. return -EADDRNOTAVAIL;
  153. }
  154. dev->dfsentry->shm32read_routing_next = routing;
  155. dev->dfsentry->shm32read_addr_next = addr;
  156. return 0;
  157. }
  158. static int shm32write__write_file(struct b43_wldev *dev,
  159. const char *buf, size_t count)
  160. {
  161. unsigned int routing, addr, mask, set;
  162. u32 val;
  163. int res;
  164. res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
  165. &routing, &addr, &mask, &set);
  166. if (res != 4)
  167. return -EINVAL;
  168. if (routing > B43_MAX_SHM_ROUTING)
  169. return -EADDRNOTAVAIL;
  170. if (addr > B43_MAX_SHM_ADDR)
  171. return -EADDRNOTAVAIL;
  172. if (routing == B43_SHM_SHARED) {
  173. if ((addr % 2) != 0)
  174. return -EADDRNOTAVAIL;
  175. }
  176. if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
  177. return -E2BIG;
  178. if (mask == 0)
  179. val = 0;
  180. else
  181. val = b43_shm_read32(dev, routing, addr);
  182. val &= mask;
  183. val |= set;
  184. b43_shm_write32(dev, routing, addr, val);
  185. return 0;
  186. }
  187. /* The biggest MMIO address that we allow access to from the debugfs files. */
  188. #define B43_MAX_MMIO_ACCESS (0xF00 - 1)
  189. static ssize_t mmio16read__read_file(struct b43_wldev *dev,
  190. char *buf, size_t bufsize)
  191. {
  192. ssize_t count = 0;
  193. unsigned int addr;
  194. u16 val;
  195. addr = dev->dfsentry->mmio16read_next;
  196. if (addr > B43_MAX_MMIO_ACCESS)
  197. return -EDESTADDRREQ;
  198. val = b43_read16(dev, addr);
  199. fappend("0x%04X\n", val);
  200. return count;
  201. }
  202. static int mmio16read__write_file(struct b43_wldev *dev,
  203. const char *buf, size_t count)
  204. {
  205. unsigned int addr;
  206. int res;
  207. res = sscanf(buf, "0x%X", &addr);
  208. if (res != 1)
  209. return -EINVAL;
  210. if (addr > B43_MAX_MMIO_ACCESS)
  211. return -EADDRNOTAVAIL;
  212. if ((addr % 2) != 0)
  213. return -EINVAL;
  214. dev->dfsentry->mmio16read_next = addr;
  215. return 0;
  216. }
  217. static int mmio16write__write_file(struct b43_wldev *dev,
  218. const char *buf, size_t count)
  219. {
  220. unsigned int addr, mask, set;
  221. int res;
  222. u16 val;
  223. res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
  224. if (res != 3)
  225. return -EINVAL;
  226. if (addr > B43_MAX_MMIO_ACCESS)
  227. return -EADDRNOTAVAIL;
  228. if ((mask > 0xFFFF) || (set > 0xFFFF))
  229. return -E2BIG;
  230. if ((addr % 2) != 0)
  231. return -EINVAL;
  232. if (mask == 0)
  233. val = 0;
  234. else
  235. val = b43_read16(dev, addr);
  236. val &= mask;
  237. val |= set;
  238. b43_write16(dev, addr, val);
  239. return 0;
  240. }
  241. static ssize_t mmio32read__read_file(struct b43_wldev *dev,
  242. char *buf, size_t bufsize)
  243. {
  244. ssize_t count = 0;
  245. unsigned int addr;
  246. u32 val;
  247. addr = dev->dfsentry->mmio32read_next;
  248. if (addr > B43_MAX_MMIO_ACCESS)
  249. return -EDESTADDRREQ;
  250. val = b43_read32(dev, addr);
  251. fappend("0x%08X\n", val);
  252. return count;
  253. }
  254. static int mmio32read__write_file(struct b43_wldev *dev,
  255. const char *buf, size_t count)
  256. {
  257. unsigned int addr;
  258. int res;
  259. res = sscanf(buf, "0x%X", &addr);
  260. if (res != 1)
  261. return -EINVAL;
  262. if (addr > B43_MAX_MMIO_ACCESS)
  263. return -EADDRNOTAVAIL;
  264. if ((addr % 4) != 0)
  265. return -EINVAL;
  266. dev->dfsentry->mmio32read_next = addr;
  267. return 0;
  268. }
  269. static int mmio32write__write_file(struct b43_wldev *dev,
  270. const char *buf, size_t count)
  271. {
  272. unsigned int addr, mask, set;
  273. int res;
  274. u32 val;
  275. res = sscanf(buf, "0x%X 0x%X 0x%X", &addr, &mask, &set);
  276. if (res != 3)
  277. return -EINVAL;
  278. if (addr > B43_MAX_MMIO_ACCESS)
  279. return -EADDRNOTAVAIL;
  280. if ((mask > 0xFFFFFFFF) || (set > 0xFFFFFFFF))
  281. return -E2BIG;
  282. if ((addr % 4) != 0)
  283. return -EINVAL;
  284. if (mask == 0)
  285. val = 0;
  286. else
  287. val = b43_read32(dev, addr);
  288. val &= mask;
  289. val |= set;
  290. b43_write32(dev, addr, val);
  291. return 0;
  292. }
  293. static ssize_t txstat_read_file(struct b43_wldev *dev,
  294. char *buf, size_t bufsize)
  295. {
  296. struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
  297. ssize_t count = 0;
  298. int i, idx;
  299. struct b43_txstatus *stat;
  300. if (log->end < 0) {
  301. fappend("Nothing transmitted, yet\n");
  302. goto out;
  303. }
  304. fappend("b43 TX status reports:\n\n"
  305. "index | cookie | seq | phy_stat | frame_count | "
  306. "rts_count | supp_reason | pm_indicated | "
  307. "intermediate | for_ampdu | acked\n" "---\n");
  308. i = log->end + 1;
  309. idx = 0;
  310. while (1) {
  311. if (i == B43_NR_LOGGED_TXSTATUS)
  312. i = 0;
  313. stat = &(log->log[i]);
  314. if (stat->cookie) {
  315. fappend("%03d | "
  316. "0x%04X | 0x%04X | 0x%02X | "
  317. "0x%X | 0x%X | "
  318. "%u | %u | "
  319. "%u | %u | %u\n",
  320. idx,
  321. stat->cookie, stat->seq, stat->phy_stat,
  322. stat->frame_count, stat->rts_count,
  323. stat->supp_reason, stat->pm_indicated,
  324. stat->intermediate, stat->for_ampdu,
  325. stat->acked);
  326. idx++;
  327. }
  328. if (i == log->end)
  329. break;
  330. i++;
  331. }
  332. out:
  333. return count;
  334. }
  335. static int restart_write_file(struct b43_wldev *dev,
  336. const char *buf, size_t count)
  337. {
  338. int err = 0;
  339. if (count > 0 && buf[0] == '1') {
  340. b43_controller_restart(dev, "manually restarted");
  341. } else
  342. err = -EINVAL;
  343. return err;
  344. }
  345. static unsigned long calc_expire_secs(unsigned long now,
  346. unsigned long time,
  347. unsigned long expire)
  348. {
  349. expire = time + expire;
  350. if (time_after(now, expire))
  351. return 0; /* expired */
  352. if (expire < now) {
  353. /* jiffies wrapped */
  354. expire -= MAX_JIFFY_OFFSET;
  355. now -= MAX_JIFFY_OFFSET;
  356. }
  357. B43_WARN_ON(expire < now);
  358. return (expire - now) / HZ;
  359. }
  360. static ssize_t loctls_read_file(struct b43_wldev *dev,
  361. char *buf, size_t bufsize)
  362. {
  363. ssize_t count = 0;
  364. struct b43_txpower_lo_control *lo;
  365. int i, err = 0;
  366. struct b43_lo_calib *cal;
  367. unsigned long now = jiffies;
  368. struct b43_phy *phy = &dev->phy;
  369. if (phy->type != B43_PHYTYPE_G) {
  370. fappend("Device is not a G-PHY\n");
  371. err = -ENODEV;
  372. goto out;
  373. }
  374. lo = phy->g->lo_control;
  375. fappend("-- Local Oscillator calibration data --\n\n");
  376. fappend("HW-power-control enabled: %d\n",
  377. dev->phy.hardware_power_control);
  378. fappend("TX Bias: 0x%02X, TX Magn: 0x%02X (expire in %lu sec)\n",
  379. lo->tx_bias, lo->tx_magn,
  380. calc_expire_secs(now, lo->txctl_measured_time,
  381. B43_LO_TXCTL_EXPIRE));
  382. fappend("Power Vector: 0x%08X%08X (expires in %lu sec)\n",
  383. (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
  384. (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL),
  385. calc_expire_secs(now, lo->pwr_vec_read_time,
  386. B43_LO_PWRVEC_EXPIRE));
  387. fappend("\nCalibrated settings:\n");
  388. list_for_each_entry(cal, &lo->calib_list, list) {
  389. bool active;
  390. active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) &&
  391. b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt));
  392. fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d "
  393. "(expires in %lu sec)%s\n",
  394. cal->bbatt.att,
  395. cal->rfatt.att, cal->rfatt.with_padmix,
  396. cal->ctl.i, cal->ctl.q,
  397. calc_expire_secs(now, cal->calib_time,
  398. B43_LO_CALIB_EXPIRE),
  399. active ? " ACTIVE" : "");
  400. }
  401. fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
  402. for (i = 0; i < lo->rfatt_list.len; i++) {
  403. fappend("%u(%d), ",
  404. lo->rfatt_list.list[i].att,
  405. lo->rfatt_list.list[i].with_padmix);
  406. }
  407. fappend("\n");
  408. fappend("\nUsed Baseband attenuation values:\n");
  409. for (i = 0; i < lo->bbatt_list.len; i++) {
  410. fappend("%u, ",
  411. lo->bbatt_list.list[i].att);
  412. }
  413. fappend("\n");
  414. out:
  415. return err ? err : count;
  416. }
  417. #undef fappend
  418. static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
  419. size_t count, loff_t *ppos)
  420. {
  421. struct b43_wldev *dev;
  422. struct b43_debugfs_fops *dfops;
  423. struct b43_dfs_file *dfile;
  424. ssize_t uninitialized_var(ret);
  425. char *buf;
  426. const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
  427. const size_t buforder = get_order(bufsize);
  428. int err = 0;
  429. if (!count)
  430. return 0;
  431. dev = file->private_data;
  432. if (!dev)
  433. return -ENODEV;
  434. mutex_lock(&dev->wl->mutex);
  435. if (b43_status(dev) < B43_STAT_INITIALIZED) {
  436. err = -ENODEV;
  437. goto out_unlock;
  438. }
  439. dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
  440. if (!dfops->read) {
  441. err = -ENOSYS;
  442. goto out_unlock;
  443. }
  444. dfile = fops_to_dfs_file(dev, dfops);
  445. if (!dfile->buffer) {
  446. buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
  447. if (!buf) {
  448. err = -ENOMEM;
  449. goto out_unlock;
  450. }
  451. memset(buf, 0, bufsize);
  452. ret = dfops->read(dev, buf, bufsize);
  453. if (ret <= 0) {
  454. free_pages((unsigned long)buf, buforder);
  455. err = ret;
  456. goto out_unlock;
  457. }
  458. dfile->data_len = ret;
  459. dfile->buffer = buf;
  460. }
  461. ret = simple_read_from_buffer(userbuf, count, ppos,
  462. dfile->buffer,
  463. dfile->data_len);
  464. if (*ppos >= dfile->data_len) {
  465. free_pages((unsigned long)dfile->buffer, buforder);
  466. dfile->buffer = NULL;
  467. dfile->data_len = 0;
  468. }
  469. out_unlock:
  470. mutex_unlock(&dev->wl->mutex);
  471. return err ? err : ret;
  472. }
  473. static ssize_t b43_debugfs_write(struct file *file,
  474. const char __user *userbuf,
  475. size_t count, loff_t *ppos)
  476. {
  477. struct b43_wldev *dev;
  478. struct b43_debugfs_fops *dfops;
  479. char *buf;
  480. int err = 0;
  481. if (!count)
  482. return 0;
  483. if (count > PAGE_SIZE)
  484. return -E2BIG;
  485. dev = file->private_data;
  486. if (!dev)
  487. return -ENODEV;
  488. mutex_lock(&dev->wl->mutex);
  489. if (b43_status(dev) < B43_STAT_INITIALIZED) {
  490. err = -ENODEV;
  491. goto out_unlock;
  492. }
  493. dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
  494. if (!dfops->write) {
  495. err = -ENOSYS;
  496. goto out_unlock;
  497. }
  498. buf = (char *)get_zeroed_page(GFP_KERNEL);
  499. if (!buf) {
  500. err = -ENOMEM;
  501. goto out_unlock;
  502. }
  503. if (copy_from_user(buf, userbuf, count)) {
  504. err = -EFAULT;
  505. goto out_freepage;
  506. }
  507. err = dfops->write(dev, buf, count);
  508. if (err)
  509. goto out_freepage;
  510. out_freepage:
  511. free_page((unsigned long)buf);
  512. out_unlock:
  513. mutex_unlock(&dev->wl->mutex);
  514. return err ? err : count;
  515. }
  516. #define B43_DEBUGFS_FOPS(name, _read, _write) \
  517. static struct b43_debugfs_fops fops_##name = { \
  518. .read = _read, \
  519. .write = _write, \
  520. .fops = { \
  521. .open = simple_open, \
  522. .read = b43_debugfs_read, \
  523. .write = b43_debugfs_write, \
  524. .llseek = generic_file_llseek, \
  525. }, \
  526. .file_struct_offset = offsetof(struct b43_dfsentry, \
  527. file_##name), \
  528. }
  529. B43_DEBUGFS_FOPS(shm16read, shm16read__read_file, shm16read__write_file);
  530. B43_DEBUGFS_FOPS(shm16write, NULL, shm16write__write_file);
  531. B43_DEBUGFS_FOPS(shm32read, shm32read__read_file, shm32read__write_file);
  532. B43_DEBUGFS_FOPS(shm32write, NULL, shm32write__write_file);
  533. B43_DEBUGFS_FOPS(mmio16read, mmio16read__read_file, mmio16read__write_file);
  534. B43_DEBUGFS_FOPS(mmio16write, NULL, mmio16write__write_file);
  535. B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file);
  536. B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file);
  537. B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL);
  538. B43_DEBUGFS_FOPS(restart, NULL, restart_write_file);
  539. B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL);
  540. bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
  541. {
  542. bool enabled;
  543. enabled = (dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
  544. if (unlikely(enabled)) {
  545. /* Force full debugging messages, if the user enabled
  546. * some dynamic debugging feature. */
  547. b43_modparam_verbose = B43_VERBOSITY_MAX;
  548. }
  549. return enabled;
  550. }
  551. static void b43_remove_dynamic_debug(struct b43_wldev *dev)
  552. {
  553. struct b43_dfsentry *e = dev->dfsentry;
  554. int i;
  555. for (i = 0; i < __B43_NR_DYNDBG; i++)
  556. debugfs_remove(e->dyn_debug_dentries[i]);
  557. }
  558. static void b43_add_dynamic_debug(struct b43_wldev *dev)
  559. {
  560. struct b43_dfsentry *e = dev->dfsentry;
  561. struct dentry *d;
  562. #define add_dyn_dbg(name, id, initstate) do { \
  563. e->dyn_debug[id] = (initstate); \
  564. d = debugfs_create_bool(name, 0600, e->subdir, \
  565. &(e->dyn_debug[id])); \
  566. if (!IS_ERR(d)) \
  567. e->dyn_debug_dentries[id] = d; \
  568. } while (0)
  569. add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, false);
  570. add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, false);
  571. add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, false);
  572. add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, false);
  573. add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, false);
  574. add_dyn_dbg("debug_lo", B43_DBG_LO, false);
  575. add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, false);
  576. add_dyn_dbg("debug_keys", B43_DBG_KEYS, false);
  577. add_dyn_dbg("debug_verbose_stats", B43_DBG_VERBOSESTATS, false);
  578. #undef add_dyn_dbg
  579. }
  580. void b43_debugfs_add_device(struct b43_wldev *dev)
  581. {
  582. struct b43_dfsentry *e;
  583. struct b43_txstatus_log *log;
  584. char devdir[16];
  585. B43_WARN_ON(!dev);
  586. e = kzalloc(sizeof(*e), GFP_KERNEL);
  587. if (!e) {
  588. b43err(dev->wl, "debugfs: add device OOM\n");
  589. return;
  590. }
  591. e->dev = dev;
  592. log = &e->txstatlog;
  593. log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
  594. sizeof(struct b43_txstatus), GFP_KERNEL);
  595. if (!log->log) {
  596. b43err(dev->wl, "debugfs: add device txstatus OOM\n");
  597. kfree(e);
  598. return;
  599. }
  600. log->end = -1;
  601. dev->dfsentry = e;
  602. snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
  603. e->subdir = debugfs_create_dir(devdir, rootdir);
  604. if (!e->subdir || IS_ERR(e->subdir)) {
  605. if (e->subdir == ERR_PTR(-ENODEV)) {
  606. b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
  607. "enabled in kernel config\n");
  608. } else {
  609. b43err(dev->wl, "debugfs: cannot create %s directory\n",
  610. devdir);
  611. }
  612. dev->dfsentry = NULL;
  613. kfree(log->log);
  614. kfree(e);
  615. return;
  616. }
  617. e->mmio16read_next = 0xFFFF; /* invalid address */
  618. e->mmio32read_next = 0xFFFF; /* invalid address */
  619. e->shm16read_routing_next = 0xFFFFFFFF; /* invalid routing */
  620. e->shm16read_addr_next = 0xFFFFFFFF; /* invalid address */
  621. e->shm32read_routing_next = 0xFFFFFFFF; /* invalid routing */
  622. e->shm32read_addr_next = 0xFFFFFFFF; /* invalid address */
  623. #define ADD_FILE(name, mode) \
  624. do { \
  625. struct dentry *d; \
  626. d = debugfs_create_file(__stringify(name), \
  627. mode, e->subdir, dev, \
  628. &fops_##name.fops); \
  629. e->file_##name.dentry = NULL; \
  630. if (!IS_ERR(d)) \
  631. e->file_##name.dentry = d; \
  632. } while (0)
  633. ADD_FILE(shm16read, 0600);
  634. ADD_FILE(shm16write, 0200);
  635. ADD_FILE(shm32read, 0600);
  636. ADD_FILE(shm32write, 0200);
  637. ADD_FILE(mmio16read, 0600);
  638. ADD_FILE(mmio16write, 0200);
  639. ADD_FILE(mmio32read, 0600);
  640. ADD_FILE(mmio32write, 0200);
  641. ADD_FILE(txstat, 0400);
  642. ADD_FILE(restart, 0200);
  643. ADD_FILE(loctls, 0400);
  644. #undef ADD_FILE
  645. b43_add_dynamic_debug(dev);
  646. }
  647. void b43_debugfs_remove_device(struct b43_wldev *dev)
  648. {
  649. struct b43_dfsentry *e;
  650. if (!dev)
  651. return;
  652. e = dev->dfsentry;
  653. if (!e)
  654. return;
  655. b43_remove_dynamic_debug(dev);
  656. debugfs_remove(e->file_shm16read.dentry);
  657. debugfs_remove(e->file_shm16write.dentry);
  658. debugfs_remove(e->file_shm32read.dentry);
  659. debugfs_remove(e->file_shm32write.dentry);
  660. debugfs_remove(e->file_mmio16read.dentry);
  661. debugfs_remove(e->file_mmio16write.dentry);
  662. debugfs_remove(e->file_mmio32read.dentry);
  663. debugfs_remove(e->file_mmio32write.dentry);
  664. debugfs_remove(e->file_txstat.dentry);
  665. debugfs_remove(e->file_restart.dentry);
  666. debugfs_remove(e->file_loctls.dentry);
  667. debugfs_remove(e->subdir);
  668. kfree(e->txstatlog.log);
  669. kfree(e);
  670. }
  671. void b43_debugfs_log_txstat(struct b43_wldev *dev,
  672. const struct b43_txstatus *status)
  673. {
  674. struct b43_dfsentry *e = dev->dfsentry;
  675. struct b43_txstatus_log *log;
  676. struct b43_txstatus *cur;
  677. int i;
  678. if (!e)
  679. return;
  680. log = &e->txstatlog;
  681. i = log->end + 1;
  682. if (i == B43_NR_LOGGED_TXSTATUS)
  683. i = 0;
  684. log->end = i;
  685. cur = &(log->log[i]);
  686. memcpy(cur, status, sizeof(*cur));
  687. }
  688. void b43_debugfs_init(void)
  689. {
  690. rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
  691. if (IS_ERR(rootdir))
  692. rootdir = NULL;
  693. }
  694. void b43_debugfs_exit(void)
  695. {
  696. debugfs_remove(rootdir);
  697. }