gsi_dbg.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/completion.h>
  6. #include <linux/debugfs.h>
  7. #include <linux/dma-mapping.h>
  8. #include <linux/random.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/msm_gsi.h>
  11. #include "gsi.h"
  12. #include "gsihal.h"
  13. #define TERR(fmt, args...) \
  14. pr_err("%s:%d " fmt, __func__, __LINE__, ## args)
  15. #define TDBG(fmt, args...) \
  16. pr_debug("%s:%d " fmt, __func__, __LINE__, ## args)
  17. #define PRT_STAT(fmt, args...) \
  18. pr_err(fmt, ## args)
  19. static struct dentry *dent;
  20. static char dbg_buff[4096];
  21. static void *gsi_ipc_logbuf_low;
  22. static void gsi_wq_print_dp_stats(struct work_struct *work);
  23. static DECLARE_DELAYED_WORK(gsi_print_dp_stats_work, gsi_wq_print_dp_stats);
  24. static void gsi_wq_update_dp_stats(struct work_struct *work);
  25. static DECLARE_DELAYED_WORK(gsi_update_dp_stats_work, gsi_wq_update_dp_stats);
  26. static ssize_t gsi_dump_evt(struct file *file,
  27. const char __user *buf, size_t count, loff_t *ppos)
  28. {
  29. u32 arg1;
  30. u32 arg2;
  31. unsigned long missing;
  32. char *sptr, *token;
  33. uint32_t val;
  34. struct gsi_evt_ctx *ctx;
  35. uint16_t i;
  36. if (count >= sizeof(dbg_buff))
  37. return -EINVAL;
  38. missing = copy_from_user(dbg_buff, buf, count);
  39. if (missing)
  40. return -EFAULT;
  41. dbg_buff[count] = '\0';
  42. sptr = dbg_buff;
  43. token = strsep(&sptr, " ");
  44. if (!token)
  45. return -EINVAL;
  46. if (kstrtou32(token, 0, &arg1))
  47. return -EINVAL;
  48. token = strsep(&sptr, " ");
  49. if (!token)
  50. return -EINVAL;
  51. if (kstrtou32(token, 0, &arg2))
  52. return -EINVAL;
  53. TDBG("arg1=%u arg2=%u\n", arg1, arg2);
  54. if (arg1 >= gsi_ctx->max_ev) {
  55. TERR("invalid evt ring id %u\n", arg1);
  56. return -EINVAL;
  57. }
  58. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_0,
  59. gsi_ctx->per.ee, arg1);
  60. TERR("EV%2d CTX0 0x%x\n", arg1, val);
  61. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_1,
  62. gsi_ctx->per.ee, arg1);
  63. TERR("EV%2d CTX1 0x%x\n", arg1, val);
  64. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_2,
  65. gsi_ctx->per.ee, arg1);
  66. TERR("EV%2d CTX2 0x%x\n", arg1, val);
  67. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_3,
  68. gsi_ctx->per.ee, arg1);
  69. TERR("EV%2d CTX3 0x%x\n", arg1, val);
  70. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_4,
  71. gsi_ctx->per.ee, arg1);
  72. TERR("EV%2d CTX4 0x%x\n", arg1, val);
  73. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_5,
  74. gsi_ctx->per.ee, arg1);
  75. TERR("EV%2d CTX5 0x%x\n", arg1, val);
  76. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_6,
  77. gsi_ctx->per.ee, arg1);
  78. TERR("EV%2d CTX6 0x%x\n", arg1, val);
  79. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_7,
  80. gsi_ctx->per.ee, arg1);
  81. TERR("EV%2d CTX7 0x%x\n", arg1, val);
  82. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_8,
  83. gsi_ctx->per.ee, arg1);
  84. TERR("EV%2d CTX8 0x%x\n", arg1, val);
  85. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_9,
  86. gsi_ctx->per.ee, arg1);
  87. TERR("EV%2d CTX9 0x%x\n", arg1, val);
  88. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_10,
  89. gsi_ctx->per.ee, arg1);
  90. TERR("EV%2d CTX10 0x%x\n", arg1, val);
  91. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_11,
  92. gsi_ctx->per.ee, arg1);
  93. TERR("EV%2d CTX11 0x%x\n", arg1, val);
  94. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_12,
  95. gsi_ctx->per.ee, arg1);
  96. TERR("EV%2d CTX12 0x%x\n", arg1, val);
  97. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_CNTXT_13,
  98. gsi_ctx->per.ee, arg1);
  99. TERR("EV%2d CTX13 0x%x\n", arg1, val);
  100. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_SCRATCH_0,
  101. gsi_ctx->per.ee, arg1);
  102. TERR("EV%2d SCR0 0x%x\n", arg1, val);
  103. val = gsihal_read_reg_nk(GSI_EE_n_EV_CH_k_SCRATCH_1,
  104. gsi_ctx->per.ee, arg1);
  105. TERR("EV%2d SCR1 0x%x\n", arg1, val);
  106. if (arg2) {
  107. ctx = &gsi_ctx->evtr[arg1];
  108. if (ctx->props.ring_base_vaddr) {
  109. for (i = 0; i < ctx->props.ring_len / 16; i++)
  110. TERR("EV%2d (0x%08llx) %08x %08x %08x %08x\n",
  111. arg1, ctx->props.ring_base_addr + i * 16,
  112. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  113. i * 16 + 0),
  114. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  115. i * 16 + 4),
  116. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  117. i * 16 + 8),
  118. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  119. i * 16 + 12));
  120. } else {
  121. TERR("No VA supplied for event ring id %u\n", arg1);
  122. }
  123. }
  124. return count;
  125. }
  126. static ssize_t gsi_dump_ch(struct file *file,
  127. const char __user *buf, size_t count, loff_t *ppos)
  128. {
  129. u32 arg1;
  130. u32 arg2;
  131. unsigned long missing;
  132. char *sptr, *token;
  133. struct gsi_chan_ctx *ctx;
  134. uint16_t i;
  135. if (count >= sizeof(dbg_buff))
  136. return -EINVAL;
  137. missing = copy_from_user(dbg_buff, buf, count);
  138. if (missing)
  139. return -EFAULT;
  140. dbg_buff[count] = '\0';
  141. sptr = dbg_buff;
  142. token = strsep(&sptr, " ");
  143. if (!token)
  144. return -EINVAL;
  145. if (kstrtou32(token, 0, &arg1))
  146. return -EINVAL;
  147. token = strsep(&sptr, " ");
  148. if (!token)
  149. return -EINVAL;
  150. if (kstrtou32(token, 0, &arg2))
  151. return -EINVAL;
  152. TDBG("arg1=%u arg2=%u\n", arg1, arg2);
  153. if (arg1 >= gsi_ctx->max_ch) {
  154. TERR("invalid chan id %u\n", arg1);
  155. return -EINVAL;
  156. }
  157. gsi_dump_ch_info(arg1);
  158. if (arg2) {
  159. ctx = &gsi_ctx->chan[arg1];
  160. if (ctx->props.ring_base_vaddr) {
  161. for (i = 0; i < ctx->props.ring_len / 16; i++)
  162. TERR("CH%2d (0x%08llx) %08x %08x %08x %08x\n",
  163. arg1, ctx->props.ring_base_addr + i * 16,
  164. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  165. i * 16 + 0),
  166. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  167. i * 16 + 4),
  168. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  169. i * 16 + 8),
  170. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  171. i * 16 + 12));
  172. } else {
  173. TERR("No VA supplied for chan id %u\n", arg1);
  174. }
  175. }
  176. return count;
  177. }
  178. static void gsi_dump_ch_stats(struct gsi_chan_ctx *ctx)
  179. {
  180. if (!ctx->allocated)
  181. return;
  182. PRT_STAT("CH%2d:\n", ctx->props.ch_id);
  183. PRT_STAT("queued=%lu compl=%lu\n",
  184. ctx->stats.queued,
  185. ctx->stats.completed);
  186. PRT_STAT("cb->poll=%lu poll->cb=%lu poll_pend_irq=%lu\n",
  187. ctx->stats.callback_to_poll,
  188. ctx->stats.poll_to_callback,
  189. ctx->stats.poll_pending_irq);
  190. PRT_STAT("invalid_tre_error=%lu\n",
  191. ctx->stats.invalid_tre_error);
  192. PRT_STAT("poll_ok=%lu poll_empty=%lu\n",
  193. ctx->stats.poll_ok, ctx->stats.poll_empty);
  194. if (ctx->evtr)
  195. PRT_STAT("compl_evt=%lu\n",
  196. ctx->evtr->stats.completed);
  197. PRT_STAT("userdata_in_use=%lu\n", ctx->stats.userdata_in_use);
  198. PRT_STAT("ch_below_lo=%lu\n", ctx->stats.dp.ch_below_lo);
  199. PRT_STAT("ch_below_hi=%lu\n", ctx->stats.dp.ch_below_hi);
  200. PRT_STAT("ch_above_hi=%lu\n", ctx->stats.dp.ch_above_hi);
  201. PRT_STAT("time_empty=%lums\n", ctx->stats.dp.empty_time);
  202. PRT_STAT("\n");
  203. }
  204. static ssize_t gsi_dump_stats(struct file *file,
  205. const char __user *buf, size_t count, loff_t *ppos)
  206. {
  207. int ch_id;
  208. int min, max, ret;
  209. ret = kstrtos32_from_user(buf, count, 0, &ch_id);
  210. if (ret)
  211. return ret;
  212. if (ch_id == -1) {
  213. min = 0;
  214. max = gsi_ctx->max_ch;
  215. } else if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  216. !gsi_ctx->chan[ch_id].allocated) {
  217. goto error;
  218. } else {
  219. min = ch_id;
  220. max = ch_id + 1;
  221. }
  222. for (ch_id = min; ch_id < max; ch_id++)
  223. gsi_dump_ch_stats(&gsi_ctx->chan[ch_id]);
  224. return count;
  225. error:
  226. TERR("Usage: echo ch_id > stats. Use -1 for all\n");
  227. return -EINVAL;
  228. }
  229. static int gsi_dbg_create_stats_wq(void)
  230. {
  231. gsi_ctx->dp_stat_wq =
  232. create_singlethread_workqueue("gsi_stat");
  233. if (!gsi_ctx->dp_stat_wq) {
  234. TERR("failed create workqueue\n");
  235. return -ENOMEM;
  236. }
  237. return 0;
  238. }
  239. static void gsi_dbg_destroy_stats_wq(void)
  240. {
  241. cancel_delayed_work_sync(&gsi_update_dp_stats_work);
  242. cancel_delayed_work_sync(&gsi_print_dp_stats_work);
  243. flush_workqueue(gsi_ctx->dp_stat_wq);
  244. destroy_workqueue(gsi_ctx->dp_stat_wq);
  245. gsi_ctx->dp_stat_wq = NULL;
  246. }
  247. static ssize_t gsi_enable_dp_stats(struct file *file,
  248. const char __user *buf, size_t count, loff_t *ppos)
  249. {
  250. int ch_id;
  251. bool enable;
  252. int ret;
  253. if (count >= sizeof(dbg_buff))
  254. goto error;
  255. if (copy_from_user(dbg_buff, buf, count))
  256. goto error;
  257. dbg_buff[count] = '\0';
  258. if (dbg_buff[0] != '+' && dbg_buff[0] != '-')
  259. goto error;
  260. enable = (dbg_buff[0] == '+');
  261. if (kstrtos32(dbg_buff + 1, 0, &ch_id))
  262. goto error;
  263. if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  264. !gsi_ctx->chan[ch_id].allocated) {
  265. goto error;
  266. }
  267. if (gsi_ctx->chan[ch_id].enable_dp_stats == enable) {
  268. TERR("ch_%d: already enabled/disabled\n", ch_id);
  269. return -EINVAL;
  270. }
  271. gsi_ctx->chan[ch_id].enable_dp_stats = enable;
  272. if (enable)
  273. gsi_ctx->num_ch_dp_stats++;
  274. else
  275. gsi_ctx->num_ch_dp_stats--;
  276. if (enable) {
  277. if (gsi_ctx->num_ch_dp_stats == 1) {
  278. ret = gsi_dbg_create_stats_wq();
  279. if (ret)
  280. return ret;
  281. }
  282. cancel_delayed_work_sync(&gsi_update_dp_stats_work);
  283. queue_delayed_work(gsi_ctx->dp_stat_wq,
  284. &gsi_update_dp_stats_work, msecs_to_jiffies(10));
  285. } else if (!enable && gsi_ctx->num_ch_dp_stats == 0) {
  286. gsi_dbg_destroy_stats_wq();
  287. }
  288. return count;
  289. error:
  290. TERR("Usage: echo [+-]ch_id > enable_dp_stats\n");
  291. return -EINVAL;
  292. }
  293. static ssize_t gsi_set_max_elem_dp_stats(struct file *file,
  294. const char __user *buf, size_t count, loff_t *ppos)
  295. {
  296. u32 ch_id;
  297. u32 max_elem;
  298. unsigned long missing;
  299. char *sptr, *token;
  300. if (count >= sizeof(dbg_buff))
  301. goto error;
  302. missing = copy_from_user(dbg_buff, buf, count);
  303. if (missing)
  304. goto error;
  305. dbg_buff[count] = '\0';
  306. sptr = dbg_buff;
  307. token = strsep(&sptr, " ");
  308. if (!token) {
  309. TERR("\n");
  310. goto error;
  311. }
  312. if (kstrtou32(token, 0, &ch_id)) {
  313. TERR("\n");
  314. goto error;
  315. }
  316. token = strsep(&sptr, " ");
  317. if (!token) {
  318. /* get */
  319. if (kstrtou32(dbg_buff, 0, &ch_id))
  320. goto error;
  321. if (ch_id >= gsi_ctx->max_ch)
  322. goto error;
  323. PRT_STAT("ch %d: max_re_expected=%d\n", ch_id,
  324. gsi_ctx->chan[ch_id].props.max_re_expected);
  325. return count;
  326. }
  327. if (kstrtou32(token, 0, &max_elem)) {
  328. TERR("\n");
  329. goto error;
  330. }
  331. TDBG("ch_id=%u max_elem=%u\n", ch_id, max_elem);
  332. if (ch_id >= gsi_ctx->max_ch) {
  333. TERR("invalid chan id %u\n", ch_id);
  334. goto error;
  335. }
  336. gsi_ctx->chan[ch_id].props.max_re_expected = max_elem;
  337. return count;
  338. error:
  339. TERR("Usage: (set) echo <ch_id> <max_elem> > max_elem_dp_stats\n");
  340. TERR("Usage: (get) echo <ch_id> > max_elem_dp_stats\n");
  341. return -EINVAL;
  342. }
  343. static void gsi_wq_print_dp_stats(struct work_struct *work)
  344. {
  345. int ch_id;
  346. for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
  347. if (gsi_ctx->chan[ch_id].print_dp_stats)
  348. gsi_dump_ch_stats(&gsi_ctx->chan[ch_id]);
  349. }
  350. queue_delayed_work(gsi_ctx->dp_stat_wq, &gsi_print_dp_stats_work,
  351. msecs_to_jiffies(1000));
  352. }
  353. static void gsi_dbg_update_ch_dp_stats(struct gsi_chan_ctx *ctx)
  354. {
  355. uint16_t start_hw;
  356. uint16_t end_hw;
  357. uint64_t rp_hw;
  358. uint64_t wp_hw;
  359. int ee = gsi_ctx->per.ee;
  360. uint16_t used_hw;
  361. rp_hw = gsihal_read_reg_nk(GSI_EE_n_GSI_CH_k_CNTXT_4,
  362. ee, ctx->props.ch_id);
  363. rp_hw |= ((uint64_t)gsihal_read_reg_nk(GSI_EE_n_GSI_CH_k_CNTXT_5,
  364. ee, ctx->props.ch_id)) << 32;
  365. wp_hw = gsihal_read_reg_nk(GSI_EE_n_GSI_CH_k_CNTXT_6,
  366. ee, ctx->props.ch_id);
  367. wp_hw |= ((uint64_t)gsihal_read_reg_nk(GSI_EE_n_GSI_CH_k_CNTXT_7,
  368. ee, ctx->props.ch_id)) << 32;
  369. start_hw = gsi_find_idx_from_addr(&ctx->ring, rp_hw);
  370. end_hw = gsi_find_idx_from_addr(&ctx->ring, wp_hw);
  371. if (end_hw >= start_hw)
  372. used_hw = end_hw - start_hw;
  373. else
  374. used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end_hw);
  375. TDBG("ch %d used %d\n", ctx->props.ch_id, used_hw);
  376. gsi_update_ch_dp_stats(ctx, used_hw);
  377. }
  378. static void gsi_wq_update_dp_stats(struct work_struct *work)
  379. {
  380. int ch_id;
  381. for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
  382. if (gsi_ctx->chan[ch_id].allocated &&
  383. gsi_ctx->chan[ch_id].enable_dp_stats)
  384. gsi_dbg_update_ch_dp_stats(&gsi_ctx->chan[ch_id]);
  385. }
  386. queue_delayed_work(gsi_ctx->dp_stat_wq, &gsi_update_dp_stats_work,
  387. msecs_to_jiffies(10));
  388. }
  389. static ssize_t gsi_rst_stats(struct file *file,
  390. const char __user *buf, size_t count, loff_t *ppos)
  391. {
  392. int ch_id;
  393. int min, max, ret;
  394. ret = kstrtos32_from_user(buf, count, 0, &ch_id);
  395. if (ret)
  396. return ret;
  397. if (ch_id == -1) {
  398. min = 0;
  399. max = gsi_ctx->max_ch;
  400. } else if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  401. !gsi_ctx->chan[ch_id].allocated) {
  402. goto error;
  403. } else {
  404. min = ch_id;
  405. max = ch_id + 1;
  406. }
  407. for (ch_id = min; ch_id < max; ch_id++)
  408. memset(&gsi_ctx->chan[ch_id].stats, 0,
  409. sizeof(gsi_ctx->chan[ch_id].stats));
  410. return count;
  411. error:
  412. TERR("Usage: echo ch_id > rst_stats. Use -1 for all\n");
  413. return -EINVAL;
  414. }
  415. static ssize_t gsi_print_dp_stats(struct file *file,
  416. const char __user *buf, size_t count, loff_t *ppos)
  417. {
  418. int ch_id;
  419. bool enable;
  420. int ret;
  421. if (count >= sizeof(dbg_buff))
  422. goto error;
  423. if (copy_from_user(dbg_buff, buf, count))
  424. goto error;
  425. dbg_buff[count] = '\0';
  426. if (dbg_buff[0] != '+' && dbg_buff[0] != '-')
  427. goto error;
  428. enable = (dbg_buff[0] == '+');
  429. if (kstrtos32(dbg_buff + 1, 0, &ch_id))
  430. goto error;
  431. if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  432. !gsi_ctx->chan[ch_id].allocated) {
  433. goto error;
  434. }
  435. if (gsi_ctx->chan[ch_id].print_dp_stats == enable) {
  436. TERR("ch_%d: already enabled/disabled\n", ch_id);
  437. return -EINVAL;
  438. }
  439. gsi_ctx->chan[ch_id].print_dp_stats = enable;
  440. if (enable)
  441. gsi_ctx->num_ch_dp_stats++;
  442. else
  443. gsi_ctx->num_ch_dp_stats--;
  444. if (enable) {
  445. if (gsi_ctx->num_ch_dp_stats == 1) {
  446. ret = gsi_dbg_create_stats_wq();
  447. if (ret)
  448. return ret;
  449. }
  450. cancel_delayed_work_sync(&gsi_print_dp_stats_work);
  451. queue_delayed_work(gsi_ctx->dp_stat_wq,
  452. &gsi_print_dp_stats_work, msecs_to_jiffies(10));
  453. } else if (!enable && gsi_ctx->num_ch_dp_stats == 0) {
  454. gsi_dbg_destroy_stats_wq();
  455. }
  456. return count;
  457. error:
  458. TERR("Usage: echo [+-]ch_id > print_dp_stats\n");
  459. return -EINVAL;
  460. }
  461. static ssize_t gsi_enable_ipc_low(struct file *file,
  462. const char __user *ubuf, size_t count, loff_t *ppos)
  463. {
  464. s8 option = 0;
  465. int ret;
  466. ret = kstrtos8_from_user(ubuf, count, 0, &option);
  467. if (ret)
  468. return ret;
  469. mutex_lock(&gsi_ctx->mlock);
  470. if (option) {
  471. if (!gsi_ipc_logbuf_low) {
  472. gsi_ipc_logbuf_low =
  473. ipc_log_context_create(GSI_IPC_LOG_PAGES,
  474. "gsi_low", 0);
  475. if (gsi_ipc_logbuf_low == NULL)
  476. TERR("failed to get ipc_logbuf_low\n");
  477. }
  478. gsi_ctx->ipc_logbuf_low = gsi_ipc_logbuf_low;
  479. } else {
  480. gsi_ctx->ipc_logbuf_low = NULL;
  481. }
  482. mutex_unlock(&gsi_ctx->mlock);
  483. return count;
  484. }
  485. static const struct file_operations gsi_ev_dump_ops = {
  486. .write = gsi_dump_evt,
  487. };
  488. static const struct file_operations gsi_ch_dump_ops = {
  489. .write = gsi_dump_ch,
  490. };
  491. static const struct file_operations gsi_stats_ops = {
  492. .write = gsi_dump_stats,
  493. };
  494. static const struct file_operations gsi_enable_dp_stats_ops = {
  495. .write = gsi_enable_dp_stats,
  496. };
  497. static const struct file_operations gsi_max_elem_dp_stats_ops = {
  498. .write = gsi_set_max_elem_dp_stats,
  499. };
  500. static const struct file_operations gsi_rst_stats_ops = {
  501. .write = gsi_rst_stats,
  502. };
  503. static const struct file_operations gsi_print_dp_stats_ops = {
  504. .write = gsi_print_dp_stats,
  505. };
  506. static const struct file_operations gsi_ipc_low_ops = {
  507. .write = gsi_enable_ipc_low,
  508. };
  509. void gsi_debugfs_init(void)
  510. {
  511. static struct dentry *dfile;
  512. const mode_t write_only_mode = 0220;
  513. dent = debugfs_create_dir("gsi", 0);
  514. if (IS_ERR(dent)) {
  515. TERR("fail to create dir\n");
  516. return;
  517. }
  518. dfile = debugfs_create_file("ev_dump", write_only_mode,
  519. dent, 0, &gsi_ev_dump_ops);
  520. if (!dfile || IS_ERR(dfile)) {
  521. TERR("fail to create ev_dump file\n");
  522. goto fail;
  523. }
  524. dfile = debugfs_create_file("ch_dump", write_only_mode,
  525. dent, 0, &gsi_ch_dump_ops);
  526. if (!dfile || IS_ERR(dfile)) {
  527. TERR("fail to create ch_dump file\n");
  528. goto fail;
  529. }
  530. dfile = debugfs_create_file("stats", write_only_mode, dent,
  531. 0, &gsi_stats_ops);
  532. if (!dfile || IS_ERR(dfile)) {
  533. TERR("fail to create stats file\n");
  534. goto fail;
  535. }
  536. dfile = debugfs_create_file("enable_dp_stats", write_only_mode, dent,
  537. 0, &gsi_enable_dp_stats_ops);
  538. if (!dfile || IS_ERR(dfile)) {
  539. TERR("fail to create stats file\n");
  540. goto fail;
  541. }
  542. dfile = debugfs_create_file("max_elem_dp_stats", write_only_mode,
  543. dent, 0, &gsi_max_elem_dp_stats_ops);
  544. if (!dfile || IS_ERR(dfile)) {
  545. TERR("fail to create stats file\n");
  546. goto fail;
  547. }
  548. dfile = debugfs_create_file("rst_stats", write_only_mode,
  549. dent, 0, &gsi_rst_stats_ops);
  550. if (!dfile || IS_ERR(dfile)) {
  551. TERR("fail to create stats file\n");
  552. goto fail;
  553. }
  554. dfile = debugfs_create_file("print_dp_stats",
  555. write_only_mode, dent, 0, &gsi_print_dp_stats_ops);
  556. if (!dfile || IS_ERR(dfile)) {
  557. TERR("fail to create stats file\n");
  558. goto fail;
  559. }
  560. dfile = debugfs_create_file("ipc_low", write_only_mode,
  561. dent, 0, &gsi_ipc_low_ops);
  562. if (!dfile || IS_ERR(dfile)) {
  563. TERR("could not create ipc_low\n");
  564. goto fail;
  565. }
  566. return;
  567. fail:
  568. debugfs_remove_recursive(dent);
  569. }