iwl-debugfs.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /******************************************************************************
  2. *
  3. * GPL LICENSE SUMMARY
  4. *
  5. * Copyright(c) 2008 Intel Corporation. All rights reserved.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of version 2 of the GNU General Public License as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  19. * USA
  20. *
  21. * The full GNU General Public License is included in this distribution
  22. * in the file called LICENSE.GPL.
  23. *
  24. * Contact Information:
  25. * Intel Linux Wireless <ilw@linux.intel.com>
  26. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  27. *****************************************************************************/
  28. #include <linux/kernel.h>
  29. #include <linux/module.h>
  30. #include <linux/debugfs.h>
  31. #include <linux/ieee80211.h>
  32. #include <net/mac80211.h>
  33. #include "iwl-dev.h"
  34. #include "iwl-debug.h"
  35. #include "iwl-core.h"
  36. #include "iwl-io.h"
  37. /* create and remove of files */
  38. #define DEBUGFS_ADD_DIR(name, parent) do { \
  39. dbgfs->dir_##name = debugfs_create_dir(#name, parent); \
  40. if (!(dbgfs->dir_##name)) \
  41. goto err; \
  42. } while (0)
  43. #define DEBUGFS_ADD_FILE(name, parent) do { \
  44. dbgfs->dbgfs_##parent##_files.file_##name = \
  45. debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
  46. &iwl_dbgfs_##name##_ops); \
  47. if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
  48. goto err; \
  49. } while (0)
  50. #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
  51. dbgfs->dbgfs_##parent##_files.file_##name = \
  52. debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
  53. if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
  54. || !dbgfs->dbgfs_##parent##_files.file_##name) \
  55. goto err; \
  56. } while (0)
  57. #define DEBUGFS_REMOVE(name) do { \
  58. debugfs_remove(name); \
  59. name = NULL; \
  60. } while (0);
  61. /* file operation */
  62. #define DEBUGFS_READ_FUNC(name) \
  63. static ssize_t iwl_dbgfs_##name##_read(struct file *file, \
  64. char __user *user_buf, \
  65. size_t count, loff_t *ppos);
  66. #define DEBUGFS_WRITE_FUNC(name) \
  67. static ssize_t iwl_dbgfs_##name##_write(struct file *file, \
  68. const char __user *user_buf, \
  69. size_t count, loff_t *ppos);
  70. static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
  71. {
  72. file->private_data = inode->i_private;
  73. return 0;
  74. }
  75. #define DEBUGFS_READ_FILE_OPS(name) \
  76. DEBUGFS_READ_FUNC(name); \
  77. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  78. .read = iwl_dbgfs_##name##_read, \
  79. .open = iwl_dbgfs_open_file_generic, \
  80. };
  81. #define DEBUGFS_WRITE_FILE_OPS(name) \
  82. DEBUGFS_WRITE_FUNC(name); \
  83. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  84. .write = iwl_dbgfs_##name##_write, \
  85. .open = iwl_dbgfs_open_file_generic, \
  86. };
  87. #define DEBUGFS_READ_WRITE_FILE_OPS(name) \
  88. DEBUGFS_READ_FUNC(name); \
  89. DEBUGFS_WRITE_FUNC(name); \
  90. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  91. .write = iwl_dbgfs_##name##_write, \
  92. .read = iwl_dbgfs_##name##_read, \
  93. .open = iwl_dbgfs_open_file_generic, \
  94. };
  95. static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
  96. char __user *user_buf,
  97. size_t count, loff_t *ppos) {
  98. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  99. char buf[256];
  100. int pos = 0;
  101. const size_t bufsz = sizeof(buf);
  102. pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
  103. priv->tx_stats[0].cnt);
  104. pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
  105. priv->tx_stats[1].cnt);
  106. pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
  107. priv->tx_stats[2].cnt);
  108. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  109. }
  110. static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
  111. char __user *user_buf,
  112. size_t count, loff_t *ppos) {
  113. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  114. char buf[256];
  115. int pos = 0;
  116. const size_t bufsz = sizeof(buf);
  117. pos += scnprintf(buf + pos, bufsz - pos, "mgmt: %u\n",
  118. priv->rx_stats[0].cnt);
  119. pos += scnprintf(buf + pos, bufsz - pos, "ctrl: %u\n",
  120. priv->rx_stats[1].cnt);
  121. pos += scnprintf(buf + pos, bufsz - pos, "data: %u\n",
  122. priv->rx_stats[2].cnt);
  123. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  124. }
  125. #define BYTE1_MASK 0x000000ff;
  126. #define BYTE2_MASK 0x0000ffff;
  127. #define BYTE3_MASK 0x00ffffff;
  128. static ssize_t iwl_dbgfs_sram_read(struct file *file,
  129. char __user *user_buf,
  130. size_t count, loff_t *ppos)
  131. {
  132. u32 val;
  133. char buf[1024];
  134. ssize_t ret;
  135. int i;
  136. int pos = 0;
  137. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  138. const size_t bufsz = sizeof(buf);
  139. printk(KERN_DEBUG "offset is: 0x%x\tlen is: 0x%x\n",
  140. priv->dbgfs->sram_offset, priv->dbgfs->sram_len);
  141. iwl_grab_nic_access(priv);
  142. for (i = priv->dbgfs->sram_len; i > 0; i -= 4) {
  143. val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \
  144. priv->dbgfs->sram_len - i);
  145. if (i < 4) {
  146. switch (i) {
  147. case 1:
  148. val &= BYTE1_MASK;
  149. break;
  150. case 2:
  151. val &= BYTE2_MASK;
  152. break;
  153. case 3:
  154. val &= BYTE3_MASK;
  155. break;
  156. }
  157. }
  158. pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
  159. }
  160. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  161. iwl_release_nic_access(priv);
  162. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  163. return ret;
  164. }
  165. static ssize_t iwl_dbgfs_sram_write(struct file *file,
  166. const char __user *user_buf,
  167. size_t count, loff_t *ppos)
  168. {
  169. struct iwl_priv *priv = file->private_data;
  170. char buf[64];
  171. int buf_size;
  172. u32 offset, len;
  173. memset(buf, 0, sizeof(buf));
  174. buf_size = min(count, sizeof(buf) - 1);
  175. if (copy_from_user(buf, user_buf, buf_size))
  176. return -EFAULT;
  177. if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
  178. priv->dbgfs->sram_offset = offset;
  179. priv->dbgfs->sram_len = len;
  180. } else {
  181. priv->dbgfs->sram_offset = 0;
  182. priv->dbgfs->sram_len = 0;
  183. }
  184. return count;
  185. }
  186. static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
  187. size_t count, loff_t *ppos)
  188. {
  189. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  190. struct iwl_station_entry *station;
  191. int max_sta = priv->hw_params.max_stations;
  192. char *buf;
  193. int i, j, pos = 0;
  194. ssize_t ret;
  195. /* Add 30 for initial string */
  196. const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
  197. buf = kmalloc(bufsz, GFP_KERNEL);
  198. if (!buf)
  199. return -ENOMEM;
  200. pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
  201. priv->num_stations);
  202. for (i = 0; i < max_sta; i++) {
  203. station = &priv->stations[i];
  204. if (station->used) {
  205. pos += scnprintf(buf + pos, bufsz - pos,
  206. "station %d:\ngeneral data:\n", i+1);
  207. pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
  208. station->sta.sta.sta_id);
  209. pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
  210. station->sta.mode);
  211. pos += scnprintf(buf + pos, bufsz - pos,
  212. "flags: 0x%x\n",
  213. station->sta.station_flags_msk);
  214. pos += scnprintf(buf + pos, bufsz - pos,
  215. "ps_status: %u\n", station->ps_status);
  216. pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
  217. pos += scnprintf(buf + pos, bufsz - pos,
  218. "seq_num\t\ttxq_id");
  219. pos += scnprintf(buf + pos, bufsz - pos,
  220. "\tframe_count\twait_for_ba\t");
  221. pos += scnprintf(buf + pos, bufsz - pos,
  222. "start_idx\tbitmap0\t");
  223. pos += scnprintf(buf + pos, bufsz - pos,
  224. "bitmap1\trate_n_flags");
  225. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  226. for (j = 0; j < MAX_TID_COUNT; j++) {
  227. pos += scnprintf(buf + pos, bufsz - pos,
  228. "[%d]:\t\t%u", j,
  229. station->tid[j].seq_number);
  230. pos += scnprintf(buf + pos, bufsz - pos,
  231. "\t%u\t\t%u\t\t%u\t\t",
  232. station->tid[j].agg.txq_id,
  233. station->tid[j].agg.frame_count,
  234. station->tid[j].agg.wait_for_ba);
  235. pos += scnprintf(buf + pos, bufsz - pos,
  236. "%u\t%llu\t%u",
  237. station->tid[j].agg.start_idx,
  238. (unsigned long long)station->tid[j].agg.bitmap,
  239. station->tid[j].agg.rate_n_flags);
  240. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  241. }
  242. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  243. }
  244. }
  245. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  246. kfree(buf);
  247. return ret;
  248. }
  249. static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
  250. char __user *user_buf,
  251. size_t count,
  252. loff_t *ppos)
  253. {
  254. ssize_t ret;
  255. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  256. int pos = 0, ofs = 0, buf_size = 0;
  257. const u8 *ptr;
  258. char *buf;
  259. size_t eeprom_len = priv->cfg->eeprom_size;
  260. buf_size = 4 * eeprom_len + 256;
  261. if (eeprom_len % 16) {
  262. IWL_ERROR("EEPROM size is not multiple of 16.\n");
  263. return -ENODATA;
  264. }
  265. /* 4 characters for byte 0xYY */
  266. buf = kzalloc(buf_size, GFP_KERNEL);
  267. if (!buf) {
  268. IWL_ERROR("Can not allocate Buffer\n");
  269. return -ENOMEM;
  270. }
  271. ptr = priv->eeprom;
  272. for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
  273. pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
  274. hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
  275. buf_size - pos, 0);
  276. pos += strlen(buf);
  277. if (buf_size - pos > 0)
  278. buf[pos++] = '\n';
  279. }
  280. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  281. kfree(buf);
  282. return ret;
  283. }
  284. static ssize_t iwl_dbgfs_log_event_write(struct file *file,
  285. const char __user *user_buf,
  286. size_t count, loff_t *ppos)
  287. {
  288. struct iwl_priv *priv = file->private_data;
  289. u32 event_log_flag;
  290. char buf[8];
  291. int buf_size;
  292. memset(buf, 0, sizeof(buf));
  293. buf_size = min(count, sizeof(buf) - 1);
  294. if (copy_from_user(buf, user_buf, buf_size))
  295. return -EFAULT;
  296. if (sscanf(buf, "%d", &event_log_flag) != 1)
  297. return -EFAULT;
  298. if (event_log_flag == 1)
  299. iwl_dump_nic_event_log(priv);
  300. return count;
  301. }
  302. static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
  303. size_t count, loff_t *ppos)
  304. {
  305. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  306. struct ieee80211_channel *channels = NULL;
  307. const struct ieee80211_supported_band *supp_band = NULL;
  308. int pos = 0, i, bufsz = PAGE_SIZE;
  309. char *buf;
  310. ssize_t ret;
  311. if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
  312. return -EAGAIN;
  313. buf = kzalloc(bufsz, GFP_KERNEL);
  314. if (!buf) {
  315. IWL_ERROR("Can not allocate Buffer\n");
  316. return -ENOMEM;
  317. }
  318. supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
  319. channels = supp_band->channels;
  320. pos += scnprintf(buf + pos, bufsz - pos,
  321. "Displaying %d channels in 2.4GHz band 802.11bg):\n",
  322. supp_band->n_channels);
  323. for (i = 0; i < supp_band->n_channels; i++)
  324. pos += scnprintf(buf + pos, bufsz - pos,
  325. "%d: %ddBm: BSS%s%s, %s.\n",
  326. ieee80211_frequency_to_channel(
  327. channels[i].center_freq),
  328. channels[i].max_power,
  329. channels[i].flags & IEEE80211_CHAN_RADAR ?
  330. " (IEEE 802.11h required)" : "",
  331. (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS)
  332. || (channels[i].flags &
  333. IEEE80211_CHAN_RADAR)) ? "" :
  334. ", IBSS",
  335. channels[i].flags &
  336. IEEE80211_CHAN_PASSIVE_SCAN ?
  337. "passive only" : "active/passive");
  338. supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
  339. channels = supp_band->channels;
  340. pos += scnprintf(buf + pos, bufsz - pos,
  341. "Displaying %d channels in 5.2GHz band (802.11a)\n",
  342. supp_band->n_channels);
  343. for (i = 0; i < supp_band->n_channels; i++)
  344. pos += scnprintf(buf + pos, bufsz - pos,
  345. "%d: %ddBm: BSS%s%s, %s.\n",
  346. ieee80211_frequency_to_channel(
  347. channels[i].center_freq),
  348. channels[i].max_power,
  349. channels[i].flags & IEEE80211_CHAN_RADAR ?
  350. " (IEEE 802.11h required)" : "",
  351. ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
  352. || (channels[i].flags &
  353. IEEE80211_CHAN_RADAR)) ? "" :
  354. ", IBSS",
  355. channels[i].flags &
  356. IEEE80211_CHAN_PASSIVE_SCAN ?
  357. "passive only" : "active/passive");
  358. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  359. kfree(buf);
  360. return ret;
  361. }
  362. DEBUGFS_READ_WRITE_FILE_OPS(sram);
  363. DEBUGFS_WRITE_FILE_OPS(log_event);
  364. DEBUGFS_READ_FILE_OPS(eeprom);
  365. DEBUGFS_READ_FILE_OPS(stations);
  366. DEBUGFS_READ_FILE_OPS(rx_statistics);
  367. DEBUGFS_READ_FILE_OPS(tx_statistics);
  368. DEBUGFS_READ_FILE_OPS(channels);
  369. /*
  370. * Create the debugfs files and directories
  371. *
  372. */
  373. int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
  374. {
  375. struct iwl_debugfs *dbgfs;
  376. struct dentry *phyd = priv->hw->wiphy->debugfsdir;
  377. int ret = 0;
  378. dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
  379. if (!dbgfs) {
  380. ret = -ENOMEM;
  381. goto err;
  382. }
  383. priv->dbgfs = dbgfs;
  384. dbgfs->name = name;
  385. dbgfs->dir_drv = debugfs_create_dir(name, phyd);
  386. if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) {
  387. ret = -ENOENT;
  388. goto err;
  389. }
  390. DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
  391. DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
  392. DEBUGFS_ADD_FILE(eeprom, data);
  393. DEBUGFS_ADD_FILE(sram, data);
  394. DEBUGFS_ADD_FILE(log_event, data);
  395. DEBUGFS_ADD_FILE(stations, data);
  396. DEBUGFS_ADD_FILE(rx_statistics, data);
  397. DEBUGFS_ADD_FILE(tx_statistics, data);
  398. DEBUGFS_ADD_FILE(channels, data);
  399. DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
  400. DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
  401. &priv->disable_chain_noise_cal);
  402. DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal);
  403. return 0;
  404. err:
  405. IWL_ERROR("Can't open the debugfs directory\n");
  406. iwl_dbgfs_unregister(priv);
  407. return ret;
  408. }
  409. EXPORT_SYMBOL(iwl_dbgfs_register);
  410. /**
  411. * Remove the debugfs files and directories
  412. *
  413. */
  414. void iwl_dbgfs_unregister(struct iwl_priv *priv)
  415. {
  416. if (!priv->dbgfs)
  417. return;
  418. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom);
  419. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
  420. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
  421. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
  422. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
  423. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
  424. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
  425. DEBUGFS_REMOVE(priv->dbgfs->dir_data);
  426. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
  427. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
  428. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
  429. DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
  430. DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
  431. kfree(priv->dbgfs);
  432. priv->dbgfs = NULL;
  433. }
  434. EXPORT_SYMBOL(iwl_dbgfs_unregister);