debug.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /*
  2. * Copyright (c) 2004-2011 Atheros Communications Inc.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "core.h"
  17. #include <linux/circ_buf.h>
  18. #include "debug.h"
  19. #include "target.h"
  20. struct ath6kl_fwlog_slot {
  21. __le32 timestamp;
  22. __le32 length;
  23. /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */
  24. u8 payload[0];
  25. };
  26. #define ATH6KL_FWLOG_SIZE 32768
  27. #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \
  28. ATH6KL_FWLOG_PAYLOAD_SIZE)
  29. int ath6kl_printk(const char *level, const char *fmt, ...)
  30. {
  31. struct va_format vaf;
  32. va_list args;
  33. int rtn;
  34. va_start(args, fmt);
  35. vaf.fmt = fmt;
  36. vaf.va = &args;
  37. rtn = printk("%sath6kl: %pV", level, &vaf);
  38. va_end(args);
  39. return rtn;
  40. }
  41. #ifdef CONFIG_ATH6KL_DEBUG
  42. void ath6kl_dump_registers(struct ath6kl_device *dev,
  43. struct ath6kl_irq_proc_registers *irq_proc_reg,
  44. struct ath6kl_irq_enable_reg *irq_enable_reg)
  45. {
  46. ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n"));
  47. if (irq_proc_reg != NULL) {
  48. ath6kl_dbg(ATH6KL_DBG_ANY,
  49. "Host Int status: 0x%x\n",
  50. irq_proc_reg->host_int_status);
  51. ath6kl_dbg(ATH6KL_DBG_ANY,
  52. "CPU Int status: 0x%x\n",
  53. irq_proc_reg->cpu_int_status);
  54. ath6kl_dbg(ATH6KL_DBG_ANY,
  55. "Error Int status: 0x%x\n",
  56. irq_proc_reg->error_int_status);
  57. ath6kl_dbg(ATH6KL_DBG_ANY,
  58. "Counter Int status: 0x%x\n",
  59. irq_proc_reg->counter_int_status);
  60. ath6kl_dbg(ATH6KL_DBG_ANY,
  61. "Mbox Frame: 0x%x\n",
  62. irq_proc_reg->mbox_frame);
  63. ath6kl_dbg(ATH6KL_DBG_ANY,
  64. "Rx Lookahead Valid: 0x%x\n",
  65. irq_proc_reg->rx_lkahd_valid);
  66. ath6kl_dbg(ATH6KL_DBG_ANY,
  67. "Rx Lookahead 0: 0x%x\n",
  68. irq_proc_reg->rx_lkahd[0]);
  69. ath6kl_dbg(ATH6KL_DBG_ANY,
  70. "Rx Lookahead 1: 0x%x\n",
  71. irq_proc_reg->rx_lkahd[1]);
  72. if (dev->ar->mbox_info.gmbox_addr != 0) {
  73. /*
  74. * If the target supports GMBOX hardware, dump some
  75. * additional state.
  76. */
  77. ath6kl_dbg(ATH6KL_DBG_ANY,
  78. "GMBOX Host Int status 2: 0x%x\n",
  79. irq_proc_reg->host_int_status2);
  80. ath6kl_dbg(ATH6KL_DBG_ANY,
  81. "GMBOX RX Avail: 0x%x\n",
  82. irq_proc_reg->gmbox_rx_avail);
  83. ath6kl_dbg(ATH6KL_DBG_ANY,
  84. "GMBOX lookahead alias 0: 0x%x\n",
  85. irq_proc_reg->rx_gmbox_lkahd_alias[0]);
  86. ath6kl_dbg(ATH6KL_DBG_ANY,
  87. "GMBOX lookahead alias 1: 0x%x\n",
  88. irq_proc_reg->rx_gmbox_lkahd_alias[1]);
  89. }
  90. }
  91. if (irq_enable_reg != NULL) {
  92. ath6kl_dbg(ATH6KL_DBG_ANY,
  93. "Int status Enable: 0x%x\n",
  94. irq_enable_reg->int_status_en);
  95. ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n",
  96. irq_enable_reg->cntr_int_status_en);
  97. }
  98. ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n");
  99. }
  100. static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist)
  101. {
  102. ath6kl_dbg(ATH6KL_DBG_ANY,
  103. "--- endpoint: %d svc_id: 0x%X ---\n",
  104. ep_dist->endpoint, ep_dist->svc_id);
  105. ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n",
  106. ep_dist->dist_flags);
  107. ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n",
  108. ep_dist->cred_norm);
  109. ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n",
  110. ep_dist->cred_min);
  111. ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n",
  112. ep_dist->credits);
  113. ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n",
  114. ep_dist->cred_assngd);
  115. ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n",
  116. ep_dist->seek_cred);
  117. ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n",
  118. ep_dist->cred_sz);
  119. ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n",
  120. ep_dist->cred_per_msg);
  121. ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n",
  122. ep_dist->cred_to_dist);
  123. ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n",
  124. get_queue_depth(&((struct htc_endpoint *)
  125. ep_dist->htc_rsvd)->txq));
  126. ath6kl_dbg(ATH6KL_DBG_ANY,
  127. "----------------------------------\n");
  128. }
  129. void dump_cred_dist_stats(struct htc_target *target)
  130. {
  131. struct htc_endpoint_credit_dist *ep_list;
  132. if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC))
  133. return;
  134. list_for_each_entry(ep_list, &target->cred_dist_list, list)
  135. dump_cred_dist(ep_list);
  136. ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n",
  137. target->cred_dist_cntxt, NULL);
  138. ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n",
  139. target->cred_dist_cntxt->total_avail_credits,
  140. target->cred_dist_cntxt->cur_free_credits);
  141. }
  142. static int ath6kl_debugfs_open(struct inode *inode, struct file *file)
  143. {
  144. file->private_data = inode->i_private;
  145. return 0;
  146. }
  147. static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf,
  148. size_t buf_len)
  149. {
  150. struct circ_buf *fwlog = &ar->debug.fwlog_buf;
  151. size_t space;
  152. int i;
  153. /* entries must all be equal size */
  154. if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE))
  155. return;
  156. space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE);
  157. if (space < buf_len)
  158. /* discard oldest slot */
  159. fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) &
  160. (ATH6KL_FWLOG_SIZE - 1);
  161. for (i = 0; i < buf_len; i += space) {
  162. space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail,
  163. ATH6KL_FWLOG_SIZE);
  164. if ((size_t) space > buf_len - i)
  165. space = buf_len - i;
  166. memcpy(&fwlog->buf[fwlog->head], buf, space);
  167. fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1);
  168. }
  169. }
  170. void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len)
  171. {
  172. struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp;
  173. size_t slot_len;
  174. if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE))
  175. return;
  176. spin_lock_bh(&ar->debug.fwlog_lock);
  177. slot->timestamp = cpu_to_le32(jiffies);
  178. slot->length = cpu_to_le32(len);
  179. memcpy(slot->payload, buf, len);
  180. slot_len = sizeof(*slot) + len;
  181. if (slot_len < ATH6KL_FWLOG_SLOT_SIZE)
  182. memset(slot->payload + len, 0,
  183. ATH6KL_FWLOG_SLOT_SIZE - slot_len);
  184. ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE);
  185. spin_unlock_bh(&ar->debug.fwlog_lock);
  186. }
  187. static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar)
  188. {
  189. return CIRC_CNT(ar->debug.fwlog_buf.head,
  190. ar->debug.fwlog_buf.tail,
  191. ATH6KL_FWLOG_SLOT_SIZE) == 0;
  192. }
  193. static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf,
  194. size_t count, loff_t *ppos)
  195. {
  196. struct ath6kl *ar = file->private_data;
  197. struct circ_buf *fwlog = &ar->debug.fwlog_buf;
  198. size_t len = 0, buf_len = count;
  199. ssize_t ret_cnt;
  200. char *buf;
  201. int ccnt;
  202. buf = vmalloc(buf_len);
  203. if (!buf)
  204. return -ENOMEM;
  205. spin_lock_bh(&ar->debug.fwlog_lock);
  206. while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) {
  207. ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail,
  208. ATH6KL_FWLOG_SIZE);
  209. if ((size_t) ccnt > buf_len - len)
  210. ccnt = buf_len - len;
  211. memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt);
  212. len += ccnt;
  213. fwlog->tail = (fwlog->tail + ccnt) &
  214. (ATH6KL_FWLOG_SIZE - 1);
  215. }
  216. spin_unlock_bh(&ar->debug.fwlog_lock);
  217. if (WARN_ON(len > buf_len))
  218. len = buf_len;
  219. ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
  220. vfree(buf);
  221. return ret_cnt;
  222. }
  223. static const struct file_operations fops_fwlog = {
  224. .open = ath6kl_debugfs_open,
  225. .read = ath6kl_fwlog_read,
  226. .owner = THIS_MODULE,
  227. .llseek = default_llseek,
  228. };
  229. static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
  230. size_t count, loff_t *ppos)
  231. {
  232. struct ath6kl *ar = file->private_data;
  233. struct target_stats *tgt_stats = &ar->target_stats;
  234. char *buf;
  235. unsigned int len = 0, buf_len = 1500;
  236. int i;
  237. long left;
  238. ssize_t ret_cnt;
  239. buf = kzalloc(buf_len, GFP_KERNEL);
  240. if (!buf)
  241. return -ENOMEM;
  242. if (down_interruptible(&ar->sem)) {
  243. kfree(buf);
  244. return -EBUSY;
  245. }
  246. set_bit(STATS_UPDATE_PEND, &ar->flag);
  247. if (ath6kl_wmi_get_stats_cmd(ar->wmi)) {
  248. up(&ar->sem);
  249. kfree(buf);
  250. return -EIO;
  251. }
  252. left = wait_event_interruptible_timeout(ar->event_wq,
  253. !test_bit(STATS_UPDATE_PEND,
  254. &ar->flag), WMI_TIMEOUT);
  255. up(&ar->sem);
  256. if (left <= 0) {
  257. kfree(buf);
  258. return -ETIMEDOUT;
  259. }
  260. len += scnprintf(buf + len, buf_len - len, "\n");
  261. len += scnprintf(buf + len, buf_len - len, "%25s\n",
  262. "Target Tx stats");
  263. len += scnprintf(buf + len, buf_len - len, "%25s\n\n",
  264. "=================");
  265. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  266. "Ucast packets", tgt_stats->tx_ucast_pkt);
  267. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  268. "Bcast packets", tgt_stats->tx_bcast_pkt);
  269. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  270. "Ucast byte", tgt_stats->tx_ucast_byte);
  271. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  272. "Bcast byte", tgt_stats->tx_bcast_byte);
  273. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  274. "Rts success cnt", tgt_stats->tx_rts_success_cnt);
  275. for (i = 0; i < 4; i++)
  276. len += scnprintf(buf + len, buf_len - len,
  277. "%18s %d %10llu\n", "PER on ac",
  278. i, tgt_stats->tx_pkt_per_ac[i]);
  279. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  280. "Error", tgt_stats->tx_err);
  281. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  282. "Fail count", tgt_stats->tx_fail_cnt);
  283. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  284. "Retry count", tgt_stats->tx_retry_cnt);
  285. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  286. "Multi retry cnt", tgt_stats->tx_mult_retry_cnt);
  287. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  288. "Rts fail cnt", tgt_stats->tx_rts_fail_cnt);
  289. len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n",
  290. "TKIP counter measure used",
  291. tgt_stats->tkip_cnter_measures_invoked);
  292. len += scnprintf(buf + len, buf_len - len, "%25s\n",
  293. "Target Rx stats");
  294. len += scnprintf(buf + len, buf_len - len, "%25s\n",
  295. "=================");
  296. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  297. "Ucast packets", tgt_stats->rx_ucast_pkt);
  298. len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
  299. "Ucast Rate", tgt_stats->rx_ucast_rate);
  300. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  301. "Bcast packets", tgt_stats->rx_bcast_pkt);
  302. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  303. "Ucast byte", tgt_stats->rx_ucast_byte);
  304. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  305. "Bcast byte", tgt_stats->rx_bcast_byte);
  306. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  307. "Fragmented pkt", tgt_stats->rx_frgment_pkt);
  308. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  309. "Error", tgt_stats->rx_err);
  310. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  311. "CRC Err", tgt_stats->rx_crc_err);
  312. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  313. "Key chache miss", tgt_stats->rx_key_cache_miss);
  314. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  315. "Decrypt Err", tgt_stats->rx_decrypt_err);
  316. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  317. "Duplicate frame", tgt_stats->rx_dupl_frame);
  318. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  319. "Tkip Mic failure", tgt_stats->tkip_local_mic_fail);
  320. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  321. "TKIP format err", tgt_stats->tkip_fmt_err);
  322. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  323. "CCMP format Err", tgt_stats->ccmp_fmt_err);
  324. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n",
  325. "CCMP Replay Err", tgt_stats->ccmp_replays);
  326. len += scnprintf(buf + len, buf_len - len, "%25s\n",
  327. "Misc Target stats");
  328. len += scnprintf(buf + len, buf_len - len, "%25s\n",
  329. "=================");
  330. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  331. "Beacon Miss count", tgt_stats->cs_bmiss_cnt);
  332. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  333. "Num Connects", tgt_stats->cs_connect_cnt);
  334. len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n",
  335. "Num disconnects", tgt_stats->cs_discon_cnt);
  336. len += scnprintf(buf + len, buf_len - len, "%20s %10d\n",
  337. "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi);
  338. if (len > buf_len)
  339. len = buf_len;
  340. ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
  341. kfree(buf);
  342. return ret_cnt;
  343. }
  344. static const struct file_operations fops_tgt_stats = {
  345. .read = read_file_tgt_stats,
  346. .open = ath6kl_debugfs_open,
  347. .owner = THIS_MODULE,
  348. .llseek = default_llseek,
  349. };
  350. #define print_credit_info(fmt_str, ep_list_field) \
  351. (len += scnprintf(buf + len, buf_len - len, fmt_str, \
  352. ep_list->ep_list_field))
  353. #define CREDIT_INFO_DISPLAY_STRING_LEN 200
  354. #define CREDIT_INFO_LEN 128
  355. static ssize_t read_file_credit_dist_stats(struct file *file,
  356. char __user *user_buf,
  357. size_t count, loff_t *ppos)
  358. {
  359. struct ath6kl *ar = file->private_data;
  360. struct htc_target *target = ar->htc_target;
  361. struct htc_endpoint_credit_dist *ep_list;
  362. char *buf;
  363. unsigned int buf_len, len = 0;
  364. ssize_t ret_cnt;
  365. buf_len = CREDIT_INFO_DISPLAY_STRING_LEN +
  366. get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN;
  367. buf = kzalloc(buf_len, GFP_KERNEL);
  368. if (!buf)
  369. return -ENOMEM;
  370. len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
  371. "Total Avail Credits: ",
  372. target->cred_dist_cntxt->total_avail_credits);
  373. len += scnprintf(buf + len, buf_len - len, "%25s%5d\n",
  374. "Free credits :",
  375. target->cred_dist_cntxt->cur_free_credits);
  376. len += scnprintf(buf + len, buf_len - len,
  377. " Epid Flags Cred_norm Cred_min Credits Cred_assngd"
  378. " Seek_cred Cred_sz Cred_per_msg Cred_to_dist"
  379. " qdepth\n");
  380. list_for_each_entry(ep_list, &target->cred_dist_list, list) {
  381. print_credit_info(" %2d", endpoint);
  382. print_credit_info("%10x", dist_flags);
  383. print_credit_info("%8d", cred_norm);
  384. print_credit_info("%9d", cred_min);
  385. print_credit_info("%9d", credits);
  386. print_credit_info("%10d", cred_assngd);
  387. print_credit_info("%13d", seek_cred);
  388. print_credit_info("%12d", cred_sz);
  389. print_credit_info("%9d", cred_per_msg);
  390. print_credit_info("%14d", cred_to_dist);
  391. len += scnprintf(buf + len, buf_len - len, "%12d\n",
  392. get_queue_depth(&((struct htc_endpoint *)
  393. ep_list->htc_rsvd)->txq));
  394. }
  395. if (len > buf_len)
  396. len = buf_len;
  397. ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
  398. kfree(buf);
  399. return ret_cnt;
  400. }
  401. static const struct file_operations fops_credit_dist_stats = {
  402. .read = read_file_credit_dist_stats,
  403. .open = ath6kl_debugfs_open,
  404. .owner = THIS_MODULE,
  405. .llseek = default_llseek,
  406. };
  407. int ath6kl_debug_init(struct ath6kl *ar)
  408. {
  409. ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE);
  410. if (ar->debug.fwlog_buf.buf == NULL)
  411. return -ENOMEM;
  412. ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL);
  413. if (ar->debug.fwlog_tmp == NULL) {
  414. vfree(ar->debug.fwlog_buf.buf);
  415. return -ENOMEM;
  416. }
  417. spin_lock_init(&ar->debug.fwlog_lock);
  418. ar->debugfs_phy = debugfs_create_dir("ath6kl",
  419. ar->wdev->wiphy->debugfsdir);
  420. if (!ar->debugfs_phy) {
  421. vfree(ar->debug.fwlog_buf.buf);
  422. kfree(ar->debug.fwlog_tmp);
  423. return -ENOMEM;
  424. }
  425. debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
  426. &fops_tgt_stats);
  427. debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
  428. &fops_credit_dist_stats);
  429. debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar,
  430. &fops_fwlog);
  431. return 0;
  432. }
  433. void ath6kl_debug_cleanup(struct ath6kl *ar)
  434. {
  435. vfree(ar->debug.fwlog_buf.buf);
  436. kfree(ar->debug.fwlog_tmp);
  437. }
  438. #endif