htc_drv_debug.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*
  2. * Copyright (c) 2010-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 "htc.h"
  17. static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
  18. size_t count, loff_t *ppos)
  19. {
  20. struct ath9k_htc_priv *priv = file->private_data;
  21. struct ath9k_htc_target_int_stats cmd_rsp;
  22. char buf[512];
  23. unsigned int len = 0;
  24. int ret = 0;
  25. memset(&cmd_rsp, 0, sizeof(cmd_rsp));
  26. ath9k_htc_ps_wakeup(priv);
  27. WMI_CMD(WMI_INT_STATS_CMDID);
  28. if (ret) {
  29. ath9k_htc_ps_restore(priv);
  30. return -EINVAL;
  31. }
  32. ath9k_htc_ps_restore(priv);
  33. len += scnprintf(buf + len, sizeof(buf) - len,
  34. "%20s : %10u\n", "RX",
  35. be32_to_cpu(cmd_rsp.rx));
  36. len += scnprintf(buf + len, sizeof(buf) - len,
  37. "%20s : %10u\n", "RXORN",
  38. be32_to_cpu(cmd_rsp.rxorn));
  39. len += scnprintf(buf + len, sizeof(buf) - len,
  40. "%20s : %10u\n", "RXEOL",
  41. be32_to_cpu(cmd_rsp.rxeol));
  42. len += scnprintf(buf + len, sizeof(buf) - len,
  43. "%20s : %10u\n", "TXURN",
  44. be32_to_cpu(cmd_rsp.txurn));
  45. len += scnprintf(buf + len, sizeof(buf) - len,
  46. "%20s : %10u\n", "TXTO",
  47. be32_to_cpu(cmd_rsp.txto));
  48. len += scnprintf(buf + len, sizeof(buf) - len,
  49. "%20s : %10u\n", "CST",
  50. be32_to_cpu(cmd_rsp.cst));
  51. if (len > sizeof(buf))
  52. len = sizeof(buf);
  53. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  54. }
  55. static const struct file_operations fops_tgt_int_stats = {
  56. .read = read_file_tgt_int_stats,
  57. .open = simple_open,
  58. .owner = THIS_MODULE,
  59. .llseek = default_llseek,
  60. };
  61. static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
  62. size_t count, loff_t *ppos)
  63. {
  64. struct ath9k_htc_priv *priv = file->private_data;
  65. struct ath9k_htc_target_tx_stats cmd_rsp;
  66. char buf[512];
  67. unsigned int len = 0;
  68. int ret = 0;
  69. memset(&cmd_rsp, 0, sizeof(cmd_rsp));
  70. ath9k_htc_ps_wakeup(priv);
  71. WMI_CMD(WMI_TX_STATS_CMDID);
  72. if (ret) {
  73. ath9k_htc_ps_restore(priv);
  74. return -EINVAL;
  75. }
  76. ath9k_htc_ps_restore(priv);
  77. len += scnprintf(buf + len, sizeof(buf) - len,
  78. "%20s : %10u\n", "Xretries",
  79. be32_to_cpu(cmd_rsp.xretries));
  80. len += scnprintf(buf + len, sizeof(buf) - len,
  81. "%20s : %10u\n", "FifoErr",
  82. be32_to_cpu(cmd_rsp.fifoerr));
  83. len += scnprintf(buf + len, sizeof(buf) - len,
  84. "%20s : %10u\n", "Filtered",
  85. be32_to_cpu(cmd_rsp.filtered));
  86. len += scnprintf(buf + len, sizeof(buf) - len,
  87. "%20s : %10u\n", "TimerExp",
  88. be32_to_cpu(cmd_rsp.timer_exp));
  89. len += scnprintf(buf + len, sizeof(buf) - len,
  90. "%20s : %10u\n", "ShortRetries",
  91. be32_to_cpu(cmd_rsp.shortretries));
  92. len += scnprintf(buf + len, sizeof(buf) - len,
  93. "%20s : %10u\n", "LongRetries",
  94. be32_to_cpu(cmd_rsp.longretries));
  95. len += scnprintf(buf + len, sizeof(buf) - len,
  96. "%20s : %10u\n", "QueueNull",
  97. be32_to_cpu(cmd_rsp.qnull));
  98. len += scnprintf(buf + len, sizeof(buf) - len,
  99. "%20s : %10u\n", "EncapFail",
  100. be32_to_cpu(cmd_rsp.encap_fail));
  101. len += scnprintf(buf + len, sizeof(buf) - len,
  102. "%20s : %10u\n", "NoBuf",
  103. be32_to_cpu(cmd_rsp.nobuf));
  104. if (len > sizeof(buf))
  105. len = sizeof(buf);
  106. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  107. }
  108. static const struct file_operations fops_tgt_tx_stats = {
  109. .read = read_file_tgt_tx_stats,
  110. .open = simple_open,
  111. .owner = THIS_MODULE,
  112. .llseek = default_llseek,
  113. };
  114. static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
  115. size_t count, loff_t *ppos)
  116. {
  117. struct ath9k_htc_priv *priv = file->private_data;
  118. struct ath9k_htc_target_rx_stats cmd_rsp;
  119. char buf[512];
  120. unsigned int len = 0;
  121. int ret = 0;
  122. memset(&cmd_rsp, 0, sizeof(cmd_rsp));
  123. ath9k_htc_ps_wakeup(priv);
  124. WMI_CMD(WMI_RX_STATS_CMDID);
  125. if (ret) {
  126. ath9k_htc_ps_restore(priv);
  127. return -EINVAL;
  128. }
  129. ath9k_htc_ps_restore(priv);
  130. len += scnprintf(buf + len, sizeof(buf) - len,
  131. "%20s : %10u\n", "NoBuf",
  132. be32_to_cpu(cmd_rsp.nobuf));
  133. len += scnprintf(buf + len, sizeof(buf) - len,
  134. "%20s : %10u\n", "HostSend",
  135. be32_to_cpu(cmd_rsp.host_send));
  136. len += scnprintf(buf + len, sizeof(buf) - len,
  137. "%20s : %10u\n", "HostDone",
  138. be32_to_cpu(cmd_rsp.host_done));
  139. if (len > sizeof(buf))
  140. len = sizeof(buf);
  141. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  142. }
  143. static const struct file_operations fops_tgt_rx_stats = {
  144. .read = read_file_tgt_rx_stats,
  145. .open = simple_open,
  146. .owner = THIS_MODULE,
  147. .llseek = default_llseek,
  148. };
  149. static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
  150. size_t count, loff_t *ppos)
  151. {
  152. struct ath9k_htc_priv *priv = file->private_data;
  153. char buf[512];
  154. unsigned int len = 0;
  155. len += scnprintf(buf + len, sizeof(buf) - len,
  156. "%20s : %10u\n", "Buffers queued",
  157. priv->debug.tx_stats.buf_queued);
  158. len += scnprintf(buf + len, sizeof(buf) - len,
  159. "%20s : %10u\n", "Buffers completed",
  160. priv->debug.tx_stats.buf_completed);
  161. len += scnprintf(buf + len, sizeof(buf) - len,
  162. "%20s : %10u\n", "SKBs queued",
  163. priv->debug.tx_stats.skb_queued);
  164. len += scnprintf(buf + len, sizeof(buf) - len,
  165. "%20s : %10u\n", "SKBs success",
  166. priv->debug.tx_stats.skb_success);
  167. len += scnprintf(buf + len, sizeof(buf) - len,
  168. "%20s : %10u\n", "SKBs failed",
  169. priv->debug.tx_stats.skb_failed);
  170. len += scnprintf(buf + len, sizeof(buf) - len,
  171. "%20s : %10u\n", "CAB queued",
  172. priv->debug.tx_stats.cab_queued);
  173. len += scnprintf(buf + len, sizeof(buf) - len,
  174. "%20s : %10u\n", "BE queued",
  175. priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]);
  176. len += scnprintf(buf + len, sizeof(buf) - len,
  177. "%20s : %10u\n", "BK queued",
  178. priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]);
  179. len += scnprintf(buf + len, sizeof(buf) - len,
  180. "%20s : %10u\n", "VI queued",
  181. priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]);
  182. len += scnprintf(buf + len, sizeof(buf) - len,
  183. "%20s : %10u\n", "VO queued",
  184. priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]);
  185. if (len > sizeof(buf))
  186. len = sizeof(buf);
  187. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  188. }
  189. static const struct file_operations fops_xmit = {
  190. .read = read_file_xmit,
  191. .open = simple_open,
  192. .owner = THIS_MODULE,
  193. .llseek = default_llseek,
  194. };
  195. void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
  196. struct ath_rx_status *rs)
  197. {
  198. ath9k_cmn_debug_stat_rx(&priv->debug.rx_stats, rs);
  199. }
  200. static ssize_t read_file_skb_rx(struct file *file, char __user *user_buf,
  201. size_t count, loff_t *ppos)
  202. {
  203. struct ath9k_htc_priv *priv = file->private_data;
  204. char *buf;
  205. unsigned int len = 0, size = 1500;
  206. ssize_t retval = 0;
  207. buf = kzalloc(size, GFP_KERNEL);
  208. if (buf == NULL)
  209. return -ENOMEM;
  210. len += scnprintf(buf + len, size - len,
  211. "%20s : %10u\n", "SKBs allocated",
  212. priv->debug.skbrx_stats.skb_allocated);
  213. len += scnprintf(buf + len, size - len,
  214. "%20s : %10u\n", "SKBs completed",
  215. priv->debug.skbrx_stats.skb_completed);
  216. len += scnprintf(buf + len, size - len,
  217. "%20s : %10u\n", "SKBs Dropped",
  218. priv->debug.skbrx_stats.skb_dropped);
  219. if (len > size)
  220. len = size;
  221. retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
  222. kfree(buf);
  223. return retval;
  224. }
  225. static const struct file_operations fops_skb_rx = {
  226. .read = read_file_skb_rx,
  227. .open = simple_open,
  228. .owner = THIS_MODULE,
  229. .llseek = default_llseek,
  230. };
  231. static ssize_t read_file_slot(struct file *file, char __user *user_buf,
  232. size_t count, loff_t *ppos)
  233. {
  234. struct ath9k_htc_priv *priv = file->private_data;
  235. char buf[512];
  236. unsigned int len;
  237. spin_lock_bh(&priv->tx.tx_lock);
  238. len = scnprintf(buf, sizeof(buf),
  239. "TX slot bitmap : %*pb\n"
  240. "Used slots : %d\n",
  241. MAX_TX_BUF_NUM, priv->tx.tx_slot,
  242. bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
  243. spin_unlock_bh(&priv->tx.tx_lock);
  244. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  245. }
  246. static const struct file_operations fops_slot = {
  247. .read = read_file_slot,
  248. .open = simple_open,
  249. .owner = THIS_MODULE,
  250. .llseek = default_llseek,
  251. };
  252. static ssize_t read_file_queue(struct file *file, char __user *user_buf,
  253. size_t count, loff_t *ppos)
  254. {
  255. struct ath9k_htc_priv *priv = file->private_data;
  256. char buf[512];
  257. unsigned int len = 0;
  258. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  259. "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
  260. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  261. "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
  262. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  263. "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
  264. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  265. "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
  266. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  267. "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
  268. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  269. "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
  270. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  271. "Failed queue", skb_queue_len(&priv->tx.tx_failed));
  272. spin_lock_bh(&priv->tx.tx_lock);
  273. len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
  274. "Queued count", priv->tx.queued_cnt);
  275. spin_unlock_bh(&priv->tx.tx_lock);
  276. if (len > sizeof(buf))
  277. len = sizeof(buf);
  278. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  279. }
  280. static const struct file_operations fops_queue = {
  281. .read = read_file_queue,
  282. .open = simple_open,
  283. .owner = THIS_MODULE,
  284. .llseek = default_llseek,
  285. };
  286. static ssize_t read_file_debug(struct file *file, char __user *user_buf,
  287. size_t count, loff_t *ppos)
  288. {
  289. struct ath9k_htc_priv *priv = file->private_data;
  290. struct ath_common *common = ath9k_hw_common(priv->ah);
  291. char buf[32];
  292. unsigned int len;
  293. len = sprintf(buf, "0x%08x\n", common->debug_mask);
  294. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  295. }
  296. static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
  297. size_t count, loff_t *ppos)
  298. {
  299. struct ath9k_htc_priv *priv = file->private_data;
  300. struct ath_common *common = ath9k_hw_common(priv->ah);
  301. unsigned long mask;
  302. char buf[32];
  303. ssize_t len;
  304. len = min(count, sizeof(buf) - 1);
  305. if (copy_from_user(buf, user_buf, len))
  306. return -EFAULT;
  307. buf[len] = '\0';
  308. if (kstrtoul(buf, 0, &mask))
  309. return -EINVAL;
  310. common->debug_mask = mask;
  311. return count;
  312. }
  313. static const struct file_operations fops_debug = {
  314. .read = read_file_debug,
  315. .write = write_file_debug,
  316. .open = simple_open,
  317. .owner = THIS_MODULE,
  318. .llseek = default_llseek,
  319. };
  320. /* Ethtool support for get-stats */
  321. #define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
  322. static const char ath9k_htc_gstrings_stats[][ETH_GSTRING_LEN] = {
  323. "tx_pkts_nic",
  324. "tx_bytes_nic",
  325. "rx_pkts_nic",
  326. "rx_bytes_nic",
  327. AMKSTR(d_tx_pkts),
  328. "d_rx_crc_err",
  329. "d_rx_decrypt_crc_err",
  330. "d_rx_phy_err",
  331. "d_rx_mic_err",
  332. "d_rx_pre_delim_crc_err",
  333. "d_rx_post_delim_crc_err",
  334. "d_rx_decrypt_busy_err",
  335. "d_rx_phyerr_radar",
  336. "d_rx_phyerr_ofdm_timing",
  337. "d_rx_phyerr_cck_timing",
  338. };
  339. #define ATH9K_HTC_SSTATS_LEN ARRAY_SIZE(ath9k_htc_gstrings_stats)
  340. void ath9k_htc_get_et_strings(struct ieee80211_hw *hw,
  341. struct ieee80211_vif *vif,
  342. u32 sset, u8 *data)
  343. {
  344. if (sset == ETH_SS_STATS)
  345. memcpy(data, *ath9k_htc_gstrings_stats,
  346. sizeof(ath9k_htc_gstrings_stats));
  347. }
  348. int ath9k_htc_get_et_sset_count(struct ieee80211_hw *hw,
  349. struct ieee80211_vif *vif, int sset)
  350. {
  351. if (sset == ETH_SS_STATS)
  352. return ATH9K_HTC_SSTATS_LEN;
  353. return 0;
  354. }
  355. #define STXBASE priv->debug.tx_stats
  356. #define SRXBASE priv->debug.rx_stats
  357. #define SKBTXBASE priv->debug.tx_stats
  358. #define SKBRXBASE priv->debug.skbrx_stats
  359. #define ASTXQ(a) \
  360. data[i++] = STXBASE.a[IEEE80211_AC_BE]; \
  361. data[i++] = STXBASE.a[IEEE80211_AC_BK]; \
  362. data[i++] = STXBASE.a[IEEE80211_AC_VI]; \
  363. data[i++] = STXBASE.a[IEEE80211_AC_VO]
  364. void ath9k_htc_get_et_stats(struct ieee80211_hw *hw,
  365. struct ieee80211_vif *vif,
  366. struct ethtool_stats *stats, u64 *data)
  367. {
  368. struct ath9k_htc_priv *priv = hw->priv;
  369. int i = 0;
  370. data[i++] = SKBTXBASE.skb_success;
  371. data[i++] = SKBTXBASE.skb_success_bytes;
  372. data[i++] = SKBRXBASE.skb_completed;
  373. data[i++] = SKBRXBASE.skb_completed_bytes;
  374. ASTXQ(queue_stats);
  375. data[i++] = SRXBASE.crc_err;
  376. data[i++] = SRXBASE.decrypt_crc_err;
  377. data[i++] = SRXBASE.phy_err;
  378. data[i++] = SRXBASE.mic_err;
  379. data[i++] = SRXBASE.pre_delim_crc_err;
  380. data[i++] = SRXBASE.post_delim_crc_err;
  381. data[i++] = SRXBASE.decrypt_busy_err;
  382. data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_RADAR];
  383. data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_OFDM_TIMING];
  384. data[i++] = SRXBASE.phy_err_stats[ATH9K_PHYERR_CCK_TIMING];
  385. WARN_ON(i != ATH9K_HTC_SSTATS_LEN);
  386. }
  387. void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv)
  388. {
  389. ath9k_cmn_spectral_deinit_debug(&priv->spec_priv);
  390. }
  391. int ath9k_htc_init_debug(struct ath_hw *ah)
  392. {
  393. struct ath_common *common = ath9k_hw_common(ah);
  394. struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
  395. priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
  396. priv->hw->wiphy->debugfsdir);
  397. if (!priv->debug.debugfs_phy)
  398. return -ENOMEM;
  399. ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy);
  400. debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
  401. priv, &fops_tgt_int_stats);
  402. debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
  403. priv, &fops_tgt_tx_stats);
  404. debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
  405. priv, &fops_tgt_rx_stats);
  406. debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
  407. priv, &fops_xmit);
  408. debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy,
  409. priv, &fops_skb_rx);
  410. ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats);
  411. ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats);
  412. debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
  413. priv, &fops_slot);
  414. debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
  415. priv, &fops_queue);
  416. debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
  417. priv, &fops_debug);
  418. ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah);
  419. ath9k_cmn_debug_modal_eeprom(priv->debug.debugfs_phy, priv->ah);
  420. return 0;
  421. }