debugfs.c 17 KB

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