iwl-debugfs.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. /******************************************************************************
  2. *
  3. * GPL LICENSE SUMMARY
  4. *
  5. * Copyright(c) 2008 - 2011 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/ieee80211.h>
  29. #include <net/mac80211.h>
  30. #include "iwl-dev.h"
  31. #include "iwl-debug.h"
  32. #include "iwl-core.h"
  33. #include "iwl-io.h"
  34. /* create and remove of files */
  35. #define DEBUGFS_ADD_FILE(name, parent, mode) do { \
  36. if (!debugfs_create_file(#name, mode, parent, priv, \
  37. &iwl_legacy_dbgfs_##name##_ops)) \
  38. goto err; \
  39. } while (0)
  40. #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
  41. struct dentry *__tmp; \
  42. __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
  43. parent, ptr); \
  44. if (IS_ERR(__tmp) || !__tmp) \
  45. goto err; \
  46. } while (0)
  47. #define DEBUGFS_ADD_X32(name, parent, ptr) do { \
  48. struct dentry *__tmp; \
  49. __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
  50. parent, ptr); \
  51. if (IS_ERR(__tmp) || !__tmp) \
  52. goto err; \
  53. } while (0)
  54. /* file operation */
  55. #define DEBUGFS_READ_FUNC(name) \
  56. static ssize_t iwl_legacy_dbgfs_##name##_read(struct file *file, \
  57. char __user *user_buf, \
  58. size_t count, loff_t *ppos);
  59. #define DEBUGFS_WRITE_FUNC(name) \
  60. static ssize_t iwl_legacy_dbgfs_##name##_write(struct file *file, \
  61. const char __user *user_buf, \
  62. size_t count, loff_t *ppos);
  63. static int
  64. iwl_legacy_dbgfs_open_file_generic(struct inode *inode, struct file *file)
  65. {
  66. file->private_data = inode->i_private;
  67. return 0;
  68. }
  69. #define DEBUGFS_READ_FILE_OPS(name) \
  70. DEBUGFS_READ_FUNC(name); \
  71. static const struct file_operations iwl_legacy_dbgfs_##name##_ops = { \
  72. .read = iwl_legacy_dbgfs_##name##_read, \
  73. .open = iwl_legacy_dbgfs_open_file_generic, \
  74. .llseek = generic_file_llseek, \
  75. };
  76. #define DEBUGFS_WRITE_FILE_OPS(name) \
  77. DEBUGFS_WRITE_FUNC(name); \
  78. static const struct file_operations iwl_legacy_dbgfs_##name##_ops = { \
  79. .write = iwl_legacy_dbgfs_##name##_write, \
  80. .open = iwl_legacy_dbgfs_open_file_generic, \
  81. .llseek = generic_file_llseek, \
  82. };
  83. #define DEBUGFS_READ_WRITE_FILE_OPS(name) \
  84. DEBUGFS_READ_FUNC(name); \
  85. DEBUGFS_WRITE_FUNC(name); \
  86. static const struct file_operations iwl_legacy_dbgfs_##name##_ops = { \
  87. .write = iwl_legacy_dbgfs_##name##_write, \
  88. .read = iwl_legacy_dbgfs_##name##_read, \
  89. .open = iwl_legacy_dbgfs_open_file_generic, \
  90. .llseek = generic_file_llseek, \
  91. };
  92. static ssize_t iwl_legacy_dbgfs_tx_statistics_read(struct file *file,
  93. char __user *user_buf,
  94. size_t count, loff_t *ppos) {
  95. struct iwl_priv *priv = file->private_data;
  96. char *buf;
  97. int pos = 0;
  98. int cnt;
  99. ssize_t ret;
  100. const size_t bufsz = 100 +
  101. sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
  102. buf = kzalloc(bufsz, GFP_KERNEL);
  103. if (!buf)
  104. return -ENOMEM;
  105. pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
  106. for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
  107. pos += scnprintf(buf + pos, bufsz - pos,
  108. "\t%25s\t\t: %u\n",
  109. iwl_legacy_get_mgmt_string(cnt),
  110. priv->tx_stats.mgmt[cnt]);
  111. }
  112. pos += scnprintf(buf + pos, bufsz - pos, "Control\n");
  113. for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
  114. pos += scnprintf(buf + pos, bufsz - pos,
  115. "\t%25s\t\t: %u\n",
  116. iwl_legacy_get_ctrl_string(cnt),
  117. priv->tx_stats.ctrl[cnt]);
  118. }
  119. pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
  120. pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
  121. priv->tx_stats.data_cnt);
  122. pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
  123. priv->tx_stats.data_bytes);
  124. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  125. kfree(buf);
  126. return ret;
  127. }
  128. static ssize_t
  129. iwl_legacy_dbgfs_clear_traffic_statistics_write(struct file *file,
  130. const char __user *user_buf,
  131. size_t count, loff_t *ppos)
  132. {
  133. struct iwl_priv *priv = file->private_data;
  134. u32 clear_flag;
  135. char buf[8];
  136. int buf_size;
  137. memset(buf, 0, sizeof(buf));
  138. buf_size = min(count, sizeof(buf) - 1);
  139. if (copy_from_user(buf, user_buf, buf_size))
  140. return -EFAULT;
  141. if (sscanf(buf, "%x", &clear_flag) != 1)
  142. return -EFAULT;
  143. iwl_legacy_clear_traffic_stats(priv);
  144. return count;
  145. }
  146. static ssize_t iwl_legacy_dbgfs_rx_statistics_read(struct file *file,
  147. char __user *user_buf,
  148. size_t count, loff_t *ppos) {
  149. struct iwl_priv *priv = file->private_data;
  150. char *buf;
  151. int pos = 0;
  152. int cnt;
  153. ssize_t ret;
  154. const size_t bufsz = 100 +
  155. sizeof(char) * 50 * (MANAGEMENT_MAX + CONTROL_MAX);
  156. buf = kzalloc(bufsz, GFP_KERNEL);
  157. if (!buf)
  158. return -ENOMEM;
  159. pos += scnprintf(buf + pos, bufsz - pos, "Management:\n");
  160. for (cnt = 0; cnt < MANAGEMENT_MAX; cnt++) {
  161. pos += scnprintf(buf + pos, bufsz - pos,
  162. "\t%25s\t\t: %u\n",
  163. iwl_legacy_get_mgmt_string(cnt),
  164. priv->rx_stats.mgmt[cnt]);
  165. }
  166. pos += scnprintf(buf + pos, bufsz - pos, "Control:\n");
  167. for (cnt = 0; cnt < CONTROL_MAX; cnt++) {
  168. pos += scnprintf(buf + pos, bufsz - pos,
  169. "\t%25s\t\t: %u\n",
  170. iwl_legacy_get_ctrl_string(cnt),
  171. priv->rx_stats.ctrl[cnt]);
  172. }
  173. pos += scnprintf(buf + pos, bufsz - pos, "Data:\n");
  174. pos += scnprintf(buf + pos, bufsz - pos, "\tcnt: %u\n",
  175. priv->rx_stats.data_cnt);
  176. pos += scnprintf(buf + pos, bufsz - pos, "\tbytes: %llu\n",
  177. priv->rx_stats.data_bytes);
  178. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  179. kfree(buf);
  180. return ret;
  181. }
  182. #define BYTE1_MASK 0x000000ff;
  183. #define BYTE2_MASK 0x0000ffff;
  184. #define BYTE3_MASK 0x00ffffff;
  185. static ssize_t iwl_legacy_dbgfs_sram_read(struct file *file,
  186. char __user *user_buf,
  187. size_t count, loff_t *ppos)
  188. {
  189. u32 val;
  190. char *buf;
  191. ssize_t ret;
  192. int i;
  193. int pos = 0;
  194. struct iwl_priv *priv = file->private_data;
  195. size_t bufsz;
  196. /* default is to dump the entire data segment */
  197. if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
  198. priv->dbgfs_sram_offset = 0x800000;
  199. if (priv->ucode_type == UCODE_INIT)
  200. priv->dbgfs_sram_len = priv->ucode_init_data.len;
  201. else
  202. priv->dbgfs_sram_len = priv->ucode_data.len;
  203. }
  204. bufsz = 30 + priv->dbgfs_sram_len * sizeof(char) * 10;
  205. buf = kmalloc(bufsz, GFP_KERNEL);
  206. if (!buf)
  207. return -ENOMEM;
  208. pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n",
  209. priv->dbgfs_sram_len);
  210. pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n",
  211. priv->dbgfs_sram_offset);
  212. for (i = priv->dbgfs_sram_len; i > 0; i -= 4) {
  213. val = iwl_legacy_read_targ_mem(priv, priv->dbgfs_sram_offset + \
  214. priv->dbgfs_sram_len - i);
  215. if (i < 4) {
  216. switch (i) {
  217. case 1:
  218. val &= BYTE1_MASK;
  219. break;
  220. case 2:
  221. val &= BYTE2_MASK;
  222. break;
  223. case 3:
  224. val &= BYTE3_MASK;
  225. break;
  226. }
  227. }
  228. if (!(i % 16))
  229. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  230. pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val);
  231. }
  232. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  233. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  234. kfree(buf);
  235. return ret;
  236. }
  237. static ssize_t iwl_legacy_dbgfs_sram_write(struct file *file,
  238. const char __user *user_buf,
  239. size_t count, loff_t *ppos)
  240. {
  241. struct iwl_priv *priv = file->private_data;
  242. char buf[64];
  243. int buf_size;
  244. u32 offset, len;
  245. memset(buf, 0, sizeof(buf));
  246. buf_size = min(count, sizeof(buf) - 1);
  247. if (copy_from_user(buf, user_buf, buf_size))
  248. return -EFAULT;
  249. if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
  250. priv->dbgfs_sram_offset = offset;
  251. priv->dbgfs_sram_len = len;
  252. } else {
  253. priv->dbgfs_sram_offset = 0;
  254. priv->dbgfs_sram_len = 0;
  255. }
  256. return count;
  257. }
  258. static ssize_t
  259. iwl_legacy_dbgfs_stations_read(struct file *file, char __user *user_buf,
  260. size_t count, loff_t *ppos)
  261. {
  262. struct iwl_priv *priv = file->private_data;
  263. struct iwl_station_entry *station;
  264. int max_sta = priv->hw_params.max_stations;
  265. char *buf;
  266. int i, j, pos = 0;
  267. ssize_t ret;
  268. /* Add 30 for initial string */
  269. const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations);
  270. buf = kmalloc(bufsz, GFP_KERNEL);
  271. if (!buf)
  272. return -ENOMEM;
  273. pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
  274. priv->num_stations);
  275. for (i = 0; i < max_sta; i++) {
  276. station = &priv->stations[i];
  277. if (!station->used)
  278. continue;
  279. pos += scnprintf(buf + pos, bufsz - pos,
  280. "station %d - addr: %pM, flags: %#x\n",
  281. i, station->sta.sta.addr,
  282. station->sta.station_flags_msk);
  283. pos += scnprintf(buf + pos, bufsz - pos,
  284. "TID\tseq_num\ttxq_id\tframes\ttfds\t");
  285. pos += scnprintf(buf + pos, bufsz - pos,
  286. "start_idx\tbitmap\t\t\trate_n_flags\n");
  287. for (j = 0; j < MAX_TID_COUNT; j++) {
  288. pos += scnprintf(buf + pos, bufsz - pos,
  289. "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
  290. j, station->tid[j].seq_number,
  291. station->tid[j].agg.txq_id,
  292. station->tid[j].agg.frame_count,
  293. station->tid[j].tfds_in_queue,
  294. station->tid[j].agg.start_idx,
  295. station->tid[j].agg.bitmap,
  296. station->tid[j].agg.rate_n_flags);
  297. if (station->tid[j].agg.wait_for_ba)
  298. pos += scnprintf(buf + pos, bufsz - pos,
  299. " - waitforba");
  300. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  301. }
  302. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  303. }
  304. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  305. kfree(buf);
  306. return ret;
  307. }
  308. static ssize_t iwl_legacy_dbgfs_nvm_read(struct file *file,
  309. char __user *user_buf,
  310. size_t count,
  311. loff_t *ppos)
  312. {
  313. ssize_t ret;
  314. struct iwl_priv *priv = file->private_data;
  315. int pos = 0, ofs = 0, buf_size = 0;
  316. const u8 *ptr;
  317. char *buf;
  318. u16 eeprom_ver;
  319. size_t eeprom_len = priv->cfg->base_params->eeprom_size;
  320. buf_size = 4 * eeprom_len + 256;
  321. if (eeprom_len % 16) {
  322. IWL_ERR(priv, "NVM size is not multiple of 16.\n");
  323. return -ENODATA;
  324. }
  325. ptr = priv->eeprom;
  326. if (!ptr) {
  327. IWL_ERR(priv, "Invalid EEPROM memory\n");
  328. return -ENOMEM;
  329. }
  330. /* 4 characters for byte 0xYY */
  331. buf = kzalloc(buf_size, GFP_KERNEL);
  332. if (!buf) {
  333. IWL_ERR(priv, "Can not allocate Buffer\n");
  334. return -ENOMEM;
  335. }
  336. eeprom_ver = iwl_legacy_eeprom_query16(priv, EEPROM_VERSION);
  337. pos += scnprintf(buf + pos, buf_size - pos, "EEPROM "
  338. "version: 0x%x\n", eeprom_ver);
  339. for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
  340. pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
  341. hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
  342. buf_size - pos, 0);
  343. pos += strlen(buf + pos);
  344. if (buf_size - pos > 0)
  345. buf[pos++] = '\n';
  346. }
  347. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  348. kfree(buf);
  349. return ret;
  350. }
  351. static ssize_t
  352. iwl_legacy_dbgfs_channels_read(struct file *file, char __user *user_buf,
  353. size_t count, loff_t *ppos)
  354. {
  355. struct iwl_priv *priv = file->private_data;
  356. struct ieee80211_channel *channels = NULL;
  357. const struct ieee80211_supported_band *supp_band = NULL;
  358. int pos = 0, i, bufsz = PAGE_SIZE;
  359. char *buf;
  360. ssize_t ret;
  361. if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status))
  362. return -EAGAIN;
  363. buf = kzalloc(bufsz, GFP_KERNEL);
  364. if (!buf) {
  365. IWL_ERR(priv, "Can not allocate Buffer\n");
  366. return -ENOMEM;
  367. }
  368. supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ);
  369. if (supp_band) {
  370. channels = supp_band->channels;
  371. pos += scnprintf(buf + pos, bufsz - pos,
  372. "Displaying %d channels in 2.4GHz band 802.11bg):\n",
  373. supp_band->n_channels);
  374. for (i = 0; i < supp_band->n_channels; i++)
  375. pos += scnprintf(buf + pos, bufsz - pos,
  376. "%d: %ddBm: BSS%s%s, %s.\n",
  377. channels[i].hw_value,
  378. channels[i].max_power,
  379. channels[i].flags & IEEE80211_CHAN_RADAR ?
  380. " (IEEE 802.11h required)" : "",
  381. ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
  382. || (channels[i].flags &
  383. IEEE80211_CHAN_RADAR)) ? "" :
  384. ", IBSS",
  385. channels[i].flags &
  386. IEEE80211_CHAN_PASSIVE_SCAN ?
  387. "passive only" : "active/passive");
  388. }
  389. supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ);
  390. if (supp_band) {
  391. channels = supp_band->channels;
  392. pos += scnprintf(buf + pos, bufsz - pos,
  393. "Displaying %d channels in 5.2GHz band (802.11a)\n",
  394. supp_band->n_channels);
  395. for (i = 0; i < supp_band->n_channels; i++)
  396. pos += scnprintf(buf + pos, bufsz - pos,
  397. "%d: %ddBm: BSS%s%s, %s.\n",
  398. channels[i].hw_value,
  399. channels[i].max_power,
  400. channels[i].flags & IEEE80211_CHAN_RADAR ?
  401. " (IEEE 802.11h required)" : "",
  402. ((channels[i].flags & IEEE80211_CHAN_NO_IBSS)
  403. || (channels[i].flags &
  404. IEEE80211_CHAN_RADAR)) ? "" :
  405. ", IBSS",
  406. channels[i].flags &
  407. IEEE80211_CHAN_PASSIVE_SCAN ?
  408. "passive only" : "active/passive");
  409. }
  410. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  411. kfree(buf);
  412. return ret;
  413. }
  414. static ssize_t iwl_legacy_dbgfs_status_read(struct file *file,
  415. char __user *user_buf,
  416. size_t count, loff_t *ppos) {
  417. struct iwl_priv *priv = file->private_data;
  418. char buf[512];
  419. int pos = 0;
  420. const size_t bufsz = sizeof(buf);
  421. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n",
  422. test_bit(STATUS_HCMD_ACTIVE, &priv->status));
  423. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n",
  424. test_bit(STATUS_INT_ENABLED, &priv->status));
  425. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
  426. test_bit(STATUS_RF_KILL_HW, &priv->status));
  427. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n",
  428. test_bit(STATUS_CT_KILL, &priv->status));
  429. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
  430. test_bit(STATUS_INIT, &priv->status));
  431. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
  432. test_bit(STATUS_ALIVE, &priv->status));
  433. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n",
  434. test_bit(STATUS_READY, &priv->status));
  435. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n",
  436. test_bit(STATUS_TEMPERATURE, &priv->status));
  437. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n",
  438. test_bit(STATUS_GEO_CONFIGURED, &priv->status));
  439. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n",
  440. test_bit(STATUS_EXIT_PENDING, &priv->status));
  441. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n",
  442. test_bit(STATUS_STATISTICS, &priv->status));
  443. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n",
  444. test_bit(STATUS_SCANNING, &priv->status));
  445. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n",
  446. test_bit(STATUS_SCAN_ABORTING, &priv->status));
  447. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n",
  448. test_bit(STATUS_SCAN_HW, &priv->status));
  449. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n",
  450. test_bit(STATUS_POWER_PMI, &priv->status));
  451. pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
  452. test_bit(STATUS_FW_ERROR, &priv->status));
  453. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  454. }
  455. static ssize_t iwl_legacy_dbgfs_interrupt_read(struct file *file,
  456. char __user *user_buf,
  457. size_t count, loff_t *ppos) {
  458. struct iwl_priv *priv = file->private_data;
  459. int pos = 0;
  460. int cnt = 0;
  461. char *buf;
  462. int bufsz = 24 * 64; /* 24 items * 64 char per item */
  463. ssize_t ret;
  464. buf = kzalloc(bufsz, GFP_KERNEL);
  465. if (!buf) {
  466. IWL_ERR(priv, "Can not allocate Buffer\n");
  467. return -ENOMEM;
  468. }
  469. pos += scnprintf(buf + pos, bufsz - pos,
  470. "Interrupt Statistics Report:\n");
  471. pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
  472. priv->isr_stats.hw);
  473. pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
  474. priv->isr_stats.sw);
  475. if (priv->isr_stats.sw || priv->isr_stats.hw) {
  476. pos += scnprintf(buf + pos, bufsz - pos,
  477. "\tLast Restarting Code: 0x%X\n",
  478. priv->isr_stats.err_code);
  479. }
  480. #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
  481. pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
  482. priv->isr_stats.sch);
  483. pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
  484. priv->isr_stats.alive);
  485. #endif
  486. pos += scnprintf(buf + pos, bufsz - pos,
  487. "HW RF KILL switch toggled:\t %u\n",
  488. priv->isr_stats.rfkill);
  489. pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
  490. priv->isr_stats.ctkill);
  491. pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
  492. priv->isr_stats.wakeup);
  493. pos += scnprintf(buf + pos, bufsz - pos,
  494. "Rx command responses:\t\t %u\n",
  495. priv->isr_stats.rx);
  496. for (cnt = 0; cnt < REPLY_MAX; cnt++) {
  497. if (priv->isr_stats.rx_handlers[cnt] > 0)
  498. pos += scnprintf(buf + pos, bufsz - pos,
  499. "\tRx handler[%36s]:\t\t %u\n",
  500. iwl_legacy_get_cmd_string(cnt),
  501. priv->isr_stats.rx_handlers[cnt]);
  502. }
  503. pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
  504. priv->isr_stats.tx);
  505. pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
  506. priv->isr_stats.unhandled);
  507. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  508. kfree(buf);
  509. return ret;
  510. }
  511. static ssize_t iwl_legacy_dbgfs_interrupt_write(struct file *file,
  512. const char __user *user_buf,
  513. size_t count, loff_t *ppos)
  514. {
  515. struct iwl_priv *priv = file->private_data;
  516. char buf[8];
  517. int buf_size;
  518. u32 reset_flag;
  519. memset(buf, 0, sizeof(buf));
  520. buf_size = min(count, sizeof(buf) - 1);
  521. if (copy_from_user(buf, user_buf, buf_size))
  522. return -EFAULT;
  523. if (sscanf(buf, "%x", &reset_flag) != 1)
  524. return -EFAULT;
  525. if (reset_flag == 0)
  526. iwl_legacy_clear_isr_stats(priv);
  527. return count;
  528. }
  529. static ssize_t
  530. iwl_legacy_dbgfs_qos_read(struct file *file, char __user *user_buf,
  531. size_t count, loff_t *ppos)
  532. {
  533. struct iwl_priv *priv = file->private_data;
  534. struct iwl_rxon_context *ctx;
  535. int pos = 0, i;
  536. char buf[256 * NUM_IWL_RXON_CTX];
  537. const size_t bufsz = sizeof(buf);
  538. for_each_context(priv, ctx) {
  539. pos += scnprintf(buf + pos, bufsz - pos, "context %d:\n",
  540. ctx->ctxid);
  541. for (i = 0; i < AC_NUM; i++) {
  542. pos += scnprintf(buf + pos, bufsz - pos,
  543. "\tcw_min\tcw_max\taifsn\ttxop\n");
  544. pos += scnprintf(buf + pos, bufsz - pos,
  545. "AC[%d]\t%u\t%u\t%u\t%u\n", i,
  546. ctx->qos_data.def_qos_parm.ac[i].cw_min,
  547. ctx->qos_data.def_qos_parm.ac[i].cw_max,
  548. ctx->qos_data.def_qos_parm.ac[i].aifsn,
  549. ctx->qos_data.def_qos_parm.ac[i].edca_txop);
  550. }
  551. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  552. }
  553. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  554. }
  555. static ssize_t iwl_legacy_dbgfs_disable_ht40_write(struct file *file,
  556. const char __user *user_buf,
  557. size_t count, loff_t *ppos)
  558. {
  559. struct iwl_priv *priv = file->private_data;
  560. char buf[8];
  561. int buf_size;
  562. int ht40;
  563. memset(buf, 0, sizeof(buf));
  564. buf_size = min(count, sizeof(buf) - 1);
  565. if (copy_from_user(buf, user_buf, buf_size))
  566. return -EFAULT;
  567. if (sscanf(buf, "%d", &ht40) != 1)
  568. return -EFAULT;
  569. if (!iwl_legacy_is_any_associated(priv))
  570. priv->disable_ht40 = ht40 ? true : false;
  571. else {
  572. IWL_ERR(priv, "Sta associated with AP - "
  573. "Change to 40MHz channel support is not allowed\n");
  574. return -EINVAL;
  575. }
  576. return count;
  577. }
  578. static ssize_t iwl_legacy_dbgfs_disable_ht40_read(struct file *file,
  579. char __user *user_buf,
  580. size_t count, loff_t *ppos)
  581. {
  582. struct iwl_priv *priv = file->private_data;
  583. char buf[100];
  584. int pos = 0;
  585. const size_t bufsz = sizeof(buf);
  586. pos += scnprintf(buf + pos, bufsz - pos,
  587. "11n 40MHz Mode: %s\n",
  588. priv->disable_ht40 ? "Disabled" : "Enabled");
  589. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  590. }
  591. DEBUGFS_READ_WRITE_FILE_OPS(sram);
  592. DEBUGFS_READ_FILE_OPS(nvm);
  593. DEBUGFS_READ_FILE_OPS(stations);
  594. DEBUGFS_READ_FILE_OPS(channels);
  595. DEBUGFS_READ_FILE_OPS(status);
  596. DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
  597. DEBUGFS_READ_FILE_OPS(qos);
  598. DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
  599. static ssize_t iwl_legacy_dbgfs_traffic_log_read(struct file *file,
  600. char __user *user_buf,
  601. size_t count, loff_t *ppos)
  602. {
  603. struct iwl_priv *priv = file->private_data;
  604. int pos = 0, ofs = 0;
  605. int cnt = 0, entry;
  606. struct iwl_tx_queue *txq;
  607. struct iwl_queue *q;
  608. struct iwl_rx_queue *rxq = &priv->rxq;
  609. char *buf;
  610. int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) +
  611. (priv->cfg->base_params->num_of_queues * 32 * 8) + 400;
  612. const u8 *ptr;
  613. ssize_t ret;
  614. if (!priv->txq) {
  615. IWL_ERR(priv, "txq not ready\n");
  616. return -EAGAIN;
  617. }
  618. buf = kzalloc(bufsz, GFP_KERNEL);
  619. if (!buf) {
  620. IWL_ERR(priv, "Can not allocate buffer\n");
  621. return -ENOMEM;
  622. }
  623. pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n");
  624. for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
  625. txq = &priv->txq[cnt];
  626. q = &txq->q;
  627. pos += scnprintf(buf + pos, bufsz - pos,
  628. "q[%d]: read_ptr: %u, write_ptr: %u\n",
  629. cnt, q->read_ptr, q->write_ptr);
  630. }
  631. if (priv->tx_traffic && (iwlegacy_debug_level & IWL_DL_TX)) {
  632. ptr = priv->tx_traffic;
  633. pos += scnprintf(buf + pos, bufsz - pos,
  634. "Tx Traffic idx: %u\n", priv->tx_traffic_idx);
  635. for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
  636. for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
  637. entry++, ofs += 16) {
  638. pos += scnprintf(buf + pos, bufsz - pos,
  639. "0x%.4x ", ofs);
  640. hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
  641. buf + pos, bufsz - pos, 0);
  642. pos += strlen(buf + pos);
  643. if (bufsz - pos > 0)
  644. buf[pos++] = '\n';
  645. }
  646. }
  647. }
  648. pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n");
  649. pos += scnprintf(buf + pos, bufsz - pos,
  650. "read: %u, write: %u\n",
  651. rxq->read, rxq->write);
  652. if (priv->rx_traffic && (iwlegacy_debug_level & IWL_DL_RX)) {
  653. ptr = priv->rx_traffic;
  654. pos += scnprintf(buf + pos, bufsz - pos,
  655. "Rx Traffic idx: %u\n", priv->rx_traffic_idx);
  656. for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) {
  657. for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16;
  658. entry++, ofs += 16) {
  659. pos += scnprintf(buf + pos, bufsz - pos,
  660. "0x%.4x ", ofs);
  661. hex_dump_to_buffer(ptr + ofs, 16, 16, 2,
  662. buf + pos, bufsz - pos, 0);
  663. pos += strlen(buf + pos);
  664. if (bufsz - pos > 0)
  665. buf[pos++] = '\n';
  666. }
  667. }
  668. }
  669. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  670. kfree(buf);
  671. return ret;
  672. }
  673. static ssize_t iwl_legacy_dbgfs_traffic_log_write(struct file *file,
  674. const char __user *user_buf,
  675. size_t count, loff_t *ppos)
  676. {
  677. struct iwl_priv *priv = file->private_data;
  678. char buf[8];
  679. int buf_size;
  680. int traffic_log;
  681. memset(buf, 0, sizeof(buf));
  682. buf_size = min(count, sizeof(buf) - 1);
  683. if (copy_from_user(buf, user_buf, buf_size))
  684. return -EFAULT;
  685. if (sscanf(buf, "%d", &traffic_log) != 1)
  686. return -EFAULT;
  687. if (traffic_log == 0)
  688. iwl_legacy_reset_traffic_log(priv);
  689. return count;
  690. }
  691. static ssize_t iwl_legacy_dbgfs_tx_queue_read(struct file *file,
  692. char __user *user_buf,
  693. size_t count, loff_t *ppos) {
  694. struct iwl_priv *priv = file->private_data;
  695. struct iwl_tx_queue *txq;
  696. struct iwl_queue *q;
  697. char *buf;
  698. int pos = 0;
  699. int cnt;
  700. int ret;
  701. const size_t bufsz = sizeof(char) * 64 *
  702. priv->cfg->base_params->num_of_queues;
  703. if (!priv->txq) {
  704. IWL_ERR(priv, "txq not ready\n");
  705. return -EAGAIN;
  706. }
  707. buf = kzalloc(bufsz, GFP_KERNEL);
  708. if (!buf)
  709. return -ENOMEM;
  710. for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
  711. txq = &priv->txq[cnt];
  712. q = &txq->q;
  713. pos += scnprintf(buf + pos, bufsz - pos,
  714. "hwq %.2d: read=%u write=%u stop=%d"
  715. " swq_id=%#.2x (ac %d/hwq %d)\n",
  716. cnt, q->read_ptr, q->write_ptr,
  717. !!test_bit(cnt, priv->queue_stopped),
  718. txq->swq_id, txq->swq_id & 3,
  719. (txq->swq_id >> 2) & 0x1f);
  720. if (cnt >= 4)
  721. continue;
  722. /* for the ACs, display the stop count too */
  723. pos += scnprintf(buf + pos, bufsz - pos,
  724. " stop-count: %d\n",
  725. atomic_read(&priv->queue_stop_count[cnt]));
  726. }
  727. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  728. kfree(buf);
  729. return ret;
  730. }
  731. static ssize_t iwl_legacy_dbgfs_rx_queue_read(struct file *file,
  732. char __user *user_buf,
  733. size_t count, loff_t *ppos) {
  734. struct iwl_priv *priv = file->private_data;
  735. struct iwl_rx_queue *rxq = &priv->rxq;
  736. char buf[256];
  737. int pos = 0;
  738. const size_t bufsz = sizeof(buf);
  739. pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
  740. rxq->read);
  741. pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
  742. rxq->write);
  743. pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
  744. rxq->free_count);
  745. if (rxq->rb_stts) {
  746. pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
  747. le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF);
  748. } else {
  749. pos += scnprintf(buf + pos, bufsz - pos,
  750. "closed_rb_num: Not Allocated\n");
  751. }
  752. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  753. }
  754. static ssize_t iwl_legacy_dbgfs_ucode_rx_stats_read(struct file *file,
  755. char __user *user_buf,
  756. size_t count, loff_t *ppos)
  757. {
  758. struct iwl_priv *priv = file->private_data;
  759. return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
  760. user_buf, count, ppos);
  761. }
  762. static ssize_t iwl_legacy_dbgfs_ucode_tx_stats_read(struct file *file,
  763. char __user *user_buf,
  764. size_t count, loff_t *ppos)
  765. {
  766. struct iwl_priv *priv = file->private_data;
  767. return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
  768. user_buf, count, ppos);
  769. }
  770. static ssize_t iwl_legacy_dbgfs_ucode_general_stats_read(struct file *file,
  771. char __user *user_buf,
  772. size_t count, loff_t *ppos)
  773. {
  774. struct iwl_priv *priv = file->private_data;
  775. return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
  776. user_buf, count, ppos);
  777. }
  778. static ssize_t iwl_legacy_dbgfs_sensitivity_read(struct file *file,
  779. char __user *user_buf,
  780. size_t count, loff_t *ppos) {
  781. struct iwl_priv *priv = file->private_data;
  782. int pos = 0;
  783. int cnt = 0;
  784. char *buf;
  785. int bufsz = sizeof(struct iwl_sensitivity_data) * 4 + 100;
  786. ssize_t ret;
  787. struct iwl_sensitivity_data *data;
  788. data = &priv->sensitivity_data;
  789. buf = kzalloc(bufsz, GFP_KERNEL);
  790. if (!buf) {
  791. IWL_ERR(priv, "Can not allocate Buffer\n");
  792. return -ENOMEM;
  793. }
  794. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm:\t\t\t %u\n",
  795. data->auto_corr_ofdm);
  796. pos += scnprintf(buf + pos, bufsz - pos,
  797. "auto_corr_ofdm_mrc:\t\t %u\n",
  798. data->auto_corr_ofdm_mrc);
  799. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_ofdm_x1:\t\t %u\n",
  800. data->auto_corr_ofdm_x1);
  801. pos += scnprintf(buf + pos, bufsz - pos,
  802. "auto_corr_ofdm_mrc_x1:\t\t %u\n",
  803. data->auto_corr_ofdm_mrc_x1);
  804. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck:\t\t\t %u\n",
  805. data->auto_corr_cck);
  806. pos += scnprintf(buf + pos, bufsz - pos, "auto_corr_cck_mrc:\t\t %u\n",
  807. data->auto_corr_cck_mrc);
  808. pos += scnprintf(buf + pos, bufsz - pos,
  809. "last_bad_plcp_cnt_ofdm:\t\t %u\n",
  810. data->last_bad_plcp_cnt_ofdm);
  811. pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_ofdm:\t\t %u\n",
  812. data->last_fa_cnt_ofdm);
  813. pos += scnprintf(buf + pos, bufsz - pos,
  814. "last_bad_plcp_cnt_cck:\t\t %u\n",
  815. data->last_bad_plcp_cnt_cck);
  816. pos += scnprintf(buf + pos, bufsz - pos, "last_fa_cnt_cck:\t\t %u\n",
  817. data->last_fa_cnt_cck);
  818. pos += scnprintf(buf + pos, bufsz - pos, "nrg_curr_state:\t\t\t %u\n",
  819. data->nrg_curr_state);
  820. pos += scnprintf(buf + pos, bufsz - pos, "nrg_prev_state:\t\t\t %u\n",
  821. data->nrg_prev_state);
  822. pos += scnprintf(buf + pos, bufsz - pos, "nrg_value:\t\t\t");
  823. for (cnt = 0; cnt < 10; cnt++) {
  824. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  825. data->nrg_value[cnt]);
  826. }
  827. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  828. pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_rssi:\t\t");
  829. for (cnt = 0; cnt < NRG_NUM_PREV_STAT_L; cnt++) {
  830. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  831. data->nrg_silence_rssi[cnt]);
  832. }
  833. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  834. pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_ref:\t\t %u\n",
  835. data->nrg_silence_ref);
  836. pos += scnprintf(buf + pos, bufsz - pos, "nrg_energy_idx:\t\t\t %u\n",
  837. data->nrg_energy_idx);
  838. pos += scnprintf(buf + pos, bufsz - pos, "nrg_silence_idx:\t\t %u\n",
  839. data->nrg_silence_idx);
  840. pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_cck:\t\t\t %u\n",
  841. data->nrg_th_cck);
  842. pos += scnprintf(buf + pos, bufsz - pos,
  843. "nrg_auto_corr_silence_diff:\t %u\n",
  844. data->nrg_auto_corr_silence_diff);
  845. pos += scnprintf(buf + pos, bufsz - pos, "num_in_cck_no_fa:\t\t %u\n",
  846. data->num_in_cck_no_fa);
  847. pos += scnprintf(buf + pos, bufsz - pos, "nrg_th_ofdm:\t\t\t %u\n",
  848. data->nrg_th_ofdm);
  849. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  850. kfree(buf);
  851. return ret;
  852. }
  853. static ssize_t iwl_legacy_dbgfs_chain_noise_read(struct file *file,
  854. char __user *user_buf,
  855. size_t count, loff_t *ppos) {
  856. struct iwl_priv *priv = file->private_data;
  857. int pos = 0;
  858. int cnt = 0;
  859. char *buf;
  860. int bufsz = sizeof(struct iwl_chain_noise_data) * 4 + 100;
  861. ssize_t ret;
  862. struct iwl_chain_noise_data *data;
  863. data = &priv->chain_noise_data;
  864. buf = kzalloc(bufsz, GFP_KERNEL);
  865. if (!buf) {
  866. IWL_ERR(priv, "Can not allocate Buffer\n");
  867. return -ENOMEM;
  868. }
  869. pos += scnprintf(buf + pos, bufsz - pos, "active_chains:\t\t\t %u\n",
  870. data->active_chains);
  871. pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_a:\t\t\t %u\n",
  872. data->chain_noise_a);
  873. pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_b:\t\t\t %u\n",
  874. data->chain_noise_b);
  875. pos += scnprintf(buf + pos, bufsz - pos, "chain_noise_c:\t\t\t %u\n",
  876. data->chain_noise_c);
  877. pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_a:\t\t\t %u\n",
  878. data->chain_signal_a);
  879. pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_b:\t\t\t %u\n",
  880. data->chain_signal_b);
  881. pos += scnprintf(buf + pos, bufsz - pos, "chain_signal_c:\t\t\t %u\n",
  882. data->chain_signal_c);
  883. pos += scnprintf(buf + pos, bufsz - pos, "beacon_count:\t\t\t %u\n",
  884. data->beacon_count);
  885. pos += scnprintf(buf + pos, bufsz - pos, "disconn_array:\t\t\t");
  886. for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
  887. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  888. data->disconn_array[cnt]);
  889. }
  890. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  891. pos += scnprintf(buf + pos, bufsz - pos, "delta_gain_code:\t\t");
  892. for (cnt = 0; cnt < NUM_RX_CHAINS; cnt++) {
  893. pos += scnprintf(buf + pos, bufsz - pos, " %u",
  894. data->delta_gain_code[cnt]);
  895. }
  896. pos += scnprintf(buf + pos, bufsz - pos, "\n");
  897. pos += scnprintf(buf + pos, bufsz - pos, "radio_write:\t\t\t %u\n",
  898. data->radio_write);
  899. pos += scnprintf(buf + pos, bufsz - pos, "state:\t\t\t\t %u\n",
  900. data->state);
  901. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  902. kfree(buf);
  903. return ret;
  904. }
  905. static ssize_t iwl_legacy_dbgfs_power_save_status_read(struct file *file,
  906. char __user *user_buf,
  907. size_t count, loff_t *ppos)
  908. {
  909. struct iwl_priv *priv = file->private_data;
  910. char buf[60];
  911. int pos = 0;
  912. const size_t bufsz = sizeof(buf);
  913. u32 pwrsave_status;
  914. pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) &
  915. CSR_GP_REG_POWER_SAVE_STATUS_MSK;
  916. pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: ");
  917. pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
  918. (pwrsave_status == CSR_GP_REG_NO_POWER_SAVE) ? "none" :
  919. (pwrsave_status == CSR_GP_REG_MAC_POWER_SAVE) ? "MAC" :
  920. (pwrsave_status == CSR_GP_REG_PHY_POWER_SAVE) ? "PHY" :
  921. "error");
  922. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  923. }
  924. static ssize_t iwl_legacy_dbgfs_clear_ucode_statistics_write(struct file *file,
  925. const char __user *user_buf,
  926. size_t count, loff_t *ppos)
  927. {
  928. struct iwl_priv *priv = file->private_data;
  929. char buf[8];
  930. int buf_size;
  931. int clear;
  932. memset(buf, 0, sizeof(buf));
  933. buf_size = min(count, sizeof(buf) - 1);
  934. if (copy_from_user(buf, user_buf, buf_size))
  935. return -EFAULT;
  936. if (sscanf(buf, "%d", &clear) != 1)
  937. return -EFAULT;
  938. /* make request to uCode to retrieve statistics information */
  939. mutex_lock(&priv->mutex);
  940. iwl_legacy_send_statistics_request(priv, CMD_SYNC, true);
  941. mutex_unlock(&priv->mutex);
  942. return count;
  943. }
  944. static ssize_t iwl_legacy_dbgfs_rxon_flags_read(struct file *file,
  945. char __user *user_buf,
  946. size_t count, loff_t *ppos) {
  947. struct iwl_priv *priv = file->private_data;
  948. int len = 0;
  949. char buf[20];
  950. len = sprintf(buf, "0x%04X\n",
  951. le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.flags));
  952. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  953. }
  954. static ssize_t iwl_legacy_dbgfs_rxon_filter_flags_read(struct file *file,
  955. char __user *user_buf,
  956. size_t count, loff_t *ppos) {
  957. struct iwl_priv *priv = file->private_data;
  958. int len = 0;
  959. char buf[20];
  960. len = sprintf(buf, "0x%04X\n",
  961. le32_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.filter_flags));
  962. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  963. }
  964. static ssize_t iwl_legacy_dbgfs_fh_reg_read(struct file *file,
  965. char __user *user_buf,
  966. size_t count, loff_t *ppos)
  967. {
  968. struct iwl_priv *priv = file->private_data;
  969. char *buf;
  970. int pos = 0;
  971. ssize_t ret = -EFAULT;
  972. if (priv->cfg->ops->lib->dump_fh) {
  973. ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
  974. if (buf) {
  975. ret = simple_read_from_buffer(user_buf,
  976. count, ppos, buf, pos);
  977. kfree(buf);
  978. }
  979. }
  980. return ret;
  981. }
  982. static ssize_t iwl_legacy_dbgfs_missed_beacon_read(struct file *file,
  983. char __user *user_buf,
  984. size_t count, loff_t *ppos) {
  985. struct iwl_priv *priv = file->private_data;
  986. int pos = 0;
  987. char buf[12];
  988. const size_t bufsz = sizeof(buf);
  989. pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
  990. priv->missed_beacon_threshold);
  991. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  992. }
  993. static ssize_t iwl_legacy_dbgfs_missed_beacon_write(struct file *file,
  994. const char __user *user_buf,
  995. size_t count, loff_t *ppos)
  996. {
  997. struct iwl_priv *priv = file->private_data;
  998. char buf[8];
  999. int buf_size;
  1000. int missed;
  1001. memset(buf, 0, sizeof(buf));
  1002. buf_size = min(count, sizeof(buf) - 1);
  1003. if (copy_from_user(buf, user_buf, buf_size))
  1004. return -EFAULT;
  1005. if (sscanf(buf, "%d", &missed) != 1)
  1006. return -EINVAL;
  1007. if (missed < IWL_MISSED_BEACON_THRESHOLD_MIN ||
  1008. missed > IWL_MISSED_BEACON_THRESHOLD_MAX)
  1009. priv->missed_beacon_threshold =
  1010. IWL_MISSED_BEACON_THRESHOLD_DEF;
  1011. else
  1012. priv->missed_beacon_threshold = missed;
  1013. return count;
  1014. }
  1015. static ssize_t iwl_legacy_dbgfs_force_reset_read(struct file *file,
  1016. char __user *user_buf,
  1017. size_t count, loff_t *ppos) {
  1018. struct iwl_priv *priv = file->private_data;
  1019. int pos = 0;
  1020. char buf[300];
  1021. const size_t bufsz = sizeof(buf);
  1022. struct iwl_force_reset *force_reset;
  1023. force_reset = &priv->force_reset;
  1024. pos += scnprintf(buf + pos, bufsz - pos,
  1025. "\tnumber of reset request: %d\n",
  1026. force_reset->reset_request_count);
  1027. pos += scnprintf(buf + pos, bufsz - pos,
  1028. "\tnumber of reset request success: %d\n",
  1029. force_reset->reset_success_count);
  1030. pos += scnprintf(buf + pos, bufsz - pos,
  1031. "\tnumber of reset request reject: %d\n",
  1032. force_reset->reset_reject_count);
  1033. pos += scnprintf(buf + pos, bufsz - pos,
  1034. "\treset duration: %lu\n",
  1035. force_reset->reset_duration);
  1036. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  1037. }
  1038. static ssize_t iwl_legacy_dbgfs_force_reset_write(struct file *file,
  1039. const char __user *user_buf,
  1040. size_t count, loff_t *ppos) {
  1041. int ret;
  1042. struct iwl_priv *priv = file->private_data;
  1043. ret = iwl_legacy_force_reset(priv, true);
  1044. return ret ? ret : count;
  1045. }
  1046. static ssize_t iwl_legacy_dbgfs_wd_timeout_write(struct file *file,
  1047. const char __user *user_buf,
  1048. size_t count, loff_t *ppos) {
  1049. struct iwl_priv *priv = file->private_data;
  1050. char buf[8];
  1051. int buf_size;
  1052. int timeout;
  1053. memset(buf, 0, sizeof(buf));
  1054. buf_size = min(count, sizeof(buf) - 1);
  1055. if (copy_from_user(buf, user_buf, buf_size))
  1056. return -EFAULT;
  1057. if (sscanf(buf, "%d", &timeout) != 1)
  1058. return -EINVAL;
  1059. if (timeout < 0 || timeout > IWL_MAX_WD_TIMEOUT)
  1060. timeout = IWL_DEF_WD_TIMEOUT;
  1061. priv->cfg->base_params->wd_timeout = timeout;
  1062. iwl_legacy_setup_watchdog(priv);
  1063. return count;
  1064. }
  1065. DEBUGFS_READ_FILE_OPS(rx_statistics);
  1066. DEBUGFS_READ_FILE_OPS(tx_statistics);
  1067. DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
  1068. DEBUGFS_READ_FILE_OPS(rx_queue);
  1069. DEBUGFS_READ_FILE_OPS(tx_queue);
  1070. DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
  1071. DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
  1072. DEBUGFS_READ_FILE_OPS(ucode_general_stats);
  1073. DEBUGFS_READ_FILE_OPS(sensitivity);
  1074. DEBUGFS_READ_FILE_OPS(chain_noise);
  1075. DEBUGFS_READ_FILE_OPS(power_save_status);
  1076. DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
  1077. DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
  1078. DEBUGFS_READ_FILE_OPS(fh_reg);
  1079. DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
  1080. DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
  1081. DEBUGFS_READ_FILE_OPS(rxon_flags);
  1082. DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
  1083. DEBUGFS_WRITE_FILE_OPS(wd_timeout);
  1084. /*
  1085. * Create the debugfs files and directories
  1086. *
  1087. */
  1088. int iwl_legacy_dbgfs_register(struct iwl_priv *priv, const char *name)
  1089. {
  1090. struct dentry *phyd = priv->hw->wiphy->debugfsdir;
  1091. struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug;
  1092. dir_drv = debugfs_create_dir(name, phyd);
  1093. if (!dir_drv)
  1094. return -ENOMEM;
  1095. priv->debugfs_dir = dir_drv;
  1096. dir_data = debugfs_create_dir("data", dir_drv);
  1097. if (!dir_data)
  1098. goto err;
  1099. dir_rf = debugfs_create_dir("rf", dir_drv);
  1100. if (!dir_rf)
  1101. goto err;
  1102. dir_debug = debugfs_create_dir("debug", dir_drv);
  1103. if (!dir_debug)
  1104. goto err;
  1105. DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR);
  1106. DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR);
  1107. DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR);
  1108. DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR);
  1109. DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
  1110. DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
  1111. DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
  1112. DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
  1113. DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
  1114. DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
  1115. DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
  1116. DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
  1117. DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
  1118. DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
  1119. DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
  1120. DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
  1121. DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
  1122. DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
  1123. DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
  1124. DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
  1125. DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
  1126. DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
  1127. if (priv->cfg->base_params->sensitivity_calib_by_driver)
  1128. DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
  1129. if (priv->cfg->base_params->chain_noise_calib_by_driver)
  1130. DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
  1131. DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
  1132. DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
  1133. DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
  1134. if (priv->cfg->base_params->sensitivity_calib_by_driver)
  1135. DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
  1136. &priv->disable_sens_cal);
  1137. if (priv->cfg->base_params->chain_noise_calib_by_driver)
  1138. DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
  1139. &priv->disable_chain_noise_cal);
  1140. DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
  1141. &priv->disable_tx_power_cal);
  1142. return 0;
  1143. err:
  1144. IWL_ERR(priv, "Can't create the debugfs directory\n");
  1145. iwl_legacy_dbgfs_unregister(priv);
  1146. return -ENOMEM;
  1147. }
  1148. EXPORT_SYMBOL(iwl_legacy_dbgfs_register);
  1149. /**
  1150. * Remove the debugfs files and directories
  1151. *
  1152. */
  1153. void iwl_legacy_dbgfs_unregister(struct iwl_priv *priv)
  1154. {
  1155. if (!priv->debugfs_dir)
  1156. return;
  1157. debugfs_remove_recursive(priv->debugfs_dir);
  1158. priv->debugfs_dir = NULL;
  1159. }
  1160. EXPORT_SYMBOL(iwl_legacy_dbgfs_unregister);