hab_stat.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include "hab.h"
  7. #include "hab_grantable.h"
  8. #define MAX_LINE_SIZE 128
  9. int hab_stat_init(struct hab_driver *driver)
  10. {
  11. return hab_stat_init_sub(driver);
  12. }
  13. int hab_stat_deinit(struct hab_driver *driver)
  14. {
  15. return hab_stat_deinit_sub(driver);
  16. }
  17. /*
  18. * If all goes well the return value is the formated print and concatenated
  19. * original dest string.
  20. */
  21. int hab_stat_buffer_print(char *dest,
  22. int dest_size, const char *fmt, ...)
  23. {
  24. va_list args;
  25. char line[MAX_LINE_SIZE];
  26. int ret;
  27. va_start(args, fmt);
  28. ret = vsnprintf(line, sizeof(line), fmt, args);
  29. va_end(args);
  30. if (ret > 0)
  31. ret = strlcat(dest, line, dest_size);
  32. return ret;
  33. }
  34. int hab_stat_show_vchan(struct hab_driver *driver,
  35. char *buf, int size)
  36. {
  37. int i, ret = 0;
  38. ret = strscpy(buf, "", size);
  39. for (i = 0; i < driver->ndevices; i++) {
  40. struct hab_device *dev = &driver->devp[i];
  41. struct physical_channel *pchan;
  42. struct virtual_channel *vc;
  43. read_lock_bh(&dev->pchan_lock);
  44. list_for_each_entry(pchan, &dev->pchannels, node) {
  45. if (!pchan->vcnt)
  46. continue;
  47. ret = hab_stat_buffer_print(buf, size,
  48. "nm %s r %d lc %d rm %d sq_t %d sq_r %d st 0x%x vn %d:\n",
  49. pchan->name, pchan->is_be, pchan->vmid_local,
  50. pchan->vmid_remote, pchan->sequence_tx,
  51. pchan->sequence_rx, pchan->status, pchan->vcnt);
  52. read_lock(&pchan->vchans_lock);
  53. list_for_each_entry(vc, &pchan->vchannels, pnode) {
  54. ret = hab_stat_buffer_print(buf, size,
  55. "%08X(%d:%d:%d:%ld:%ld:%d) ", vc->id,
  56. get_refcnt(vc->refcount),
  57. vc->otherend_closed,
  58. vc->closed,
  59. atomic64_read(&vc->tx_cnt),
  60. atomic64_read(&vc->rx_cnt),
  61. vc->rx_inflight);
  62. }
  63. ret = hab_stat_buffer_print(buf, size, "\n");
  64. read_unlock(&pchan->vchans_lock);
  65. }
  66. read_unlock_bh(&dev->pchan_lock);
  67. }
  68. return ret;
  69. }
  70. int hab_stat_show_ctx(struct hab_driver *driver,
  71. char *buf, int size)
  72. {
  73. int ret = 0;
  74. struct uhab_context *ctx;
  75. ret = strscpy(buf, "", size);
  76. spin_lock_bh(&hab_driver.drvlock);
  77. ret = hab_stat_buffer_print(buf, size,
  78. "Total contexts %d\n",
  79. driver->ctx_cnt);
  80. list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
  81. ret = hab_stat_buffer_print(buf, size,
  82. "ctx %d K %d close %d vc %d exp %d imp %d open %d ref %d grp %s\n",
  83. ctx->owner, ctx->kernel, ctx->closing,
  84. ctx->vcnt, ctx->export_total,
  85. ctx->import_total, ctx->pending_cnt,
  86. get_refcnt(ctx->refcount),
  87. ctx->kernel ? "" : HAB_MMID_MAP_NODE(ctx->mmid_grp_index * 100));
  88. }
  89. spin_unlock_bh(&hab_driver.drvlock);
  90. return ret;
  91. }
  92. static int get_pft_tbl_total_size(struct compressed_pfns *pfn_table)
  93. {
  94. int i, total_size = 0;
  95. for (i = 0; i < pfn_table->nregions; i++)
  96. total_size += pfn_table->region[i].size * PAGE_SIZE;
  97. return total_size;
  98. }
  99. static int print_ctx_total_expimp(struct uhab_context *ctx,
  100. char *buf, int size)
  101. {
  102. struct compressed_pfns *pfn_table = NULL;
  103. int exp_total = 0, imp_total = 0;
  104. int exp_cnt = 0, imp_cnt = 0;
  105. struct export_desc *exp = NULL;
  106. int exim_size = 0;
  107. int ret = 0;
  108. read_lock(&ctx->exp_lock);
  109. list_for_each_entry(exp, &ctx->exp_whse, node) {
  110. pfn_table = (struct compressed_pfns *)exp->payload;
  111. exim_size = get_pft_tbl_total_size(pfn_table);
  112. exp_total += exim_size;
  113. exp_cnt++;
  114. }
  115. read_unlock(&ctx->exp_lock);
  116. spin_lock_bh(&ctx->imp_lock);
  117. list_for_each_entry(exp, &ctx->imp_whse, node) {
  118. if (habmm_imp_hyp_map_check(ctx->import_ctx, exp)) {
  119. pfn_table = (struct compressed_pfns *)exp->payload;
  120. exim_size = get_pft_tbl_total_size(pfn_table);
  121. imp_total += exim_size;
  122. imp_cnt++;
  123. }
  124. }
  125. spin_unlock_bh(&ctx->imp_lock);
  126. if (exp_cnt || exp_total || imp_cnt || imp_total)
  127. hab_stat_buffer_print(buf, size,
  128. "ctx %d exp %d size %d imp %d size %d\n",
  129. ctx->owner, exp_cnt, exp_total,
  130. imp_cnt, imp_total);
  131. else
  132. return 0;
  133. read_lock(&ctx->exp_lock);
  134. hab_stat_buffer_print(buf, size, "export[expid:vcid:size]: ");
  135. list_for_each_entry(exp, &ctx->exp_whse, node) {
  136. pfn_table = (struct compressed_pfns *)exp->payload;
  137. exim_size = get_pft_tbl_total_size(pfn_table);
  138. hab_stat_buffer_print(buf, size,
  139. "[%d:%x:%d] ", exp->export_id,
  140. exp->vcid_local, exim_size);
  141. }
  142. hab_stat_buffer_print(buf, size, "\n");
  143. read_unlock(&ctx->exp_lock);
  144. spin_lock_bh(&ctx->imp_lock);
  145. hab_stat_buffer_print(buf, size, "import[expid:vcid:size]: ");
  146. list_for_each_entry(exp, &ctx->imp_whse, node) {
  147. if (habmm_imp_hyp_map_check(ctx->import_ctx, exp)) {
  148. pfn_table = (struct compressed_pfns *)exp->payload;
  149. exim_size = get_pft_tbl_total_size(pfn_table);
  150. hab_stat_buffer_print(buf, size,
  151. "[%d:%x:%d] ", exp->export_id,
  152. exp->vcid_local, exim_size);
  153. }
  154. }
  155. ret = hab_stat_buffer_print(buf, size, "\n");
  156. spin_unlock_bh(&ctx->imp_lock);
  157. return ret;
  158. }
  159. int hab_stat_show_expimp(struct hab_driver *driver,
  160. int pid, char *buf, int size)
  161. {
  162. struct uhab_context *ctx = NULL;
  163. int ret = 0;
  164. struct virtual_channel *vchan = NULL;
  165. int mmid = 0;
  166. struct physical_channel *pchans[HABCFG_MMID_NUM];
  167. int pchan_count = 0;
  168. (void)driver;
  169. ret = strscpy(buf, "", size);
  170. spin_lock_bh(&hab_driver.drvlock);
  171. list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
  172. if (pid == ctx->owner) {
  173. ret = print_ctx_total_expimp(ctx, buf, size);
  174. list_for_each_entry(vchan, &ctx->vchannels, node) {
  175. if (vchan->pchan->habdev->id != mmid) {
  176. mmid = vchan->pchan->habdev->id;
  177. pchans[pchan_count++] = vchan->pchan;
  178. if (pchan_count >= HABCFG_MMID_NUM)
  179. break;
  180. }
  181. }
  182. }
  183. }
  184. spin_unlock_bh(&hab_driver.drvlock);
  185. /* print pchannel status, drvlock is not required */
  186. if (pchan_count > 0)
  187. ret = hab_stat_log(pchans, pchan_count, buf, size);
  188. return ret;
  189. }
  190. int hab_stat_show_reclaim(struct hab_driver *driver, char *buf, int size)
  191. {
  192. struct export_desc *exp = NULL;
  193. struct compressed_pfns *pfn_table = NULL;
  194. int exim_size = 0;
  195. size_t total_size = 0, total_num = 0;
  196. (void)strscpy(buf, "", size);
  197. (void)hab_stat_buffer_print(buf, size, "export[expid:vcid:size:pchan]:\n");
  198. spin_lock(&hab_driver.reclaim_lock);
  199. list_for_each_entry(exp, &hab_driver.reclaim_list, node) {
  200. pfn_table = (struct compressed_pfns *)exp->payload;
  201. exim_size = get_pft_tbl_total_size(pfn_table);
  202. total_size += exim_size;
  203. total_num++;
  204. (void)hab_stat_buffer_print(buf, size, "[%d:%x:%d:%s] ",
  205. exp->export_id,
  206. exp->vcid_local,
  207. exim_size,
  208. exp->pchan->name);
  209. (void)hab_stat_buffer_print(buf, size, "\n");
  210. }
  211. spin_unlock(&hab_driver.reclaim_lock);
  212. return hab_stat_buffer_print(buf, size, "total: %u, size %u\n", total_num, total_size);
  213. }
  214. #define HAB_PIPE_DUMP_FILE_NAME "/sdcard/habpipe-"
  215. #define HAB_PIPE_DUMP_FILE_EXT ".dat"
  216. #define HAB_PIPEDUMP_SIZE (768*1024*4)
  217. static char *filp;
  218. static int pipedump_idx;
  219. int dump_hab_open(void)
  220. {
  221. int rc = 0;
  222. char file_path[256];
  223. char file_time[100];
  224. rc = dump_hab_get_file_name(file_time, sizeof(file_time));
  225. strscpy(file_path, HAB_PIPE_DUMP_FILE_NAME, sizeof(file_path));
  226. strlcat(file_path, file_time, sizeof(file_path));
  227. strlcat(file_path, HAB_PIPE_DUMP_FILE_EXT, sizeof(file_path));
  228. filp = vmalloc(HAB_PIPEDUMP_SIZE);
  229. if (IS_ERR(filp)) {
  230. rc = PTR_ERR(filp);
  231. pr_err("failed to create pipe dump buffer rc %d\n", rc);
  232. filp = NULL;
  233. } else {
  234. pr_info("hab pipe dump buffer opened %s\n", file_path);
  235. pipedump_idx = 0;
  236. dump_hab_buf(file_path, strlen(file_path)); /* id first */
  237. }
  238. return rc;
  239. }
  240. void dump_hab_close(void)
  241. {
  242. pr_info("pipe dump content size %d completed\n", pipedump_idx);
  243. /* transfer buffer ownership to devcoredump */
  244. filp = NULL;
  245. pipedump_idx = 0;
  246. }
  247. int dump_hab_buf(void *buf, int size)
  248. {
  249. if (!buf || !size || size > HAB_PIPEDUMP_SIZE - pipedump_idx) {
  250. pr_err("wrong parameters buf %pK size %d allowed %d\n",
  251. buf, size, HAB_PIPEDUMP_SIZE - pipedump_idx);
  252. return 0;
  253. }
  254. memcpy(&filp[pipedump_idx], buf, size);
  255. pipedump_idx += size;
  256. return size;
  257. }
  258. void dump_hab(int mmid)
  259. {
  260. struct physical_channel *pchan = NULL;
  261. int i = 0;
  262. char str[8] = {35, 35, 35, 35, 35, 35, 35, 35}; /* ## */
  263. dump_hab_open();
  264. for (i = 0; i < hab_driver.ndevices; i++) {
  265. struct hab_device *habdev = &hab_driver.devp[i];
  266. if (habdev->id == mmid) {
  267. list_for_each_entry(pchan, &habdev->pchannels, node) {
  268. if (pchan->vcnt > 0) {
  269. pr_info("***** dump pchan %s vcnt %d *****\n",
  270. pchan->name, pchan->vcnt);
  271. hab_pipe_read_dump(pchan);
  272. break;
  273. }
  274. }
  275. dump_hab_buf(str, 8); /* separator */
  276. }
  277. }
  278. dev_coredumpv(hab_driver.dev[mmid / 100], filp, pipedump_idx, GFP_KERNEL);
  279. dump_hab_close();
  280. }