debug.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
  4. * DebugFS code
  5. *
  6. * Copyright (c) 2010, ST-Ericsson
  7. * Author: Dmitry Tarnyagin <[email protected]>
  8. */
  9. #include <linux/module.h>
  10. #include <linux/debugfs.h>
  11. #include <linux/seq_file.h>
  12. #include "cw1200.h"
  13. #include "debug.h"
  14. #include "fwio.h"
  15. /* join_status */
  16. static const char * const cw1200_debug_join_status[] = {
  17. "passive",
  18. "monitor",
  19. "station (joining)",
  20. "station (not authenticated yet)",
  21. "station",
  22. "adhoc",
  23. "access point",
  24. };
  25. /* WSM_JOIN_PREAMBLE_... */
  26. static const char * const cw1200_debug_preamble[] = {
  27. "long",
  28. "short",
  29. "long on 1 and 2 Mbps",
  30. };
  31. static const char * const cw1200_debug_link_id[] = {
  32. "OFF",
  33. "REQ",
  34. "SOFT",
  35. "HARD",
  36. "RESET",
  37. "RESET_REMAP",
  38. };
  39. static const char *cw1200_debug_mode(int mode)
  40. {
  41. switch (mode) {
  42. case NL80211_IFTYPE_UNSPECIFIED:
  43. return "unspecified";
  44. case NL80211_IFTYPE_MONITOR:
  45. return "monitor";
  46. case NL80211_IFTYPE_STATION:
  47. return "station";
  48. case NL80211_IFTYPE_ADHOC:
  49. return "adhoc";
  50. case NL80211_IFTYPE_MESH_POINT:
  51. return "mesh point";
  52. case NL80211_IFTYPE_AP:
  53. return "access point";
  54. case NL80211_IFTYPE_P2P_CLIENT:
  55. return "p2p client";
  56. case NL80211_IFTYPE_P2P_GO:
  57. return "p2p go";
  58. default:
  59. return "unsupported";
  60. }
  61. }
  62. static void cw1200_queue_status_show(struct seq_file *seq,
  63. struct cw1200_queue *q)
  64. {
  65. int i;
  66. seq_printf(seq, "Queue %d:\n", q->queue_id);
  67. seq_printf(seq, " capacity: %zu\n", q->capacity);
  68. seq_printf(seq, " queued: %zu\n", q->num_queued);
  69. seq_printf(seq, " pending: %zu\n", q->num_pending);
  70. seq_printf(seq, " sent: %zu\n", q->num_sent);
  71. seq_printf(seq, " locked: %s\n", q->tx_locked_cnt ? "yes" : "no");
  72. seq_printf(seq, " overfull: %s\n", q->overfull ? "yes" : "no");
  73. seq_puts(seq, " link map: 0-> ");
  74. for (i = 0; i < q->stats->map_capacity; ++i)
  75. seq_printf(seq, "%.2d ", q->link_map_cache[i]);
  76. seq_printf(seq, "<-%zu\n", q->stats->map_capacity);
  77. }
  78. static void cw1200_debug_print_map(struct seq_file *seq,
  79. struct cw1200_common *priv,
  80. const char *label,
  81. u32 map)
  82. {
  83. int i;
  84. seq_printf(seq, "%s0-> ", label);
  85. for (i = 0; i < priv->tx_queue_stats.map_capacity; ++i)
  86. seq_printf(seq, "%s ", (map & BIT(i)) ? "**" : "..");
  87. seq_printf(seq, "<-%zu\n", priv->tx_queue_stats.map_capacity - 1);
  88. }
  89. static int cw1200_status_show(struct seq_file *seq, void *v)
  90. {
  91. int i;
  92. struct list_head *item;
  93. struct cw1200_common *priv = seq->private;
  94. struct cw1200_debug_priv *d = priv->debug;
  95. seq_puts(seq, "CW1200 Wireless LAN driver status\n");
  96. seq_printf(seq, "Hardware: %d.%d\n",
  97. priv->wsm_caps.hw_id,
  98. priv->wsm_caps.hw_subid);
  99. seq_printf(seq, "Firmware: %s %d.%d\n",
  100. cw1200_fw_types[priv->wsm_caps.fw_type],
  101. priv->wsm_caps.fw_ver,
  102. priv->wsm_caps.fw_build);
  103. seq_printf(seq, "FW API: %d\n",
  104. priv->wsm_caps.fw_api);
  105. seq_printf(seq, "FW caps: 0x%.4X\n",
  106. priv->wsm_caps.fw_cap);
  107. seq_printf(seq, "FW label: '%s'\n",
  108. priv->wsm_caps.fw_label);
  109. seq_printf(seq, "Mode: %s%s\n",
  110. cw1200_debug_mode(priv->mode),
  111. priv->listening ? " (listening)" : "");
  112. seq_printf(seq, "Join state: %s\n",
  113. cw1200_debug_join_status[priv->join_status]);
  114. if (priv->channel)
  115. seq_printf(seq, "Channel: %d%s\n",
  116. priv->channel->hw_value,
  117. priv->channel_switch_in_progress ?
  118. " (switching)" : "");
  119. if (priv->rx_filter.promiscuous)
  120. seq_puts(seq, "Filter: promisc\n");
  121. else if (priv->rx_filter.fcs)
  122. seq_puts(seq, "Filter: fcs\n");
  123. if (priv->rx_filter.bssid)
  124. seq_puts(seq, "Filter: bssid\n");
  125. if (!priv->disable_beacon_filter)
  126. seq_puts(seq, "Filter: beacons\n");
  127. if (priv->enable_beacon ||
  128. priv->mode == NL80211_IFTYPE_AP ||
  129. priv->mode == NL80211_IFTYPE_ADHOC ||
  130. priv->mode == NL80211_IFTYPE_MESH_POINT ||
  131. priv->mode == NL80211_IFTYPE_P2P_GO)
  132. seq_printf(seq, "Beaconing: %s\n",
  133. priv->enable_beacon ?
  134. "enabled" : "disabled");
  135. for (i = 0; i < 4; ++i)
  136. seq_printf(seq, "EDCA(%d): %d, %d, %d, %d, %d\n", i,
  137. priv->edca.params[i].cwmin,
  138. priv->edca.params[i].cwmax,
  139. priv->edca.params[i].aifns,
  140. priv->edca.params[i].txop_limit,
  141. priv->edca.params[i].max_rx_lifetime);
  142. if (priv->join_status == CW1200_JOIN_STATUS_STA) {
  143. static const char *pm_mode = "unknown";
  144. switch (priv->powersave_mode.mode) {
  145. case WSM_PSM_ACTIVE:
  146. pm_mode = "off";
  147. break;
  148. case WSM_PSM_PS:
  149. pm_mode = "on";
  150. break;
  151. case WSM_PSM_FAST_PS:
  152. pm_mode = "dynamic";
  153. break;
  154. }
  155. seq_printf(seq, "Preamble: %s\n",
  156. cw1200_debug_preamble[priv->association_mode.preamble]);
  157. seq_printf(seq, "AMPDU spcn: %d\n",
  158. priv->association_mode.mpdu_start_spacing);
  159. seq_printf(seq, "Basic rate: 0x%.8X\n",
  160. le32_to_cpu(priv->association_mode.basic_rate_set));
  161. seq_printf(seq, "Bss lost: %d beacons\n",
  162. priv->bss_params.beacon_lost_count);
  163. seq_printf(seq, "AID: %d\n",
  164. priv->bss_params.aid);
  165. seq_printf(seq, "Rates: 0x%.8X\n",
  166. priv->bss_params.operational_rate_set);
  167. seq_printf(seq, "Powersave: %s\n", pm_mode);
  168. }
  169. seq_printf(seq, "HT: %s\n",
  170. cw1200_is_ht(&priv->ht_info) ? "on" : "off");
  171. if (cw1200_is_ht(&priv->ht_info)) {
  172. seq_printf(seq, "Greenfield: %s\n",
  173. cw1200_ht_greenfield(&priv->ht_info) ? "yes" : "no");
  174. seq_printf(seq, "AMPDU dens: %d\n",
  175. cw1200_ht_ampdu_density(&priv->ht_info));
  176. }
  177. seq_printf(seq, "RSSI thold: %d\n",
  178. priv->cqm_rssi_thold);
  179. seq_printf(seq, "RSSI hyst: %d\n",
  180. priv->cqm_rssi_hyst);
  181. seq_printf(seq, "Long retr: %d\n",
  182. priv->long_frame_max_tx_count);
  183. seq_printf(seq, "Short retr: %d\n",
  184. priv->short_frame_max_tx_count);
  185. spin_lock_bh(&priv->tx_policy_cache.lock);
  186. i = 0;
  187. list_for_each(item, &priv->tx_policy_cache.used)
  188. ++i;
  189. spin_unlock_bh(&priv->tx_policy_cache.lock);
  190. seq_printf(seq, "RC in use: %d\n", i);
  191. seq_puts(seq, "\n");
  192. for (i = 0; i < 4; ++i) {
  193. cw1200_queue_status_show(seq, &priv->tx_queue[i]);
  194. seq_puts(seq, "\n");
  195. }
  196. cw1200_debug_print_map(seq, priv, "Link map: ",
  197. priv->link_id_map);
  198. cw1200_debug_print_map(seq, priv, "Asleep map: ",
  199. priv->sta_asleep_mask);
  200. cw1200_debug_print_map(seq, priv, "PSPOLL map: ",
  201. priv->pspoll_mask);
  202. seq_puts(seq, "\n");
  203. for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) {
  204. if (priv->link_id_db[i].status) {
  205. seq_printf(seq, "Link %d: %s, %pM\n",
  206. i + 1,
  207. cw1200_debug_link_id[priv->link_id_db[i].status],
  208. priv->link_id_db[i].mac);
  209. }
  210. }
  211. seq_puts(seq, "\n");
  212. seq_printf(seq, "BH status: %s\n",
  213. atomic_read(&priv->bh_term) ? "terminated" : "alive");
  214. seq_printf(seq, "Pending RX: %d\n",
  215. atomic_read(&priv->bh_rx));
  216. seq_printf(seq, "Pending TX: %d\n",
  217. atomic_read(&priv->bh_tx));
  218. if (priv->bh_error)
  219. seq_printf(seq, "BH errcode: %d\n",
  220. priv->bh_error);
  221. seq_printf(seq, "TX bufs: %d x %d bytes\n",
  222. priv->wsm_caps.input_buffers,
  223. priv->wsm_caps.input_buffer_size);
  224. seq_printf(seq, "Used bufs: %d\n",
  225. priv->hw_bufs_used);
  226. seq_printf(seq, "Powermgmt: %s\n",
  227. priv->powersave_enabled ? "on" : "off");
  228. seq_printf(seq, "Device: %s\n",
  229. priv->device_can_sleep ? "asleep" : "awake");
  230. spin_lock(&priv->wsm_cmd.lock);
  231. seq_printf(seq, "WSM status: %s\n",
  232. priv->wsm_cmd.done ? "idle" : "active");
  233. seq_printf(seq, "WSM cmd: 0x%.4X (%td bytes)\n",
  234. priv->wsm_cmd.cmd, priv->wsm_cmd.len);
  235. seq_printf(seq, "WSM retval: %d\n",
  236. priv->wsm_cmd.ret);
  237. spin_unlock(&priv->wsm_cmd.lock);
  238. seq_printf(seq, "Datapath: %s\n",
  239. atomic_read(&priv->tx_lock) ? "locked" : "unlocked");
  240. if (atomic_read(&priv->tx_lock))
  241. seq_printf(seq, "TXlock cnt: %d\n",
  242. atomic_read(&priv->tx_lock));
  243. seq_printf(seq, "TXed: %d\n",
  244. d->tx);
  245. seq_printf(seq, "AGG TXed: %d\n",
  246. d->tx_agg);
  247. seq_printf(seq, "MULTI TXed: %d (%d)\n",
  248. d->tx_multi, d->tx_multi_frames);
  249. seq_printf(seq, "RXed: %d\n",
  250. d->rx);
  251. seq_printf(seq, "AGG RXed: %d\n",
  252. d->rx_agg);
  253. seq_printf(seq, "TX miss: %d\n",
  254. d->tx_cache_miss);
  255. seq_printf(seq, "TX align: %d\n",
  256. d->tx_align);
  257. seq_printf(seq, "TX burst: %d\n",
  258. d->tx_burst);
  259. seq_printf(seq, "TX TTL: %d\n",
  260. d->tx_ttl);
  261. seq_printf(seq, "Scan: %s\n",
  262. atomic_read(&priv->scan.in_progress) ? "active" : "idle");
  263. return 0;
  264. }
  265. DEFINE_SHOW_ATTRIBUTE(cw1200_status);
  266. static int cw1200_counters_show(struct seq_file *seq, void *v)
  267. {
  268. int ret;
  269. struct cw1200_common *priv = seq->private;
  270. struct wsm_mib_counters_table counters;
  271. ret = wsm_get_counters_table(priv, &counters);
  272. if (ret)
  273. return ret;
  274. #define PUT_COUNTER(tab, name) \
  275. seq_printf(seq, "%s:" tab "%d\n", #name, \
  276. __le32_to_cpu(counters.name))
  277. PUT_COUNTER("\t\t", plcp_errors);
  278. PUT_COUNTER("\t\t", fcs_errors);
  279. PUT_COUNTER("\t\t", tx_packets);
  280. PUT_COUNTER("\t\t", rx_packets);
  281. PUT_COUNTER("\t\t", rx_packet_errors);
  282. PUT_COUNTER("\t", rx_decryption_failures);
  283. PUT_COUNTER("\t\t", rx_mic_failures);
  284. PUT_COUNTER("\t", rx_no_key_failures);
  285. PUT_COUNTER("\t", tx_multicast_frames);
  286. PUT_COUNTER("\t", tx_frames_success);
  287. PUT_COUNTER("\t", tx_frame_failures);
  288. PUT_COUNTER("\t", tx_frames_retried);
  289. PUT_COUNTER("\t", tx_frames_multi_retried);
  290. PUT_COUNTER("\t", rx_frame_duplicates);
  291. PUT_COUNTER("\t\t", rts_success);
  292. PUT_COUNTER("\t\t", rts_failures);
  293. PUT_COUNTER("\t\t", ack_failures);
  294. PUT_COUNTER("\t", rx_multicast_frames);
  295. PUT_COUNTER("\t", rx_frames_success);
  296. PUT_COUNTER("\t", rx_cmac_icv_errors);
  297. PUT_COUNTER("\t\t", rx_cmac_replays);
  298. PUT_COUNTER("\t", rx_mgmt_ccmp_replays);
  299. #undef PUT_COUNTER
  300. return 0;
  301. }
  302. DEFINE_SHOW_ATTRIBUTE(cw1200_counters);
  303. static ssize_t cw1200_wsm_dumps(struct file *file,
  304. const char __user *user_buf, size_t count, loff_t *ppos)
  305. {
  306. struct cw1200_common *priv = file->private_data;
  307. char buf[1];
  308. if (!count)
  309. return -EINVAL;
  310. if (copy_from_user(buf, user_buf, 1))
  311. return -EFAULT;
  312. if (buf[0] == '1')
  313. priv->wsm_enable_wsm_dumps = 1;
  314. else
  315. priv->wsm_enable_wsm_dumps = 0;
  316. return count;
  317. }
  318. static const struct file_operations fops_wsm_dumps = {
  319. .open = simple_open,
  320. .write = cw1200_wsm_dumps,
  321. .llseek = default_llseek,
  322. };
  323. int cw1200_debug_init(struct cw1200_common *priv)
  324. {
  325. int ret = -ENOMEM;
  326. struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv),
  327. GFP_KERNEL);
  328. priv->debug = d;
  329. if (!d)
  330. return ret;
  331. d->debugfs_phy = debugfs_create_dir("cw1200",
  332. priv->hw->wiphy->debugfsdir);
  333. debugfs_create_file("status", 0400, d->debugfs_phy, priv,
  334. &cw1200_status_fops);
  335. debugfs_create_file("counters", 0400, d->debugfs_phy, priv,
  336. &cw1200_counters_fops);
  337. debugfs_create_file("wsm_dumps", 0200, d->debugfs_phy, priv,
  338. &fops_wsm_dumps);
  339. return 0;
  340. }
  341. void cw1200_debug_release(struct cw1200_common *priv)
  342. {
  343. struct cw1200_debug_priv *d = priv->debug;
  344. if (d) {
  345. debugfs_remove_recursive(d->debugfs_phy);
  346. priv->debug = NULL;
  347. kfree(d);
  348. }
  349. }