debugfs.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. /******************************************************************************
  2. *
  3. * This file is provided under a dual BSD/GPLv2 license. When using or
  4. * redistributing this file, you may do so under either license.
  5. *
  6. * GPL LICENSE SUMMARY
  7. *
  8. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of version 2 of the GNU General Public License as
  12. * published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
  22. * USA
  23. *
  24. * The full GNU General Public License is included in this distribution
  25. * in the file called COPYING.
  26. *
  27. * Contact Information:
  28. * Intel Linux Wireless <ilw@linux.intel.com>
  29. * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  30. *
  31. * BSD LICENSE
  32. *
  33. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  34. * All rights reserved.
  35. *
  36. * Redistribution and use in source and binary forms, with or without
  37. * modification, are permitted provided that the following conditions
  38. * are met:
  39. *
  40. * * Redistributions of source code must retain the above copyright
  41. * notice, this list of conditions and the following disclaimer.
  42. * * Redistributions in binary form must reproduce the above copyright
  43. * notice, this list of conditions and the following disclaimer in
  44. * the documentation and/or other materials provided with the
  45. * distribution.
  46. * * Neither the name Intel Corporation nor the names of its
  47. * contributors may be used to endorse or promote products derived
  48. * from this software without specific prior written permission.
  49. *
  50. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  54. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  55. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  56. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  57. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  58. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  59. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  60. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61. *
  62. *****************************************************************************/
  63. #include "mvm.h"
  64. #include "sta.h"
  65. #include "iwl-io.h"
  66. #include "iwl-prph.h"
  67. #include "debugfs.h"
  68. static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
  69. size_t count, loff_t *ppos)
  70. {
  71. int ret;
  72. u32 scd_q_msk;
  73. if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  74. return -EIO;
  75. if (sscanf(buf, "%x", &scd_q_msk) != 1)
  76. return -EINVAL;
  77. IWL_ERR(mvm, "FLUSHING queues: scd_q_msk = 0x%x\n", scd_q_msk);
  78. mutex_lock(&mvm->mutex);
  79. ret = iwl_mvm_flush_tx_path(mvm, scd_q_msk, true) ? : count;
  80. mutex_unlock(&mvm->mutex);
  81. return ret;
  82. }
  83. static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
  84. size_t count, loff_t *ppos)
  85. {
  86. struct iwl_mvm_sta *mvmsta;
  87. int sta_id, drain, ret;
  88. if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
  89. return -EIO;
  90. if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
  91. return -EINVAL;
  92. if (sta_id < 0 || sta_id >= IWL_MVM_STATION_COUNT)
  93. return -EINVAL;
  94. if (drain < 0 || drain > 1)
  95. return -EINVAL;
  96. mutex_lock(&mvm->mutex);
  97. mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
  98. if (!mvmsta)
  99. ret = -ENOENT;
  100. else
  101. ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count;
  102. mutex_unlock(&mvm->mutex);
  103. return ret;
  104. }
  105. static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
  106. size_t count, loff_t *ppos)
  107. {
  108. struct iwl_mvm *mvm = file->private_data;
  109. const struct fw_img *img;
  110. unsigned int ofs, len;
  111. size_t ret;
  112. u8 *ptr;
  113. if (!mvm->ucode_loaded)
  114. return -EINVAL;
  115. /* default is to dump the entire data segment */
  116. img = &mvm->fw->img[mvm->cur_ucode];
  117. ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
  118. len = img->sec[IWL_UCODE_SECTION_DATA].len;
  119. if (mvm->dbgfs_sram_len) {
  120. ofs = mvm->dbgfs_sram_offset;
  121. len = mvm->dbgfs_sram_len;
  122. }
  123. ptr = kzalloc(len, GFP_KERNEL);
  124. if (!ptr)
  125. return -ENOMEM;
  126. iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
  127. ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
  128. kfree(ptr);
  129. return ret;
  130. }
  131. static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
  132. size_t count, loff_t *ppos)
  133. {
  134. const struct fw_img *img;
  135. u32 offset, len;
  136. u32 img_offset, img_len;
  137. if (!mvm->ucode_loaded)
  138. return -EINVAL;
  139. img = &mvm->fw->img[mvm->cur_ucode];
  140. img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
  141. img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
  142. if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
  143. if ((offset & 0x3) || (len & 0x3))
  144. return -EINVAL;
  145. if (offset + len > img_offset + img_len)
  146. return -EINVAL;
  147. mvm->dbgfs_sram_offset = offset;
  148. mvm->dbgfs_sram_len = len;
  149. } else {
  150. mvm->dbgfs_sram_offset = 0;
  151. mvm->dbgfs_sram_len = 0;
  152. }
  153. return count;
  154. }
  155. static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
  156. size_t count, loff_t *ppos)
  157. {
  158. struct iwl_mvm *mvm = file->private_data;
  159. struct ieee80211_sta *sta;
  160. char buf[400];
  161. int i, pos = 0, bufsz = sizeof(buf);
  162. mutex_lock(&mvm->mutex);
  163. for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
  164. pos += scnprintf(buf + pos, bufsz - pos, "%.2d: ", i);
  165. sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
  166. lockdep_is_held(&mvm->mutex));
  167. if (!sta)
  168. pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
  169. else if (IS_ERR(sta))
  170. pos += scnprintf(buf + pos, bufsz - pos, "%ld\n",
  171. PTR_ERR(sta));
  172. else
  173. pos += scnprintf(buf + pos, bufsz - pos, "%pM\n",
  174. sta->addr);
  175. }
  176. mutex_unlock(&mvm->mutex);
  177. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  178. }
  179. static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
  180. char __user *user_buf,
  181. size_t count, loff_t *ppos)
  182. {
  183. struct iwl_mvm *mvm = file->private_data;
  184. char buf[64];
  185. int bufsz = sizeof(buf);
  186. int pos = 0;
  187. pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n",
  188. mvm->disable_power_off);
  189. pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n",
  190. mvm->disable_power_off_d3);
  191. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  192. }
  193. static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
  194. size_t count, loff_t *ppos)
  195. {
  196. int ret, val;
  197. if (!mvm->ucode_loaded)
  198. return -EIO;
  199. if (!strncmp("disable_power_off_d0=", buf, 21)) {
  200. if (sscanf(buf + 21, "%d", &val) != 1)
  201. return -EINVAL;
  202. mvm->disable_power_off = val;
  203. } else if (!strncmp("disable_power_off_d3=", buf, 21)) {
  204. if (sscanf(buf + 21, "%d", &val) != 1)
  205. return -EINVAL;
  206. mvm->disable_power_off_d3 = val;
  207. } else {
  208. return -EINVAL;
  209. }
  210. mutex_lock(&mvm->mutex);
  211. ret = iwl_mvm_power_update_device(mvm);
  212. mutex_unlock(&mvm->mutex);
  213. return ret ?: count;
  214. }
  215. #define BT_MBOX_MSG(_notif, _num, _field) \
  216. ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
  217. >> BT_MBOX##_num##_##_field##_POS)
  218. #define BT_MBOX_PRINT(_num, _field, _end) \
  219. pos += scnprintf(buf + pos, bufsz - pos, \
  220. "\t%s: %d%s", \
  221. #_field, \
  222. BT_MBOX_MSG(notif, _num, _field), \
  223. true ? "\n" : ", ");
  224. static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
  225. size_t count, loff_t *ppos)
  226. {
  227. struct iwl_mvm *mvm = file->private_data;
  228. struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
  229. char *buf;
  230. int ret, pos = 0, bufsz = sizeof(char) * 1024;
  231. buf = kmalloc(bufsz, GFP_KERNEL);
  232. if (!buf)
  233. return -ENOMEM;
  234. mutex_lock(&mvm->mutex);
  235. pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
  236. BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
  237. BT_MBOX_PRINT(0, LE_PROF1, false);
  238. BT_MBOX_PRINT(0, LE_PROF2, false);
  239. BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
  240. BT_MBOX_PRINT(0, CHL_SEQ_N, false);
  241. BT_MBOX_PRINT(0, INBAND_S, false);
  242. BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
  243. BT_MBOX_PRINT(0, LE_SCAN, false);
  244. BT_MBOX_PRINT(0, LE_ADV, false);
  245. BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
  246. BT_MBOX_PRINT(0, OPEN_CON_1, true);
  247. pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
  248. BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
  249. BT_MBOX_PRINT(1, IP_SR, false);
  250. BT_MBOX_PRINT(1, LE_MSTR, false);
  251. BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
  252. BT_MBOX_PRINT(1, MSG_TYPE, false);
  253. BT_MBOX_PRINT(1, SSN, true);
  254. pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
  255. BT_MBOX_PRINT(2, SNIFF_ACT, false);
  256. BT_MBOX_PRINT(2, PAG, false);
  257. BT_MBOX_PRINT(2, INQUIRY, false);
  258. BT_MBOX_PRINT(2, CONN, false);
  259. BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
  260. BT_MBOX_PRINT(2, DISC, false);
  261. BT_MBOX_PRINT(2, SCO_TX_ACT, false);
  262. BT_MBOX_PRINT(2, SCO_RX_ACT, false);
  263. BT_MBOX_PRINT(2, ESCO_RE_TX, false);
  264. BT_MBOX_PRINT(2, SCO_DURATION, true);
  265. pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
  266. BT_MBOX_PRINT(3, SCO_STATE, false);
  267. BT_MBOX_PRINT(3, SNIFF_STATE, false);
  268. BT_MBOX_PRINT(3, A2DP_STATE, false);
  269. BT_MBOX_PRINT(3, ACL_STATE, false);
  270. BT_MBOX_PRINT(3, MSTR_STATE, false);
  271. BT_MBOX_PRINT(3, OBX_STATE, false);
  272. BT_MBOX_PRINT(3, OPEN_CON_2, false);
  273. BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
  274. BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
  275. BT_MBOX_PRINT(3, INBAND_P, false);
  276. BT_MBOX_PRINT(3, MSG_TYPE_2, false);
  277. BT_MBOX_PRINT(3, SSN_2, false);
  278. BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
  279. pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
  280. notif->bt_status);
  281. pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
  282. notif->bt_open_conn);
  283. pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
  284. notif->bt_traffic_load);
  285. pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
  286. notif->bt_agg_traffic_load);
  287. pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
  288. notif->bt_ci_compliance);
  289. pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n",
  290. le32_to_cpu(notif->primary_ch_lut));
  291. pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n",
  292. le32_to_cpu(notif->secondary_ch_lut));
  293. pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n",
  294. le32_to_cpu(notif->bt_activity_grading));
  295. pos += scnprintf(buf+pos, bufsz-pos,
  296. "antenna isolation = %d CORUN LUT index = %d\n",
  297. mvm->last_ant_isol, mvm->last_corun_lut);
  298. mutex_unlock(&mvm->mutex);
  299. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  300. kfree(buf);
  301. return ret;
  302. }
  303. #undef BT_MBOX_PRINT
  304. static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
  305. size_t count, loff_t *ppos)
  306. {
  307. struct iwl_mvm *mvm = file->private_data;
  308. struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
  309. char buf[256];
  310. int bufsz = sizeof(buf);
  311. int pos = 0;
  312. mutex_lock(&mvm->mutex);
  313. pos += scnprintf(buf+pos, bufsz-pos, "Channel inhibition CMD\n");
  314. pos += scnprintf(buf+pos, bufsz-pos,
  315. "\tPrimary Channel Bitmap 0x%016llx Fat: %d\n",
  316. le64_to_cpu(cmd->bt_primary_ci),
  317. !!cmd->co_run_bw_primary);
  318. pos += scnprintf(buf+pos, bufsz-pos,
  319. "\tSecondary Channel Bitmap 0x%016llx Fat: %d\n",
  320. le64_to_cpu(cmd->bt_secondary_ci),
  321. !!cmd->co_run_bw_secondary);
  322. pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
  323. pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n",
  324. iwl_bt_ack_kill_msk[mvm->bt_kill_msk]);
  325. pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
  326. iwl_bt_cts_kill_msk[mvm->bt_kill_msk]);
  327. mutex_unlock(&mvm->mutex);
  328. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  329. }
  330. #define PRINT_STATS_LE32(_str, _val) \
  331. pos += scnprintf(buf + pos, bufsz - pos, \
  332. fmt_table, _str, \
  333. le32_to_cpu(_val))
  334. static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
  335. char __user *user_buf, size_t count,
  336. loff_t *ppos)
  337. {
  338. struct iwl_mvm *mvm = file->private_data;
  339. static const char *fmt_table = "\t%-30s %10u\n";
  340. static const char *fmt_header = "%-32s\n";
  341. int pos = 0;
  342. char *buf;
  343. int ret;
  344. /* 43 is the size of each data line, 33 is the size of each header */
  345. size_t bufsz =
  346. ((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) +
  347. (4 * 33) + 1;
  348. struct mvm_statistics_rx_phy *ofdm;
  349. struct mvm_statistics_rx_phy *cck;
  350. struct mvm_statistics_rx_non_phy *general;
  351. struct mvm_statistics_rx_ht_phy *ht;
  352. buf = kzalloc(bufsz, GFP_KERNEL);
  353. if (!buf)
  354. return -ENOMEM;
  355. mutex_lock(&mvm->mutex);
  356. ofdm = &mvm->rx_stats.ofdm;
  357. cck = &mvm->rx_stats.cck;
  358. general = &mvm->rx_stats.general;
  359. ht = &mvm->rx_stats.ofdm_ht;
  360. pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
  361. "Statistics_Rx - OFDM");
  362. PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt);
  363. PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt);
  364. PRINT_STATS_LE32("plcp_err", ofdm->plcp_err);
  365. PRINT_STATS_LE32("crc32_err", ofdm->crc32_err);
  366. PRINT_STATS_LE32("overrun_err", ofdm->overrun_err);
  367. PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err);
  368. PRINT_STATS_LE32("crc32_good", ofdm->crc32_good);
  369. PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt);
  370. PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt);
  371. PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout);
  372. PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout);
  373. PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts);
  374. PRINT_STATS_LE32("rxe_frame_lmt_overrun",
  375. ofdm->rxe_frame_limit_overrun);
  376. PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt);
  377. PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt);
  378. PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt);
  379. PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill);
  380. PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err);
  381. PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum);
  382. PRINT_STATS_LE32("reserved", ofdm->reserved);
  383. pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
  384. "Statistics_Rx - CCK");
  385. PRINT_STATS_LE32("ina_cnt", cck->ina_cnt);
  386. PRINT_STATS_LE32("fina_cnt", cck->fina_cnt);
  387. PRINT_STATS_LE32("plcp_err", cck->plcp_err);
  388. PRINT_STATS_LE32("crc32_err", cck->crc32_err);
  389. PRINT_STATS_LE32("overrun_err", cck->overrun_err);
  390. PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err);
  391. PRINT_STATS_LE32("crc32_good", cck->crc32_good);
  392. PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt);
  393. PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt);
  394. PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout);
  395. PRINT_STATS_LE32("fina_timeout", cck->fina_timeout);
  396. PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts);
  397. PRINT_STATS_LE32("rxe_frame_lmt_overrun",
  398. cck->rxe_frame_limit_overrun);
  399. PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt);
  400. PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt);
  401. PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt);
  402. PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill);
  403. PRINT_STATS_LE32("mh_format_err", cck->mh_format_err);
  404. PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum);
  405. PRINT_STATS_LE32("reserved", cck->reserved);
  406. pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
  407. "Statistics_Rx - GENERAL");
  408. PRINT_STATS_LE32("bogus_cts", general->bogus_cts);
  409. PRINT_STATS_LE32("bogus_ack", general->bogus_ack);
  410. PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames);
  411. PRINT_STATS_LE32("filtered_frames", general->filtered_frames);
  412. PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons);
  413. PRINT_STATS_LE32("channel_beacons", general->channel_beacons);
  414. PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon);
  415. PRINT_STATS_LE32("adc_rx_saturation_time",
  416. general->adc_rx_saturation_time);
  417. PRINT_STATS_LE32("ina_detection_search_time",
  418. general->ina_detection_search_time);
  419. PRINT_STATS_LE32("beacon_silence_rssi_a",
  420. general->beacon_silence_rssi_a);
  421. PRINT_STATS_LE32("beacon_silence_rssi_b",
  422. general->beacon_silence_rssi_b);
  423. PRINT_STATS_LE32("beacon_silence_rssi_c",
  424. general->beacon_silence_rssi_c);
  425. PRINT_STATS_LE32("interference_data_flag",
  426. general->interference_data_flag);
  427. PRINT_STATS_LE32("channel_load", general->channel_load);
  428. PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms);
  429. PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a);
  430. PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b);
  431. PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c);
  432. PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a);
  433. PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b);
  434. PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c);
  435. PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills);
  436. PRINT_STATS_LE32("mac_id", general->mac_id);
  437. PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu);
  438. pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
  439. "Statistics_Rx - HT");
  440. PRINT_STATS_LE32("plcp_err", ht->plcp_err);
  441. PRINT_STATS_LE32("overrun_err", ht->overrun_err);
  442. PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err);
  443. PRINT_STATS_LE32("crc32_good", ht->crc32_good);
  444. PRINT_STATS_LE32("crc32_err", ht->crc32_err);
  445. PRINT_STATS_LE32("mh_format_err", ht->mh_format_err);
  446. PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good);
  447. PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt);
  448. PRINT_STATS_LE32("agg_cnt", ht->agg_cnt);
  449. PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs);
  450. mutex_unlock(&mvm->mutex);
  451. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  452. kfree(buf);
  453. return ret;
  454. }
  455. #undef PRINT_STAT_LE32
  456. static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
  457. char __user *user_buf, size_t count,
  458. loff_t *ppos,
  459. struct iwl_mvm_frame_stats *stats)
  460. {
  461. char *buff, *pos, *endpos;
  462. int idx, i;
  463. int ret;
  464. static const size_t bufsz = 1024;
  465. buff = kmalloc(bufsz, GFP_KERNEL);
  466. if (!buff)
  467. return -ENOMEM;
  468. spin_lock_bh(&mvm->drv_stats_lock);
  469. pos = buff;
  470. endpos = pos + bufsz;
  471. pos += scnprintf(pos, endpos - pos,
  472. "Legacy/HT/VHT\t:\t%d/%d/%d\n",
  473. stats->legacy_frames,
  474. stats->ht_frames,
  475. stats->vht_frames);
  476. pos += scnprintf(pos, endpos - pos, "20/40/80\t:\t%d/%d/%d\n",
  477. stats->bw_20_frames,
  478. stats->bw_40_frames,
  479. stats->bw_80_frames);
  480. pos += scnprintf(pos, endpos - pos, "NGI/SGI\t\t:\t%d/%d\n",
  481. stats->ngi_frames,
  482. stats->sgi_frames);
  483. pos += scnprintf(pos, endpos - pos, "SISO/MIMO2\t:\t%d/%d\n",
  484. stats->siso_frames,
  485. stats->mimo2_frames);
  486. pos += scnprintf(pos, endpos - pos, "FAIL/SCSS\t:\t%d/%d\n",
  487. stats->fail_frames,
  488. stats->success_frames);
  489. pos += scnprintf(pos, endpos - pos, "MPDUs agg\t:\t%d\n",
  490. stats->agg_frames);
  491. pos += scnprintf(pos, endpos - pos, "A-MPDUs\t\t:\t%d\n",
  492. stats->ampdu_count);
  493. pos += scnprintf(pos, endpos - pos, "Avg MPDUs/A-MPDU:\t%d\n",
  494. stats->ampdu_count > 0 ?
  495. (stats->agg_frames / stats->ampdu_count) : 0);
  496. pos += scnprintf(pos, endpos - pos, "Last Rates\n");
  497. idx = stats->last_frame_idx - 1;
  498. for (i = 0; i < ARRAY_SIZE(stats->last_rates); i++) {
  499. idx = (idx + 1) % ARRAY_SIZE(stats->last_rates);
  500. if (stats->last_rates[idx] == 0)
  501. continue;
  502. pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
  503. (int)(ARRAY_SIZE(stats->last_rates) - i));
  504. pos += rs_pretty_print_rate(pos, stats->last_rates[idx]);
  505. }
  506. spin_unlock_bh(&mvm->drv_stats_lock);
  507. ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff);
  508. kfree(buff);
  509. return ret;
  510. }
  511. static ssize_t iwl_dbgfs_drv_rx_stats_read(struct file *file,
  512. char __user *user_buf, size_t count,
  513. loff_t *ppos)
  514. {
  515. struct iwl_mvm *mvm = file->private_data;
  516. return iwl_dbgfs_frame_stats_read(mvm, user_buf, count, ppos,
  517. &mvm->drv_rx_stats);
  518. }
  519. static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
  520. size_t count, loff_t *ppos)
  521. {
  522. int ret;
  523. mutex_lock(&mvm->mutex);
  524. /* allow one more restart that we're provoking here */
  525. if (mvm->restart_fw >= 0)
  526. mvm->restart_fw++;
  527. /* take the return value to make compiler happy - it will fail anyway */
  528. ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
  529. mutex_unlock(&mvm->mutex);
  530. return count;
  531. }
  532. static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
  533. size_t count, loff_t *ppos)
  534. {
  535. iwl_write_prph(mvm->trans, DEVICE_SET_NMI_REG, 1);
  536. return count;
  537. }
  538. static ssize_t
  539. iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
  540. char __user *user_buf,
  541. size_t count, loff_t *ppos)
  542. {
  543. struct iwl_mvm *mvm = file->private_data;
  544. int pos = 0;
  545. char buf[32];
  546. const size_t bufsz = sizeof(buf);
  547. /* print which antennas were set for the scan command by the user */
  548. pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: ");
  549. if (mvm->scan_rx_ant & ANT_A)
  550. pos += scnprintf(buf + pos, bufsz - pos, "A");
  551. if (mvm->scan_rx_ant & ANT_B)
  552. pos += scnprintf(buf + pos, bufsz - pos, "B");
  553. if (mvm->scan_rx_ant & ANT_C)
  554. pos += scnprintf(buf + pos, bufsz - pos, "C");
  555. pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
  556. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  557. }
  558. static ssize_t
  559. iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
  560. size_t count, loff_t *ppos)
  561. {
  562. u8 scan_rx_ant;
  563. if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
  564. return -EINVAL;
  565. if (scan_rx_ant > ANT_ABC)
  566. return -EINVAL;
  567. if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
  568. return -EINVAL;
  569. mvm->scan_rx_ant = scan_rx_ant;
  570. return count;
  571. }
  572. #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
  573. #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
  574. static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
  575. char __user *user_buf,
  576. size_t count, loff_t *ppos)
  577. {
  578. struct iwl_mvm *mvm = file->private_data;
  579. struct iwl_bcast_filter_cmd cmd;
  580. const struct iwl_fw_bcast_filter *filter;
  581. char *buf;
  582. int bufsz = 1024;
  583. int i, j, pos = 0;
  584. ssize_t ret;
  585. buf = kzalloc(bufsz, GFP_KERNEL);
  586. if (!buf)
  587. return -ENOMEM;
  588. mutex_lock(&mvm->mutex);
  589. if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
  590. ADD_TEXT("None\n");
  591. mutex_unlock(&mvm->mutex);
  592. goto out;
  593. }
  594. mutex_unlock(&mvm->mutex);
  595. for (i = 0; cmd.filters[i].attrs[0].mask; i++) {
  596. filter = &cmd.filters[i];
  597. ADD_TEXT("Filter [%d]:\n", i);
  598. ADD_TEXT("\tDiscard=%d\n", filter->discard);
  599. ADD_TEXT("\tFrame Type: %s\n",
  600. filter->frame_type ? "IPv4" : "Generic");
  601. for (j = 0; j < ARRAY_SIZE(filter->attrs); j++) {
  602. const struct iwl_fw_bcast_filter_attr *attr;
  603. attr = &filter->attrs[j];
  604. if (!attr->mask)
  605. break;
  606. ADD_TEXT("\tAttr [%d]: offset=%d (from %s), mask=0x%x, value=0x%x reserved=0x%x\n",
  607. j, attr->offset,
  608. attr->offset_type ? "IP End" :
  609. "Payload Start",
  610. be32_to_cpu(attr->mask),
  611. be32_to_cpu(attr->val),
  612. le16_to_cpu(attr->reserved1));
  613. }
  614. }
  615. out:
  616. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  617. kfree(buf);
  618. return ret;
  619. }
  620. static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
  621. size_t count, loff_t *ppos)
  622. {
  623. int pos, next_pos;
  624. struct iwl_fw_bcast_filter filter = {};
  625. struct iwl_bcast_filter_cmd cmd;
  626. u32 filter_id, attr_id, mask, value;
  627. int err = 0;
  628. if (sscanf(buf, "%d %hhi %hhi %n", &filter_id, &filter.discard,
  629. &filter.frame_type, &pos) != 3)
  630. return -EINVAL;
  631. if (filter_id >= ARRAY_SIZE(mvm->dbgfs_bcast_filtering.cmd.filters) ||
  632. filter.frame_type > BCAST_FILTER_FRAME_TYPE_IPV4)
  633. return -EINVAL;
  634. for (attr_id = 0; attr_id < ARRAY_SIZE(filter.attrs);
  635. attr_id++) {
  636. struct iwl_fw_bcast_filter_attr *attr =
  637. &filter.attrs[attr_id];
  638. if (pos >= count)
  639. break;
  640. if (sscanf(&buf[pos], "%hhi %hhi %i %i %n",
  641. &attr->offset, &attr->offset_type,
  642. &mask, &value, &next_pos) != 4)
  643. return -EINVAL;
  644. attr->mask = cpu_to_be32(mask);
  645. attr->val = cpu_to_be32(value);
  646. if (mask)
  647. filter.num_attrs++;
  648. pos += next_pos;
  649. }
  650. mutex_lock(&mvm->mutex);
  651. memcpy(&mvm->dbgfs_bcast_filtering.cmd.filters[filter_id],
  652. &filter, sizeof(filter));
  653. /* send updated bcast filtering configuration */
  654. if (mvm->dbgfs_bcast_filtering.override &&
  655. iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
  656. err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
  657. sizeof(cmd), &cmd);
  658. mutex_unlock(&mvm->mutex);
  659. return err ?: count;
  660. }
  661. static ssize_t iwl_dbgfs_bcast_filters_macs_read(struct file *file,
  662. char __user *user_buf,
  663. size_t count, loff_t *ppos)
  664. {
  665. struct iwl_mvm *mvm = file->private_data;
  666. struct iwl_bcast_filter_cmd cmd;
  667. char *buf;
  668. int bufsz = 1024;
  669. int i, pos = 0;
  670. ssize_t ret;
  671. buf = kzalloc(bufsz, GFP_KERNEL);
  672. if (!buf)
  673. return -ENOMEM;
  674. mutex_lock(&mvm->mutex);
  675. if (!iwl_mvm_bcast_filter_build_cmd(mvm, &cmd)) {
  676. ADD_TEXT("None\n");
  677. mutex_unlock(&mvm->mutex);
  678. goto out;
  679. }
  680. mutex_unlock(&mvm->mutex);
  681. for (i = 0; i < ARRAY_SIZE(cmd.macs); i++) {
  682. const struct iwl_fw_bcast_mac *mac = &cmd.macs[i];
  683. ADD_TEXT("Mac [%d]: discard=%d attached_filters=0x%x\n",
  684. i, mac->default_discard, mac->attached_filters);
  685. }
  686. out:
  687. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  688. kfree(buf);
  689. return ret;
  690. }
  691. static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
  692. char *buf, size_t count,
  693. loff_t *ppos)
  694. {
  695. struct iwl_bcast_filter_cmd cmd;
  696. struct iwl_fw_bcast_mac mac = {};
  697. u32 mac_id, attached_filters;
  698. int err = 0;
  699. if (!mvm->bcast_filters)
  700. return -ENOENT;
  701. if (sscanf(buf, "%d %hhi %i", &mac_id, &mac.default_discard,
  702. &attached_filters) != 3)
  703. return -EINVAL;
  704. if (mac_id >= ARRAY_SIZE(cmd.macs) ||
  705. mac.default_discard > 1 ||
  706. attached_filters >= BIT(ARRAY_SIZE(cmd.filters)))
  707. return -EINVAL;
  708. mac.attached_filters = cpu_to_le16(attached_filters);
  709. mutex_lock(&mvm->mutex);
  710. memcpy(&mvm->dbgfs_bcast_filtering.cmd.macs[mac_id],
  711. &mac, sizeof(mac));
  712. /* send updated bcast filtering configuration */
  713. if (mvm->dbgfs_bcast_filtering.override &&
  714. iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
  715. err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, CMD_SYNC,
  716. sizeof(cmd), &cmd);
  717. mutex_unlock(&mvm->mutex);
  718. return err ?: count;
  719. }
  720. #endif
  721. #ifdef CONFIG_PM_SLEEP
  722. static ssize_t iwl_dbgfs_d3_sram_write(struct iwl_mvm *mvm, char *buf,
  723. size_t count, loff_t *ppos)
  724. {
  725. int store;
  726. if (sscanf(buf, "%d", &store) != 1)
  727. return -EINVAL;
  728. mvm->store_d3_resume_sram = store;
  729. return count;
  730. }
  731. static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
  732. size_t count, loff_t *ppos)
  733. {
  734. struct iwl_mvm *mvm = file->private_data;
  735. const struct fw_img *img;
  736. int ofs, len, pos = 0;
  737. size_t bufsz, ret;
  738. char *buf;
  739. u8 *ptr = mvm->d3_resume_sram;
  740. img = &mvm->fw->img[IWL_UCODE_WOWLAN];
  741. len = img->sec[IWL_UCODE_SECTION_DATA].len;
  742. bufsz = len * 4 + 256;
  743. buf = kzalloc(bufsz, GFP_KERNEL);
  744. if (!buf)
  745. return -ENOMEM;
  746. pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n",
  747. mvm->store_d3_resume_sram ? "en" : "dis");
  748. if (ptr) {
  749. for (ofs = 0; ofs < len; ofs += 16) {
  750. pos += scnprintf(buf + pos, bufsz - pos,
  751. "0x%.4x ", ofs);
  752. hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
  753. bufsz - pos, false);
  754. pos += strlen(buf + pos);
  755. if (bufsz - pos > 0)
  756. buf[pos++] = '\n';
  757. }
  758. } else {
  759. pos += scnprintf(buf + pos, bufsz - pos,
  760. "(no data captured)\n");
  761. }
  762. ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  763. kfree(buf);
  764. return ret;
  765. }
  766. #endif
  767. #define PRINT_MVM_REF(ref) do { \
  768. if (test_bit(ref, mvm->ref_bitmap)) \
  769. pos += scnprintf(buf + pos, bufsz - pos, \
  770. "\t(0x%lx) %s\n", \
  771. BIT(ref), #ref); \
  772. } while (0)
  773. static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
  774. char __user *user_buf,
  775. size_t count, loff_t *ppos)
  776. {
  777. struct iwl_mvm *mvm = file->private_data;
  778. int pos = 0;
  779. char buf[256];
  780. const size_t bufsz = sizeof(buf);
  781. pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n",
  782. mvm->ref_bitmap[0]);
  783. PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
  784. PRINT_MVM_REF(IWL_MVM_REF_SCAN);
  785. PRINT_MVM_REF(IWL_MVM_REF_ROC);
  786. PRINT_MVM_REF(IWL_MVM_REF_P2P_CLIENT);
  787. PRINT_MVM_REF(IWL_MVM_REF_AP_IBSS);
  788. PRINT_MVM_REF(IWL_MVM_REF_USER);
  789. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  790. }
  791. static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
  792. size_t count, loff_t *ppos)
  793. {
  794. unsigned long value;
  795. int ret;
  796. bool taken;
  797. ret = kstrtoul(buf, 10, &value);
  798. if (ret < 0)
  799. return ret;
  800. mutex_lock(&mvm->mutex);
  801. taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap);
  802. if (value == 1 && !taken)
  803. iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
  804. else if (value == 0 && taken)
  805. iwl_mvm_unref(mvm, IWL_MVM_REF_USER);
  806. else
  807. ret = -EINVAL;
  808. mutex_unlock(&mvm->mutex);
  809. if (ret < 0)
  810. return ret;
  811. return count;
  812. }
  813. #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
  814. _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
  815. #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
  816. _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_mvm)
  817. #define MVM_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \
  818. if (!debugfs_create_file(alias, mode, parent, mvm, \
  819. &iwl_dbgfs_##name##_ops)) \
  820. goto err; \
  821. } while (0)
  822. #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
  823. MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
  824. static ssize_t
  825. iwl_dbgfs_prph_reg_read(struct file *file,
  826. char __user *user_buf,
  827. size_t count, loff_t *ppos)
  828. {
  829. struct iwl_mvm *mvm = file->private_data;
  830. int pos = 0;
  831. char buf[32];
  832. const size_t bufsz = sizeof(buf);
  833. if (!mvm->dbgfs_prph_reg_addr)
  834. return -EINVAL;
  835. pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
  836. mvm->dbgfs_prph_reg_addr,
  837. iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
  838. return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
  839. }
  840. static ssize_t
  841. iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
  842. size_t count, loff_t *ppos)
  843. {
  844. u8 args;
  845. u32 value;
  846. args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
  847. /* if we only want to set the reg address - nothing more to do */
  848. if (args == 1)
  849. goto out;
  850. /* otherwise, make sure we have both address and value */
  851. if (args != 2)
  852. return -EINVAL;
  853. iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
  854. out:
  855. return count;
  856. }
  857. MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
  858. /* Device wide debugfs entries */
  859. MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
  860. MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
  861. MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
  862. MVM_DEBUGFS_READ_FILE_OPS(stations);
  863. MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
  864. MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
  865. MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
  866. MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
  867. MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats);
  868. MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10);
  869. MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10);
  870. MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
  871. MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
  872. #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
  873. MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
  874. MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
  875. #endif
  876. #ifdef CONFIG_PM_SLEEP
  877. MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
  878. #endif
  879. int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
  880. {
  881. struct dentry *bcast_dir __maybe_unused;
  882. char buf[100];
  883. spin_lock_init(&mvm->drv_stats_lock);
  884. mvm->debugfs_dir = dbgfs_dir;
  885. MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
  886. MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
  887. MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
  888. MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
  889. MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
  890. MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
  891. if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)
  892. MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
  893. S_IRUSR | S_IWUSR);
  894. MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
  895. MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR);
  896. MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
  897. MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR);
  898. MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
  899. S_IWUSR | S_IRUSR);
  900. MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
  901. MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
  902. #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
  903. if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
  904. bcast_dir = debugfs_create_dir("bcast_filtering",
  905. mvm->debugfs_dir);
  906. if (!bcast_dir)
  907. goto err;
  908. if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR,
  909. bcast_dir,
  910. &mvm->dbgfs_bcast_filtering.override))
  911. goto err;
  912. MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters,
  913. bcast_dir, S_IWUSR | S_IRUSR);
  914. MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs,
  915. bcast_dir, S_IWUSR | S_IRUSR);
  916. }
  917. #endif
  918. #ifdef CONFIG_PM_SLEEP
  919. MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
  920. MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
  921. if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
  922. mvm->debugfs_dir, &mvm->d3_wake_sysassert))
  923. goto err;
  924. #endif
  925. if (!debugfs_create_blob("nvm_hw", S_IRUSR,
  926. mvm->debugfs_dir, &mvm->nvm_hw_blob))
  927. goto err;
  928. if (!debugfs_create_blob("nvm_sw", S_IRUSR,
  929. mvm->debugfs_dir, &mvm->nvm_sw_blob))
  930. goto err;
  931. if (!debugfs_create_blob("nvm_calib", S_IRUSR,
  932. mvm->debugfs_dir, &mvm->nvm_calib_blob))
  933. goto err;
  934. if (!debugfs_create_blob("nvm_prod", S_IRUSR,
  935. mvm->debugfs_dir, &mvm->nvm_prod_blob))
  936. goto err;
  937. /*
  938. * Create a symlink with mac80211. It will be removed when mac80211
  939. * exists (before the opmode exists which removes the target.)
  940. */
  941. snprintf(buf, 100, "../../%s/%s",
  942. dbgfs_dir->d_parent->d_parent->d_name.name,
  943. dbgfs_dir->d_parent->d_name.name);
  944. if (!debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf))
  945. goto err;
  946. return 0;
  947. err:
  948. IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
  949. return -ENOMEM;
  950. }