gsi_dbg.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015-2019, 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_reg.h"
  12. #include "gsi.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 = gsi_readl(gsi_ctx->base +
  59. GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(arg1, gsi_ctx->per.ee));
  60. TERR("EV%2d CTX0 0x%x\n", arg1, val);
  61. val = gsi_readl(gsi_ctx->base +
  62. GSI_EE_n_EV_CH_k_CNTXT_1_OFFS(arg1, gsi_ctx->per.ee));
  63. TERR("EV%2d CTX1 0x%x\n", arg1, val);
  64. val = gsi_readl(gsi_ctx->base +
  65. GSI_EE_n_EV_CH_k_CNTXT_2_OFFS(arg1, gsi_ctx->per.ee));
  66. TERR("EV%2d CTX2 0x%x\n", arg1, val);
  67. val = gsi_readl(gsi_ctx->base +
  68. GSI_EE_n_EV_CH_k_CNTXT_3_OFFS(arg1, gsi_ctx->per.ee));
  69. TERR("EV%2d CTX3 0x%x\n", arg1, val);
  70. val = gsi_readl(gsi_ctx->base +
  71. GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(arg1, gsi_ctx->per.ee));
  72. TERR("EV%2d CTX4 0x%x\n", arg1, val);
  73. val = gsi_readl(gsi_ctx->base +
  74. GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(arg1, gsi_ctx->per.ee));
  75. TERR("EV%2d CTX5 0x%x\n", arg1, val);
  76. val = gsi_readl(gsi_ctx->base +
  77. GSI_EE_n_EV_CH_k_CNTXT_6_OFFS(arg1, gsi_ctx->per.ee));
  78. TERR("EV%2d CTX6 0x%x\n", arg1, val);
  79. val = gsi_readl(gsi_ctx->base +
  80. GSI_EE_n_EV_CH_k_CNTXT_7_OFFS(arg1, gsi_ctx->per.ee));
  81. TERR("EV%2d CTX7 0x%x\n", arg1, val);
  82. val = gsi_readl(gsi_ctx->base +
  83. GSI_EE_n_EV_CH_k_CNTXT_8_OFFS(arg1, gsi_ctx->per.ee));
  84. TERR("EV%2d CTX8 0x%x\n", arg1, val);
  85. val = gsi_readl(gsi_ctx->base +
  86. GSI_EE_n_EV_CH_k_CNTXT_9_OFFS(arg1, gsi_ctx->per.ee));
  87. TERR("EV%2d CTX9 0x%x\n", arg1, val);
  88. val = gsi_readl(gsi_ctx->base +
  89. GSI_EE_n_EV_CH_k_CNTXT_10_OFFS(arg1, gsi_ctx->per.ee));
  90. TERR("EV%2d CTX10 0x%x\n", arg1, val);
  91. val = gsi_readl(gsi_ctx->base +
  92. GSI_EE_n_EV_CH_k_CNTXT_11_OFFS(arg1, gsi_ctx->per.ee));
  93. TERR("EV%2d CTX11 0x%x\n", arg1, val);
  94. val = gsi_readl(gsi_ctx->base +
  95. GSI_EE_n_EV_CH_k_CNTXT_12_OFFS(arg1, gsi_ctx->per.ee));
  96. TERR("EV%2d CTX12 0x%x\n", arg1, val);
  97. val = gsi_readl(gsi_ctx->base +
  98. GSI_EE_n_EV_CH_k_CNTXT_13_OFFS(arg1, gsi_ctx->per.ee));
  99. TERR("EV%2d CTX13 0x%x\n", arg1, val);
  100. val = gsi_readl(gsi_ctx->base +
  101. GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(arg1, gsi_ctx->per.ee));
  102. TERR("EV%2d SCR0 0x%x\n", arg1, val);
  103. val = gsi_readl(gsi_ctx->base +
  104. GSI_EE_n_EV_CH_k_SCRATCH_1_OFFS(arg1, gsi_ctx->per.ee));
  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. uint32_t val;
  134. struct gsi_chan_ctx *ctx;
  135. uint16_t i;
  136. if (count >= sizeof(dbg_buff))
  137. return -EINVAL;
  138. missing = copy_from_user(dbg_buff, buf, count);
  139. if (missing)
  140. return -EFAULT;
  141. dbg_buff[count] = '\0';
  142. sptr = dbg_buff;
  143. token = strsep(&sptr, " ");
  144. if (!token)
  145. return -EINVAL;
  146. if (kstrtou32(token, 0, &arg1))
  147. return -EINVAL;
  148. token = strsep(&sptr, " ");
  149. if (!token)
  150. return -EINVAL;
  151. if (kstrtou32(token, 0, &arg2))
  152. return -EINVAL;
  153. TDBG("arg1=%u arg2=%u\n", arg1, arg2);
  154. if (arg1 >= gsi_ctx->max_ch) {
  155. TERR("invalid chan id %u\n", arg1);
  156. return -EINVAL;
  157. }
  158. val = gsi_readl(gsi_ctx->base +
  159. GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(arg1, gsi_ctx->per.ee));
  160. TERR("CH%2d CTX0 0x%x\n", arg1, val);
  161. val = gsi_readl(gsi_ctx->base +
  162. GSI_EE_n_GSI_CH_k_CNTXT_1_OFFS(arg1, gsi_ctx->per.ee));
  163. TERR("CH%2d CTX1 0x%x\n", arg1, val);
  164. val = gsi_readl(gsi_ctx->base +
  165. GSI_EE_n_GSI_CH_k_CNTXT_2_OFFS(arg1, gsi_ctx->per.ee));
  166. TERR("CH%2d CTX2 0x%x\n", arg1, val);
  167. val = gsi_readl(gsi_ctx->base +
  168. GSI_EE_n_GSI_CH_k_CNTXT_3_OFFS(arg1, gsi_ctx->per.ee));
  169. TERR("CH%2d CTX3 0x%x\n", arg1, val);
  170. val = gsi_readl(gsi_ctx->base +
  171. GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(arg1, gsi_ctx->per.ee));
  172. TERR("CH%2d CTX4 0x%x\n", arg1, val);
  173. val = gsi_readl(gsi_ctx->base +
  174. GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(arg1, gsi_ctx->per.ee));
  175. TERR("CH%2d CTX5 0x%x\n", arg1, val);
  176. val = gsi_readl(gsi_ctx->base +
  177. GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(arg1, gsi_ctx->per.ee));
  178. TERR("CH%2d CTX6 0x%x\n", arg1, val);
  179. val = gsi_readl(gsi_ctx->base +
  180. GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(arg1, gsi_ctx->per.ee));
  181. TERR("CH%2d CTX7 0x%x\n", arg1, val);
  182. val = gsi_readl(gsi_ctx->base +
  183. GSI_EE_n_GSI_CH_k_RE_FETCH_READ_PTR_OFFS(arg1,
  184. gsi_ctx->per.ee));
  185. TERR("CH%2d REFRP 0x%x\n", arg1, val);
  186. val = gsi_readl(gsi_ctx->base +
  187. GSI_EE_n_GSI_CH_k_RE_FETCH_WRITE_PTR_OFFS(arg1,
  188. gsi_ctx->per.ee));
  189. TERR("CH%2d REFWP 0x%x\n", arg1, val);
  190. if (gsi_ctx->per.ver >= GSI_VER_2_5) {
  191. val = gsi_readl(gsi_ctx->base +
  192. GSI_V2_5_EE_n_GSI_CH_k_QOS_OFFS(arg1, gsi_ctx->per.ee));
  193. } else {
  194. val = gsi_readl(gsi_ctx->base +
  195. GSI_EE_n_GSI_CH_k_QOS_OFFS(arg1, gsi_ctx->per.ee));
  196. }
  197. TERR("CH%2d QOS 0x%x\n", arg1, val);
  198. val = gsi_readl(gsi_ctx->base +
  199. GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(arg1, gsi_ctx->per.ee));
  200. TERR("CH%2d SCR0 0x%x\n", arg1, val);
  201. val = gsi_readl(gsi_ctx->base +
  202. GSI_EE_n_GSI_CH_k_SCRATCH_1_OFFS(arg1, gsi_ctx->per.ee));
  203. TERR("CH%2d SCR1 0x%x\n", arg1, val);
  204. val = gsi_readl(gsi_ctx->base +
  205. GSI_EE_n_GSI_CH_k_SCRATCH_2_OFFS(arg1, gsi_ctx->per.ee));
  206. TERR("CH%2d SCR2 0x%x\n", arg1, val);
  207. val = gsi_readl(gsi_ctx->base +
  208. GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(arg1, gsi_ctx->per.ee));
  209. TERR("CH%2d SCR3 0x%x\n", arg1, val);
  210. if (arg2) {
  211. ctx = &gsi_ctx->chan[arg1];
  212. if (ctx->props.ring_base_vaddr) {
  213. for (i = 0; i < ctx->props.ring_len / 16; i++)
  214. TERR("CH%2d (0x%08llx) %08x %08x %08x %08x\n",
  215. arg1, ctx->props.ring_base_addr + i * 16,
  216. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  217. i * 16 + 0),
  218. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  219. i * 16 + 4),
  220. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  221. i * 16 + 8),
  222. *(u32 *)((u8 *)ctx->props.ring_base_vaddr +
  223. i * 16 + 12));
  224. } else {
  225. TERR("No VA supplied for chan id %u\n", arg1);
  226. }
  227. }
  228. return count;
  229. }
  230. static void gsi_dump_ch_stats(struct gsi_chan_ctx *ctx)
  231. {
  232. if (!ctx->allocated)
  233. return;
  234. PRT_STAT("CH%2d:\n", ctx->props.ch_id);
  235. PRT_STAT("queued=%lu compl=%lu\n",
  236. ctx->stats.queued,
  237. ctx->stats.completed);
  238. PRT_STAT("cb->poll=%lu poll->cb=%lu poll_pend_irq=%lu\n",
  239. ctx->stats.callback_to_poll,
  240. ctx->stats.poll_to_callback,
  241. ctx->stats.poll_pending_irq);
  242. PRT_STAT("invalid_tre_error=%lu\n",
  243. ctx->stats.invalid_tre_error);
  244. PRT_STAT("poll_ok=%lu poll_empty=%lu\n",
  245. ctx->stats.poll_ok, ctx->stats.poll_empty);
  246. if (ctx->evtr)
  247. PRT_STAT("compl_evt=%lu\n",
  248. ctx->evtr->stats.completed);
  249. PRT_STAT("userdata_in_use=%lu\n", ctx->stats.userdata_in_use);
  250. PRT_STAT("ch_below_lo=%lu\n", ctx->stats.dp.ch_below_lo);
  251. PRT_STAT("ch_below_hi=%lu\n", ctx->stats.dp.ch_below_hi);
  252. PRT_STAT("ch_above_hi=%lu\n", ctx->stats.dp.ch_above_hi);
  253. PRT_STAT("time_empty=%lums\n", ctx->stats.dp.empty_time);
  254. PRT_STAT("\n");
  255. }
  256. static ssize_t gsi_dump_stats(struct file *file,
  257. const char __user *buf, size_t count, loff_t *ppos)
  258. {
  259. int ch_id;
  260. int min, max, ret;
  261. ret = kstrtos32_from_user(buf, count, 0, &ch_id);
  262. if (ret)
  263. return ret;
  264. if (ch_id == -1) {
  265. min = 0;
  266. max = gsi_ctx->max_ch;
  267. } else if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  268. !gsi_ctx->chan[ch_id].allocated) {
  269. goto error;
  270. } else {
  271. min = ch_id;
  272. max = ch_id + 1;
  273. }
  274. for (ch_id = min; ch_id < max; ch_id++)
  275. gsi_dump_ch_stats(&gsi_ctx->chan[ch_id]);
  276. return count;
  277. error:
  278. TERR("Usage: echo ch_id > stats. Use -1 for all\n");
  279. return -EINVAL;
  280. }
  281. static int gsi_dbg_create_stats_wq(void)
  282. {
  283. gsi_ctx->dp_stat_wq =
  284. create_singlethread_workqueue("gsi_stat");
  285. if (!gsi_ctx->dp_stat_wq) {
  286. TERR("failed create workqueue\n");
  287. return -ENOMEM;
  288. }
  289. return 0;
  290. }
  291. static void gsi_dbg_destroy_stats_wq(void)
  292. {
  293. cancel_delayed_work_sync(&gsi_update_dp_stats_work);
  294. cancel_delayed_work_sync(&gsi_print_dp_stats_work);
  295. flush_workqueue(gsi_ctx->dp_stat_wq);
  296. destroy_workqueue(gsi_ctx->dp_stat_wq);
  297. gsi_ctx->dp_stat_wq = NULL;
  298. }
  299. static ssize_t gsi_enable_dp_stats(struct file *file,
  300. const char __user *buf, size_t count, loff_t *ppos)
  301. {
  302. int ch_id;
  303. bool enable;
  304. int ret;
  305. if (count >= sizeof(dbg_buff))
  306. goto error;
  307. if (copy_from_user(dbg_buff, buf, count))
  308. goto error;
  309. dbg_buff[count] = '\0';
  310. if (dbg_buff[0] != '+' && dbg_buff[0] != '-')
  311. goto error;
  312. enable = (dbg_buff[0] == '+');
  313. if (kstrtos32(dbg_buff + 1, 0, &ch_id))
  314. goto error;
  315. if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  316. !gsi_ctx->chan[ch_id].allocated) {
  317. goto error;
  318. }
  319. if (gsi_ctx->chan[ch_id].enable_dp_stats == enable) {
  320. TERR("ch_%d: already enabled/disabled\n", ch_id);
  321. return -EINVAL;
  322. }
  323. gsi_ctx->chan[ch_id].enable_dp_stats = enable;
  324. if (enable)
  325. gsi_ctx->num_ch_dp_stats++;
  326. else
  327. gsi_ctx->num_ch_dp_stats--;
  328. if (enable) {
  329. if (gsi_ctx->num_ch_dp_stats == 1) {
  330. ret = gsi_dbg_create_stats_wq();
  331. if (ret)
  332. return ret;
  333. }
  334. cancel_delayed_work_sync(&gsi_update_dp_stats_work);
  335. queue_delayed_work(gsi_ctx->dp_stat_wq,
  336. &gsi_update_dp_stats_work, msecs_to_jiffies(10));
  337. } else if (!enable && gsi_ctx->num_ch_dp_stats == 0) {
  338. gsi_dbg_destroy_stats_wq();
  339. }
  340. return count;
  341. error:
  342. TERR("Usage: echo [+-]ch_id > enable_dp_stats\n");
  343. return -EINVAL;
  344. }
  345. static ssize_t gsi_set_max_elem_dp_stats(struct file *file,
  346. const char __user *buf, size_t count, loff_t *ppos)
  347. {
  348. u32 ch_id;
  349. u32 max_elem;
  350. unsigned long missing;
  351. char *sptr, *token;
  352. if (count >= sizeof(dbg_buff))
  353. goto error;
  354. missing = copy_from_user(dbg_buff, buf, count);
  355. if (missing)
  356. goto error;
  357. dbg_buff[count] = '\0';
  358. sptr = dbg_buff;
  359. token = strsep(&sptr, " ");
  360. if (!token) {
  361. TERR("\n");
  362. goto error;
  363. }
  364. if (kstrtou32(token, 0, &ch_id)) {
  365. TERR("\n");
  366. goto error;
  367. }
  368. token = strsep(&sptr, " ");
  369. if (!token) {
  370. /* get */
  371. if (kstrtou32(dbg_buff, 0, &ch_id))
  372. goto error;
  373. if (ch_id >= gsi_ctx->max_ch)
  374. goto error;
  375. PRT_STAT("ch %d: max_re_expected=%d\n", ch_id,
  376. gsi_ctx->chan[ch_id].props.max_re_expected);
  377. return count;
  378. }
  379. if (kstrtou32(token, 0, &max_elem)) {
  380. TERR("\n");
  381. goto error;
  382. }
  383. TDBG("ch_id=%u max_elem=%u\n", ch_id, max_elem);
  384. if (ch_id >= gsi_ctx->max_ch) {
  385. TERR("invalid chan id %u\n", ch_id);
  386. goto error;
  387. }
  388. gsi_ctx->chan[ch_id].props.max_re_expected = max_elem;
  389. return count;
  390. error:
  391. TERR("Usage: (set) echo <ch_id> <max_elem> > max_elem_dp_stats\n");
  392. TERR("Usage: (get) echo <ch_id> > max_elem_dp_stats\n");
  393. return -EINVAL;
  394. }
  395. static void gsi_wq_print_dp_stats(struct work_struct *work)
  396. {
  397. int ch_id;
  398. for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
  399. if (gsi_ctx->chan[ch_id].print_dp_stats)
  400. gsi_dump_ch_stats(&gsi_ctx->chan[ch_id]);
  401. }
  402. queue_delayed_work(gsi_ctx->dp_stat_wq, &gsi_print_dp_stats_work,
  403. msecs_to_jiffies(1000));
  404. }
  405. static void gsi_dbg_update_ch_dp_stats(struct gsi_chan_ctx *ctx)
  406. {
  407. uint16_t start_hw;
  408. uint16_t end_hw;
  409. uint64_t rp_hw;
  410. uint64_t wp_hw;
  411. int ee = gsi_ctx->per.ee;
  412. uint16_t used_hw;
  413. rp_hw = gsi_readl(gsi_ctx->base +
  414. GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
  415. rp_hw |= ((uint64_t)gsi_readl(gsi_ctx->base +
  416. GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee)))
  417. << 32;
  418. wp_hw = gsi_readl(gsi_ctx->base +
  419. GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(ctx->props.ch_id, ee));
  420. wp_hw |= ((uint64_t)gsi_readl(gsi_ctx->base +
  421. GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(ctx->props.ch_id, ee)))
  422. << 32;
  423. start_hw = gsi_find_idx_from_addr(&ctx->ring, rp_hw);
  424. end_hw = gsi_find_idx_from_addr(&ctx->ring, wp_hw);
  425. if (end_hw >= start_hw)
  426. used_hw = end_hw - start_hw;
  427. else
  428. used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end_hw);
  429. TDBG("ch %d used %d\n", ctx->props.ch_id, used_hw);
  430. gsi_update_ch_dp_stats(ctx, used_hw);
  431. }
  432. static void gsi_wq_update_dp_stats(struct work_struct *work)
  433. {
  434. int ch_id;
  435. for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
  436. if (gsi_ctx->chan[ch_id].allocated &&
  437. gsi_ctx->chan[ch_id].enable_dp_stats)
  438. gsi_dbg_update_ch_dp_stats(&gsi_ctx->chan[ch_id]);
  439. }
  440. queue_delayed_work(gsi_ctx->dp_stat_wq, &gsi_update_dp_stats_work,
  441. msecs_to_jiffies(10));
  442. }
  443. static ssize_t gsi_rst_stats(struct file *file,
  444. const char __user *buf, size_t count, loff_t *ppos)
  445. {
  446. int ch_id;
  447. int min, max, ret;
  448. ret = kstrtos32_from_user(buf, count, 0, &ch_id);
  449. if (ret)
  450. return ret;
  451. if (ch_id == -1) {
  452. min = 0;
  453. max = gsi_ctx->max_ch;
  454. } else if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  455. !gsi_ctx->chan[ch_id].allocated) {
  456. goto error;
  457. } else {
  458. min = ch_id;
  459. max = ch_id + 1;
  460. }
  461. for (ch_id = min; ch_id < max; ch_id++)
  462. memset(&gsi_ctx->chan[ch_id].stats, 0,
  463. sizeof(gsi_ctx->chan[ch_id].stats));
  464. return count;
  465. error:
  466. TERR("Usage: echo ch_id > rst_stats. Use -1 for all\n");
  467. return -EINVAL;
  468. }
  469. static ssize_t gsi_print_dp_stats(struct file *file,
  470. const char __user *buf, size_t count, loff_t *ppos)
  471. {
  472. int ch_id;
  473. bool enable;
  474. int ret;
  475. if (count >= sizeof(dbg_buff))
  476. goto error;
  477. if (copy_from_user(dbg_buff, buf, count))
  478. goto error;
  479. dbg_buff[count] = '\0';
  480. if (dbg_buff[0] != '+' && dbg_buff[0] != '-')
  481. goto error;
  482. enable = (dbg_buff[0] == '+');
  483. if (kstrtos32(dbg_buff + 1, 0, &ch_id))
  484. goto error;
  485. if (ch_id < 0 || ch_id >= gsi_ctx->max_ch ||
  486. !gsi_ctx->chan[ch_id].allocated) {
  487. goto error;
  488. }
  489. if (gsi_ctx->chan[ch_id].print_dp_stats == enable) {
  490. TERR("ch_%d: already enabled/disabled\n", ch_id);
  491. return -EINVAL;
  492. }
  493. gsi_ctx->chan[ch_id].print_dp_stats = enable;
  494. if (enable)
  495. gsi_ctx->num_ch_dp_stats++;
  496. else
  497. gsi_ctx->num_ch_dp_stats--;
  498. if (enable) {
  499. if (gsi_ctx->num_ch_dp_stats == 1) {
  500. ret = gsi_dbg_create_stats_wq();
  501. if (ret)
  502. return ret;
  503. }
  504. cancel_delayed_work_sync(&gsi_print_dp_stats_work);
  505. queue_delayed_work(gsi_ctx->dp_stat_wq,
  506. &gsi_print_dp_stats_work, msecs_to_jiffies(10));
  507. } else if (!enable && gsi_ctx->num_ch_dp_stats == 0) {
  508. gsi_dbg_destroy_stats_wq();
  509. }
  510. return count;
  511. error:
  512. TERR("Usage: echo [+-]ch_id > print_dp_stats\n");
  513. return -EINVAL;
  514. }
  515. static ssize_t gsi_enable_ipc_low(struct file *file,
  516. const char __user *ubuf, size_t count, loff_t *ppos)
  517. {
  518. s8 option = 0;
  519. int ret;
  520. ret = kstrtos8_from_user(ubuf, count, 0, &option);
  521. if (ret)
  522. return ret;
  523. mutex_lock(&gsi_ctx->mlock);
  524. if (option) {
  525. if (!gsi_ipc_logbuf_low) {
  526. gsi_ipc_logbuf_low =
  527. ipc_log_context_create(GSI_IPC_LOG_PAGES,
  528. "gsi_low", 0);
  529. if (gsi_ipc_logbuf_low == NULL)
  530. TERR("failed to get ipc_logbuf_low\n");
  531. }
  532. gsi_ctx->ipc_logbuf_low = gsi_ipc_logbuf_low;
  533. } else {
  534. gsi_ctx->ipc_logbuf_low = NULL;
  535. }
  536. mutex_unlock(&gsi_ctx->mlock);
  537. return count;
  538. }
  539. static const struct file_operations gsi_ev_dump_ops = {
  540. .write = gsi_dump_evt,
  541. };
  542. static const struct file_operations gsi_ch_dump_ops = {
  543. .write = gsi_dump_ch,
  544. };
  545. static const struct file_operations gsi_stats_ops = {
  546. .write = gsi_dump_stats,
  547. };
  548. static const struct file_operations gsi_enable_dp_stats_ops = {
  549. .write = gsi_enable_dp_stats,
  550. };
  551. static const struct file_operations gsi_max_elem_dp_stats_ops = {
  552. .write = gsi_set_max_elem_dp_stats,
  553. };
  554. static const struct file_operations gsi_rst_stats_ops = {
  555. .write = gsi_rst_stats,
  556. };
  557. static const struct file_operations gsi_print_dp_stats_ops = {
  558. .write = gsi_print_dp_stats,
  559. };
  560. static const struct file_operations gsi_ipc_low_ops = {
  561. .write = gsi_enable_ipc_low,
  562. };
  563. void gsi_debugfs_init(void)
  564. {
  565. static struct dentry *dfile;
  566. const mode_t write_only_mode = 0220;
  567. dent = debugfs_create_dir("gsi", 0);
  568. if (IS_ERR(dent)) {
  569. TERR("fail to create dir\n");
  570. return;
  571. }
  572. dfile = debugfs_create_file("ev_dump", write_only_mode,
  573. dent, 0, &gsi_ev_dump_ops);
  574. if (!dfile || IS_ERR(dfile)) {
  575. TERR("fail to create ev_dump file\n");
  576. goto fail;
  577. }
  578. dfile = debugfs_create_file("ch_dump", write_only_mode,
  579. dent, 0, &gsi_ch_dump_ops);
  580. if (!dfile || IS_ERR(dfile)) {
  581. TERR("fail to create ch_dump file\n");
  582. goto fail;
  583. }
  584. dfile = debugfs_create_file("stats", write_only_mode, dent,
  585. 0, &gsi_stats_ops);
  586. if (!dfile || IS_ERR(dfile)) {
  587. TERR("fail to create stats file\n");
  588. goto fail;
  589. }
  590. dfile = debugfs_create_file("enable_dp_stats", write_only_mode, dent,
  591. 0, &gsi_enable_dp_stats_ops);
  592. if (!dfile || IS_ERR(dfile)) {
  593. TERR("fail to create stats file\n");
  594. goto fail;
  595. }
  596. dfile = debugfs_create_file("max_elem_dp_stats", write_only_mode,
  597. dent, 0, &gsi_max_elem_dp_stats_ops);
  598. if (!dfile || IS_ERR(dfile)) {
  599. TERR("fail to create stats file\n");
  600. goto fail;
  601. }
  602. dfile = debugfs_create_file("rst_stats", write_only_mode,
  603. dent, 0, &gsi_rst_stats_ops);
  604. if (!dfile || IS_ERR(dfile)) {
  605. TERR("fail to create stats file\n");
  606. goto fail;
  607. }
  608. dfile = debugfs_create_file("print_dp_stats",
  609. write_only_mode, dent, 0, &gsi_print_dp_stats_ops);
  610. if (!dfile || IS_ERR(dfile)) {
  611. TERR("fail to create stats file\n");
  612. goto fail;
  613. }
  614. dfile = debugfs_create_file("ipc_low", write_only_mode,
  615. dent, 0, &gsi_ipc_low_ops);
  616. if (!dfile || IS_ERR(dfile)) {
  617. TERR("could not create ipc_low\n");
  618. goto fail;
  619. }
  620. return;
  621. fail:
  622. debugfs_remove_recursive(dent);
  623. }