debug.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  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 u64 icnss_get_serial_id(struct icnss_priv *priv)
  277. {
  278. u32 msb = priv->serial_id.serial_id_msb;
  279. u32 lsb = priv->serial_id.serial_id_lsb;
  280. msb &= 0xFFFF;
  281. return (((u64)msb << 32) | lsb);
  282. }
  283. static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
  284. {
  285. enum icnss_driver_state i;
  286. int skip = 0;
  287. unsigned long state;
  288. seq_printf(s, "\nSerial Number: 0x%llx", icnss_get_serial_id(priv));
  289. seq_printf(s, "\nState: 0x%lx(", priv->state);
  290. for (i = 0, state = priv->state; state != 0; state >>= 1, i++) {
  291. if (!(state & 0x1))
  292. continue;
  293. if (skip++)
  294. seq_puts(s, " | ");
  295. switch (i) {
  296. case ICNSS_WLFW_CONNECTED:
  297. seq_puts(s, "FW CONN");
  298. continue;
  299. case ICNSS_POWER_ON:
  300. seq_puts(s, "POWER ON");
  301. continue;
  302. case ICNSS_FW_READY:
  303. seq_puts(s, "FW READY");
  304. continue;
  305. case ICNSS_DRIVER_PROBED:
  306. seq_puts(s, "DRIVER PROBED");
  307. continue;
  308. case ICNSS_FW_TEST_MODE:
  309. seq_puts(s, "FW TEST MODE");
  310. continue;
  311. case ICNSS_PM_SUSPEND:
  312. seq_puts(s, "PM SUSPEND");
  313. continue;
  314. case ICNSS_PM_SUSPEND_NOIRQ:
  315. seq_puts(s, "PM SUSPEND NOIRQ");
  316. continue;
  317. case ICNSS_SSR_REGISTERED:
  318. seq_puts(s, "SSR REGISTERED");
  319. continue;
  320. case ICNSS_PDR_REGISTERED:
  321. seq_puts(s, "PDR REGISTERED");
  322. continue;
  323. case ICNSS_PD_RESTART:
  324. seq_puts(s, "PD RESTART");
  325. continue;
  326. case ICNSS_WLFW_EXISTS:
  327. seq_puts(s, "WLAN FW EXISTS");
  328. continue;
  329. case ICNSS_SHUTDOWN_DONE:
  330. seq_puts(s, "SHUTDOWN DONE");
  331. continue;
  332. case ICNSS_HOST_TRIGGERED_PDR:
  333. seq_puts(s, "HOST TRIGGERED PDR");
  334. continue;
  335. case ICNSS_FW_DOWN:
  336. seq_puts(s, "FW DOWN");
  337. continue;
  338. case ICNSS_DRIVER_UNLOADING:
  339. seq_puts(s, "DRIVER UNLOADING");
  340. continue;
  341. case ICNSS_REJUVENATE:
  342. seq_puts(s, "FW REJUVENATE");
  343. continue;
  344. case ICNSS_MODE_ON:
  345. seq_puts(s, "MODE ON DONE");
  346. continue;
  347. case ICNSS_BLOCK_SHUTDOWN:
  348. seq_puts(s, "BLOCK SHUTDOWN");
  349. continue;
  350. case ICNSS_PDR:
  351. seq_puts(s, "PDR TRIGGERED");
  352. continue;
  353. case ICNSS_IMS_CONNECTED:
  354. seq_puts(s, "IMS_CONNECTED");
  355. continue;
  356. case ICNSS_DEL_SERVER:
  357. seq_puts(s, "DEL SERVER");
  358. continue;
  359. case ICNSS_COLD_BOOT_CAL:
  360. seq_puts(s, "COLD BOOT CALIBRATION");
  361. continue;
  362. case ICNSS_QMI_DMS_CONNECTED:
  363. seq_puts(s, "DMS_CONNECTED");
  364. continue;
  365. case ICNSS_SLATE_SSR_REGISTERED:
  366. seq_puts(s, "SLATE SSR REGISTERED");
  367. continue;
  368. case ICNSS_SLATE_UP:
  369. seq_puts(s, "ICNSS SLATE UP");
  370. continue;
  371. case ICNSS_SLATE_READY:
  372. seq_puts(s, "ICNSS SLATE READY");
  373. continue;
  374. case ICNSS_LOW_POWER:
  375. seq_puts(s, "ICNSS LOW POWER");
  376. }
  377. seq_printf(s, "UNKNOWN-%d", i);
  378. }
  379. seq_puts(s, ")\n");
  380. return 0;
  381. }
  382. #define ICNSS_STATS_DUMP(_s, _priv, _x) \
  383. seq_printf(_s, "%24s: %u\n", #_x, _priv->stats._x)
  384. static int icnss_stats_show(struct seq_file *s, void *data)
  385. {
  386. struct icnss_priv *priv = s->private;
  387. ICNSS_STATS_DUMP(s, priv, ind_register_req);
  388. ICNSS_STATS_DUMP(s, priv, ind_register_resp);
  389. ICNSS_STATS_DUMP(s, priv, ind_register_err);
  390. ICNSS_STATS_DUMP(s, priv, cap_req);
  391. ICNSS_STATS_DUMP(s, priv, cap_resp);
  392. ICNSS_STATS_DUMP(s, priv, cap_err);
  393. ICNSS_STATS_DUMP(s, priv, pin_connect_result);
  394. ICNSS_STATS_DUMP(s, priv, cfg_req);
  395. ICNSS_STATS_DUMP(s, priv, cfg_resp);
  396. ICNSS_STATS_DUMP(s, priv, cfg_req_err);
  397. ICNSS_STATS_DUMP(s, priv, mode_req);
  398. ICNSS_STATS_DUMP(s, priv, mode_resp);
  399. ICNSS_STATS_DUMP(s, priv, mode_req_err);
  400. ICNSS_STATS_DUMP(s, priv, ini_req);
  401. ICNSS_STATS_DUMP(s, priv, ini_resp);
  402. ICNSS_STATS_DUMP(s, priv, ini_req_err);
  403. ICNSS_STATS_DUMP(s, priv, recovery.pdr_fw_crash);
  404. ICNSS_STATS_DUMP(s, priv, recovery.pdr_host_error);
  405. ICNSS_STATS_DUMP(s, priv, recovery.root_pd_crash);
  406. ICNSS_STATS_DUMP(s, priv, recovery.root_pd_shutdown);
  407. seq_puts(s, "\n<------------------ PM stats ------------------->\n");
  408. ICNSS_STATS_DUMP(s, priv, pm_suspend);
  409. ICNSS_STATS_DUMP(s, priv, pm_suspend_err);
  410. ICNSS_STATS_DUMP(s, priv, pm_resume);
  411. ICNSS_STATS_DUMP(s, priv, pm_resume_err);
  412. ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq);
  413. ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq_err);
  414. ICNSS_STATS_DUMP(s, priv, pm_resume_noirq);
  415. ICNSS_STATS_DUMP(s, priv, pm_resume_noirq_err);
  416. ICNSS_STATS_DUMP(s, priv, pm_stay_awake);
  417. ICNSS_STATS_DUMP(s, priv, pm_relax);
  418. if (priv->device_id == ADRASTEA_DEVICE_ID) {
  419. seq_puts(s, "\n<------------------ MSA stats ------------------->\n");
  420. ICNSS_STATS_DUMP(s, priv, msa_info_req);
  421. ICNSS_STATS_DUMP(s, priv, msa_info_resp);
  422. ICNSS_STATS_DUMP(s, priv, msa_info_err);
  423. ICNSS_STATS_DUMP(s, priv, msa_ready_req);
  424. ICNSS_STATS_DUMP(s, priv, msa_ready_resp);
  425. ICNSS_STATS_DUMP(s, priv, msa_ready_err);
  426. ICNSS_STATS_DUMP(s, priv, msa_ready_ind);
  427. seq_puts(s, "\n<------------------ Rejuvenate stats ------------------->\n");
  428. ICNSS_STATS_DUMP(s, priv, rejuvenate_ind);
  429. ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
  430. ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
  431. ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
  432. icnss_stats_show_rejuvenate_info(s, priv);
  433. }
  434. icnss_stats_show_irqs(s, priv);
  435. icnss_stats_show_capability(s, priv);
  436. icnss_stats_show_events(s, priv);
  437. icnss_stats_show_state(s, priv);
  438. return 0;
  439. }
  440. static int icnss_stats_open(struct inode *inode, struct file *file)
  441. {
  442. return single_open(file, icnss_stats_show, inode->i_private);
  443. }
  444. static const struct file_operations icnss_stats_fops = {
  445. .read = seq_read,
  446. .write = icnss_stats_write,
  447. .release = single_release,
  448. .open = icnss_stats_open,
  449. .owner = THIS_MODULE,
  450. .llseek = seq_lseek,
  451. };
  452. static int icnss_fw_debug_show(struct seq_file *s, void *data)
  453. {
  454. struct icnss_priv *priv = s->private;
  455. seq_puts(s, "\nUsage: echo <CMD> <VAL> > <DEBUGFS>/icnss/fw_debug\n");
  456. seq_puts(s, "\nCMD: test_mode\n");
  457. seq_puts(s, " VAL: 0 (Test mode disable)\n");
  458. seq_puts(s, " VAL: 1 (WLAN FW test)\n");
  459. seq_puts(s, " VAL: 2 (CCPM test)\n");
  460. seq_puts(s, " VAL: 3 (Trigger Recovery)\n");
  461. seq_puts(s, " VAL: 4 (allow recursive recovery)\n");
  462. seq_puts(s, " VAL: 5 (Disallow recursive recovery)\n");
  463. seq_puts(s, " VAL: 6 (Trigger power supply callback)\n");
  464. seq_puts(s, "\nCMD: dynamic_feature_mask\n");
  465. seq_puts(s, " VAL: (64 bit feature mask)\n");
  466. if (!test_bit(ICNSS_FW_READY, &priv->state)) {
  467. seq_puts(s, "Firmware is not ready yet, can't run test_mode!\n");
  468. goto out;
  469. }
  470. if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
  471. seq_puts(s, "Machine mode is running, can't run test_mode!\n");
  472. goto out;
  473. }
  474. if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
  475. seq_puts(s, "test_mode is running, can't run test_mode!\n");
  476. goto out;
  477. }
  478. out:
  479. seq_puts(s, "\n");
  480. return 0;
  481. }
  482. static int icnss_test_mode_fw_test_off(struct icnss_priv *priv)
  483. {
  484. int ret;
  485. if (!test_bit(ICNSS_FW_READY, &priv->state)) {
  486. icnss_pr_err("Firmware is not ready yet!, wait for FW READY: state: 0x%lx\n",
  487. priv->state);
  488. ret = -ENODEV;
  489. goto out;
  490. }
  491. if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
  492. icnss_pr_err("Machine mode is running, can't run test mode: state: 0x%lx\n",
  493. priv->state);
  494. ret = -EINVAL;
  495. goto out;
  496. }
  497. if (!test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
  498. icnss_pr_err("Test mode not started, state: 0x%lx\n",
  499. priv->state);
  500. ret = -EINVAL;
  501. goto out;
  502. }
  503. icnss_wlan_disable(&priv->pdev->dev, ICNSS_OFF);
  504. ret = icnss_hw_power_off(priv);
  505. clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
  506. out:
  507. return ret;
  508. }
  509. static int icnss_test_mode_fw_test(struct icnss_priv *priv,
  510. enum icnss_driver_mode mode)
  511. {
  512. int ret;
  513. if (!test_bit(ICNSS_FW_READY, &priv->state)) {
  514. icnss_pr_err("Firmware is not ready yet!, wait for FW READY, state: 0x%lx\n",
  515. priv->state);
  516. ret = -ENODEV;
  517. goto out;
  518. }
  519. if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) {
  520. icnss_pr_err("Machine mode is running, can't run test mode, state: 0x%lx\n",
  521. priv->state);
  522. ret = -EINVAL;
  523. goto out;
  524. }
  525. if (test_bit(ICNSS_FW_TEST_MODE, &priv->state)) {
  526. icnss_pr_err("Test mode already started, state: 0x%lx\n",
  527. priv->state);
  528. ret = -EBUSY;
  529. goto out;
  530. }
  531. ret = icnss_hw_power_on(priv);
  532. if (ret)
  533. goto out;
  534. set_bit(ICNSS_FW_TEST_MODE, &priv->state);
  535. ret = icnss_wlan_enable(&priv->pdev->dev, NULL, mode, NULL);
  536. if (ret)
  537. goto power_off;
  538. return 0;
  539. power_off:
  540. icnss_hw_power_off(priv);
  541. clear_bit(ICNSS_FW_TEST_MODE, &priv->state);
  542. out:
  543. return ret;
  544. }
  545. static ssize_t icnss_fw_debug_write(struct file *fp,
  546. const char __user *user_buf,
  547. size_t count, loff_t *off)
  548. {
  549. struct icnss_priv *priv =
  550. ((struct seq_file *)fp->private_data)->private;
  551. char buf[64];
  552. char *sptr, *token;
  553. unsigned int len = 0;
  554. char *cmd;
  555. uint64_t val;
  556. const char *delim = " ";
  557. int ret = 0;
  558. len = min(count, sizeof(buf) - 1);
  559. if (copy_from_user(buf, user_buf, len))
  560. return -EINVAL;
  561. buf[len] = '\0';
  562. sptr = buf;
  563. token = strsep(&sptr, delim);
  564. if (!token)
  565. return -EINVAL;
  566. if (!sptr)
  567. return -EINVAL;
  568. cmd = token;
  569. token = strsep(&sptr, delim);
  570. if (!token)
  571. return -EINVAL;
  572. if (kstrtou64(token, 0, &val))
  573. return -EINVAL;
  574. if (strcmp(cmd, "test_mode") == 0) {
  575. switch (val) {
  576. case 0:
  577. ret = icnss_test_mode_fw_test_off(priv);
  578. break;
  579. case 1:
  580. ret = icnss_test_mode_fw_test(priv, ICNSS_WALTEST);
  581. break;
  582. case 2:
  583. ret = icnss_test_mode_fw_test(priv, ICNSS_CCPM);
  584. break;
  585. case 3:
  586. ret = icnss_trigger_recovery(&priv->pdev->dev);
  587. break;
  588. case 4:
  589. icnss_allow_recursive_recovery(&priv->pdev->dev);
  590. break;
  591. case 5:
  592. icnss_disallow_recursive_recovery(&priv->pdev->dev);
  593. break;
  594. case 6:
  595. power_supply_changed(priv->batt_psy);
  596. break;
  597. default:
  598. return -EINVAL;
  599. }
  600. } else if (strcmp(cmd, "dynamic_feature_mask") == 0) {
  601. ret = wlfw_dynamic_feature_mask_send_sync_msg(priv, val);
  602. } else {
  603. return -EINVAL;
  604. }
  605. if (ret)
  606. return ret;
  607. return count;
  608. }
  609. static int icnss_fw_debug_open(struct inode *inode, struct file *file)
  610. {
  611. return single_open(file, icnss_fw_debug_show, inode->i_private);
  612. }
  613. static const struct file_operations icnss_fw_debug_fops = {
  614. .read = seq_read,
  615. .write = icnss_fw_debug_write,
  616. .release = single_release,
  617. .open = icnss_fw_debug_open,
  618. .owner = THIS_MODULE,
  619. .llseek = seq_lseek,
  620. };
  621. static ssize_t icnss_control_params_debug_write(struct file *fp,
  622. const char __user *user_buf,
  623. size_t count, loff_t *off)
  624. {
  625. struct icnss_priv *priv =
  626. ((struct seq_file *)fp->private_data)->private;
  627. char buf[64];
  628. char *sptr, *token;
  629. char *cmd;
  630. u32 val;
  631. unsigned int len = 0;
  632. const char *delim = " ";
  633. if (!priv)
  634. return -ENODEV;
  635. len = min(count, sizeof(buf) - 1);
  636. if (copy_from_user(buf, user_buf, len))
  637. return -EINVAL;
  638. buf[len] = '\0';
  639. sptr = buf;
  640. token = strsep(&sptr, delim);
  641. if (!token)
  642. return -EINVAL;
  643. if (!sptr)
  644. return -EINVAL;
  645. cmd = token;
  646. token = strsep(&sptr, delim);
  647. if (!token)
  648. return -EINVAL;
  649. if (kstrtou32(token, 0, &val))
  650. return -EINVAL;
  651. if (strcmp(cmd, "qmi_timeout") == 0)
  652. priv->ctrl_params.qmi_timeout = msecs_to_jiffies(val);
  653. else
  654. return -EINVAL;
  655. return count;
  656. }
  657. static int icnss_control_params_debug_show(struct seq_file *s, void *data)
  658. {
  659. struct icnss_priv *priv = s->private;
  660. seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs>/icnss/control_params\n");
  661. seq_puts(s, "<params_name> can be from below:\n");
  662. seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
  663. seq_puts(s, "\nCurrent value:\n");
  664. seq_printf(s, "qmi_timeout: %u\n", jiffies_to_msecs(priv->ctrl_params.qmi_timeout));
  665. return 0;
  666. }
  667. static int icnss_control_params_debug_open(struct inode *inode,
  668. struct file *file)
  669. {
  670. return single_open(file, icnss_control_params_debug_show,
  671. inode->i_private);
  672. }
  673. static const struct file_operations icnss_control_params_debug_fops = {
  674. .read = seq_read,
  675. .write = icnss_control_params_debug_write,
  676. .release = single_release,
  677. .open = icnss_control_params_debug_open,
  678. .owner = THIS_MODULE,
  679. .llseek = seq_lseek,
  680. };
  681. #ifdef CONFIG_ICNSS2_DEBUG
  682. int icnss_debugfs_create(struct icnss_priv *priv)
  683. {
  684. int ret = 0;
  685. struct dentry *root_dentry;
  686. root_dentry = debugfs_create_dir("icnss", NULL);
  687. if (IS_ERR(root_dentry)) {
  688. ret = PTR_ERR(root_dentry);
  689. icnss_pr_err("Unable to create debugfs %d\n", ret);
  690. goto out;
  691. }
  692. priv->root_dentry = root_dentry;
  693. debugfs_create_file("fw_debug", 0600, root_dentry, priv,
  694. &icnss_fw_debug_fops);
  695. debugfs_create_file("stats", 0600, root_dentry, priv,
  696. &icnss_stats_fops);
  697. debugfs_create_file("reg_read", 0600, root_dentry, priv,
  698. &icnss_regread_fops);
  699. debugfs_create_file("reg_write", 0600, root_dentry, priv,
  700. &icnss_regwrite_fops);
  701. debugfs_create_file("control_params", 0600, root_dentry, priv,
  702. &icnss_control_params_debug_fops);
  703. out:
  704. return ret;
  705. }
  706. #else
  707. int icnss_debugfs_create(struct icnss_priv *priv)
  708. {
  709. int ret = 0;
  710. struct dentry *root_dentry;
  711. root_dentry = debugfs_create_dir("icnss", NULL);
  712. if (IS_ERR(root_dentry)) {
  713. ret = PTR_ERR(root_dentry);
  714. icnss_pr_err("Unable to create debugfs %d\n", ret);
  715. return ret;
  716. }
  717. priv->root_dentry = root_dentry;
  718. debugfs_create_file("stats", 0600, root_dentry, priv,
  719. &icnss_stats_fops);
  720. return 0;
  721. }
  722. #endif
  723. void icnss_debugfs_destroy(struct icnss_priv *priv)
  724. {
  725. debugfs_remove_recursive(priv->root_dentry);
  726. }
  727. void icnss_debug_init(void)
  728. {
  729. icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
  730. "icnss", 0);
  731. if (!icnss_ipc_log_context)
  732. icnss_pr_err("Unable to create log context\n");
  733. icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
  734. "icnss_long", 0);
  735. if (!icnss_ipc_log_long_context)
  736. icnss_pr_err("Unable to create log long context\n");
  737. icnss_ipc_log_smp2p_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
  738. "icnss_smp2p", 0);
  739. if (!icnss_ipc_log_smp2p_context)
  740. icnss_pr_err("Unable to create log smp2p context\n");
  741. icnss_ipc_soc_wake_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
  742. "icnss_soc_wake", 0);
  743. if (!icnss_ipc_soc_wake_context)
  744. icnss_pr_err("Unable to create log soc_wake context\n");
  745. }
  746. void icnss_debug_deinit(void)
  747. {
  748. if (icnss_ipc_log_context) {
  749. ipc_log_context_destroy(icnss_ipc_log_context);
  750. icnss_ipc_log_context = NULL;
  751. }
  752. if (icnss_ipc_log_long_context) {
  753. ipc_log_context_destroy(icnss_ipc_log_long_context);
  754. icnss_ipc_log_long_context = NULL;
  755. }
  756. if (icnss_ipc_log_smp2p_context) {
  757. ipc_log_context_destroy(icnss_ipc_log_smp2p_context);
  758. icnss_ipc_log_smp2p_context = NULL;
  759. }
  760. if (icnss_ipc_soc_wake_context) {
  761. ipc_log_context_destroy(icnss_ipc_soc_wake_context);
  762. icnss_ipc_soc_wake_context = NULL;
  763. }
  764. }