iwl-debugfs.c 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645
  1. /******************************************************************************
  2. *
  3. * GPL LICENSE SUMMARY
  4. *
  5. * Copyright(c) 2008 - 2010 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/slab.h>
  29. #include <linux/kernel.h>
  30. #include <linux/module.h>
  31. #include <linux/debugfs.h>
  32. #include <linux/ieee80211.h>
  33. #include <net/mac80211.h>
  34. #include "iwl-dev.h"
  35. #include "iwl-debug.h"
  36. #include "iwl-core.h"
  37. #include "iwl-io.h"
  38. #include "iwl-calib.h"
  39. /* create and remove of files */
  40. #define DEBUGFS_ADD_FILE(name, parent, mode) do { \
  41. if (!debugfs_create_file(#name, mode, parent, priv, \
  42. &iwl_dbgfs_##name##_ops)) \
  43. goto err; \
  44. } while (0)
  45. #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
  46. struct dentry *__tmp; \
  47. __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
  48. parent, ptr); \
  49. if (IS_ERR(__tmp) || !__tmp) \
  50. goto err; \
  51. } while (0)
  52. #define DEBUGFS_ADD_X32(name, parent, ptr) do { \
  53. struct dentry *__tmp; \
  54. __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
  55. parent, ptr); \
  56. if (IS_ERR(__tmp) || !__tmp) \
  57. goto err; \
  58. } while (0)
  59. /* file operation */
  60. #define DEBUGFS_READ_FUNC(name) \
  61. static ssize_t iwl_dbgfs_##name##_read(struct file *file, \
  62. char __user *user_buf, \
  63. size_t count, loff_t *ppos);
  64. #define DEBUGFS_WRITE_FUNC(name) \
  65. static ssize_t iwl_dbgfs_##name##_write(struct file *file, \
  66. const char __user *user_buf, \
  67. size_t count, loff_t *ppos);
  68. static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
  69. {
  70. file->private_data = inode->i_private;
  71. return 0;
  72. }
  73. #define DEBUGFS_READ_FILE_OPS(name) \
  74. DEBUGFS_READ_FUNC(name); \
  75. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  76. .read = iwl_dbgfs_##name##_read, \
  77. .open = iwl_dbgfs_open_file_generic, \
  78. };
  79. #define DEBUGFS_WRITE_FILE_OPS(name) \
  80. DEBUGFS_WRITE_FUNC(name); \
  81. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  82. .write = iwl_dbgfs_##name##_write, \
  83. .open = iwl_dbgfs_open_file_generic, \
  84. };
  85. #define DEBUGFS_READ_WRITE_FILE_OPS(name) \
  86. DEBUGFS_READ_FUNC(name); \
  87. DEBUGFS_WRITE_FUNC(name); \
  88. static const struct file_operations iwl_dbgfs_##name##_ops = { \
  89. .write = iwl_dbgfs_##name##_write, \
  90. .read = iwl_dbgfs_##name##_read, \
  91. .open = iwl_dbgfs_open_file_generic, \
  92. };
  93. int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
  94. {
  95. int p = 0;
  96. p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
  97. le32_to_cpu(priv->statistics.flag));
  98. if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
  99. p += scnprintf(buf + p, bufsz - p,
  100. "\tStatistics have been cleared\n");
  101. p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
  102. (le32_to_cpu(priv->statistics.flag) &
  103. UCODE_STATISTICS_FREQUENCY_MSK)
  104. ? "2.4 GHz" : "5.2 GHz");
  105. p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
  106. (le32_to_cpu(priv->statistics.flag) &
  107. UCODE_STATISTICS_NARROW_BAND_MSK)
  108. ? "enabled" : "disabled");
  109. return p;
  110. }
  111. EXPORT_SYMBOL(iwl_dbgfs_statistics_flag);
  112. static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
  113. char __user *user_buf,
  114. size_t count, loff_t *ppos) {
  115. struct iwl_priv *priv = file->private_data;
  116. char *buf;
  117. int pos = 0;
  118. int cnt;
  119. ssize_t ret;
  120. const size_t bufsz = 100 +
  121. sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
  122. buf = kzalloc(bufsz, GFP_KERNEL);
  123. if (!buf)
  124. return -ENOMEM;
  125. pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
  126. for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
  127. pos += scnprintf(buf + pos, bufsz - pos,
  128. "\t%25s\t\t: %u\n",
  129. get_mgmt_string(cnt),
  130. priv->tx_stats.mgmt[cnt]);
  131. }
  132. pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
  133. for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
  134. pos += scnprintf(buf + pos, bufsz - pos,
  135. "\t%25s\t\t: %u\n",
  136. get_ctrl_string(cnt),
  137. priv->tx_stats.ctrl[cnt]);
  138. }
  139. pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
  140. pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
  141. priv->tx_stats.data_cnt);
  142. pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
  143. priv->tx_stats.data_bytes);
  144. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  145. kfree(buf);
  146. return ret;
  147. }
  148. static ssize_t iwl_dbgfs_clear_traffic_statistics_write(struct file *file,
  149. const char __user *user_buf,
  150. size_t count, loff_t *ppos)
  151. {
  152. struct iwl_priv *priv = file->private_data;
  153. u32 clear_flag;
  154. char buf[8];
  155. int buf_size;
  156. memset(buf, 0, sizeof(buf));
  157. buf_size = min(count, sizeof(buf) - 1);
  158. if (copy_from_user(buf, user_buf, buf_size))
  159. return -EFAULT;
  160. if (sscanf(buf, "%x", &clear_flag) != 1)
  161. return -EFAULT;
  162. iwl_clear_traffic_stats(priv);
  163. return count;
  164. }
  165. static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file,
  166. char __user *user_buf,
  167. size_t count, loff_t *ppos) {
  168. struct iwl_priv *priv = file->private_data;
  169. char *buf;
  170. int pos = 0;
  171. int cnt;
  172. ssize_t ret;
  173. const size_t bufsz = 100 +
  174. sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
  175. buf = kzalloc(bufsz, GFP_KERNEL);
  176. if (!buf)
  177. return -ENOMEM;
  178. pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
  179. for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
  180. pos += scnprintf(buf + pos, bufsz - pos,
  181. "\t%25s\t\t: %u\n",
  182. get_mgmt_string(cnt),
  183. priv->rx_stats.mgmt[cnt]);
  184. }
  185. pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
  186. for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
  187. pos += scnprintf(buf + pos, bufsz - pos,
  188. "\t%25s\t\t: %u\n",
  189. get_ctrl_string(cnt),
  190. priv->rx_stats.ctrl[cnt]);
  191. }
  192. pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
  193. pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
  194. priv->rx_stats.data_cnt);
  195. pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
  196. priv->rx_stats.data_bytes);
  197. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  198. kfree(buf);
  199. return ret;
  200. }
  201. #define BYTE1_MASK 0x000000ff;
  202. #define BYTE2_MASK 0x0000ffff;
  203. #define BYTE3_MASK 0x00ffffff;
  204. static ssize_t iwl_dbgfs_sram_read(struct file *file,
  205. char __user *user_buf,
  206. size_t count, loff_t *ppos)
  207. {
  208. u32 val;
  209. char *buf;
  210. ssize_t ret;
  211. int i;
  212. int pos = 0;
  213. struct iwl_priv *priv = file->private_data;
  214. size_t bufsz;
  215. /* default is to dump the entire data segment */
  216. if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
  217. priv->dbgfs_sram_offset = 0x800000;
  218. if (priv->ucode_type == UCODE_INIT)
  219. priv->dbgfs_sram_len = priv->ucode_init_data.len;
  220. else
  221. priv->dbgfs_sram_len = priv->ucode_data.len;
  222. }
  223. bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10;
  224. buf = kmalloc(bufsz, GFP_KERNEL);
  225. if (!buf)
  226. return -ENOMEM;
  227. pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
  228. priv->dbgfs_sram_len);
  229. pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
  230. priv->dbgfs_sram_offset);
  231. for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
  232. val = iwl_read_targ_mem(priv, priv->dbgfs_sram_offset + \
  233. priv->dbgfs_sram_len - i);
  234. if (i < 4) {
  235. switch (i) {
  236. case 1:
  237. val &= BYTE1_MASK;
  238. break;
  239. case 2:
  240. val &= BYTE2_MASK;
  241. break;
  242. case 3:
  243. val &= BYTE3_MASK;
  244. break;
  245. }
  246. }
  247. if (!(i % 16))
  248. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  249. pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
  250. }
  251. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  252. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  253. kfree(buf);
  254. return ret;
  255. }
  256. static ssize_t iwl_dbgfs_sram_write(struct file *file,
  257. const char __user *user_buf,
  258. size_t count, loff_t *ppos)
  259. {
  260. struct iwl_priv *priv = file->private_data;
  261. char buf[64];
  262. int buf_size;
  263. u32 offset, len;
  264. memset(buf, 0, sizeof(buf));
  265. buf_size = min(count, sizeof(buf) - 1);
  266. if (copy_from_user(buf, user_buf, buf_size))
  267. return -EFAULT;
  268. if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
  269. priv->dbgfs_sram_offset = offset;
  270. priv->dbgfs_sram_len = len;
  271. } else {
  272. priv->dbgfs_sram_offset = 0;
  273. priv->dbgfs_sram_len = 0;
  274. }
  275. return count;
  276. }
  277. static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
  278. size_t count, loff_t *ppos)
  279. {
  280. struct iwl_priv *priv = file->private_data;
  281. struct iwl_station_entry *station;
  282. int max_sta = priv->hw_params.max_stations;
  283. char *buf;
  284. int i, j, pos = 0;
  285. ssize_t ret;
  286. /* Add 30 for initial string */
  287. const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
  288. buf = kmalloc(bufsz, GFP_KERNEL);
  289. if (!buf)
  290. return -ENOMEM;
  291. pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
  292. priv->num_stations);
  293. for (i = 0; i < max_sta; i++) {
  294. station = &priv->stations[i];
  295. if (station->used) {
  296. pos += scnprintf(buf + pos, bufsz - pos,
  297. "station %d:\ngeneral data:\n", i+1);
  298. pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
  299. station->sta.sta.sta_id);
  300. pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
  301. station->sta.mode);
  302. pos += scnprintf(buf + pos, bufsz - pos,
  303. "flags: 0x%x\n",
  304. station->sta.station_flags_msk);
  305. pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
  306. pos += scnprintf(buf + pos, bufsz - pos,
  307. "seq_num\t\ttxq_id");
  308. pos += scnprintf(buf + pos, bufsz - pos,
  309. "\tframe_count\twait_for_ba\t");
  310. pos += scnprintf(buf + pos, bufsz - pos,
  311. "start_idx\tbitmap0\t");
  312. pos += scnprintf(buf + pos, bufsz - pos,
  313. "bitmap1\trate_n_flags");
  314. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  315. for (j = 0; j < MAX_TID_COUNT; j++) {
  316. pos += scnprintf(buf + pos, bufsz - pos,
  317. "[%d]:\t\t%u", j,
  318. station->tid[j].seq_number);
  319. pos += scnprintf(buf + pos, bufsz - pos,
  320. "\t%u\t\t%u\t\t%u\t\t",
  321. station->tid[j].agg.txq_id,
  322. station->tid[j].agg.frame_count,
  323. station->tid[j].agg.wait_for_ba);
  324. pos += scnprintf(buf + pos, bufsz - pos,
  325. "%u\t%llu\t%u",
  326. station->tid[j].agg.start_idx,
  327. (unsigned long long)station->tid[j].agg.bitmap,
  328. station->tid[j].agg.rate_n_flags);
  329. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  330. }
  331. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  332. }
  333. }
  334. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  335. kfree(buf);
  336. return ret;
  337. }
  338. static ssize_t iwl_dbgfs_nvm_read(struct file *file,
  339. char __user *user_buf,
  340. size_t count,
  341. loff_t *ppos)
  342. {
  343. ssize_t ret;
  344. struct iwl_priv *priv = file->private_data;
  345. int pos = 0, ofs = 0, buf_size = 0;
  346. const u8 *ptr;
  347. char *buf;
  348. u16 eeprom_ver;
  349. size_t eeprom_len = priv->cfg->eeprom_size;
  350. buf_size = 4 * eeprom_len + 256;
  351. if (eeprom_len % 16) {
  352. IWL_ERR(priv, "NVM size is not multiple of 16.\n");
  353. return -ENODATA;
  354. }
  355. ptr = priv->eeprom;
  356. if (!ptr) {
  357. IWL_ERR(priv, "Invalid EEPROM/OTP memory\n");
  358. return -ENOMEM;
  359. }
  360. /* 4 characters for byte 0xYY */
  361. buf = kzalloc(buf_size, GFP_KERNEL);
  362. if (!buf) {
  363. IWL_ERR(priv, "Can not allocate Buffer\n");
  364. return -ENOMEM;
  365. }
  366. eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
  367. pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
  368. "version: 0x%x\n",
  369. (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
  370. ? "OTP" : "EEPROM", eeprom_ver);
  371. for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
  372. pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
  373. hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
  374. buf_size - pos, 0);
  375. pos += strlen(buf + pos);
  376. if (buf_size - pos > 0)
  377. buf[pos++] = '\n';
  378. }
  379. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  380. kfree(buf);
  381. return ret;
  382. }
  383. static ssize_t iwl_dbgfs_log_event_read(struct file *file,
  384. char __user *user_buf,
  385. size_t count, loff_t *ppos)
  386. {
  387. struct iwl_priv *priv = file->private_data;
  388. char *buf;
  389. int pos = 0;
  390. ssize_t ret = -ENOMEM;
  391. ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
  392. priv, true, &buf, true);
  393. if (buf) {
  394. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  395. kfree(buf);
  396. }
  397. return ret;
  398. }
  399. static ssize_t iwl_dbgfs_log_event_write(struct file *file,
  400. const char __user *user_buf,
  401. size_t count, loff_t *ppos)
  402. {
  403. struct iwl_priv *priv = file->private_data;
  404. u32 event_log_flag;
  405. char buf[8];
  406. int buf_size;
  407. memset(buf, 0, sizeof(buf));
  408. buf_size = min(count, sizeof(buf) - 1);
  409. if (copy_from_user(buf, user_buf, buf_size))
  410. return -EFAULT;
  411. if (sscanf(buf, "%d", &event_log_flag) != 1)
  412. return -EFAULT;
  413. if (event_log_flag == 1)
  414. priv->cfg->ops->lib->dump_nic_event_log(priv, true,
  415. NULL, false);
  416. return count;
  417. }
  418. static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf,
  419. size_t count, loff_t *ppos)
  420. {
  421. struct iwl_priv *priv = file->private_data;
  422. struct ieee80211_channel *channels = NULL;
  423. const struct ieee80211_supported_band *supp_band = NULL;
  424. int pos = 0, i, bufsz = PAGE_SIZE;
  425. char *buf;
  426. ssize_t ret;
  427. if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
  428. return -EAGAIN;
  429. buf = kzalloc(bufsz, GFP_KERNEL);
  430. if (!buf) {
  431. IWL_ERR(priv, "Can not allocate Buffer\n");
  432. return -ENOMEM;
  433. }
  434. supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
  435. if (supp_band) {
  436. channels = supp_band->channels;
  437. pos += scnprintf(buf + pos, bufsz - pos,
  438. "Displaying %d channels in 2.4GHz band 802.11bg):\n",
  439. supp_band->n_channels);
  440. for (i = 0; i < supp_band->n_channels; i++)
  441. pos += scnprintf(buf + pos, bufsz - pos,
  442. "%d: %ddBm: BSS%s%s, %s.\n",
  443. ieee80211_frequency_to_channel(
  444. channels[i].center_freq),
  445. channels[i].max_power,
  446. channels[i].flags & IEEE80211_CHAN_RADAR ?
  447. " (IEEE 802.11h required)" : "",
  448. ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
  449. || (channels[i].flags &
  450. IEEE80211_CHAN_RADAR)) ? "" :
  451. ", IBSS",
  452. channels[i].flags &
  453. IEEE80211_CHAN_PASSIVE_SCAN ?
  454. "passive only" : "active/passive");
  455. }
  456. supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
  457. if (supp_band) {
  458. channels = supp_band->channels;
  459. pos += scnprintf(buf + pos, bufsz - pos,
  460. "Displaying %d channels in 5.2GHz band (802.11a)\n",
  461. supp_band->n_channels);
  462. for (i = 0; i < supp_band->n_channels; i++)
  463. pos += scnprintf(buf + pos, bufsz - pos,
  464. "%d: %ddBm: BSS%s%s, %s.\n",
  465. ieee80211_frequency_to_channel(
  466. channels[i].center_freq),
  467. channels[i].max_power,
  468. channels[i].flags & IEEE80211_CHAN_RADAR ?
  469. " (IEEE 802.11h required)" : "",
  470. ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
  471. || (channels[i].flags &
  472. IEEE80211_CHAN_RADAR)) ? "" :
  473. ", IBSS",
  474. channels[i].flags &
  475. IEEE80211_CHAN_PASSIVE_SCAN ?
  476. "passive only" : "active/passive");
  477. }
  478. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  479. kfree(buf);
  480. return ret;
  481. }
  482. static ssize_t iwl_dbgfs_status_read(struct file *file,
  483. char __user *user_buf,
  484. size_t count, loff_t *ppos) {
  485. struct iwl_priv *priv = file->private_data;
  486. char buf[512];
  487. int pos = 0;
  488. const size_t bufsz = sizeof(buf);
  489. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
  490. test_bit(STATUS_HCMD_ACTIVE, &priv->status));
  491. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
  492. test_bit(STATUS_INT_ENABLED, &priv->status));
  493. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
  494. test_bit(STATUS_RF_KILL_HW, &priv->status));
  495. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
  496. test_bit(STATUS_CT_KILL, &priv->status));
  497. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
  498. test_bit(STATUS_INIT, &priv->status));
  499. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
  500. test_bit(STATUS_ALIVE, &priv->status));
  501. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
  502. test_bit(STATUS_READY, &priv->status));
  503. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
  504. test_bit(STATUS_TEMPERATURE, &priv->status));
  505. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
  506. test_bit(STATUS_GEO_CONFIGURED, &priv->status));
  507. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
  508. test_bit(STATUS_EXIT_PENDING, &priv->status));
  509. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
  510. test_bit(STATUS_STATISTICS, &priv->status));
  511. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
  512. test_bit(STATUS_SCANNING, &priv->status));
  513. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
  514. test_bit(STATUS_SCAN_ABORTING, &priv->status));
  515. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
  516. test_bit(STATUS_SCAN_HW, &priv->status));
  517. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
  518. test_bit(STATUS_POWER_PMI, &priv->status));
  519. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
  520. test_bit(STATUS_FW_ERROR, &priv->status));
  521. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  522. }
  523. static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
  524. char __user *user_buf,
  525. size_t count, loff_t *ppos) {
  526. struct iwl_priv *priv = file->private_data;
  527. int pos = 0;
  528. int cnt = 0;
  529. char *buf;
  530. int bufsz = 24 * 64; /* 24 items * 64 char per item */
  531. ssize_t ret;
  532. buf = kzalloc(bufsz, GFP_KERNEL);
  533. if (!buf) {
  534. IWL_ERR(priv, "Can not allocate Buffer\n");
  535. return -ENOMEM;
  536. }
  537. pos += scnprintf(buf + pos, bufsz - pos,
  538. "Interrupt Statistics Report:\n");
  539. pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
  540. priv->isr_stats.hw);
  541. pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
  542. priv->isr_stats.sw);
  543. if (priv->isr_stats.sw > 0) {
  544. pos += scnprintf(buf + pos, bufsz - pos,
  545. "\tLast Restarting Code: 0x%X\n",
  546. priv->isr_stats.sw_err);
  547. }
  548. #ifdef CONFIG_IWLWIFI_DEBUG
  549. pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
  550. priv->isr_stats.sch);
  551. pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
  552. priv->isr_stats.alive);
  553. #endif
  554. pos += scnprintf(buf + pos, bufsz - pos,
  555. "HW RF KILL switch toggled:\t %u\n",
  556. priv->isr_stats.rfkill);
  557. pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
  558. priv->isr_stats.ctkill);
  559. pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
  560. priv->isr_stats.wakeup);
  561. pos += scnprintf(buf + pos, bufsz - pos,
  562. "Rx command responses:\t\t %u\n",
  563. priv->isr_stats.rx);
  564. for (cnt = 0; cnt < REPLY_MAX; cnt++) {
  565. if (priv->isr_stats.rx_handlers[cnt] > 0)
  566. pos += scnprintf(buf + pos, bufsz - pos,
  567. "\tRx handler[%36s]:\t\t %u\n",
  568. get_cmd_string(cnt),
  569. priv->isr_stats.rx_handlers[cnt]);
  570. }
  571. pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
  572. priv->isr_stats.tx);
  573. pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
  574. priv->isr_stats.unhandled);
  575. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  576. kfree(buf);
  577. return ret;
  578. }
  579. static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
  580. const char __user *user_buf,
  581. size_t count, loff_t *ppos)
  582. {
  583. struct iwl_priv *priv = file->private_data;
  584. char buf[8];
  585. int buf_size;
  586. u32 reset_flag;
  587. memset(buf, 0, sizeof(buf));
  588. buf_size = min(count, sizeof(buf) - 1);
  589. if (copy_from_user(buf, user_buf, buf_size))
  590. return -EFAULT;
  591. if (sscanf(buf, "%x", &reset_flag) != 1)
  592. return -EFAULT;
  593. if (reset_flag == 0)
  594. iwl_clear_isr_stats(priv);
  595. return count;
  596. }
  597. static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
  598. size_t count, loff_t *ppos)
  599. {
  600. struct iwl_priv *priv = file->private_data;
  601. int pos = 0, i;
  602. char buf[256];
  603. const size_t bufsz = sizeof(buf);
  604. for (i = 0; i < AC_NUM; i++) {
  605. pos += scnprintf(buf + pos, bufsz - pos,
  606. "\tcw_min\tcw_max\taifsn\ttxop\n");
  607. pos += scnprintf(buf + pos, bufsz - pos,
  608. "AC[%d]\t%u\t%u\t%u\t%u\n", i,
  609. priv->qos_data.def_qos_parm.ac[i].cw_min,
  610. priv->qos_data.def_qos_parm.ac[i].cw_max,
  611. priv->qos_data.def_qos_parm.ac[i].aifsn,
  612. priv->qos_data.def_qos_parm.ac[i].edca_txop);
  613. }
  614. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  615. }
  616. static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
  617. size_t count, loff_t *ppos)
  618. {
  619. struct iwl_priv *priv = file->private_data;
  620. int pos = 0;
  621. char buf[256];
  622. const size_t bufsz = sizeof(buf);
  623. pos += scnprintf(buf + pos, bufsz - pos,
  624. "allow blinking: %s\n",
  625. (priv->allow_blinking) ? "True" : "False");
  626. if (priv->allow_blinking) {
  627. pos += scnprintf(buf + pos, bufsz - pos,
  628. "Led blinking rate: %u\n",
  629. priv->last_blink_rate);
  630. pos += scnprintf(buf + pos, bufsz - pos,
  631. "Last blink time: %lu\n",
  632. priv->last_blink_time);
  633. }
  634. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  635. }
  636. static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
  637. char __user *user_buf,
  638. size_t count, loff_t *ppos)
  639. {
  640. struct iwl_priv *priv = file->private_data;
  641. struct iwl_tt_mgmt *tt = &priv->thermal_throttle;
  642. struct iwl_tt_restriction *restriction;
  643. char buf[100];
  644. int pos = 0;
  645. const size_t bufsz = sizeof(buf);
  646. pos += scnprintf(buf + pos, bufsz - pos,
  647. "Thermal Throttling Mode: %s\n",
  648. tt->advanced_tt ? "Advance" : "Legacy");
  649. pos += scnprintf(buf + pos, bufsz - pos,
  650. "Thermal Throttling State: %d\n",
  651. tt->state);
  652. if (tt->advanced_tt) {
  653. restriction = tt->restriction + tt->state;
  654. pos += scnprintf(buf + pos, bufsz - pos,
  655. "Tx mode: %d\n",
  656. restriction->tx_stream);
  657. pos += scnprintf(buf + pos, bufsz - pos,
  658. "Rx mode: %d\n",
  659. restriction->rx_stream);
  660. pos += scnprintf(buf + pos, bufsz - pos,
  661. "HT mode: %d\n",
  662. restriction->is_ht);
  663. }
  664. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  665. }
  666. static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
  667. const char __user *user_buf,
  668. size_t count, loff_t *ppos)
  669. {
  670. struct iwl_priv *priv = file->private_data;
  671. char buf[8];
  672. int buf_size;
  673. int ht40;
  674. memset(buf, 0, sizeof(buf));
  675. buf_size = min(count, sizeof(buf) - 1);
  676. if (copy_from_user(buf, user_buf, buf_size))
  677. return -EFAULT;
  678. if (sscanf(buf, "%d", &ht40) != 1)
  679. return -EFAULT;
  680. if (!iwl_is_associated(priv))
  681. priv->disable_ht40 = ht40 ? true : false;
  682. else {
  683. IWL_ERR(priv, "Sta associated with AP - "
  684. "Change to 40MHz channel support is not allowed\n");
  685. return -EINVAL;
  686. }
  687. return count;
  688. }
  689. static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
  690. char __user *user_buf,
  691. size_t count, loff_t *ppos)
  692. {
  693. struct iwl_priv *priv = file->private_data;
  694. char buf[100];
  695. int pos = 0;
  696. const size_t bufsz = sizeof(buf);
  697. pos += scnprintf(buf + pos, bufsz - pos,
  698. "11n 40MHz Mode: %s\n",
  699. priv->disable_ht40 ? "Disabled" : "Enabled");
  700. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  701. }
  702. static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
  703. const char __user *user_buf,
  704. size_t count, loff_t *ppos)
  705. {
  706. struct iwl_priv *priv = file->private_data;
  707. char buf[8];
  708. int buf_size;
  709. int value;
  710. memset(buf, 0, sizeof(buf));
  711. buf_size = min(count, sizeof(buf) - 1);
  712. if (copy_from_user(buf, user_buf, buf_size))
  713. return -EFAULT;
  714. if (sscanf(buf, "%d", &value) != 1)
  715. return -EINVAL;
  716. /*
  717. * Our users expect 0 to be "CAM", but 0 isn't actually
  718. * valid here. However, let's not confuse them and present
  719. * IWL_POWER_INDEX_1 as "1", not "0".
  720. */
  721. if (value == 0)
  722. return -EINVAL;
  723. else if (value > 0)
  724. value -= 1;
  725. if (value != -1 && (value < 0 || value >= IWL_POWER_NUM))
  726. return -EINVAL;
  727. if (!iwl_is_ready_rf(priv))
  728. return -EAGAIN;
  729. priv->power_data.debug_sleep_level_override = value;
  730. mutex_lock(&priv->mutex);
  731. iwl_power_update_mode(priv, true);
  732. mutex_unlock(&priv->mutex);
  733. return count;
  734. }
  735. static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file,
  736. char __user *user_buf,
  737. size_t count, loff_t *ppos)
  738. {
  739. struct iwl_priv *priv = file->private_data;
  740. char buf[10];
  741. int pos, value;
  742. const size_t bufsz = sizeof(buf);
  743. /* see the write function */
  744. value = priv->power_data.debug_sleep_level_override;
  745. if (value >= 0)
  746. value += 1;
  747. pos = scnprintf(buf, bufsz, "%d\n", value);
  748. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  749. }
  750. static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file,
  751. char __user *user_buf,
  752. size_t count, loff_t *ppos)
  753. {
  754. struct iwl_priv *priv = file->private_data;
  755. char buf[200];
  756. int pos = 0, i;
  757. const size_t bufsz = sizeof(buf);
  758. struct iwl_powertable_cmd *cmd = &priv->power_data.sleep_cmd;
  759. pos += scnprintf(buf + pos, bufsz - pos,
  760. "flags: %#.2x\n", le16_to_cpu(cmd->flags));
  761. pos += scnprintf(buf + pos, bufsz - pos,
  762. "RX/TX timeout: %d/%d usec\n",
  763. le32_to_cpu(cmd->rx_data_timeout),
  764. le32_to_cpu(cmd->tx_data_timeout));
  765. for (i = 0; i < IWL_POWER_VEC_SIZE; i++)
  766. pos += scnprintf(buf + pos, bufsz - pos,
  767. "sleep_interval[%d]: %d\n", i,
  768. le32_to_cpu(cmd->sleep_interval[i]));
  769. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  770. }
  771. DEBUGFS_READ_WRITE_FILE_OPS(sram);
  772. DEBUGFS_READ_WRITE_FILE_OPS(log_event);
  773. DEBUGFS_READ_FILE_OPS(nvm);
  774. DEBUGFS_READ_FILE_OPS(stations);
  775. DEBUGFS_READ_FILE_OPS(channels);
  776. DEBUGFS_READ_FILE_OPS(status);
  777. DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
  778. DEBUGFS_READ_FILE_OPS(qos);
  779. DEBUGFS_READ_FILE_OPS(led);
  780. DEBUGFS_READ_FILE_OPS(thermal_throttling);
  781. DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
  782. DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
  783. DEBUGFS_READ_FILE_OPS(current_sleep_command);
  784. static ssize_t iwl_dbgfs_traffic_log_read(struct file *file,
  785. char __user *user_buf,
  786. size_t count, loff_t *ppos)
  787. {
  788. struct iwl_priv *priv = file->private_data;
  789. int pos = 0, ofs = 0;
  790. int cnt = 0, entry;
  791. struct iwl_tx_queue *txq;
  792. struct iwl_queue *q;
  793. struct iwl_rx_queue *rxq = &priv->rxq;
  794. char *buf;
  795. int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
  796. (priv->cfg->num_of_queues * 32 * 8) + 400;
  797. const u8 *ptr;
  798. ssize_t ret;
  799. if (!priv->txq) {
  800. IWL_ERR(priv, "txq not ready\n");
  801. return -EAGAIN;
  802. }
  803. buf = kzalloc(bufsz, GFP_KERNEL);
  804. if (!buf) {
  805. IWL_ERR(priv, "Can not allocate buffer\n");
  806. return -ENOMEM;
  807. }
  808. pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
  809. for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
  810. txq = &priv->txq[cnt];
  811. q = &txq->q;
  812. pos += scnprintf(buf + pos, bufsz - pos,
  813. "q[%d]: read_ptr: %u, write_ptr: %u\n",
  814. cnt, q->read_ptr, q->write_ptr);
  815. }
  816. if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) {
  817. ptr = priv->tx_traffic;
  818. pos += scnprintf(buf + pos, bufsz - pos,
  819. "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
  820. for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
  821. for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
  822. entry++, ofs += 16) {
  823. pos += scnprintf(buf + pos, bufsz - pos,
  824. "0x%.4x ", ofs);
  825. hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
  826. buf + pos, bufsz - pos, 0);
  827. pos += strlen(buf + pos);
  828. if (bufsz - pos > 0)
  829. buf[pos++] = '\n';
  830. }
  831. }
  832. }
  833. pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
  834. pos += scnprintf(buf + pos, bufsz - pos,
  835. "read: %u, write: %u\n",
  836. rxq->read, rxq->write);
  837. if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) {
  838. ptr = priv->rx_traffic;
  839. pos += scnprintf(buf + pos, bufsz - pos,
  840. "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
  841. for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
  842. for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
  843. entry++, ofs += 16) {
  844. pos += scnprintf(buf + pos, bufsz - pos,
  845. "0x%.4x ", ofs);
  846. hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
  847. buf + pos, bufsz - pos, 0);
  848. pos += strlen(buf + pos);
  849. if (bufsz - pos > 0)
  850. buf[pos++] = '\n';
  851. }
  852. }
  853. }
  854. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  855. kfree(buf);
  856. return ret;
  857. }
  858. static ssize_t iwl_dbgfs_traffic_log_write(struct file *file,
  859. const char __user *user_buf,
  860. size_t count, loff_t *ppos)
  861. {
  862. struct iwl_priv *priv = file->private_data;
  863. char buf[8];
  864. int buf_size;
  865. int traffic_log;
  866. memset(buf, 0, sizeof(buf));
  867. buf_size = min(count, sizeof(buf) - 1);
  868. if (copy_from_user(buf, user_buf, buf_size))
  869. return -EFAULT;
  870. if (sscanf(buf, "%d", &traffic_log) != 1)
  871. return -EFAULT;
  872. if (traffic_log == 0)
  873. iwl_reset_traffic_log(priv);
  874. return count;
  875. }
  876. static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
  877. char __user *user_buf,
  878. size_t count, loff_t *ppos) {
  879. struct iwl_priv *priv = file->private_data;
  880. struct iwl_tx_queue *txq;
  881. struct iwl_queue *q;
  882. char *buf;
  883. int pos = 0;
  884. int cnt;
  885. int ret;
  886. const size_t bufsz = sizeof(char) * 64 * priv->cfg->num_of_queues;
  887. if (!priv->txq) {
  888. IWL_ERR(priv, "txq not ready\n");
  889. return -EAGAIN;
  890. }
  891. buf = kzalloc(bufsz, GFP_KERNEL);
  892. if (!buf)
  893. return -ENOMEM;
  894. for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
  895. txq = &priv->txq[cnt];
  896. q = &txq->q;
  897. pos += scnprintf(buf + pos, bufsz - pos,
  898. "hwq %.2d: read=%u write=%u stop=%d"
  899. " swq_id=%#.2x (ac %d/hwq %d)\n",
  900. cnt, q->read_ptr, q->write_ptr,
  901. !!test_bit(cnt, priv->queue_stopped),
  902. txq->swq_id,
  903. txq->swq_id & 0x80 ? txq->swq_id & 3 :
  904. txq->swq_id,
  905. txq->swq_id & 0x80 ? (txq->swq_id >> 2) &
  906. 0x1f : txq->swq_id);
  907. if (cnt >= 4)
  908. continue;
  909. /* for the ACs, display the stop count too */
  910. pos += scnprintf(buf + pos, bufsz - pos,
  911. " stop-count: %d\n",
  912. atomic_read(&priv->queue_stop_count[cnt]));
  913. }
  914. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  915. kfree(buf);
  916. return ret;
  917. }
  918. static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
  919. char __user *user_buf,
  920. size_t count, loff_t *ppos) {
  921. struct iwl_priv *priv = file->private_data;
  922. struct iwl_rx_queue *rxq = &priv->rxq;
  923. char buf[256];
  924. int pos = 0;
  925. const size_t bufsz = sizeof(buf);
  926. pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
  927. rxq->read);
  928. pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
  929. rxq->write);
  930. pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
  931. rxq->free_count);
  932. pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
  933. le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF);
  934. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  935. }
  936. static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
  937. char __user *user_buf,
  938. size_t count, loff_t *ppos)
  939. {
  940. struct iwl_priv *priv = file->private_data;
  941. return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
  942. user_buf, count, ppos);
  943. }
  944. static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
  945. char __user *user_buf,
  946. size_t count, loff_t *ppos)
  947. {
  948. struct iwl_priv *priv = file->private_data;
  949. return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
  950. user_buf, count, ppos);
  951. }
  952. static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
  953. char __user *user_buf,
  954. size_t count, loff_t *ppos)
  955. {
  956. struct iwl_priv *priv = file->private_data;
  957. return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
  958. user_buf, count, ppos);
  959. }
  960. static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
  961. char __user *user_buf,
  962. size_t count, loff_t *ppos) {
  963. struct iwl_priv *priv = file->private_data;
  964. int pos = 0;
  965. int cnt = 0;
  966. char *buf;
  967. int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
  968. ssize_t ret;
  969. struct iwl_sensitivity_data *data;
  970. data = &priv->sensitivity_data;
  971. buf = kzalloc(bufsz, GFP_KERNEL);
  972. if (!buf) {
  973. IWL_ERR(priv, "Can not allocate Buffer\n");
  974. return -ENOMEM;
  975. }
  976. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
  977. data->auto_corr_ofdm);
  978. pos += scnprintf(buf + pos, bufsz - pos,
  979. "auto_corr_ofdm_mrc:\t\t %u\n",
  980. data->auto_corr_ofdm_mrc);
  981. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
  982. data->auto_corr_ofdm_x1);
  983. pos += scnprintf(buf + pos, bufsz - pos,
  984. "auto_corr_ofdm_mrc_x1:\t\t %u\n",
  985. data->auto_corr_ofdm_mrc_x1);
  986. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
  987. data->auto_corr_cck);
  988. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
  989. data->auto_corr_cck_mrc);
  990. pos += scnprintf(buf + pos, bufsz - pos,
  991. "last_bad_plcp_cnt_ofdm:\t\t %u\n",
  992. data->last_bad_plcp_cnt_ofdm);
  993. pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
  994. data->last_fa_cnt_ofdm);
  995. pos += scnprintf(buf + pos, bufsz - pos,
  996. "last_bad_plcp_cnt_cck:\t\t %u\n",
  997. data->last_bad_plcp_cnt_cck);
  998. pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
  999. data->last_fa_cnt_cck);
  1000. pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
  1001. data->nrg_curr_state);
  1002. pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
  1003. data->nrg_prev_state);
  1004. pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
  1005. for (cnt = 0; cnt < 10; cnt++) {
  1006. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  1007. data->nrg_value[cnt]);
  1008. }
  1009. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  1010. pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
  1011. for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
  1012. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  1013. data->nrg_silence_rssi[cnt]);
  1014. }
  1015. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  1016. pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
  1017. data->nrg_silence_ref);
  1018. pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
  1019. data->nrg_energy_idx);
  1020. pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
  1021. data->nrg_silence_idx);
  1022. pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
  1023. data->nrg_th_cck);
  1024. pos += scnprintf(buf + pos, bufsz - pos,
  1025. "nrg_auto_corr_silence_diff:\t %u\n",
  1026. data->nrg_auto_corr_silence_diff);
  1027. pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
  1028. data->num_in_cck_no_fa);
  1029. pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
  1030. data->nrg_th_ofdm);
  1031. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1032. kfree(buf);
  1033. return ret;
  1034. }
  1035. static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
  1036. char __user *user_buf,
  1037. size_t count, loff_t *ppos) {
  1038. struct iwl_priv *priv = file->private_data;
  1039. int pos = 0;
  1040. int cnt = 0;
  1041. char *buf;
  1042. int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
  1043. ssize_t ret;
  1044. struct iwl_chain_noise_data *data;
  1045. data = &priv->chain_noise_data;
  1046. buf = kzalloc(bufsz, GFP_KERNEL);
  1047. if (!buf) {
  1048. IWL_ERR(priv, "Can not allocate Buffer\n");
  1049. return -ENOMEM;
  1050. }
  1051. pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
  1052. data->active_chains);
  1053. pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
  1054. data->chain_noise_a);
  1055. pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
  1056. data->chain_noise_b);
  1057. pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
  1058. data->chain_noise_c);
  1059. pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
  1060. data->chain_signal_a);
  1061. pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
  1062. data->chain_signal_b);
  1063. pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
  1064. data->chain_signal_c);
  1065. pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
  1066. data->beacon_count);
  1067. pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
  1068. for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
  1069. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  1070. data->disconn_array[cnt]);
  1071. }
  1072. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  1073. pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
  1074. for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
  1075. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  1076. data->delta_gain_code[cnt]);
  1077. }
  1078. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  1079. pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
  1080. data->radio_write);
  1081. pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
  1082. data->state);
  1083. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1084. kfree(buf);
  1085. return ret;
  1086. }
  1087. static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
  1088. char __user *user_buf,
  1089. size_t count, loff_t *ppos)
  1090. {
  1091. struct iwl_priv *priv = file->private_data;
  1092. char buf[60];
  1093. int pos = 0;
  1094. const size_t bufsz = sizeof(buf);
  1095. u32 pwrsave_status;
  1096. pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
  1097. CSR_GP_REG_POWER_SAVE_STATUS_MSK;
  1098. pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
  1099. pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
  1100. (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
  1101. (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
  1102. (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
  1103. "error");
  1104. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1105. }
  1106. static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
  1107. const char __user *user_buf,
  1108. size_t count, loff_t *ppos)
  1109. {
  1110. struct iwl_priv *priv = file->private_data;
  1111. char buf[8];
  1112. int buf_size;
  1113. int clear;
  1114. memset(buf, 0, sizeof(buf));
  1115. buf_size = min(count, sizeof(buf) - 1);
  1116. if (copy_from_user(buf, user_buf, buf_size))
  1117. return -EFAULT;
  1118. if (sscanf(buf, "%d", &clear) != 1)
  1119. return -EFAULT;
  1120. /* make request to uCode to retrieve statistics information */
  1121. mutex_lock(&priv->mutex);
  1122. iwl_send_statistics_request(priv, CMD_SYNC, true);
  1123. mutex_unlock(&priv->mutex);
  1124. return count;
  1125. }
  1126. static ssize_t iwl_dbgfs_csr_write(struct file *file,
  1127. const char __user *user_buf,
  1128. size_t count, loff_t *ppos)
  1129. {
  1130. struct iwl_priv *priv = file->private_data;
  1131. char buf[8];
  1132. int buf_size;
  1133. int csr;
  1134. memset(buf, 0, sizeof(buf));
  1135. buf_size = min(count, sizeof(buf) - 1);
  1136. if (copy_from_user(buf, user_buf, buf_size))
  1137. return -EFAULT;
  1138. if (sscanf(buf, "%d", &csr) != 1)
  1139. return -EFAULT;
  1140. if (priv->cfg->ops->lib->dump_csr)
  1141. priv->cfg->ops->lib->dump_csr(priv);
  1142. return count;
  1143. }
  1144. static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
  1145. char __user *user_buf,
  1146. size_t count, loff_t *ppos) {
  1147. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  1148. int pos = 0;
  1149. char buf[128];
  1150. const size_t bufsz = sizeof(buf);
  1151. pos += scnprintf(buf + pos, bufsz - pos, "ucode trace timer is %s\n",
  1152. priv->event_log.ucode_trace ? "On" : "Off");
  1153. pos += scnprintf(buf + pos, bufsz - pos, "non_wraps_count:\t\t %u\n",
  1154. priv->event_log.non_wraps_count);
  1155. pos += scnprintf(buf + pos, bufsz - pos, "wraps_once_count:\t\t %u\n",
  1156. priv->event_log.wraps_once_count);
  1157. pos += scnprintf(buf + pos, bufsz - pos, "wraps_more_count:\t\t %u\n",
  1158. priv->event_log.wraps_more_count);
  1159. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1160. }
  1161. static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
  1162. const char __user *user_buf,
  1163. size_t count, loff_t *ppos)
  1164. {
  1165. struct iwl_priv *priv = file->private_data;
  1166. char buf[8];
  1167. int buf_size;
  1168. int trace;
  1169. memset(buf, 0, sizeof(buf));
  1170. buf_size = min(count, sizeof(buf) - 1);
  1171. if (copy_from_user(buf, user_buf, buf_size))
  1172. return -EFAULT;
  1173. if (sscanf(buf, "%d", &trace) != 1)
  1174. return -EFAULT;
  1175. if (trace) {
  1176. priv->event_log.ucode_trace = true;
  1177. /* schedule the ucode timer to occur in UCODE_TRACE_PERIOD */
  1178. mod_timer(&priv->ucode_trace,
  1179. jiffies + msecs_to_jiffies(UCODE_TRACE_PERIOD));
  1180. } else {
  1181. priv->event_log.ucode_trace = false;
  1182. del_timer_sync(&priv->ucode_trace);
  1183. }
  1184. return count;
  1185. }
  1186. static ssize_t iwl_dbgfs_rxon_flags_read(struct file *file,
  1187. char __user *user_buf,
  1188. size_t count, loff_t *ppos) {
  1189. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  1190. int len = 0;
  1191. char buf[20];
  1192. len = sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.flags));
  1193. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  1194. }
  1195. static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file,
  1196. char __user *user_buf,
  1197. size_t count, loff_t *ppos) {
  1198. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  1199. int len = 0;
  1200. char buf[20];
  1201. len = sprintf(buf, "0x%04X\n",
  1202. le32_to_cpu(priv->active_rxon.filter_flags));
  1203. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  1204. }
  1205. static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
  1206. char __user *user_buf,
  1207. size_t count, loff_t *ppos)
  1208. {
  1209. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  1210. char *buf;
  1211. int pos = 0;
  1212. ssize_t ret = -EFAULT;
  1213. if (priv->cfg->ops->lib->dump_fh) {
  1214. ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
  1215. if (buf) {
  1216. ret = simple_read_from_buffer(user_buf,
  1217. count, ppos, buf, pos);
  1218. kfree(buf);
  1219. }
  1220. }
  1221. return ret;
  1222. }
  1223. static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
  1224. char __user *user_buf,
  1225. size_t count, loff_t *ppos) {
  1226. struct iwl_priv *priv = file->private_data;
  1227. int pos = 0;
  1228. char buf[12];
  1229. const size_t bufsz = sizeof(buf);
  1230. pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
  1231. priv->missed_beacon_threshold);
  1232. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1233. }
  1234. static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
  1235. const char __user *user_buf,
  1236. size_t count, loff_t *ppos)
  1237. {
  1238. struct iwl_priv *priv = file->private_data;
  1239. char buf[8];
  1240. int buf_size;
  1241. int missed;
  1242. memset(buf, 0, sizeof(buf));
  1243. buf_size = min(count, sizeof(buf) - 1);
  1244. if (copy_from_user(buf, user_buf, buf_size))
  1245. return -EFAULT;
  1246. if (sscanf(buf, "%d", &missed) != 1)
  1247. return -EINVAL;
  1248. if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
  1249. missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
  1250. priv->missed_beacon_threshold =
  1251. IWL_MISSED_BEACON_THRESHOLD_DEF;
  1252. else
  1253. priv->missed_beacon_threshold = missed;
  1254. return count;
  1255. }
  1256. static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
  1257. char __user *user_buf,
  1258. size_t count, loff_t *ppos) {
  1259. struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
  1260. int pos = 0;
  1261. char buf[12];
  1262. const size_t bufsz = sizeof(buf);
  1263. pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
  1264. priv->cfg->plcp_delta_threshold);
  1265. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1266. }
  1267. static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
  1268. const char __user *user_buf,
  1269. size_t count, loff_t *ppos) {
  1270. struct iwl_priv *priv = file->private_data;
  1271. char buf[8];
  1272. int buf_size;
  1273. int plcp;
  1274. memset(buf, 0, sizeof(buf));
  1275. buf_size = min(count, sizeof(buf) - 1);
  1276. if (copy_from_user(buf, user_buf, buf_size))
  1277. return -EFAULT;
  1278. if (sscanf(buf, "%d", &plcp) != 1)
  1279. return -EINVAL;
  1280. if ((plcp <= IWL_MAX_PLCP_ERR_THRESHOLD_MIN) ||
  1281. (plcp > IWL_MAX_PLCP_ERR_THRESHOLD_MAX))
  1282. priv->cfg->plcp_delta_threshold =
  1283. IWL_MAX_PLCP_ERR_THRESHOLD_DEF;
  1284. else
  1285. priv->cfg->plcp_delta_threshold = plcp;
  1286. return count;
  1287. }
  1288. static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
  1289. char __user *user_buf,
  1290. size_t count, loff_t *ppos) {
  1291. struct iwl_priv *priv = file->private_data;
  1292. int i, pos = 0;
  1293. char buf[300];
  1294. const size_t bufsz = sizeof(buf);
  1295. struct iwl_force_reset *force_reset;
  1296. for (i = 0; i < IWL_MAX_FORCE_RESET; i++) {
  1297. force_reset = &priv->force_reset[i];
  1298. pos += scnprintf(buf + pos, bufsz - pos,
  1299. "Force reset method %d\n", i);
  1300. pos += scnprintf(buf + pos, bufsz - pos,
  1301. "\tnumber of reset request: %d\n",
  1302. force_reset->reset_request_count);
  1303. pos += scnprintf(buf + pos, bufsz - pos,
  1304. "\tnumber of reset request success: %d\n",
  1305. force_reset->reset_success_count);
  1306. pos += scnprintf(buf + pos, bufsz - pos,
  1307. "\tnumber of reset request reject: %d\n",
  1308. force_reset->reset_reject_count);
  1309. pos += scnprintf(buf + pos, bufsz - pos,
  1310. "\treset duration: %lu\n",
  1311. force_reset->reset_duration);
  1312. }
  1313. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1314. }
  1315. static ssize_t iwl_dbgfs_force_reset_write(struct file *file,
  1316. const char __user *user_buf,
  1317. size_t count, loff_t *ppos) {
  1318. struct iwl_priv *priv = file->private_data;
  1319. char buf[8];
  1320. int buf_size;
  1321. int reset, ret;
  1322. memset(buf, 0, sizeof(buf));
  1323. buf_size = min(count, sizeof(buf) - 1);
  1324. if (copy_from_user(buf, user_buf, buf_size))
  1325. return -EFAULT;
  1326. if (sscanf(buf, "%d", &reset) != 1)
  1327. return -EINVAL;
  1328. switch (reset) {
  1329. case IWL_RF_RESET:
  1330. case IWL_FW_RESET:
  1331. ret = iwl_force_reset(priv, reset);
  1332. break;
  1333. default:
  1334. return -EINVAL;
  1335. }
  1336. return ret ? ret : count;
  1337. }
  1338. DEBUGFS_READ_FILE_OPS(rx_statistics);
  1339. DEBUGFS_READ_FILE_OPS(tx_statistics);
  1340. DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
  1341. DEBUGFS_READ_FILE_OPS(rx_queue);
  1342. DEBUGFS_READ_FILE_OPS(tx_queue);
  1343. DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
  1344. DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
  1345. DEBUGFS_READ_FILE_OPS(ucode_general_stats);
  1346. DEBUGFS_READ_FILE_OPS(sensitivity);
  1347. DEBUGFS_READ_FILE_OPS(chain_noise);
  1348. DEBUGFS_READ_FILE_OPS(power_save_status);
  1349. DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
  1350. DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
  1351. DEBUGFS_WRITE_FILE_OPS(csr);
  1352. DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
  1353. DEBUGFS_READ_FILE_OPS(fh_reg);
  1354. DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
  1355. DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
  1356. DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
  1357. DEBUGFS_READ_FILE_OPS(rxon_flags);
  1358. DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
  1359. /*
  1360. * Create the debugfs files and directories
  1361. *
  1362. */
  1363. int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
  1364. {
  1365. struct dentry *phyd = priv->hw->wiphy->debugfsdir;
  1366. struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
  1367. dir_drv = debugfs_create_dir(name, phyd);
  1368. if (!dir_drv)
  1369. return -ENOMEM;
  1370. priv->debugfs_dir = dir_drv;
  1371. dir_data = debugfs_create_dir("data", dir_drv);
  1372. if (!dir_data)
  1373. goto err;
  1374. dir_rf = debugfs_create_dir("rf", dir_drv);
  1375. if (!dir_rf)
  1376. goto err;
  1377. dir_debug = debugfs_create_dir("debug", dir_drv);
  1378. if (!dir_debug)
  1379. goto err;
  1380. DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
  1381. DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
  1382. DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR);
  1383. DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
  1384. DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
  1385. DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
  1386. DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
  1387. DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
  1388. DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
  1389. if (!priv->cfg->broken_powersave) {
  1390. DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
  1391. S_IWUSR | S_IRUSR);
  1392. DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
  1393. }
  1394. DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
  1395. DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
  1396. DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
  1397. DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
  1398. DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
  1399. DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
  1400. DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
  1401. DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
  1402. DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
  1403. DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
  1404. DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR);
  1405. DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
  1406. DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
  1407. DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
  1408. DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
  1409. DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
  1410. DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
  1411. DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
  1412. if (priv->cfg->sensitivity_calib_by_driver)
  1413. DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
  1414. if (priv->cfg->chain_noise_calib_by_driver)
  1415. DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
  1416. if (priv->cfg->ucode_tracing)
  1417. DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
  1418. DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
  1419. DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
  1420. if (priv->cfg->sensitivity_calib_by_driver)
  1421. DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
  1422. &priv->disable_sens_cal);
  1423. if (priv->cfg->chain_noise_calib_by_driver)
  1424. DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
  1425. &priv->disable_chain_noise_cal);
  1426. if (priv->cfg->tx_power_by_driver)
  1427. DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
  1428. &priv->disable_tx_power_cal);
  1429. return 0;
  1430. err:
  1431. IWL_ERR(priv, "Can't create the debugfs directory\n");
  1432. iwl_dbgfs_unregister(priv);
  1433. return -ENOMEM;
  1434. }
  1435. EXPORT_SYMBOL(iwl_dbgfs_register);
  1436. /**
  1437. * Remove the debugfs files and directories
  1438. *
  1439. */
  1440. void iwl_dbgfs_unregister(struct iwl_priv *priv)
  1441. {
  1442. if (!priv->debugfs_dir)
  1443. return;
  1444. debugfs_remove_recursive(priv->debugfs_dir);
  1445. priv->debugfs_dir = NULL;
  1446. }
  1447. EXPORT_SYMBOL(iwl_dbgfs_unregister);