debug.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/err.h>
  7. #include <linux/seq_file.h>
  8. #include <linux/debugfs.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/slab.h>
  11. #include "main.h"
  12. #include "debug.h"
  13. #include "qmi.h"
  14. #include "power.h"
  15. void *icnss_ipc_log_context;
  16. void *icnss_ipc_log_long_context;
  17. void *icnss_ipc_log_smp2p_context;
  18. void *icnss_ipc_soc_wake_context;
  19. static ssize_t icnss_regwrite_write(struct file *fp,
  20. const char __user *user_buf,
  21. size_t count, loff_t *off)
  22. {
  23. struct icnss_priv *priv =
  24. ((struct seq_file *)fp->private_data)->private;
  25. char buf[64];
  26. char *sptr, *token;
  27. unsigned int len = 0;
  28. uint32_t reg_offset, mem_type, reg_val;
  29. const char *delim = " ";
  30. int ret = 0;
  31. if (!test_bit(ICNSS_FW_READY, &priv->state) ||
  32. !test_bit(ICNSS_POWER_ON, &priv->state))
  33. return -EINVAL;
  34. len = min(count, sizeof(buf) - 1);
  35. if (copy_from_user(buf, user_buf, len))
  36. return -EFAULT;
  37. buf[len] = '\0';
  38. sptr = buf;
  39. token = strsep(&sptr, delim);
  40. if (!token)
  41. return -EINVAL;
  42. if (!sptr)
  43. return -EINVAL;
  44. if (kstrtou32(token, 0, &mem_type))
  45. return -EINVAL;
  46. token = strsep(&sptr, delim);
  47. if (!token)
  48. return -EINVAL;
  49. if (!sptr)
  50. return -EINVAL;
  51. if (kstrtou32(token, 0, &reg_offset))
  52. return -EINVAL;
  53. token = strsep(&sptr, delim);
  54. if (!token)
  55. return -EINVAL;
  56. if (kstrtou32(token, 0, &reg_val))
  57. return -EINVAL;
  58. ret = wlfw_athdiag_write_send_sync_msg(priv, reg_offset, mem_type,
  59. sizeof(uint32_t),
  60. (uint8_t *)&reg_val);
  61. if (ret)
  62. return ret;
  63. return count;
  64. }
  65. static int icnss_regwrite_show(struct seq_file *s, void *data)
  66. {
  67. struct icnss_priv *priv = s->private;
  68. seq_puts(s, "Usage: echo <mem_type> <offset> <reg_val> > <debugfs>/icnss/reg_write\n");
  69. if (!test_bit(ICNSS_FW_READY, &priv->state))
  70. seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
  71. return 0;
  72. }
  73. static int icnss_regwrite_open(struct inode *inode, struct file *file)
  74. {
  75. return single_open(file, icnss_regwrite_show, inode->i_private);
  76. }
  77. static const struct file_operations icnss_regwrite_fops = {
  78. .read = seq_read,
  79. .write = icnss_regwrite_write,
  80. .open = icnss_regwrite_open,
  81. .owner = THIS_MODULE,
  82. .llseek = seq_lseek,
  83. };
  84. static int icnss_regread_show(struct seq_file *s, void *data)
  85. {
  86. struct icnss_priv *priv = s->private;
  87. mutex_lock(&priv->dev_lock);
  88. if (!priv->diag_reg_read_buf) {
  89. seq_puts(s, "Usage: echo <mem_type> <offset> <data_len> > <debugfs>/icnss/reg_read\n");
  90. if (!test_bit(ICNSS_FW_READY, &priv->state))
  91. seq_puts(s, "Firmware is not ready yet!, wait for FW READY\n");
  92. mutex_unlock(&priv->dev_lock);
  93. return 0;
  94. }
  95. seq_printf(s, "REGREAD: Addr 0x%x Type 0x%x Length 0x%x\n",
  96. priv->diag_reg_read_addr, priv->diag_reg_read_mem_type,
  97. priv->diag_reg_read_len);
  98. seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4, priv->diag_reg_read_buf,
  99. priv->diag_reg_read_len, false);
  100. priv->diag_reg_read_len = 0;
  101. kfree(priv->diag_reg_read_buf);
  102. priv->diag_reg_read_buf = NULL;
  103. mutex_unlock(&priv->dev_lock);
  104. return 0;
  105. }
  106. static int icnss_regread_open(struct inode *inode, struct file *file)
  107. {
  108. return single_open(file, icnss_regread_show, inode->i_private);
  109. }
  110. static ssize_t icnss_reg_parse(const char __user *user_buf, size_t count,
  111. struct icnss_reg_info *reg_info_ptr)
  112. {
  113. char buf[64] = {0};
  114. char *sptr = NULL, *token = NULL;
  115. const char *delim = " ";
  116. unsigned int len = 0;
  117. if (user_buf == NULL)
  118. return -EFAULT;
  119. len = min(count, sizeof(buf) - 1);
  120. if (copy_from_user(buf, user_buf, len))
  121. return -EFAULT;
  122. buf[len] = '\0';
  123. sptr = buf;
  124. token = strsep(&sptr, delim);
  125. if (!token)
  126. return -EINVAL;
  127. if (!sptr)
  128. return -EINVAL;
  129. if (kstrtou32(token, 0, &reg_info_ptr->mem_type))
  130. return -EINVAL;
  131. token = strsep(&sptr, delim);
  132. if (!token)
  133. return -EINVAL;
  134. if (!sptr)
  135. return -EINVAL;
  136. if (kstrtou32(token, 0, &reg_info_ptr->reg_offset))
  137. return -EINVAL;
  138. token = strsep(&sptr, delim);
  139. if (!token)
  140. return -EINVAL;
  141. if (kstrtou32(token, 0, &reg_info_ptr->data_len))
  142. return -EINVAL;
  143. if (reg_info_ptr->data_len == 0 ||
  144. reg_info_ptr->data_len > WLFW_MAX_DATA_SIZE)
  145. return -EINVAL;
  146. return 0;
  147. }
  148. static ssize_t icnss_regread_write(struct file *fp, const char __user *user_buf,
  149. size_t count, loff_t *off)
  150. {
  151. struct icnss_priv *priv =
  152. ((struct seq_file *)fp->private_data)->private;
  153. uint8_t *reg_buf = NULL;
  154. int ret = 0;
  155. struct icnss_reg_info reg_info;
  156. if (!test_bit(ICNSS_FW_READY, &priv->state) ||
  157. !test_bit(ICNSS_POWER_ON, &priv->state))
  158. return -EINVAL;
  159. ret = icnss_reg_parse(user_buf, count, &reg_info);
  160. if (ret)
  161. return ret;
  162. mutex_lock(&priv->dev_lock);
  163. kfree(priv->diag_reg_read_buf);
  164. priv->diag_reg_read_buf = NULL;
  165. reg_buf = kzalloc(reg_info.data_len, GFP_KERNEL);
  166. if (!reg_buf) {
  167. mutex_unlock(&priv->dev_lock);
  168. return -ENOMEM;
  169. }
  170. ret = wlfw_athdiag_read_send_sync_msg(priv, reg_info.reg_offset,
  171. reg_info.mem_type,
  172. reg_info.data_len,
  173. reg_buf);
  174. if (ret) {
  175. kfree(reg_buf);
  176. mutex_unlock(&priv->dev_lock);
  177. return ret;
  178. }
  179. priv->diag_reg_read_addr = reg_info.reg_offset;
  180. priv->diag_reg_read_mem_type = reg_info.mem_type;
  181. priv->diag_reg_read_len = reg_info.data_len;
  182. priv->diag_reg_read_buf = reg_buf;
  183. mutex_unlock(&priv->dev_lock);
  184. return count;
  185. }
  186. static const struct file_operations icnss_regread_fops = {
  187. .read = seq_read,
  188. .write = icnss_regread_write,
  189. .open = icnss_regread_open,
  190. .owner = THIS_MODULE,
  191. .llseek = seq_lseek,
  192. };
  193. static ssize_t icnss_stats_write(struct file *fp, const char __user *buf,
  194. size_t count, loff_t *off)
  195. {
  196. struct icnss_priv *priv =
  197. ((struct seq_file *)fp->private_data)->private;
  198. int ret;
  199. u32 val;
  200. ret = kstrtou32_from_user(buf, count, 0, &val);
  201. if (ret)
  202. return ret;
  203. if (ret == 0)
  204. memset(&priv->stats, 0, sizeof(priv->stats));
  205. return count;
  206. }
  207. static int icnss_stats_show_rejuvenate_info(struct seq_file *s,
  208. struct icnss_priv *priv)
  209. {
  210. if (priv->stats.rejuvenate_ind) {
  211. seq_puts(s, "\n<---------------- Rejuvenate Info ----------------->\n");
  212. seq_printf(s, "Number of Rejuvenations: %u\n",
  213. priv->stats.rejuvenate_ind);
  214. seq_printf(s, "Cause for Rejuvenation: 0x%x\n",
  215. priv->cause_for_rejuvenation);
  216. seq_printf(s, "Requesting Sub-System: 0x%x\n",
  217. priv->requesting_sub_system);
  218. seq_printf(s, "Line Number: %u\n",
  219. priv->line_number);
  220. seq_printf(s, "Function Name: %s\n",
  221. priv->function_name);
  222. }
  223. return 0;
  224. }
  225. static int icnss_stats_show_irqs(struct seq_file *s, struct icnss_priv *priv)
  226. {
  227. int i;
  228. seq_puts(s, "\n<------------------ IRQ stats ------------------->\n");
  229. seq_printf(s, "%4s %4s %8s %8s %8s %8s\n", "CE_ID", "IRQ", "Request",
  230. "Free", "Enable", "Disable");
  231. for (i = 0; i < ICNSS_MAX_IRQ_REGISTRATIONS; i++)
  232. seq_printf(s, "%4d: %4u %8u %8u %8u %8u\n", i,
  233. priv->ce_irqs[i], priv->stats.ce_irqs[i].request,
  234. priv->stats.ce_irqs[i].free,
  235. priv->stats.ce_irqs[i].enable,
  236. priv->stats.ce_irqs[i].disable);
  237. return 0;
  238. }
  239. static int icnss_stats_show_capability(struct seq_file *s,
  240. struct icnss_priv *priv)
  241. {
  242. if (test_bit(ICNSS_FW_READY, &priv->state)) {
  243. seq_puts(s, "\n<---------------- FW Capability ----------------->\n");
  244. seq_printf(s, "Chip ID: 0x%x\n", priv->chip_info.chip_id);
  245. seq_printf(s, "Chip family: 0x%x\n",
  246. priv->chip_info.chip_family);
  247. seq_printf(s, "Board ID: 0x%x\n", priv->board_id);
  248. seq_printf(s, "SOC Info: 0x%x\n", priv->soc_id);
  249. seq_printf(s, "Firmware Version: 0x%x\n",
  250. priv->fw_version_info.fw_version);
  251. seq_printf(s, "Firmware Build Timestamp: %s\n",
  252. priv->fw_version_info.fw_build_timestamp);
  253. seq_printf(s, "Firmware Build ID: %s\n",
  254. priv->fw_build_id);
  255. seq_printf(s, "RD card chain cap: %d\n",
  256. priv->rd_card_chain_cap);
  257. seq_printf(s, "PHY HE channel width cap: %d\n",
  258. priv->phy_he_channel_width_cap);
  259. seq_printf(s, "PHY QAM cap: %d\n",
  260. priv->phy_qam_cap);
  261. }
  262. return 0;
  263. }
  264. static int icnss_stats_show_events(struct seq_file *s, struct icnss_priv *priv)
  265. {
  266. int i;
  267. seq_puts(s, "\n<----------------- Events stats ------------------->\n");
  268. seq_printf(s, "%24s %16s %16s\n", "Events", "Posted", "Processed");
  269. for (i = 0; i < ICNSS_DRIVER_EVENT_MAX; i++)
  270. seq_printf(s, "%24s %16u %16u\n",
  271. icnss_driver_event_to_str(i),
  272. priv->stats.events[i].posted,
  273. priv->stats.events[i].processed);
  274. return 0;
  275. }
  276. static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
  277. {
  278. enum icnss_driver_state i;
  279. int skip = 0;
  280. unsigned long state;
  281. seq_printf(s, "\nState: 0x%lx(", priv->state);
  282. for (i = 0, state = priv->state; state != 0; state >>= 1, i++) {
  283. if (!(state & 0x1))
  284. continue;
  285. if (skip++)
  286. seq_puts(s, " | ");
  287. switch (i) {
  288. case ICNSS_WLFW_CONNECTED:
  289. seq_puts(s, "FW CONN");
  290. continue;
  291. case ICNSS_POWER_ON:
  292. seq_puts(s, "POWER ON");
  293. continue;
  294. case ICNSS_FW_READY:
  295. seq_puts(s, "FW READY");
  296. continue;
  297. case ICNSS_DRIVER_PROBED:
  298. seq_puts(s, "DRIVER PROBED");
  299. continue;
  300. case ICNSS_FW_TEST_MODE:
  301. seq_puts(s, "FW TEST MODE");
  302. continue;
  303. case ICNSS_PM_SUSPEND:
  304. seq_puts(s, "PM SUSPEND");
  305. continue;
  306. case ICNSS_PM_SUSPEND_NOIRQ:
  307. seq_puts(s, "PM SUSPEND NOIRQ");
  308. continue;
  309. case ICNSS_SSR_REGISTERED:
  310. seq_puts(s, "SSR REGISTERED");
  311. continue;
  312. case ICNSS_PDR_REGISTERED:
  313. seq_puts(s, "PDR REGISTERED");
  314. continue;
  315. case ICNSS_PD_RESTART:
  316. seq_puts(s, "PD RESTART");
  317. continue;
  318. case ICNSS_WLFW_EXISTS:
  319. seq_puts(s, "WLAN FW EXISTS");
  320. continue;
  321. case ICNSS_SHUTDOWN_DONE:
  322. seq_puts(s, "SHUTDOWN DONE");
  323. continue;
  324. case ICNSS_HOST_TRIGGERED_PDR:
  325. seq_puts(s, "HOST TRIGGERED PDR");
  326. continue;
  327. case ICNSS_FW_DOWN:
  328. seq_puts(s, "FW DOWN");
  329. continue;
  330. case ICNSS_DRIVER_UNLOADING:
  331. seq_puts(s, "DRIVER UNLOADING");
  332. continue;
  333. case ICNSS_REJUVENATE:
  334. seq_puts(s, "FW REJUVENATE");
  335. continue;
  336. case ICNSS_MODE_ON:
  337. seq_puts(s, "MODE ON DONE");
  338. continue;
  339. case ICNSS_BLOCK_SHUTDOWN:
  340. seq_puts(s, "BLOCK SHUTDOWN");
  341. continue;
  342. case ICNSS_PDR:
  343. seq_puts(s, "PDR TRIGGERED");
  344. continue;
  345. case ICNSS_IMS_CONNECTED:
  346. seq_puts(s, "IMS_CONNECTED");
  347. continue;
  348. case ICNSS_DEL_SERVER:
  349. seq_puts(s, "DEL SERVER");
  350. continue;
  351. case ICNSS_COLD_BOOT_CAL:
  352. seq_puts(s, "COLD BOOT CALIBRATION");
  353. continue;
  354. case ICNSS_QMI_DMS_CONNECTED:
  355. seq_puts(s, "DMS_CONNECTED");
  356. continue;
  357. case ICNSS_SLATE_SSR_REGISTERED:
  358. seq_puts(s, "SLATE SSR REGISTERED");
  359. continue;
  360. case ICNSS_SLATE_UP:
  361. seq_puts(s, "ICNSS SLATE UP");
  362. continue;
  363. case ICNSS_SLATE_READY:
  364. seq_puts(s, "ICNSS SLATE READY");
  365. continue;
  366. case ICNSS_LOW_POWER:
  367. seq_puts(s, "ICNSS LOW POWER");
  368. }
  369. seq_printf(s, "UNKNOWN-%d", i);
  370. }
  371. seq_puts(s, ")\n");
  372. return 0;
  373. }
  374. #define ICNSS_STATS_DUMP(_s, _priv, _x) \
  375. seq_printf(_s, "%24s: %u\n", #_x, _priv->stats._x)
  376. static int icnss_stats_show(struct seq_file *s, void *data)
  377. {
  378. struct icnss_priv *priv = s->private;
  379. ICNSS_STATS_DUMP(s, priv, ind_register_req);
  380. ICNSS_STATS_DUMP(s, priv, ind_register_resp);
  381. ICNSS_STATS_DUMP(s, priv, ind_register_err);
  382. ICNSS_STATS_DUMP(s, priv, cap_req);
  383. ICNSS_STATS_DUMP(s, priv, cap_resp);
  384. ICNSS_STATS_DUMP(s, priv, cap_err);
  385. ICNSS_STATS_DUMP(s, priv, pin_connect_result);
  386. ICNSS_STATS_DUMP(s, priv, cfg_req);
  387. ICNSS_STATS_DUMP(s, priv, cfg_resp);
  388. ICNSS_STATS_DUMP(s, priv, cfg_req_err);
  389. ICNSS_STATS_DUMP(s, priv, mode_req);
  390. ICNSS_STATS_DUMP(s, priv, mode_resp);
  391. ICNSS_STATS_DUMP(s, priv, mode_req_err);
  392. ICNSS_STATS_DUMP(s, priv, ini_req);
  393. ICNSS_STATS_DUMP(s, priv, ini_resp);
  394. ICNSS_STATS_DUMP(s, priv, ini_req_err);
  395. ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash);
  396. ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error);
  397. ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash);
  398. ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown);
  399. seq_puts(s, "\n<------------------ PM stats ------------------->\n");
  400. ICNSS_STATS_DUMP(s, priv, pm_suspend);
  401. ICNSS_STATS_DUMP(s, priv, pm_suspend_err);
  402. ICNSS_STATS_DUMP(s, priv, pm_resume);
  403. ICNSS_STATS_DUMP(s, priv, pm_resume_err);
  404. ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq);
  405. ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq_err);
  406. ICNSS_STATS_DUMP(s, priv, pm_resume_noirq);
  407. ICNSS_STATS_DUMP(s, priv, pm_resume_noirq_err);
  408. ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
  409. ICNSS_STATS_DUMP(s, priv, pm_relax);
  410. if (priv->device_id == ADRASTEA_DEVICE_ID) {
  411. seq_puts(s, "\n<------------------ MSA stats ------------------->\n");
  412. ICNSS_STATS_DUMP(s, priv, msa_info_req);
  413. ICNSS_STATS_DUMP(s, priv, msa_info_resp);
  414. ICNSS_STATS_DUMP(s, priv, msa_info_err);
  415. ICNSS_STATS_DUMP(s, priv, msa_ready_req);
  416. ICNSS_STATS_DUMP(s, priv, msa_ready_resp);
  417. ICNSS_STATS_DUMP(s, priv, msa_ready_err);
  418. ICNSS_STATS_DUMP(s, priv, msa_ready_ind);
  419. seq_puts(s, "\n<------------------ Rejuvenate stats ------------------->\n");
  420. ICNSS_STATS_DUMP(s, priv, rejuvenate_ind);
  421. ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
  422. ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
  423. ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
  424. icnss_stats_show_rejuvenate_info(s, priv);
  425. }
  426. icnss_stats_show_irqs(s, priv);
  427. icnss_stats_show_capability(s, priv);
  428. icnss_stats_show_events(s, priv);
  429. icnss_stats_show_state(s, priv);
  430. return 0;
  431. }
  432. static int icnss_stats_open(struct inode *inode, struct file *file)
  433. {
  434. return single_open(file, icnss_stats_show, inode->i_private);
  435. }
  436. static const struct file_operations icnss_stats_fops = {
  437. .read = seq_read,
  438. .write = icnss_stats_write,
  439. .release = single_release,
  440. .open = icnss_stats_open,
  441. .owner = THIS_MODULE,
  442. .llseek = seq_lseek,
  443. };
  444. static int icnss_fw_debug_show(struct seq_file *s, void *data)
  445. {
  446. struct icnss_priv *priv = s->private;
  447. seq_puts(s, "\nUsage: echo <CMD> <VAL> > <DEBUGFS>/icnss/fw_debug\n");
  448. seq_puts(s, "\nCMD: test_mode\n");
  449. seq_puts(s, " VAL: 0 (Test mode disable)\n");
  450. seq_puts(s, " VAL: 1 (WLAN FW test)\n");
  451. seq_puts(s, " VAL: 2 (CCPM test)\n");
  452. seq_puts(s, " VAL: 3 (Trigger Recovery)\n");
  453. seq_puts(s, " VAL: 4 (allow recursive recovery)\n");
  454. seq_puts(s, " VAL: 5 (Disallow recursive recovery)\n");
  455. seq_puts(s, " VAL: 6 (Trigger power supply callback)\n");
  456. seq_puts(s, "\nCMD: dynamic_feature_mask\n");
  457. seq_puts(s, " VAL: (64 bit feature mask)\n");
  458. if (!test_bit(ICNSS_FW_READY, &priv->state)) {
  459. seq_puts(s, "Firmware is not ready yet, can't run test_mode!\n");
  460. goto out;
  461. }
  462. if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
  463. seq_puts(s, "Machine mode is running, can't run test_mode!\n");
  464. goto out;
  465. }
  466. if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
  467. seq_puts(s, "test_mode is running, can't run test_mode!\n");
  468. goto out;
  469. }
  470. out:
  471. seq_puts(s, "\n");
  472. return 0;
  473. }
  474. static int icnss_test_mode_fw_test_off(struct icnss_priv *priv)
  475. {
  476. int ret;
  477. if (!test_bit(ICNSS_FW_READY, &priv->state)) {
  478. icnss_pr_err("Firmware is not ready yet!, wait for FW READY: state: 0x%lx\n",
  479. priv->state);
  480. ret = -ENODEV;
  481. goto out;
  482. }
  483. if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
  484. icnss_pr_err("Machine mode is running, can't run test mode: state: 0x%lx\n",
  485. priv->state);
  486. ret = -EINVAL;
  487. goto out;
  488. }
  489. if (!test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
  490. icnss_pr_err("Test mode not started, state: 0x%lx\n",
  491. priv->state);
  492. ret = -EINVAL;
  493. goto out;
  494. }
  495. icnss_wlan_disable(&priv->pdev->dev, ICNSS_OFF);
  496. ret = icnss_hw_power_off(priv);
  497. clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
  498. out:
  499. return ret;
  500. }
  501. static int icnss_test_mode_fw_test(struct icnss_priv *priv,
  502. enum icnss_driver_mode mode)
  503. {
  504. int ret;
  505. if (!test_bit(ICNSS_FW_READY, &priv->state)) {
  506. icnss_pr_err("Firmware is not ready yet!, wait for FW READY, state: 0x%lx\n",
  507. priv->state);
  508. ret = -ENODEV;
  509. goto out;
  510. }
  511. if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
  512. icnss_pr_err("Machine mode is running, can't run test mode, state: 0x%lx\n",
  513. priv->state);
  514. ret = -EINVAL;
  515. goto out;
  516. }
  517. if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
  518. icnss_pr_err("Test mode already started, state: 0x%lx\n",
  519. priv->state);
  520. ret = -EBUSY;
  521. goto out;
  522. }
  523. ret = icnss_hw_power_on(priv);
  524. if (ret)
  525. goto out;
  526. set_bit(ICNSS_FW_TEST_MODE, &priv->state);
  527. ret = icnss_wlan_enable(&priv->pdev->dev, NULL, mode, NULL);
  528. if (ret)
  529. goto power_off;
  530. return 0;
  531. power_off:
  532. icnss_hw_power_off(priv);
  533. clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
  534. out:
  535. return ret;
  536. }
  537. static ssize_t icnss_fw_debug_write(struct file *fp,
  538. const char __user *user_buf,
  539. size_t count, loff_t *off)
  540. {
  541. struct icnss_priv *priv =
  542. ((struct seq_file *)fp->private_data)->private;
  543. char buf[64];
  544. char *sptr, *token;
  545. unsigned int len = 0;
  546. char *cmd;
  547. uint64_t val;
  548. const char *delim = " ";
  549. int ret = 0;
  550. len = min(count, sizeof(buf) - 1);
  551. if (copy_from_user(buf, user_buf, len))
  552. return -EINVAL;
  553. buf[len] = '\0';
  554. sptr = buf;
  555. token = strsep(&sptr, delim);
  556. if (!token)
  557. return -EINVAL;
  558. if (!sptr)
  559. return -EINVAL;
  560. cmd = token;
  561. token = strsep(&sptr, delim);
  562. if (!token)
  563. return -EINVAL;
  564. if (kstrtou64(token, 0, &val))
  565. return -EINVAL;
  566. if (strcmp(cmd, "test_mode") == 0) {
  567. switch (val) {
  568. case 0:
  569. ret = icnss_test_mode_fw_test_off(priv);
  570. break;
  571. case 1:
  572. ret = icnss_test_mode_fw_test(priv, ICNSS_WALTEST);
  573. break;
  574. case 2:
  575. ret = icnss_test_mode_fw_test(priv, ICNSS_CCPM);
  576. break;
  577. case 3:
  578. ret = icnss_trigger_recovery(&priv->pdev->dev);
  579. break;
  580. case 4:
  581. icnss_allow_recursive_recovery(&priv->pdev->dev);
  582. break;
  583. case 5:
  584. icnss_disallow_recursive_recovery(&priv->pdev->dev);
  585. break;
  586. case 6:
  587. power_supply_changed(priv->batt_psy);
  588. break;
  589. default:
  590. return -EINVAL;
  591. }
  592. } else if (strcmp(cmd, "dynamic_feature_mask") == 0) {
  593. ret = wlfw_dynamic_feature_mask_send_sync_msg(priv, val);
  594. } else {
  595. return -EINVAL;
  596. }
  597. if (ret)
  598. return ret;
  599. return count;
  600. }
  601. static int icnss_fw_debug_open(struct inode *inode, struct file *file)
  602. {
  603. return single_open(file, icnss_fw_debug_show, inode->i_private);
  604. }
  605. static const struct file_operations icnss_fw_debug_fops = {
  606. .read = seq_read,
  607. .write = icnss_fw_debug_write,
  608. .release = single_release,
  609. .open = icnss_fw_debug_open,
  610. .owner = THIS_MODULE,
  611. .llseek = seq_lseek,
  612. };
  613. static ssize_t icnss_control_params_debug_write(struct file *fp,
  614. const char __user *user_buf,
  615. size_t count, loff_t *off)
  616. {
  617. struct icnss_priv *priv =
  618. ((struct seq_file *)fp->private_data)->private;
  619. char buf[64];
  620. char *sptr, *token;
  621. char *cmd;
  622. u32 val;
  623. unsigned int len = 0;
  624. const char *delim = " ";
  625. if (!priv)
  626. return -ENODEV;
  627. len = min(count, sizeof(buf) - 1);
  628. if (copy_from_user(buf, user_buf, len))
  629. return -EINVAL;
  630. buf[len] = '\0';
  631. sptr = buf;
  632. token = strsep(&sptr, delim);
  633. if (!token)
  634. return -EINVAL;
  635. if (!sptr)
  636. return -EINVAL;
  637. cmd = token;
  638. token = strsep(&sptr, delim);
  639. if (!token)
  640. return -EINVAL;
  641. if (kstrtou32(token, 0, &val))
  642. return -EINVAL;
  643. if (strcmp(cmd, "qmi_timeout") == 0)
  644. priv->ctrl_params.qmi_timeout = msecs_to_jiffies(val);
  645. else
  646. return -EINVAL;
  647. return count;
  648. }
  649. static int icnss_control_params_debug_show(struct seq_file *s, void *data)
  650. {
  651. struct icnss_priv *priv = s->private;
  652. seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs>/icnss/control_params\n");
  653. seq_puts(s, "<params_name> can be from below:\n");
  654. seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
  655. seq_puts(s, "\nCurrent value:\n");
  656. seq_printf(s, "qmi_timeout: %u\n", jiffies_to_msecs(priv->ctrl_params.qmi_timeout));
  657. return 0;
  658. }
  659. static int icnss_control_params_debug_open(struct inode *inode,
  660. struct file *file)
  661. {
  662. return single_open(file, icnss_control_params_debug_show,
  663. inode->i_private);
  664. }
  665. static const struct file_operations icnss_control_params_debug_fops = {
  666. .read = seq_read,
  667. .write = icnss_control_params_debug_write,
  668. .release = single_release,
  669. .open = icnss_control_params_debug_open,
  670. .owner = THIS_MODULE,
  671. .llseek = seq_lseek,
  672. };
  673. #ifdef CONFIG_ICNSS2_DEBUG
  674. int icnss_debugfs_create(struct icnss_priv *priv)
  675. {
  676. int ret = 0;
  677. struct dentry *root_dentry;
  678. root_dentry = debugfs_create_dir("icnss", NULL);
  679. if (IS_ERR(root_dentry)) {
  680. ret = PTR_ERR(root_dentry);
  681. icnss_pr_err("Unable to create debugfs %d\n", ret);
  682. goto out;
  683. }
  684. priv->root_dentry = root_dentry;
  685. debugfs_create_file("fw_debug", 0600, root_dentry, priv,
  686. &icnss_fw_debug_fops);
  687. debugfs_create_file("stats", 0600, root_dentry, priv,
  688. &icnss_stats_fops);
  689. debugfs_create_file("reg_read", 0600, root_dentry, priv,
  690. &icnss_regread_fops);
  691. debugfs_create_file("reg_write", 0600, root_dentry, priv,
  692. &icnss_regwrite_fops);
  693. debugfs_create_file("control_params", 0600, root_dentry, priv,
  694. &icnss_control_params_debug_fops);
  695. out:
  696. return ret;
  697. }
  698. #else
  699. int icnss_debugfs_create(struct icnss_priv *priv)
  700. {
  701. int ret = 0;
  702. struct dentry *root_dentry;
  703. root_dentry = debugfs_create_dir("icnss", NULL);
  704. if (IS_ERR(root_dentry)) {
  705. ret = PTR_ERR(root_dentry);
  706. icnss_pr_err("Unable to create debugfs %d\n", ret);
  707. return ret;
  708. }
  709. priv->root_dentry = root_dentry;
  710. debugfs_create_file("stats", 0600, root_dentry, priv,
  711. &icnss_stats_fops);
  712. return 0;
  713. }
  714. #endif
  715. void icnss_debugfs_destroy(struct icnss_priv *priv)
  716. {
  717. debugfs_remove_recursive(priv->root_dentry);
  718. }
  719. void icnss_debug_init(void)
  720. {
  721. icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
  722. "icnss", 0);
  723. if (!icnss_ipc_log_context)
  724. icnss_pr_err("Unable to create log context\n");
  725. icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
  726. "icnss_long", 0);
  727. if (!icnss_ipc_log_long_context)
  728. icnss_pr_err("Unable to create log long context\n");
  729. icnss_ipc_log_smp2p_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
  730. "icnss_smp2p", 0);
  731. if (!icnss_ipc_log_smp2p_context)
  732. icnss_pr_err("Unable to create log smp2p context\n");
  733. icnss_ipc_soc_wake_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
  734. "icnss_soc_wake", 0);
  735. if (!icnss_ipc_soc_wake_context)
  736. icnss_pr_err("Unable to create log soc_wake context\n");
  737. }
  738. void icnss_debug_deinit(void)
  739. {
  740. if (icnss_ipc_log_context) {
  741. ipc_log_context_destroy(icnss_ipc_log_context);
  742. icnss_ipc_log_context = NULL;
  743. }
  744. if (icnss_ipc_log_long_context) {
  745. ipc_log_context_destroy(icnss_ipc_log_long_context);
  746. icnss_ipc_log_long_context = NULL;
  747. }
  748. if (icnss_ipc_log_smp2p_context) {
  749. ipc_log_context_destroy(icnss_ipc_log_smp2p_context);
  750. icnss_ipc_log_smp2p_context = NULL;
  751. }
  752. if (icnss_ipc_soc_wake_context) {
  753. ipc_log_context_destroy(icnss_ipc_soc_wake_context);
  754. icnss_ipc_soc_wake_context = NULL;
  755. }
  756. }