debug.c 31 KB

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