debug.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */
  3. /* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
  4. #include <linux/err.h>
  5. #include <linux/seq_file.h>
  6. #include <linux/debugfs.h>
  7. #include "main.h"
  8. #include "bus.h"
  9. #include "debug.h"
  10. #include "pci.h"
  11. #define MMIO_REG_ACCESS_MEM_TYPE 0xFF
  12. #define MMIO_REG_RAW_ACCESS_MEM_TYPE 0xFE
  13. #define DEFAULT_KERNEL_LOG_LEVEL INFO_LOG
  14. #define DEFAULT_IPC_LOG_LEVEL DEBUG_LOG
  15. enum log_level cnss_kernel_log_level = DEFAULT_KERNEL_LOG_LEVEL;
  16. #if IS_ENABLED(CONFIG_IPC_LOGGING)
  17. void *cnss_ipc_log_context;
  18. void *cnss_ipc_log_long_context;
  19. enum log_level cnss_ipc_log_level = DEFAULT_IPC_LOG_LEVEL;
  20. static int cnss_set_ipc_log_level(u32 val)
  21. {
  22. if (val < MAX_LOG) {
  23. cnss_ipc_log_level = val;
  24. return 0;
  25. }
  26. return -EINVAL;
  27. }
  28. static u32 cnss_get_ipc_log_level(void)
  29. {
  30. return cnss_ipc_log_level;
  31. }
  32. #else
  33. static int cnss_set_ipc_log_level(int val) { return -EINVAL; }
  34. static u32 cnss_get_ipc_log_level(void) { return MAX_LOG; }
  35. #endif
  36. static int cnss_pin_connect_show(struct seq_file *s, void *data)
  37. {
  38. struct cnss_plat_data *cnss_priv = s->private;
  39. seq_puts(s, "Pin connect results\n");
  40. seq_printf(s, "FW power pin result: %04x\n",
  41. cnss_priv->pin_result.fw_pwr_pin_result);
  42. seq_printf(s, "FW PHY IO pin result: %04x\n",
  43. cnss_priv->pin_result.fw_phy_io_pin_result);
  44. seq_printf(s, "FW RF pin result: %04x\n",
  45. cnss_priv->pin_result.fw_rf_pin_result);
  46. seq_printf(s, "Host pin result: %04x\n",
  47. cnss_priv->pin_result.host_pin_result);
  48. seq_puts(s, "\n");
  49. return 0;
  50. }
  51. static int cnss_pin_connect_open(struct inode *inode, struct file *file)
  52. {
  53. return single_open(file, cnss_pin_connect_show, inode->i_private);
  54. }
  55. static const struct file_operations cnss_pin_connect_fops = {
  56. .read = seq_read,
  57. .release = single_release,
  58. .open = cnss_pin_connect_open,
  59. .owner = THIS_MODULE,
  60. .llseek = seq_lseek,
  61. };
  62. static u64 cnss_get_serial_id(struct cnss_plat_data *plat_priv)
  63. {
  64. u32 msb = plat_priv->serial_id.serial_id_msb;
  65. u32 lsb = plat_priv->serial_id.serial_id_lsb;
  66. msb &= 0xFFFF;
  67. return (((u64)msb << 32) | lsb);
  68. }
  69. static int cnss_stats_show_state(struct seq_file *s,
  70. struct cnss_plat_data *plat_priv)
  71. {
  72. enum cnss_driver_state i;
  73. int skip = 0;
  74. unsigned long state;
  75. seq_printf(s, "\nSerial Number: 0x%llx",
  76. cnss_get_serial_id(plat_priv));
  77. seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
  78. for (i = 0, state = plat_priv->driver_state; state != 0;
  79. state >>= 1, i++) {
  80. if (!(state & 0x1))
  81. continue;
  82. if (skip++)
  83. seq_puts(s, " | ");
  84. switch (i) {
  85. case CNSS_QMI_WLFW_CONNECTED:
  86. seq_puts(s, "QMI_WLFW_CONNECTED");
  87. continue;
  88. case CNSS_FW_MEM_READY:
  89. seq_puts(s, "FW_MEM_READY");
  90. continue;
  91. case CNSS_FW_READY:
  92. seq_puts(s, "FW_READY");
  93. continue;
  94. case CNSS_IN_COLD_BOOT_CAL:
  95. seq_puts(s, "IN_COLD_BOOT_CAL");
  96. continue;
  97. case CNSS_DRIVER_LOADING:
  98. seq_puts(s, "DRIVER_LOADING");
  99. continue;
  100. case CNSS_DRIVER_UNLOADING:
  101. seq_puts(s, "DRIVER_UNLOADING");
  102. continue;
  103. case CNSS_DRIVER_IDLE_RESTART:
  104. seq_puts(s, "IDLE_RESTART");
  105. continue;
  106. case CNSS_DRIVER_IDLE_SHUTDOWN:
  107. seq_puts(s, "IDLE_SHUTDOWN");
  108. continue;
  109. case CNSS_DRIVER_PROBED:
  110. seq_puts(s, "DRIVER_PROBED");
  111. continue;
  112. case CNSS_DRIVER_RECOVERY:
  113. seq_puts(s, "DRIVER_RECOVERY");
  114. continue;
  115. case CNSS_FW_BOOT_RECOVERY:
  116. seq_puts(s, "FW_BOOT_RECOVERY");
  117. continue;
  118. case CNSS_DEV_ERR_NOTIFY:
  119. seq_puts(s, "DEV_ERR");
  120. continue;
  121. case CNSS_DRIVER_DEBUG:
  122. seq_puts(s, "DRIVER_DEBUG");
  123. continue;
  124. case CNSS_COEX_CONNECTED:
  125. seq_puts(s, "COEX_CONNECTED");
  126. continue;
  127. case CNSS_IMS_CONNECTED:
  128. seq_puts(s, "IMS_CONNECTED");
  129. continue;
  130. case CNSS_IN_SUSPEND_RESUME:
  131. seq_puts(s, "IN_SUSPEND_RESUME");
  132. continue;
  133. case CNSS_IN_REBOOT:
  134. seq_puts(s, "IN_REBOOT");
  135. continue;
  136. case CNSS_COLD_BOOT_CAL_DONE:
  137. seq_puts(s, "COLD_BOOT_CAL_DONE");
  138. continue;
  139. case CNSS_IN_PANIC:
  140. seq_puts(s, "IN_PANIC");
  141. continue;
  142. case CNSS_QMI_DEL_SERVER:
  143. seq_puts(s, "DEL_SERVER_IN_PROGRESS");
  144. continue;
  145. case CNSS_QMI_DMS_CONNECTED:
  146. seq_puts(s, "DMS_CONNECTED");
  147. continue;
  148. case CNSS_DMS_DEL_SERVER:
  149. seq_puts(s, "DMS_DEL_SERVER");
  150. continue;
  151. case CNSS_DAEMON_CONNECTED:
  152. seq_puts(s, "DAEMON_CONNECTED");
  153. continue;
  154. case CNSS_PCI_PROBE_DONE:
  155. seq_puts(s, "PCI PROBE DONE");
  156. continue;
  157. case CNSS_DRIVER_REGISTER:
  158. seq_puts(s, "DRIVER REGISTERED");
  159. continue;
  160. case CNSS_WLAN_HW_DISABLED:
  161. seq_puts(s, "WLAN HW DISABLED");
  162. continue;
  163. case CNSS_FS_READY:
  164. seq_puts(s, "FS READY");
  165. continue;
  166. case CNSS_DRIVER_REGISTERED:
  167. seq_puts(s, "DRIVER REGISTERED");
  168. continue;
  169. case CNSS_POWER_OFF:
  170. seq_puts(s, "POWER OFF");
  171. continue;
  172. }
  173. seq_printf(s, "UNKNOWN-%d", i);
  174. }
  175. seq_puts(s, ")\n");
  176. return 0;
  177. }
  178. static int cnss_stats_show_gpio_state(struct seq_file *s,
  179. struct cnss_plat_data *plat_priv)
  180. {
  181. seq_printf(s, "\nHost SOL: %d", cnss_get_host_sol_value(plat_priv));
  182. seq_printf(s, "\nDev SOL: %d", cnss_get_dev_sol_value(plat_priv));
  183. return 0;
  184. }
  185. static int cnss_stats_show(struct seq_file *s, void *data)
  186. {
  187. struct cnss_plat_data *plat_priv = s->private;
  188. cnss_stats_show_state(s, plat_priv);
  189. cnss_stats_show_gpio_state(s, plat_priv);
  190. return 0;
  191. }
  192. static int cnss_stats_open(struct inode *inode, struct file *file)
  193. {
  194. return single_open(file, cnss_stats_show, inode->i_private);
  195. }
  196. static const struct file_operations cnss_stats_fops = {
  197. .read = seq_read,
  198. .release = single_release,
  199. .open = cnss_stats_open,
  200. .owner = THIS_MODULE,
  201. .llseek = seq_lseek,
  202. };
  203. static ssize_t cnss_dev_boot_debug_write(struct file *fp,
  204. const char __user *user_buf,
  205. size_t count, loff_t *off)
  206. {
  207. struct cnss_plat_data *plat_priv =
  208. ((struct seq_file *)fp->private_data)->private;
  209. struct cnss_pci_data *pci_priv;
  210. char buf[64];
  211. char *cmd;
  212. unsigned int len = 0;
  213. char *sptr, *token;
  214. const char *delim = " ";
  215. int ret = 0;
  216. if (!plat_priv)
  217. return -ENODEV;
  218. len = min(count, sizeof(buf) - 1);
  219. if (copy_from_user(buf, user_buf, len))
  220. return -EFAULT;
  221. buf[len] = '\0';
  222. sptr = buf;
  223. token = strsep(&sptr, delim);
  224. if (!token)
  225. return -EINVAL;
  226. cmd = token;
  227. cnss_pr_dbg("Received dev_boot debug command: %s\n", cmd);
  228. if (sysfs_streq(cmd, "on")) {
  229. ret = cnss_power_on_device(plat_priv, false);
  230. } else if (sysfs_streq(cmd, "off")) {
  231. cnss_power_off_device(plat_priv);
  232. } else if (sysfs_streq(cmd, "enumerate")) {
  233. ret = cnss_pci_init(plat_priv);
  234. } else if (sysfs_streq(cmd, "powerup")) {
  235. set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
  236. ret = cnss_driver_event_post(plat_priv,
  237. CNSS_DRIVER_EVENT_POWER_UP,
  238. CNSS_EVENT_SYNC, NULL);
  239. } else if (sysfs_streq(cmd, "shutdown")) {
  240. ret = cnss_driver_event_post(plat_priv,
  241. CNSS_DRIVER_EVENT_POWER_DOWN,
  242. 0, NULL);
  243. clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
  244. } else if (sysfs_streq(cmd, "assert_host_sol")) {
  245. pci_priv = plat_priv->bus_priv;
  246. cnss_auto_resume(&pci_priv->pci_dev->dev);
  247. ret = cnss_set_host_sol_value(plat_priv, 1);
  248. } else if (sysfs_streq(cmd, "deassert_host_sol")) {
  249. ret = cnss_set_host_sol_value(plat_priv, 0);
  250. } else if (sysfs_streq(cmd, "pdc_update")) {
  251. if (!sptr)
  252. return -EINVAL;
  253. ret = cnss_aop_send_msg(plat_priv, sptr);
  254. } else if (sysfs_streq(cmd, "dev_check")) {
  255. cnss_wlan_hw_disable_check(plat_priv);
  256. } else if (sysfs_streq(cmd, "dev_enable")) {
  257. cnss_wlan_hw_enable();
  258. } else {
  259. pci_priv = plat_priv->bus_priv;
  260. if (!pci_priv)
  261. return -ENODEV;
  262. if (sysfs_streq(cmd, "download")) {
  263. set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
  264. ret = cnss_pci_start_mhi(pci_priv);
  265. } else if (sysfs_streq(cmd, "linkup")) {
  266. ret = cnss_resume_pci_link(pci_priv);
  267. } else if (sysfs_streq(cmd, "linkdown")) {
  268. ret = cnss_suspend_pci_link(pci_priv);
  269. } else if (sysfs_streq(cmd, "assert")) {
  270. cnss_pr_info("FW Assert triggered for debug\n");
  271. ret = cnss_force_fw_assert(&pci_priv->pci_dev->dev);
  272. } else if (sysfs_streq(cmd, "set_cbc_done")) {
  273. cnss_pr_dbg("Force set cold boot cal done status\n");
  274. set_bit(CNSS_COLD_BOOT_CAL_DONE,
  275. &plat_priv->driver_state);
  276. } else {
  277. cnss_pr_err("Device boot debugfs command is invalid\n");
  278. ret = -EINVAL;
  279. }
  280. }
  281. if (ret < 0)
  282. return ret;
  283. return count;
  284. }
  285. static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
  286. {
  287. seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
  288. seq_puts(s, "<action> can be one of below:\n");
  289. seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
  290. seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
  291. seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
  292. seq_puts(s, "download: download FW and do QMI handshake with FW\n");
  293. seq_puts(s, "linkup: bring up PCIe link\n");
  294. seq_puts(s, "linkdown: bring down PCIe link\n");
  295. seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
  296. seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
  297. seq_puts(s, "assert: trigger firmware assert\n");
  298. seq_puts(s, "set_cbc_done: Set cold boot calibration done status\n");
  299. seq_puts(s, "\npdc_update usage:");
  300. seq_puts(s, "1. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: <vreg>.<mode>, <seq>: <val>} > <debugfs_path>/cnss/dev_boot\n");
  301. seq_puts(s, "2. echo pdc_update {class: wlan_pdc ss: <pdc_ss>, res: pdc, enable: <val>} > <debugfs_path>/cnss/dev_boot\n");
  302. seq_puts(s, "assert_host_sol: Assert host sol\n");
  303. seq_puts(s, "deassert_host_sol: Deassert host sol\n");
  304. seq_puts(s, "dev_check: Check whether HW is disabled or not\n");
  305. seq_puts(s, "dev_enable: Enable HW\n");
  306. return 0;
  307. }
  308. static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
  309. {
  310. return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
  311. }
  312. static const struct file_operations cnss_dev_boot_debug_fops = {
  313. .read = seq_read,
  314. .write = cnss_dev_boot_debug_write,
  315. .release = single_release,
  316. .open = cnss_dev_boot_debug_open,
  317. .owner = THIS_MODULE,
  318. .llseek = seq_lseek,
  319. };
  320. static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
  321. {
  322. struct cnss_plat_data *plat_priv = s->private;
  323. mutex_lock(&plat_priv->dev_lock);
  324. if (!plat_priv->diag_reg_read_buf) {
  325. seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
  326. seq_puts(s, "Use mem_type = 0xff for register read by IO access, data_len will be ignored\n");
  327. seq_puts(s, "Use mem_type = 0xfe for register read by raw IO access which skips sanity checks, data_len will be ignored\n");
  328. seq_puts(s, "Use other mem_type for register read by QMI\n");
  329. mutex_unlock(&plat_priv->dev_lock);
  330. return 0;
  331. }
  332. seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
  333. plat_priv->diag_reg_read_addr,
  334. plat_priv->diag_reg_read_mem_type,
  335. plat_priv->diag_reg_read_len);
  336. seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
  337. plat_priv->diag_reg_read_buf,
  338. plat_priv->diag_reg_read_len, false);
  339. plat_priv->diag_reg_read_len = 0;
  340. kfree(plat_priv->diag_reg_read_buf);
  341. plat_priv->diag_reg_read_buf = NULL;
  342. mutex_unlock(&plat_priv->dev_lock);
  343. return 0;
  344. }
  345. static ssize_t cnss_reg_read_debug_write(struct file *fp,
  346. const char __user *user_buf,
  347. size_t count, loff_t *off)
  348. {
  349. struct cnss_plat_data *plat_priv =
  350. ((struct seq_file *)fp->private_data)->private;
  351. char buf[64];
  352. char *sptr, *token;
  353. unsigned int len = 0;
  354. u32 reg_offset, mem_type;
  355. u32 data_len = 0, reg_val = 0;
  356. u8 *reg_buf = NULL;
  357. const char *delim = " ";
  358. int ret = 0;
  359. len = min(count, sizeof(buf) - 1);
  360. if (copy_from_user(buf, user_buf, len))
  361. return -EFAULT;
  362. buf[len] = '\0';
  363. sptr = buf;
  364. token = strsep(&sptr, delim);
  365. if (!token)
  366. return -EINVAL;
  367. if (!sptr)
  368. return -EINVAL;
  369. if (kstrtou32(token, 0, &mem_type))
  370. return -EINVAL;
  371. token = strsep(&sptr, delim);
  372. if (!token)
  373. return -EINVAL;
  374. if (!sptr)
  375. return -EINVAL;
  376. if (kstrtou32(token, 0, &reg_offset))
  377. return -EINVAL;
  378. token = strsep(&sptr, delim);
  379. if (!token)
  380. return -EINVAL;
  381. if (kstrtou32(token, 0, &data_len))
  382. return -EINVAL;
  383. if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
  384. mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
  385. ret = cnss_bus_debug_reg_read(plat_priv, reg_offset, &reg_val,
  386. mem_type ==
  387. MMIO_REG_RAW_ACCESS_MEM_TYPE);
  388. if (ret)
  389. return ret;
  390. cnss_pr_dbg("Read 0x%x from register offset 0x%x\n", reg_val,
  391. reg_offset);
  392. return count;
  393. }
  394. if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
  395. cnss_pr_err("Firmware is not ready yet\n");
  396. return -EINVAL;
  397. }
  398. mutex_lock(&plat_priv->dev_lock);
  399. kfree(plat_priv->diag_reg_read_buf);
  400. plat_priv->diag_reg_read_buf = NULL;
  401. reg_buf = kzalloc(data_len, GFP_KERNEL);
  402. if (!reg_buf) {
  403. mutex_unlock(&plat_priv->dev_lock);
  404. return -ENOMEM;
  405. }
  406. ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
  407. mem_type, data_len,
  408. reg_buf);
  409. if (ret) {
  410. kfree(reg_buf);
  411. mutex_unlock(&plat_priv->dev_lock);
  412. return ret;
  413. }
  414. plat_priv->diag_reg_read_addr = reg_offset;
  415. plat_priv->diag_reg_read_mem_type = mem_type;
  416. plat_priv->diag_reg_read_len = data_len;
  417. plat_priv->diag_reg_read_buf = reg_buf;
  418. mutex_unlock(&plat_priv->dev_lock);
  419. return count;
  420. }
  421. static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
  422. {
  423. return single_open(file, cnss_reg_read_debug_show, inode->i_private);
  424. }
  425. static const struct file_operations cnss_reg_read_debug_fops = {
  426. .read = seq_read,
  427. .write = cnss_reg_read_debug_write,
  428. .open = cnss_reg_read_debug_open,
  429. .owner = THIS_MODULE,
  430. .llseek = seq_lseek,
  431. };
  432. static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
  433. {
  434. seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
  435. seq_puts(s, "Use mem_type = 0xff for register write by IO access\n");
  436. seq_puts(s, "Use mem_type = 0xfe for register write by raw IO access which skips sanity checks\n");
  437. seq_puts(s, "Use other mem_type for register write by QMI\n");
  438. return 0;
  439. }
  440. static ssize_t cnss_reg_write_debug_write(struct file *fp,
  441. const char __user *user_buf,
  442. size_t count, loff_t *off)
  443. {
  444. struct cnss_plat_data *plat_priv =
  445. ((struct seq_file *)fp->private_data)->private;
  446. char buf[64];
  447. char *sptr, *token;
  448. unsigned int len = 0;
  449. u32 reg_offset, mem_type, reg_val;
  450. const char *delim = " ";
  451. int ret = 0;
  452. len = min(count, sizeof(buf) - 1);
  453. if (copy_from_user(buf, user_buf, len))
  454. return -EFAULT;
  455. buf[len] = '\0';
  456. sptr = buf;
  457. token = strsep(&sptr, delim);
  458. if (!token)
  459. return -EINVAL;
  460. if (!sptr)
  461. return -EINVAL;
  462. if (kstrtou32(token, 0, &mem_type))
  463. return -EINVAL;
  464. token = strsep(&sptr, delim);
  465. if (!token)
  466. return -EINVAL;
  467. if (!sptr)
  468. return -EINVAL;
  469. if (kstrtou32(token, 0, &reg_offset))
  470. return -EINVAL;
  471. token = strsep(&sptr, delim);
  472. if (!token)
  473. return -EINVAL;
  474. if (kstrtou32(token, 0, &reg_val))
  475. return -EINVAL;
  476. if (mem_type == MMIO_REG_ACCESS_MEM_TYPE ||
  477. mem_type == MMIO_REG_RAW_ACCESS_MEM_TYPE) {
  478. ret = cnss_bus_debug_reg_write(plat_priv, reg_offset, reg_val,
  479. mem_type ==
  480. MMIO_REG_RAW_ACCESS_MEM_TYPE);
  481. if (ret)
  482. return ret;
  483. cnss_pr_dbg("Wrote 0x%x to register offset 0x%x\n", reg_val,
  484. reg_offset);
  485. return count;
  486. }
  487. if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
  488. cnss_pr_err("Firmware is not ready yet\n");
  489. return -EINVAL;
  490. }
  491. ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
  492. sizeof(u32),
  493. (u8 *)&reg_val);
  494. if (ret)
  495. return ret;
  496. return count;
  497. }
  498. static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
  499. {
  500. return single_open(file, cnss_reg_write_debug_show, inode->i_private);
  501. }
  502. static const struct file_operations cnss_reg_write_debug_fops = {
  503. .read = seq_read,
  504. .write = cnss_reg_write_debug_write,
  505. .open = cnss_reg_write_debug_open,
  506. .owner = THIS_MODULE,
  507. .llseek = seq_lseek,
  508. };
  509. static ssize_t cnss_runtime_pm_debug_write(struct file *fp,
  510. const char __user *user_buf,
  511. size_t count, loff_t *off)
  512. {
  513. struct cnss_plat_data *plat_priv =
  514. ((struct seq_file *)fp->private_data)->private;
  515. struct cnss_pci_data *pci_priv;
  516. char buf[64];
  517. char *cmd;
  518. unsigned int len = 0;
  519. int ret = 0;
  520. if (!plat_priv)
  521. return -ENODEV;
  522. pci_priv = plat_priv->bus_priv;
  523. if (!pci_priv)
  524. return -ENODEV;
  525. len = min(count, sizeof(buf) - 1);
  526. if (copy_from_user(buf, user_buf, len))
  527. return -EFAULT;
  528. buf[len] = '\0';
  529. cmd = buf;
  530. cnss_pr_dbg("Received runtime_pm debug command: %s\n", cmd);
  531. if (sysfs_streq(cmd, "usage_count")) {
  532. cnss_pci_pm_runtime_show_usage_count(pci_priv);
  533. } else if (sysfs_streq(cmd, "request_resume")) {
  534. ret = cnss_pci_pm_request_resume(pci_priv);
  535. } else if (sysfs_streq(cmd, "resume")) {
  536. ret = cnss_pci_pm_runtime_resume(pci_priv);
  537. } else if (sysfs_streq(cmd, "get")) {
  538. ret = cnss_pci_pm_runtime_get(pci_priv, RTPM_ID_CNSS);
  539. } else if (sysfs_streq(cmd, "get_noresume")) {
  540. cnss_pci_pm_runtime_get_noresume(pci_priv, RTPM_ID_CNSS);
  541. } else if (sysfs_streq(cmd, "put_autosuspend")) {
  542. ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv,
  543. RTPM_ID_CNSS);
  544. } else if (sysfs_streq(cmd, "put_noidle")) {
  545. cnss_pci_pm_runtime_put_noidle(pci_priv, RTPM_ID_CNSS);
  546. } else if (sysfs_streq(cmd, "mark_last_busy")) {
  547. cnss_pci_pm_runtime_mark_last_busy(pci_priv);
  548. } else if (sysfs_streq(cmd, "resume_bus")) {
  549. cnss_pci_resume_bus(pci_priv);
  550. } else if (sysfs_streq(cmd, "suspend_bus")) {
  551. cnss_pci_suspend_bus(pci_priv);
  552. } else {
  553. cnss_pr_err("Runtime PM debugfs command is invalid\n");
  554. ret = -EINVAL;
  555. }
  556. if (ret < 0)
  557. return ret;
  558. return count;
  559. }
  560. static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data)
  561. {
  562. struct cnss_plat_data *plat_priv = s->private;
  563. struct cnss_pci_data *pci_priv;
  564. int i;
  565. if (!plat_priv)
  566. return -ENODEV;
  567. pci_priv = plat_priv->bus_priv;
  568. if (!pci_priv)
  569. return -ENODEV;
  570. seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/runtime_pm\n");
  571. seq_puts(s, "<action> can be one of below:\n");
  572. seq_puts(s, "usage_count: get runtime PM usage count\n");
  573. seq_puts(s, "reques_resume: do async runtime PM resume\n");
  574. seq_puts(s, "resume: do sync runtime PM resume\n");
  575. seq_puts(s, "get: do runtime PM get\n");
  576. seq_puts(s, "get_noresume: do runtime PM get noresume\n");
  577. seq_puts(s, "put_noidle: do runtime PM put noidle\n");
  578. seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n");
  579. seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n");
  580. seq_puts(s, "resume_bus: do bus resume only\n");
  581. seq_puts(s, "suspend_bus: do bus suspend only\n");
  582. seq_puts(s, "\nStats:\n");
  583. seq_printf(s, "%s: %u\n", "get count",
  584. atomic_read(&pci_priv->pm_stats.runtime_get));
  585. seq_printf(s, "%s: %u\n", "put count",
  586. atomic_read(&pci_priv->pm_stats.runtime_put));
  587. seq_printf(s, "%-10s%-10s%-10s%-15s%-15s\n",
  588. "id:", "get", "put", "get time(us)", "put time(us)");
  589. for (i = 0; i < RTPM_ID_MAX; i++) {
  590. seq_printf(s, "%d%-9s", i, ":");
  591. seq_printf(s, "%-10d",
  592. atomic_read(&pci_priv->pm_stats.runtime_get_id[i]));
  593. seq_printf(s, "%-10d",
  594. atomic_read(&pci_priv->pm_stats.runtime_put_id[i]));
  595. seq_printf(s, "%-15llu",
  596. pci_priv->pm_stats.runtime_get_timestamp_id[i]);
  597. seq_printf(s, "%-15llu\n",
  598. pci_priv->pm_stats.runtime_put_timestamp_id[i]);
  599. }
  600. return 0;
  601. }
  602. static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file)
  603. {
  604. return single_open(file, cnss_runtime_pm_debug_show, inode->i_private);
  605. }
  606. static const struct file_operations cnss_runtime_pm_debug_fops = {
  607. .read = seq_read,
  608. .write = cnss_runtime_pm_debug_write,
  609. .open = cnss_runtime_pm_debug_open,
  610. .owner = THIS_MODULE,
  611. .llseek = seq_lseek,
  612. };
  613. static int process_drv(struct cnss_plat_data *plat_priv, bool enabled)
  614. {
  615. if (test_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state)) {
  616. cnss_pr_err("DRV cmd must be used before QMI ready\n");
  617. return -EINVAL;
  618. }
  619. enabled ? cnss_set_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01) :
  620. cnss_clear_feature_list(plat_priv, CNSS_DRV_SUPPORT_V01);
  621. cnss_pr_info("%s DRV suspend\n", enabled ? "enable" : "disable");
  622. return 0;
  623. }
  624. static int process_quirks(struct cnss_plat_data *plat_priv, u32 val)
  625. {
  626. enum cnss_debug_quirks i;
  627. int ret = 0;
  628. unsigned long state;
  629. unsigned long quirks = 0;
  630. for (i = 0, state = val; i < QUIRK_MAX_VALUE; state >>= 1, i++) {
  631. switch (i) {
  632. case DISABLE_DRV:
  633. ret = process_drv(plat_priv, !(state & 0x1));
  634. if (!ret)
  635. quirks |= (state & 0x1) << i;
  636. continue;
  637. default:
  638. quirks |= (state & 0x1) << i;
  639. continue;
  640. }
  641. }
  642. plat_priv->ctrl_params.quirks = quirks;
  643. return 0;
  644. }
  645. static ssize_t cnss_control_params_debug_write(struct file *fp,
  646. const char __user *user_buf,
  647. size_t count, loff_t *off)
  648. {
  649. struct cnss_plat_data *plat_priv =
  650. ((struct seq_file *)fp->private_data)->private;
  651. char buf[64];
  652. char *sptr, *token;
  653. char *cmd;
  654. u32 val;
  655. unsigned int len = 0;
  656. const char *delim = " ";
  657. if (!plat_priv)
  658. return -ENODEV;
  659. len = min(count, sizeof(buf) - 1);
  660. if (copy_from_user(buf, user_buf, len))
  661. return -EFAULT;
  662. buf[len] = '\0';
  663. sptr = buf;
  664. token = strsep(&sptr, delim);
  665. if (!token)
  666. return -EINVAL;
  667. if (!sptr)
  668. return -EINVAL;
  669. cmd = token;
  670. token = strsep(&sptr, delim);
  671. if (!token)
  672. return -EINVAL;
  673. if (kstrtou32(token, 0, &val))
  674. return -EINVAL;
  675. if (strcmp(cmd, "quirks") == 0)
  676. process_quirks(plat_priv, val);
  677. else if (strcmp(cmd, "mhi_timeout") == 0)
  678. plat_priv->ctrl_params.mhi_timeout = val;
  679. else if (strcmp(cmd, "mhi_m2_timeout") == 0)
  680. plat_priv->ctrl_params.mhi_m2_timeout = val;
  681. else if (strcmp(cmd, "qmi_timeout") == 0)
  682. plat_priv->ctrl_params.qmi_timeout = val;
  683. else if (strcmp(cmd, "bdf_type") == 0)
  684. plat_priv->ctrl_params.bdf_type = val;
  685. else if (strcmp(cmd, "time_sync_period") == 0)
  686. plat_priv->ctrl_params.time_sync_period = val;
  687. else if (strcmp(cmd, "kern_log_level") == 0) {
  688. if (val < MAX_LOG)
  689. cnss_kernel_log_level = val;
  690. } else if (strcmp(cmd, "ipc_log_level") == 0) {
  691. return cnss_set_ipc_log_level(val) ? -EINVAL : count;
  692. } else
  693. return -EINVAL;
  694. return count;
  695. }
  696. static int cnss_show_quirks_state(struct seq_file *s,
  697. struct cnss_plat_data *plat_priv)
  698. {
  699. enum cnss_debug_quirks i;
  700. int skip = 0;
  701. unsigned long state;
  702. seq_printf(s, "quirks: 0x%lx (", plat_priv->ctrl_params.quirks);
  703. for (i = 0, state = plat_priv->ctrl_params.quirks;
  704. state != 0; state >>= 1, i++) {
  705. if (!(state & 0x1))
  706. continue;
  707. if (skip++)
  708. seq_puts(s, " | ");
  709. switch (i) {
  710. case LINK_DOWN_SELF_RECOVERY:
  711. seq_puts(s, "LINK_DOWN_SELF_RECOVERY");
  712. continue;
  713. case SKIP_DEVICE_BOOT:
  714. seq_puts(s, "SKIP_DEVICE_BOOT");
  715. continue;
  716. case USE_CORE_ONLY_FW:
  717. seq_puts(s, "USE_CORE_ONLY_FW");
  718. continue;
  719. case SKIP_RECOVERY:
  720. seq_puts(s, "SKIP_RECOVERY");
  721. continue;
  722. case QMI_BYPASS:
  723. seq_puts(s, "QMI_BYPASS");
  724. continue;
  725. case ENABLE_WALTEST:
  726. seq_puts(s, "WALTEST");
  727. continue;
  728. case ENABLE_PCI_LINK_DOWN_PANIC:
  729. seq_puts(s, "PCI_LINK_DOWN_PANIC");
  730. continue;
  731. case FBC_BYPASS:
  732. seq_puts(s, "FBC_BYPASS");
  733. continue;
  734. case ENABLE_DAEMON_SUPPORT:
  735. seq_puts(s, "DAEMON_SUPPORT");
  736. continue;
  737. case DISABLE_DRV:
  738. seq_puts(s, "DISABLE_DRV");
  739. continue;
  740. case DISABLE_IO_COHERENCY:
  741. seq_puts(s, "DISABLE_IO_COHERENCY");
  742. continue;
  743. case IGNORE_PCI_LINK_FAILURE:
  744. seq_puts(s, "IGNORE_PCI_LINK_FAILURE");
  745. continue;
  746. case DISABLE_TIME_SYNC:
  747. seq_puts(s, "DISABLE_TIME_SYNC");
  748. continue;
  749. case FORCE_ONE_MSI:
  750. seq_puts(s, "FORCE_ONE_MSI");
  751. continue;
  752. default:
  753. continue;
  754. }
  755. }
  756. seq_puts(s, ")\n");
  757. return 0;
  758. }
  759. static int cnss_control_params_debug_show(struct seq_file *s, void *data)
  760. {
  761. struct cnss_plat_data *cnss_priv = s->private;
  762. u32 ipc_log_level;
  763. seq_puts(s, "\nUsage: echo <params_name> <value> > <debugfs_path>/cnss/control_params\n");
  764. seq_puts(s, "<params_name> can be one of below:\n");
  765. seq_puts(s, "quirks: Debug quirks for driver\n");
  766. seq_puts(s, "mhi_timeout: Timeout for MHI operation in milliseconds\n");
  767. seq_puts(s, "qmi_timeout: Timeout for QMI message in milliseconds\n");
  768. seq_puts(s, "bdf_type: Type of board data file to be downloaded\n");
  769. seq_puts(s, "time_sync_period: Time period to do time sync with device in milliseconds\n");
  770. seq_puts(s, "\nCurrent value:\n");
  771. cnss_show_quirks_state(s, cnss_priv);
  772. seq_printf(s, "mhi_timeout: %u\n", cnss_priv->ctrl_params.mhi_timeout);
  773. seq_printf(s, "mhi_m2_timeout: %u\n",
  774. cnss_priv->ctrl_params.mhi_m2_timeout);
  775. seq_printf(s, "qmi_timeout: %u\n", cnss_priv->ctrl_params.qmi_timeout);
  776. seq_printf(s, "bdf_type: %u\n", cnss_priv->ctrl_params.bdf_type);
  777. seq_printf(s, "time_sync_period: %u\n",
  778. cnss_priv->ctrl_params.time_sync_period);
  779. seq_printf(s, "kern_log_level: %u\n", cnss_kernel_log_level);
  780. ipc_log_level = cnss_get_ipc_log_level();
  781. if (ipc_log_level != MAX_LOG)
  782. seq_printf(s, "ipc_log_level: %u\n", ipc_log_level);
  783. return 0;
  784. }
  785. static int cnss_control_params_debug_open(struct inode *inode,
  786. struct file *file)
  787. {
  788. return single_open(file, cnss_control_params_debug_show,
  789. inode->i_private);
  790. }
  791. static const struct file_operations cnss_control_params_debug_fops = {
  792. .read = seq_read,
  793. .write = cnss_control_params_debug_write,
  794. .open = cnss_control_params_debug_open,
  795. .owner = THIS_MODULE,
  796. .llseek = seq_lseek,
  797. };
  798. static ssize_t cnss_dynamic_feature_write(struct file *fp,
  799. const char __user *user_buf,
  800. size_t count, loff_t *off)
  801. {
  802. struct cnss_plat_data *plat_priv =
  803. ((struct seq_file *)fp->private_data)->private;
  804. int ret = 0;
  805. u64 val;
  806. ret = kstrtou64_from_user(user_buf, count, 0, &val);
  807. if (ret)
  808. return ret;
  809. plat_priv->dynamic_feature = val;
  810. ret = cnss_wlfw_dynamic_feature_mask_send_sync(plat_priv);
  811. if (ret < 0)
  812. return ret;
  813. return count;
  814. }
  815. static int cnss_dynamic_feature_show(struct seq_file *s, void *data)
  816. {
  817. struct cnss_plat_data *cnss_priv = s->private;
  818. seq_printf(s, "dynamic_feature: 0x%llx\n", cnss_priv->dynamic_feature);
  819. return 0;
  820. }
  821. static int cnss_dynamic_feature_open(struct inode *inode,
  822. struct file *file)
  823. {
  824. return single_open(file, cnss_dynamic_feature_show,
  825. inode->i_private);
  826. }
  827. static const struct file_operations cnss_dynamic_feature_fops = {
  828. .read = seq_read,
  829. .write = cnss_dynamic_feature_write,
  830. .open = cnss_dynamic_feature_open,
  831. .owner = THIS_MODULE,
  832. .llseek = seq_lseek,
  833. };
  834. static int cnss_smmu_fault_timestamp_show(struct seq_file *s, void *data)
  835. {
  836. struct cnss_plat_data *plat_priv = s->private;
  837. struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
  838. if (!pci_priv)
  839. return -ENODEV;
  840. seq_printf(s, "smmu irq cb entry timestamp : %llu ns\n",
  841. pci_priv->smmu_fault_timestamp[SMMU_CB_ENTRY]);
  842. seq_printf(s, "smmu irq cb before doorbell ring timestamp : %llu ns\n",
  843. pci_priv->smmu_fault_timestamp[SMMU_CB_DOORBELL_RING]);
  844. seq_printf(s, "smmu irq cb after doorbell ring timestamp : %llu ns\n",
  845. pci_priv->smmu_fault_timestamp[SMMU_CB_EXIT]);
  846. return 0;
  847. }
  848. static int cnss_smmu_fault_timestamp_open(struct inode *inode,
  849. struct file *file)
  850. {
  851. return single_open(file, cnss_smmu_fault_timestamp_show,
  852. inode->i_private);
  853. }
  854. static const struct file_operations cnss_smmu_fault_timestamp_fops = {
  855. .read = seq_read,
  856. .release = single_release,
  857. .open = cnss_smmu_fault_timestamp_open,
  858. .owner = THIS_MODULE,
  859. .llseek = seq_lseek,
  860. };
  861. #ifdef CONFIG_DEBUG_FS
  862. #ifdef CONFIG_CNSS2_DEBUG
  863. static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
  864. {
  865. struct dentry *root_dentry = plat_priv->root_dentry;
  866. debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
  867. &cnss_dev_boot_debug_fops);
  868. debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
  869. &cnss_reg_read_debug_fops);
  870. debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
  871. &cnss_reg_write_debug_fops);
  872. debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv,
  873. &cnss_runtime_pm_debug_fops);
  874. debugfs_create_file("control_params", 0600, root_dentry, plat_priv,
  875. &cnss_control_params_debug_fops);
  876. debugfs_create_file("dynamic_feature", 0600, root_dentry, plat_priv,
  877. &cnss_dynamic_feature_fops);
  878. debugfs_create_file("cnss_smmu_fault_timestamp", 0600, root_dentry,
  879. plat_priv, &cnss_smmu_fault_timestamp_fops);
  880. return 0;
  881. }
  882. #else
  883. static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
  884. {
  885. return 0;
  886. }
  887. #endif
  888. int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
  889. {
  890. int ret = 0;
  891. struct dentry *root_dentry;
  892. char name[CNSS_FS_NAME_SIZE];
  893. if (cnss_is_dual_wlan_enabled())
  894. snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME "_%d",
  895. plat_priv->plat_idx);
  896. else
  897. snprintf(name, CNSS_FS_NAME_SIZE, CNSS_FS_NAME);
  898. root_dentry = debugfs_create_dir(name, 0);
  899. if (IS_ERR(root_dentry)) {
  900. ret = PTR_ERR(root_dentry);
  901. cnss_pr_err("Unable to create debugfs %d\n", ret);
  902. goto out;
  903. }
  904. plat_priv->root_dentry = root_dentry;
  905. debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
  906. &cnss_pin_connect_fops);
  907. debugfs_create_file("stats", 0644, root_dentry, plat_priv,
  908. &cnss_stats_fops);
  909. cnss_create_debug_only_node(plat_priv);
  910. out:
  911. return ret;
  912. }
  913. void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
  914. {
  915. debugfs_remove_recursive(plat_priv->root_dentry);
  916. }
  917. #else
  918. int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
  919. {
  920. plat_priv->root_dentry = NULL;
  921. return 0;
  922. }
  923. void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
  924. {
  925. }
  926. #endif
  927. #if IS_ENABLED(CONFIG_IPC_LOGGING)
  928. void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
  929. enum log_level kern_log_level,
  930. enum log_level ipc_log_level, char *fmt, ...)
  931. {
  932. struct va_format vaf;
  933. va_list va_args;
  934. va_start(va_args, fmt);
  935. vaf.fmt = fmt;
  936. vaf.va = &va_args;
  937. if (kern_log_level <= cnss_kernel_log_level) {
  938. switch (kern_log_level) {
  939. case EMERG_LOG:
  940. pr_emerg("cnss: %pV", &vaf);
  941. break;
  942. case ALERT_LOG:
  943. pr_alert("cnss: %pV", &vaf);
  944. break;
  945. case CRIT_LOG:
  946. pr_crit("cnss: %pV", &vaf);
  947. break;
  948. case ERR_LOG:
  949. pr_err("cnss: %pV", &vaf);
  950. break;
  951. case WARNING_LOG:
  952. pr_warn("cnss: %pV", &vaf);
  953. break;
  954. case NOTICE_LOG:
  955. pr_notice("cnss: %pV", &vaf);
  956. break;
  957. case INFO_LOG:
  958. pr_info("cnss: %pV", &vaf);
  959. break;
  960. case DEBUG_LOG:
  961. case DEBUG_HI_LOG:
  962. pr_debug("cnss: %pV", &vaf);
  963. break;
  964. default:
  965. break;
  966. }
  967. }
  968. if (ipc_log_level <= cnss_ipc_log_level)
  969. ipc_log_string(log_ctx, "[%s] %s: %pV", process, fn, &vaf);
  970. va_end(va_args);
  971. }
  972. static int cnss_ipc_logging_init(void)
  973. {
  974. cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
  975. "cnss", 0);
  976. if (!cnss_ipc_log_context) {
  977. cnss_pr_err("Unable to create IPC log context\n");
  978. return -EINVAL;
  979. }
  980. cnss_ipc_log_long_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
  981. "cnss-long", 0);
  982. if (!cnss_ipc_log_long_context) {
  983. cnss_pr_err("Unable to create IPC long log context\n");
  984. ipc_log_context_destroy(cnss_ipc_log_context);
  985. return -EINVAL;
  986. }
  987. return 0;
  988. }
  989. static void cnss_ipc_logging_deinit(void)
  990. {
  991. if (cnss_ipc_log_long_context) {
  992. ipc_log_context_destroy(cnss_ipc_log_long_context);
  993. cnss_ipc_log_long_context = NULL;
  994. }
  995. if (cnss_ipc_log_context) {
  996. ipc_log_context_destroy(cnss_ipc_log_context);
  997. cnss_ipc_log_context = NULL;
  998. }
  999. }
  1000. #else
  1001. static int cnss_ipc_logging_init(void) { return 0; }
  1002. static void cnss_ipc_logging_deinit(void) {}
  1003. void cnss_debug_ipc_log_print(void *log_ctx, char *process, const char *fn,
  1004. enum log_level kern_log_level,
  1005. enum log_level ipc_log_level, char *fmt, ...)
  1006. {
  1007. struct va_format vaf;
  1008. va_list va_args;
  1009. va_start(va_args, fmt);
  1010. vaf.fmt = fmt;
  1011. vaf.va = &va_args;
  1012. if (kern_log_level <= cnss_kernel_log_level) {
  1013. switch (kern_log_level) {
  1014. case EMERG_LOG:
  1015. pr_emerg("cnss: %pV", &vaf);
  1016. break;
  1017. case ALERT_LOG:
  1018. pr_alert("cnss: %pV", &vaf);
  1019. break;
  1020. case CRIT_LOG:
  1021. pr_crit("cnss: %pV", &vaf);
  1022. break;
  1023. case ERR_LOG:
  1024. pr_err("cnss: %pV", &vaf);
  1025. break;
  1026. case WARNING_LOG:
  1027. pr_warn("cnss: %pV", &vaf);
  1028. break;
  1029. case NOTICE_LOG:
  1030. pr_notice("cnss: %pV", &vaf);
  1031. break;
  1032. case INFO_LOG:
  1033. pr_info("cnss: %pV", &vaf);
  1034. break;
  1035. case DEBUG_LOG:
  1036. case DEBUG_HI_LOG:
  1037. pr_debug("cnss: %pV", &vaf);
  1038. break;
  1039. default:
  1040. break;
  1041. }
  1042. }
  1043. va_end(va_args);
  1044. }
  1045. #endif
  1046. int cnss_debug_init(void)
  1047. {
  1048. return cnss_ipc_logging_init();
  1049. }
  1050. void cnss_debug_deinit(void)
  1051. {
  1052. cnss_ipc_logging_deinit();
  1053. }