sysmon_subsystem_stats.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/of.h>
  7. #include <linux/platform_device.h>
  8. #include <linux/soc/qcom/smem.h>
  9. #include <linux/debugfs.h>
  10. #include <linux/delay.h>
  11. #include <linux/soc/qcom/sysmon_subsystem_stats.h>
  12. #define SYSMON_SMEM_ID 634
  13. #define SLEEPSTATS_SMEM_ID_ADSP 606
  14. #define SLEEPSTATS_SMEM_ID_CDSP 607
  15. #define SLEEPSTATS_SMEM_ID_SLPI 608
  16. #define SLEEPSTATS_LPI_SMEM_ID 613
  17. #define DSPPMSTATS_SMEM_ID 624
  18. #define SYS_CLK_TICKS_PER_MS 19200
  19. #define SYS_CLK_TICKS_PER_SEC 19200000
  20. #define DSPPMSTATS_NUMPD 5
  21. #define HMX_HVX_PMU_EVENTS_NA 0xFFFF
  22. struct pd_clients {
  23. int pid;
  24. u32 num_active;
  25. };
  26. struct dsppm_stats {
  27. u32 version;
  28. u32 latency_us;
  29. u32 timestamp;
  30. struct pd_clients pd[DSPPMSTATS_NUMPD];
  31. };
  32. struct sysmon_smem_power_stats_extended {
  33. struct sysmon_smem_power_stats powerstats;
  34. /**< Powerstats data */
  35. u32 last_update_time_powerstats_lsb;
  36. /**< Powerstats updated timestamp (lower significant 32 bits) */
  37. u32 last_update_time_powerstats_msb;
  38. /**< Powerstats updated timestamp (Most significant 32 bits) */
  39. };
  40. struct sysmon_smem_stats {
  41. bool smem_init_adsp;
  42. bool smem_init_cdsp;
  43. bool smem_init_slpi;
  44. bool smem_init_cdsp_v2;
  45. struct sysmon_smem_power_stats_extended *sysmon_power_stats_adsp;
  46. struct sysmon_smem_power_stats_extended *sysmon_power_stats_cdsp;
  47. struct sysmon_smem_power_stats_extended *sysmon_power_stats_slpi;
  48. struct sysmon_smem_q6_event_stats *sysmon_event_stats_adsp;
  49. struct sysmon_smem_q6_event_stats *sysmon_event_stats_cdsp;
  50. struct sysmon_smem_q6_event_stats *sysmon_event_stats_slpi;
  51. struct sleep_stats *sleep_stats_adsp;
  52. struct sleep_stats *sleep_stats_cdsp;
  53. struct sleep_stats *sleep_stats_slpi;
  54. struct sleep_stats_island *sleep_lpi_adsp;
  55. struct sleep_stats_island *sleep_lpi_slpi;
  56. u32 *q6_avg_load_adsp;
  57. u32 *q6_avg_load_cdsp;
  58. u32 *q6_avg_load_slpi;
  59. struct dsppm_stats *dsppm_stats_adsp;
  60. struct dsppm_stats *dsppm_stats_cdsp;
  61. struct dentry *debugfs_dir;
  62. struct dentry *debugfs_master_adsp_stats;
  63. struct dentry *debugfs_master_cdsp_stats;
  64. u32 *hmx_util;
  65. u32 *hvx_util;
  66. };
  67. enum feature_id {
  68. SYSMONSTATS_Q6_LOAD_FEATUREID = 1,
  69. SYSMONSTATS_Q6_EVENT_FEATUREID,
  70. SYSMON_POWER_STATS_FEATUREID,
  71. SYSMON_HMX_UTIL_FEATUREID,
  72. SYSMON_HVX_UTIL_FEATUREID
  73. };
  74. struct sysmon_smem_q6_load_stats {
  75. u32 q6load_avg;
  76. u32 Last_update_time_load_lsb;
  77. u32 Last_update_time_load_msb;
  78. };
  79. struct sysmon_smem_hvx_stats {
  80. u32 hvx_util_avg;
  81. u32 Last_update_time_load_lsb;
  82. u32 Last_update_time_load_msb;
  83. };
  84. struct sysmon_smem_hmx_stats {
  85. u32 hmx_util_avg;
  86. u32 Last_update_time_load_lsb;
  87. u32 Last_update_time_load_msb;
  88. };
  89. static struct sysmon_smem_stats g_sysmon_stats;
  90. /* Adds delta between SMEM powerstats updated time to current time */
  91. static int add_delta_time(
  92. u8 ver,
  93. u64 lpi_acc, u64 lpm_acc,
  94. struct sysmon_smem_power_stats_extended *stats
  95. )
  96. {
  97. u64 powerstats_ticks = 0, curr_timestamp = 0, diff_ticks = 0;
  98. u64 pc_time = 0, lpi_time = 0, active_time = 0, diff_time = 0;
  99. u8 j = 0;
  100. if (ver >= 2) {
  101. powerstats_ticks = (u64)(((u64)stats->last_update_time_powerstats_msb << 32) |
  102. stats->last_update_time_powerstats_lsb);
  103. curr_timestamp = __arch_counter_get_cntvct();
  104. if (curr_timestamp < powerstats_ticks)
  105. diff_ticks = curr_timestamp + (ULLONG_MAX - powerstats_ticks);
  106. else
  107. diff_ticks = (curr_timestamp - powerstats_ticks);
  108. diff_time = (diff_ticks / SYS_CLK_TICKS_PER_SEC);
  109. if (diff_time > 0) {
  110. pc_time = (lpm_acc / SYS_CLK_TICKS_PER_SEC);
  111. lpi_time = (lpi_acc / SYS_CLK_TICKS_PER_SEC);
  112. if (pc_time >= stats->powerstats.pc_time)
  113. pc_time -= stats->powerstats.pc_time;
  114. if (diff_time >= pc_time)
  115. active_time = diff_time - pc_time;
  116. if ((lpi_time) && (lpi_time >= stats->powerstats.lpi_time))
  117. lpi_time -= stats->powerstats.lpi_time;
  118. if ((lpi_time) && (pc_time >= lpi_time))
  119. pc_time -= lpi_time;
  120. for (j = 0; j < SYSMON_POWER_STATS_MAX_CLK_LEVELS; j++) {
  121. if (stats->powerstats.clk_arr[j] == stats->powerstats.current_clk) {
  122. stats->powerstats.active_time[j] += active_time;
  123. stats->powerstats.island_time[j] += lpi_time;
  124. break;
  125. }
  126. }
  127. if (j >= SYSMON_POWER_STATS_MAX_CLK_LEVELS) {
  128. pr_err("%s: Current clock level %u KHz didn't match with any clock level\n",
  129. __func__, stats->powerstats.current_clk);
  130. return -EINVAL;
  131. }
  132. stats->powerstats.pc_time += pc_time;
  133. stats->powerstats.lpi_time += lpi_time;
  134. }
  135. }
  136. return 0;
  137. }
  138. /*Updates SMEM pointers for all the sysmon Master stats*/
  139. static void update_sysmon_smem_pointers(void *smem_pointer, enum dsp_id_t dsp_id, size_t size)
  140. {
  141. u32 featureId;
  142. int feature, size_rcvd;
  143. int size_of_u32 = sizeof(u32);
  144. featureId = *(unsigned int *)smem_pointer;
  145. feature = featureId >> 28;
  146. size_rcvd = (featureId >> 16) & 0xFFF;
  147. while ((size > 0) && (size >= size_rcvd)) {
  148. switch (feature) {
  149. case SYSMON_POWER_STATS_FEATUREID:
  150. if (!IS_ERR_OR_NULL(smem_pointer + size_of_u32)) {
  151. if (dsp_id == ADSP)
  152. g_sysmon_stats.sysmon_power_stats_adsp =
  153. (struct sysmon_smem_power_stats_extended *)
  154. (smem_pointer);
  155. else if (dsp_id == CDSP)
  156. g_sysmon_stats.sysmon_power_stats_cdsp =
  157. (struct sysmon_smem_power_stats_extended *)
  158. (smem_pointer);
  159. else if (dsp_id == SLPI)
  160. g_sysmon_stats.sysmon_power_stats_slpi =
  161. (struct sysmon_smem_power_stats_extended *)
  162. (smem_pointer);
  163. else
  164. pr_err("%s: subsystem not found %d\n",
  165. __func__, SYSMON_POWER_STATS_FEATUREID);
  166. } else {
  167. pr_err("%s: Failed to fetch %d feature pointer\n",
  168. __func__, SYSMON_POWER_STATS_FEATUREID);
  169. size = 0;
  170. }
  171. break;
  172. case SYSMONSTATS_Q6_EVENT_FEATUREID:
  173. if (!IS_ERR_OR_NULL(smem_pointer + size_of_u32)) {
  174. if (dsp_id == ADSP)
  175. g_sysmon_stats.sysmon_event_stats_adsp =
  176. (struct sysmon_smem_q6_event_stats *)
  177. (smem_pointer + size_of_u32);
  178. else if (dsp_id == CDSP)
  179. g_sysmon_stats.sysmon_event_stats_cdsp =
  180. (struct sysmon_smem_q6_event_stats *)
  181. (smem_pointer + size_of_u32);
  182. else if (dsp_id == SLPI)
  183. g_sysmon_stats.sysmon_event_stats_slpi =
  184. (struct sysmon_smem_q6_event_stats *)
  185. (smem_pointer + size_of_u32);
  186. else
  187. pr_err("%s:subsystem not found %d\n",
  188. __func__, SYSMONSTATS_Q6_EVENT_FEATUREID);
  189. } else {
  190. pr_err("%s: Failed to fetch %d feature pointer\n",
  191. __func__, SYSMONSTATS_Q6_EVENT_FEATUREID);
  192. size = 0;
  193. }
  194. break;
  195. case SYSMONSTATS_Q6_LOAD_FEATUREID:
  196. if (!IS_ERR_OR_NULL(smem_pointer + size_of_u32)) {
  197. if (dsp_id == ADSP)
  198. g_sysmon_stats.q6_avg_load_adsp =
  199. (u32 *)(smem_pointer + size_of_u32);
  200. else if (dsp_id == CDSP)
  201. g_sysmon_stats.q6_avg_load_cdsp =
  202. (u32 *)(smem_pointer + size_of_u32);
  203. else if (dsp_id == SLPI)
  204. g_sysmon_stats.q6_avg_load_slpi =
  205. (u32 *)(smem_pointer + size_of_u32);
  206. else
  207. pr_err("%s:subsystem not found %d\n",
  208. __func__, SYSMONSTATS_Q6_LOAD_FEATUREID);
  209. } else {
  210. pr_err("%s: Failed to fetch %d feature pointer\n",
  211. __func__, SYSMONSTATS_Q6_LOAD_FEATUREID);
  212. size = 0;
  213. }
  214. break;
  215. case SYSMON_HMX_UTIL_FEATUREID:
  216. if (!IS_ERR_OR_NULL(smem_pointer + size_of_u32)) {
  217. if (dsp_id == CDSP) {
  218. g_sysmon_stats.hmx_util =
  219. (u32 *)(smem_pointer + size_of_u32);
  220. } else
  221. pr_err("%s:subsystem not supported %d\n",
  222. __func__, SYSMON_HMX_UTIL_FEATUREID);
  223. } else {
  224. pr_err("%s: Failed to fetch %d feature pointer\n",
  225. __func__, SYSMON_HMX_UTIL_FEATUREID);
  226. size = 0;
  227. }
  228. break;
  229. case SYSMON_HVX_UTIL_FEATUREID:
  230. if (!IS_ERR_OR_NULL(smem_pointer + size_of_u32)) {
  231. if (dsp_id == CDSP) {
  232. g_sysmon_stats.hvx_util =
  233. (u32 *)(smem_pointer + size_of_u32);
  234. } else
  235. pr_err("%s:subsystem not supported %d\n",
  236. __func__, SYSMON_HVX_UTIL_FEATUREID);
  237. } else {
  238. pr_err("%s: Failed to fetch %d feature pointer\n",
  239. __func__, SYSMON_HVX_UTIL_FEATUREID);
  240. size = 0;
  241. }
  242. break;
  243. default:
  244. pr_err("%s: Requested feature not found, Feature:%u\n",
  245. __func__, feature);
  246. break;
  247. }
  248. if (!IS_ERR_OR_NULL(smem_pointer + size_rcvd)
  249. && (size > size_rcvd)) {
  250. featureId = *(unsigned int *)(smem_pointer + size_rcvd);
  251. smem_pointer += size_rcvd;
  252. size = size - size_rcvd;
  253. feature = featureId >> 28;
  254. size_rcvd = (featureId >> 16) & 0xFFF;
  255. } else {
  256. size = 0;
  257. }
  258. }
  259. }
  260. static void sysmon_smem_init_adsp(void)
  261. {
  262. size_t size;
  263. void *smem_pointer_adsp = NULL;
  264. g_sysmon_stats.smem_init_adsp = true;
  265. g_sysmon_stats.dsppm_stats_adsp = qcom_smem_get(ADSP,
  266. DSPPMSTATS_SMEM_ID,
  267. &size);
  268. if (IS_ERR_OR_NULL(g_sysmon_stats.dsppm_stats_adsp) ||
  269. (sizeof(struct dsppm_stats) > size)) {
  270. pr_err("%s:Failed to get fetch dsppm stats from SMEM for ADSP: %d, size: %d\n",
  271. __func__, PTR_ERR(g_sysmon_stats.dsppm_stats_adsp), size);
  272. g_sysmon_stats.smem_init_adsp = false;
  273. }
  274. g_sysmon_stats.sleep_stats_adsp = qcom_smem_get(ADSP,
  275. SLEEPSTATS_SMEM_ID_ADSP,
  276. &size);
  277. if (IS_ERR_OR_NULL(g_sysmon_stats.sleep_stats_adsp) ||
  278. (sizeof(struct sleep_stats) > size)) {
  279. pr_err("%s:Failed to get fetch sleep data from SMEM for ADSP: %d, size: %d\n",
  280. __func__, PTR_ERR(g_sysmon_stats.sleep_stats_adsp), size);
  281. g_sysmon_stats.smem_init_adsp = false;
  282. }
  283. g_sysmon_stats.sleep_lpi_adsp = qcom_smem_get(ADSP,
  284. SLEEPSTATS_LPI_SMEM_ID,
  285. &size);
  286. if (IS_ERR_OR_NULL(g_sysmon_stats.sleep_lpi_adsp) ||
  287. (sizeof(struct sleep_stats_island) > size)) {
  288. pr_err("%s:Failed to get fetch LPI sleep data from SMEM for ADSP: %d, size: %d\n",
  289. __func__, PTR_ERR(g_sysmon_stats.sleep_lpi_adsp), size);
  290. g_sysmon_stats.smem_init_adsp = false;
  291. }
  292. smem_pointer_adsp = qcom_smem_get(ADSP,
  293. SYSMON_SMEM_ID,
  294. &size);
  295. if (IS_ERR_OR_NULL(smem_pointer_adsp) || !size) {
  296. pr_err("%s:Failed to get fetch sysmon data from SMEM for ADSP: %d, size: %d\n",
  297. __func__, PTR_ERR(smem_pointer_adsp), size);
  298. g_sysmon_stats.smem_init_adsp = false;
  299. }
  300. update_sysmon_smem_pointers(smem_pointer_adsp, ADSP, size);
  301. if (IS_ERR_OR_NULL(g_sysmon_stats.sysmon_event_stats_adsp)) {
  302. pr_err("%s:Failed to get stats from SMEM for ADSP:\n"
  303. "event stats:%x\n",
  304. __func__, g_sysmon_stats.sysmon_event_stats_adsp);
  305. g_sysmon_stats.smem_init_adsp = false;
  306. }
  307. if (IS_ERR_OR_NULL(g_sysmon_stats.sysmon_power_stats_adsp)) {
  308. pr_err("%s:Failed to get stats from SMEM for ADSP:\n"
  309. "power stats: %x\n",
  310. __func__, g_sysmon_stats.sysmon_power_stats_adsp);
  311. g_sysmon_stats.smem_init_adsp = false;
  312. }
  313. if (IS_ERR_OR_NULL(g_sysmon_stats.q6_avg_load_adsp)) {
  314. pr_err("%s:Failed to get stats from SMEM for ADSP:\n"
  315. "q6_avg_load: %x\n",
  316. __func__, g_sysmon_stats.q6_avg_load_adsp);
  317. g_sysmon_stats.smem_init_adsp = false;
  318. }
  319. }
  320. static void sysmon_smem_init_cdsp(void)
  321. {
  322. size_t size;
  323. void *smem_pointer_cdsp = NULL;
  324. g_sysmon_stats.smem_init_cdsp = true;
  325. g_sysmon_stats.smem_init_cdsp_v2 = true;
  326. g_sysmon_stats.dsppm_stats_cdsp = qcom_smem_get(CDSP,
  327. DSPPMSTATS_SMEM_ID,
  328. &size);
  329. if (IS_ERR_OR_NULL(g_sysmon_stats.dsppm_stats_cdsp) ||
  330. (sizeof(struct dsppm_stats) > size)) {
  331. pr_err("%s:Failed to get fetch dsppm stats from SMEM for CDSP: %d, size: %d\n",
  332. __func__, PTR_ERR(g_sysmon_stats.dsppm_stats_cdsp), size);
  333. g_sysmon_stats.smem_init_cdsp = false;
  334. }
  335. g_sysmon_stats.sleep_stats_cdsp = qcom_smem_get(CDSP,
  336. SLEEPSTATS_SMEM_ID_CDSP,
  337. &size);
  338. if (IS_ERR_OR_NULL(g_sysmon_stats.sleep_stats_cdsp) ||
  339. (sizeof(struct sleep_stats) > size)) {
  340. pr_err("%s:Failed to get fetch sleep data from SMEM for CDSP: %d, size: %d\n",
  341. __func__, PTR_ERR(g_sysmon_stats.sleep_stats_cdsp), size);
  342. g_sysmon_stats.smem_init_cdsp = false;
  343. }
  344. smem_pointer_cdsp = qcom_smem_get(CDSP,
  345. SYSMON_SMEM_ID,
  346. &size);
  347. if (IS_ERR_OR_NULL(smem_pointer_cdsp) || !size) {
  348. pr_err("%s:Failed to get fetch data from SMEM for CDSP: %d, size: %d\n",
  349. __func__, PTR_ERR(smem_pointer_cdsp), size);
  350. g_sysmon_stats.smem_init_cdsp = false;
  351. }
  352. update_sysmon_smem_pointers(smem_pointer_cdsp, CDSP, size);
  353. if (IS_ERR_OR_NULL(g_sysmon_stats.sysmon_event_stats_cdsp)) {
  354. pr_err("%s:Failed to get stats from SMEM for CDSP:\n"
  355. "event stats:%x\n",
  356. __func__, g_sysmon_stats.sysmon_event_stats_cdsp);
  357. g_sysmon_stats.smem_init_cdsp = false;
  358. }
  359. if (IS_ERR_OR_NULL(g_sysmon_stats.sysmon_power_stats_cdsp)) {
  360. pr_err("%s:Failed to get stats from SMEM for CDSP:\n"
  361. " power stats: %x\n",
  362. __func__, g_sysmon_stats.sysmon_power_stats_cdsp);
  363. g_sysmon_stats.smem_init_cdsp = false;
  364. }
  365. if (IS_ERR_OR_NULL(g_sysmon_stats.q6_avg_load_cdsp)) {
  366. pr_err("%s:Failed to get stats from SMEM for CDSP:\n"
  367. "q6_avg_load: %x\n",
  368. __func__, g_sysmon_stats.q6_avg_load_cdsp);
  369. g_sysmon_stats.smem_init_cdsp = false;
  370. }
  371. if (IS_ERR_OR_NULL(g_sysmon_stats.hmx_util)) {
  372. pr_err("%s:Failed to get stats from SMEM for CDSP:\n"
  373. "hmx_util: %x\n",
  374. __func__, g_sysmon_stats.hmx_util);
  375. g_sysmon_stats.smem_init_cdsp_v2 = false;
  376. }
  377. if (IS_ERR_OR_NULL(g_sysmon_stats.hvx_util)) {
  378. pr_err("%s:Failed to get stats from SMEM for CDSP:\n"
  379. "hmx_util: %x\n",
  380. __func__, g_sysmon_stats.hvx_util);
  381. g_sysmon_stats.smem_init_cdsp_v2 = false;
  382. }
  383. }
  384. static void sysmon_smem_init_slpi(void)
  385. {
  386. size_t size;
  387. void *smem_pointer_slpi = NULL;
  388. g_sysmon_stats.smem_init_slpi = true;
  389. g_sysmon_stats.sleep_stats_slpi = qcom_smem_get(SLPI,
  390. SLEEPSTATS_SMEM_ID_SLPI,
  391. &size);
  392. if (IS_ERR_OR_NULL(g_sysmon_stats.sleep_stats_slpi) ||
  393. (sizeof(struct sleep_stats) > size)) {
  394. pr_err("%s:Failed to get fetch sleep data from SMEM for SLPI: %d, size: %d\n",
  395. __func__, PTR_ERR(g_sysmon_stats.sleep_stats_slpi), size);
  396. g_sysmon_stats.smem_init_slpi = false;
  397. }
  398. g_sysmon_stats.sleep_lpi_slpi = qcom_smem_get(SLPI,
  399. SLEEPSTATS_LPI_SMEM_ID,
  400. &size);
  401. if (IS_ERR_OR_NULL(g_sysmon_stats.sleep_lpi_slpi) ||
  402. (sizeof(struct sleep_stats_island) > size)) {
  403. pr_err("%s:Failed to get fetch LPI sleep data from SMEM for SLPI: %d, size: %d\n",
  404. __func__, PTR_ERR(g_sysmon_stats.sleep_lpi_slpi), size);
  405. g_sysmon_stats.smem_init_slpi = false;
  406. }
  407. smem_pointer_slpi = qcom_smem_get(SLPI,
  408. SYSMON_SMEM_ID,
  409. &size);
  410. if (IS_ERR_OR_NULL(smem_pointer_slpi) || !size) {
  411. pr_err("%s:Failed to get fetch data from SMEM for SLPI: %d, size: %d\n",
  412. __func__, PTR_ERR(smem_pointer_slpi), size);
  413. }
  414. update_sysmon_smem_pointers(smem_pointer_slpi, SLPI, size);
  415. if (IS_ERR_OR_NULL(g_sysmon_stats.sysmon_event_stats_slpi)) {
  416. pr_err("%s:Failed to get stats from SMEM for SLPI:\n"
  417. "event stats:%x\n",
  418. __func__, g_sysmon_stats.sysmon_event_stats_slpi);
  419. g_sysmon_stats.smem_init_slpi = false;
  420. }
  421. if (IS_ERR_OR_NULL(g_sysmon_stats.sysmon_power_stats_slpi)) {
  422. pr_err("%s:Failed to get stats from SMEM for SLPI:\n"
  423. "power stats: %x\n",
  424. __func__, g_sysmon_stats.sysmon_power_stats_slpi);
  425. g_sysmon_stats.smem_init_slpi = false;
  426. }
  427. if (IS_ERR_OR_NULL(g_sysmon_stats.q6_avg_load_slpi)) {
  428. pr_err("%s:Failed to get stats from SMEM for SLPI:\n"
  429. "q6_avg_load: %x\n",
  430. __func__, g_sysmon_stats.q6_avg_load_slpi);
  431. g_sysmon_stats.smem_init_slpi = false;
  432. }
  433. }
  434. /**
  435. * sysmon_read_hmx_util() - Checks for CDSP power collapse
  436. * and resets the HMX utilization to zero if dsp is power collapsed.
  437. */
  438. static u32 sysmon_read_hmx_util(void)
  439. {
  440. struct sysmon_smem_hmx_stats sysmon_hmx_util;
  441. u64 curr_timestamp = __arch_counter_get_cntvct();
  442. u64 last_hmx_update_at = 0;
  443. memcpy(&sysmon_hmx_util,
  444. g_sysmon_stats.hmx_util,
  445. sizeof(struct sysmon_smem_hmx_stats));
  446. last_hmx_update_at =
  447. (u64) (((u64)sysmon_hmx_util.Last_update_time_load_msb << 32)|
  448. sysmon_hmx_util.Last_update_time_load_lsb);
  449. if ((curr_timestamp > last_hmx_update_at) &&
  450. ((curr_timestamp - last_hmx_update_at) / SYS_CLK_TICKS_PER_MS) > 100) {
  451. sysmon_hmx_util.hmx_util_avg = 0;
  452. }
  453. if (sysmon_hmx_util.hmx_util_avg == HMX_HVX_PMU_EVENTS_NA)
  454. pr_err("HMX PMU not registered, user ovveride pmu counter\n");
  455. return sysmon_hmx_util.hmx_util_avg;
  456. }
  457. /**
  458. * sysmon_stats_query_hmx_utlization() - * API to query
  459. * CDSP hmx utlization.On success, returns HMX utilization
  460. * in the hmx_util parameter.
  461. * @arg1: u32 pointer to HMX utilization in percentage.
  462. * @return: SUCCESS (0) if Query is successful
  463. * FAILURE (Non-zero) if Query could not be processed, refer error codes.
  464. */
  465. int sysmon_stats_query_hmx_utlization(u32 *hmx_util)
  466. {
  467. u32 hmx_utilization = 0;
  468. int ret = 0;
  469. if (!g_sysmon_stats.smem_init_cdsp_v2)
  470. sysmon_smem_init_cdsp();
  471. if (!IS_ERR_OR_NULL(g_sysmon_stats.hmx_util)) {
  472. hmx_utilization = sysmon_read_hmx_util();
  473. if (hmx_utilization == HMX_HVX_PMU_EVENTS_NA) {
  474. hmx_utilization = 0;
  475. ret = DSP_PMU_COUNTER_NA;
  476. }
  477. memcpy(hmx_util, &hmx_utilization, sizeof(u32));
  478. } else
  479. return -ENOKEY;
  480. return ret;
  481. }
  482. EXPORT_SYMBOL(sysmon_stats_query_hmx_utlization);
  483. /**
  484. * sysmon_read_hvx_util() - Checks for CDSP power collapse
  485. * and resets the HVX utilization to zero if dsp is power collapsed.
  486. */
  487. static u32 sysmon_read_hvx_util(void)
  488. {
  489. struct sysmon_smem_hvx_stats sysmon_hvx_util;
  490. u64 curr_timestamp = __arch_counter_get_cntvct();
  491. u64 last_hvx_update_at = 0;
  492. memcpy(&sysmon_hvx_util,
  493. g_sysmon_stats.hvx_util,
  494. sizeof(struct sysmon_smem_hvx_stats));
  495. last_hvx_update_at =
  496. (u64) (((u64)sysmon_hvx_util.Last_update_time_load_msb << 32)|
  497. sysmon_hvx_util.Last_update_time_load_lsb);
  498. if ((curr_timestamp > last_hvx_update_at) &&
  499. ((curr_timestamp - last_hvx_update_at) / SYS_CLK_TICKS_PER_MS) > 100) {
  500. sysmon_hvx_util.hvx_util_avg = 0;
  501. }
  502. if (sysmon_hvx_util.hvx_util_avg == HMX_HVX_PMU_EVENTS_NA)
  503. pr_err("HVX PMU not registered, user ovveride pmu counter\n");
  504. return sysmon_hvx_util.hvx_util_avg;
  505. }
  506. /**
  507. * sysmon_stats_query_hvx_utlization() - * API to query
  508. * CDSP subsystem hvx utlization.On success, returns HVX utilization
  509. * in the hvx_util parameter.
  510. * @arg1: u32 pointer to HVX utilization in percentage.
  511. * @return: SUCCESS (0) if Query is successful
  512. * FAILURE (Non-zero) if Query could not be processed, refer error codes.
  513. */
  514. int sysmon_stats_query_hvx_utlization(u32 *hvx_util)
  515. {
  516. u32 hvx_utilization = 0;
  517. int ret = 0;
  518. if (!g_sysmon_stats.smem_init_cdsp_v2)
  519. sysmon_smem_init_cdsp();
  520. if (!IS_ERR_OR_NULL(g_sysmon_stats.hvx_util)) {
  521. hvx_utilization = sysmon_read_hvx_util();
  522. if (hvx_utilization == HMX_HVX_PMU_EVENTS_NA) {
  523. hvx_utilization = 0;
  524. ret = DSP_PMU_COUNTER_NA;
  525. }
  526. memcpy(hvx_util, &hvx_utilization, sizeof(u32));
  527. } else
  528. return -ENOKEY;
  529. return ret;
  530. }
  531. EXPORT_SYMBOL(sysmon_stats_query_hvx_utlization);
  532. /**
  533. * sysmon_stats_query_power_residency() - * API to query requested
  534. * DSP subsystem power residency.On success, returns power residency
  535. * statistics in the given sysmon_smem_power_stats structure.
  536. */
  537. int sysmon_stats_query_power_residency(enum dsp_id_t dsp_id,
  538. struct sysmon_smem_power_stats *sysmon_power_stats)
  539. {
  540. int ret = 0, size = 0;
  541. u64 lpi_accumulated = 0;
  542. u64 lpm_accumulated = 0;
  543. struct sysmon_smem_power_stats_extended *ptr = NULL, smem_sysmon_power_stats_l = { 0 };
  544. if (!sysmon_power_stats) {
  545. pr_err("%s: Null pointer received\n", __func__);
  546. return -EINVAL;
  547. }
  548. switch (dsp_id) {
  549. case ADSP:
  550. if (!g_sysmon_stats.smem_init_adsp)
  551. sysmon_smem_init_adsp();
  552. if (!IS_ERR_OR_NULL(g_sysmon_stats.sysmon_power_stats_adsp)) {
  553. ptr = g_sysmon_stats.sysmon_power_stats_adsp;
  554. size = (((ptr->powerstats.version) >> 16) & 0xFFF) + sizeof(u32);
  555. memcpy(&smem_sysmon_power_stats_l,
  556. g_sysmon_stats.sysmon_power_stats_adsp,
  557. size <= sizeof(struct sysmon_smem_power_stats_extended) ?
  558. size :
  559. sizeof(struct sysmon_smem_power_stats_extended));
  560. if (g_sysmon_stats.sleep_stats_adsp) {
  561. lpm_accumulated = g_sysmon_stats.sleep_stats_adsp->accumulated;
  562. if (g_sysmon_stats.sleep_stats_adsp->last_entered_at >
  563. g_sysmon_stats.sleep_stats_adsp->last_exited_at)
  564. lpm_accumulated += arch_timer_read_counter() -
  565. g_sysmon_stats.sleep_stats_adsp->last_entered_at;
  566. }
  567. if (g_sysmon_stats.sleep_lpi_adsp) {
  568. lpi_accumulated = g_sysmon_stats.sleep_lpi_adsp->accumulated;
  569. if (g_sysmon_stats.sleep_lpi_adsp->last_entered_at >
  570. g_sysmon_stats.sleep_lpi_adsp->last_exited_at)
  571. lpi_accumulated += arch_timer_read_counter() -
  572. g_sysmon_stats.sleep_lpi_adsp->last_entered_at;
  573. }
  574. } else
  575. ret = -ENOKEY;
  576. break;
  577. case CDSP:
  578. if (!g_sysmon_stats.smem_init_cdsp)
  579. sysmon_smem_init_cdsp();
  580. if (!IS_ERR_OR_NULL(g_sysmon_stats.sysmon_power_stats_cdsp)) {
  581. ptr = g_sysmon_stats.sysmon_power_stats_cdsp;
  582. size = (((ptr->powerstats.version) >> 16) & 0xFFF) + sizeof(u32);
  583. memcpy(&smem_sysmon_power_stats_l, g_sysmon_stats.sysmon_power_stats_cdsp,
  584. size <= sizeof(struct sysmon_smem_power_stats_extended) ? size :
  585. sizeof(struct sysmon_smem_power_stats_extended));
  586. if (g_sysmon_stats.sleep_stats_cdsp) {
  587. lpm_accumulated = g_sysmon_stats.sleep_stats_cdsp->accumulated;
  588. if (g_sysmon_stats.sleep_stats_cdsp->last_entered_at >
  589. g_sysmon_stats.sleep_stats_cdsp->last_exited_at)
  590. lpm_accumulated += arch_timer_read_counter() -
  591. g_sysmon_stats.sleep_stats_cdsp->last_entered_at;
  592. }
  593. } else
  594. ret = -ENOKEY;
  595. break;
  596. case SLPI:
  597. if (!g_sysmon_stats.smem_init_slpi)
  598. sysmon_smem_init_slpi();
  599. if (!IS_ERR_OR_NULL(g_sysmon_stats.sysmon_power_stats_slpi)) {
  600. ptr = g_sysmon_stats.sysmon_power_stats_slpi;
  601. size = (((ptr->powerstats.version) >> 16) & 0xFFF) + sizeof(u32);
  602. memcpy(&smem_sysmon_power_stats_l, g_sysmon_stats.sysmon_power_stats_slpi,
  603. size <= sizeof(struct sysmon_smem_power_stats_extended) ? size :
  604. sizeof(struct sysmon_smem_power_stats_extended));
  605. if (g_sysmon_stats.sleep_stats_slpi) {
  606. lpm_accumulated = g_sysmon_stats.sleep_stats_slpi->accumulated;
  607. if (g_sysmon_stats.sleep_stats_slpi->last_entered_at >
  608. g_sysmon_stats.sleep_stats_slpi->last_exited_at)
  609. lpm_accumulated += arch_timer_read_counter() -
  610. g_sysmon_stats.sleep_stats_slpi->last_entered_at;
  611. }
  612. if (g_sysmon_stats.sleep_lpi_slpi) {
  613. lpi_accumulated = g_sysmon_stats.sleep_lpi_slpi->accumulated;
  614. if (g_sysmon_stats.sleep_lpi_slpi->last_entered_at >
  615. g_sysmon_stats.sleep_lpi_slpi->last_exited_at)
  616. lpi_accumulated += arch_timer_read_counter() -
  617. g_sysmon_stats.sleep_lpi_slpi->last_entered_at;
  618. }
  619. } else
  620. ret = -ENOKEY;
  621. break;
  622. default:
  623. pr_err("%s:Provided subsystem %d is not supported\n", __func__, dsp_id);
  624. ret = -EINVAL;
  625. break;
  626. }
  627. if (ret == 0) {
  628. ret = add_delta_time((ptr->powerstats.version) & 0xFF, lpi_accumulated,
  629. lpm_accumulated, &smem_sysmon_power_stats_l);
  630. if (ret == 0) {
  631. memcpy(sysmon_power_stats, &smem_sysmon_power_stats_l.powerstats,
  632. sizeof(struct sysmon_smem_power_stats));
  633. sysmon_power_stats->version = (ptr->powerstats.version) & 0xFF;
  634. }
  635. }
  636. return ret;
  637. }
  638. EXPORT_SYMBOL(sysmon_stats_query_power_residency);
  639. /**
  640. * API to query requested DSP subsystem's Q6 clock and bandwidth.
  641. * On success, returns Q6 clock and bandwidth statistics in the given
  642. * sysmon_smem_q6_event_stats structure.
  643. */
  644. int sysmon_stats_query_q6_votes(enum dsp_id_t dsp_id,
  645. struct sysmon_smem_q6_event_stats *sysmon_q6_event_stats)
  646. {
  647. int ret = 0;
  648. if (!sysmon_q6_event_stats) {
  649. pr_err("%s: Null pointer received\n", __func__);
  650. return -EINVAL;
  651. }
  652. switch (dsp_id) {
  653. case ADSP:
  654. if (!g_sysmon_stats.smem_init_adsp)
  655. sysmon_smem_init_adsp();
  656. if (!IS_ERR_OR_NULL(g_sysmon_stats.sysmon_event_stats_adsp))
  657. memcpy(sysmon_q6_event_stats, g_sysmon_stats.sysmon_event_stats_adsp,
  658. sizeof(struct sysmon_smem_q6_event_stats));
  659. else
  660. ret = -ENOKEY;
  661. break;
  662. case CDSP:
  663. if (!g_sysmon_stats.smem_init_cdsp)
  664. sysmon_smem_init_cdsp();
  665. if (!IS_ERR_OR_NULL(g_sysmon_stats.sysmon_event_stats_cdsp))
  666. memcpy(sysmon_q6_event_stats, g_sysmon_stats.sysmon_event_stats_cdsp,
  667. sizeof(struct sysmon_smem_q6_event_stats));
  668. else
  669. ret = -ENOKEY;
  670. break;
  671. case SLPI:
  672. if (!g_sysmon_stats.smem_init_slpi)
  673. sysmon_smem_init_slpi();
  674. if (!IS_ERR_OR_NULL(g_sysmon_stats.sysmon_event_stats_slpi))
  675. memcpy(sysmon_q6_event_stats, g_sysmon_stats.sysmon_event_stats_slpi,
  676. sizeof(struct sysmon_smem_q6_event_stats));
  677. else
  678. ret = -ENOKEY;
  679. break;
  680. default:
  681. pr_err("%s:Provided subsystem %d is not supported\n", __func__, dsp_id);
  682. ret = -EINVAL;
  683. break;
  684. }
  685. return ret;
  686. }
  687. EXPORT_SYMBOL(sysmon_stats_query_q6_votes);
  688. /*Checks for DSP power collapse and resets the q6 average
  689. *load to zero if dsp is power collapsed.
  690. */
  691. u32 sysmon_read_q6_load(enum dsp_id_t dsp_id)
  692. {
  693. struct sysmon_smem_q6_load_stats sysmon_q6_load;
  694. u64 last_q6load_update_at = 0;
  695. u64 curr_timestamp = __arch_counter_get_cntvct();
  696. switch (dsp_id) {
  697. case ADSP:
  698. memcpy(&sysmon_q6_load,
  699. g_sysmon_stats.q6_avg_load_adsp,
  700. sizeof(struct sysmon_smem_q6_load_stats));
  701. last_q6load_update_at =
  702. (u64) (((u64)sysmon_q6_load.Last_update_time_load_msb<<32)|
  703. sysmon_q6_load.Last_update_time_load_lsb);
  704. if ((curr_timestamp > last_q6load_update_at) &&
  705. ((curr_timestamp - last_q6load_update_at) / SYS_CLK_TICKS_PER_MS) > 100) {
  706. sysmon_q6_load.q6load_avg = 0;
  707. }
  708. break;
  709. case CDSP:
  710. memcpy(&sysmon_q6_load,
  711. g_sysmon_stats.q6_avg_load_cdsp,
  712. sizeof(struct sysmon_smem_q6_load_stats));
  713. last_q6load_update_at =
  714. (u64) (((u64)sysmon_q6_load.Last_update_time_load_msb << 32)|
  715. sysmon_q6_load.Last_update_time_load_lsb);
  716. if ((curr_timestamp > last_q6load_update_at) &&
  717. ((curr_timestamp - last_q6load_update_at) / SYS_CLK_TICKS_PER_MS) > 100) {
  718. sysmon_q6_load.q6load_avg = 0;
  719. }
  720. break;
  721. case SLPI:
  722. memcpy(&sysmon_q6_load,
  723. g_sysmon_stats.q6_avg_load_slpi,
  724. sizeof(struct sysmon_smem_q6_load_stats));
  725. last_q6load_update_at =
  726. (u64) (((u64)sysmon_q6_load.Last_update_time_load_msb << 32)|
  727. sysmon_q6_load.Last_update_time_load_lsb);
  728. if ((curr_timestamp > last_q6load_update_at) &&
  729. ((curr_timestamp - last_q6load_update_at) / SYS_CLK_TICKS_PER_MS) > 100) {
  730. sysmon_q6_load.q6load_avg = 0;
  731. }
  732. break;
  733. default:
  734. pr_err("%s:Provided subsystem %d is not supported\n", __func__, dsp_id);
  735. return -EINVAL;
  736. break;
  737. }
  738. return sysmon_q6_load.q6load_avg;
  739. }
  740. /**
  741. * API to query requested DSP subsystem's Q6 load.
  742. * On success, returns average Q6 load in KCPS for the given
  743. * q6load_avg parameter.
  744. */
  745. int sysmon_stats_query_q6_load(enum dsp_id_t dsp_id, u32 *q6load_avg)
  746. {
  747. int ret = 0;
  748. u32 q6_average_load = 0;
  749. if (!q6load_avg) {
  750. pr_err("%s: Null pointer received\n", __func__);
  751. return -EINVAL;
  752. }
  753. switch (dsp_id) {
  754. case ADSP:
  755. if (!g_sysmon_stats.smem_init_adsp)
  756. sysmon_smem_init_adsp();
  757. if (!IS_ERR_OR_NULL(g_sysmon_stats.q6_avg_load_adsp)) {
  758. q6_average_load = sysmon_read_q6_load(ADSP);
  759. memcpy(q6load_avg, &q6_average_load, sizeof(u32));
  760. } else
  761. ret = -ENOKEY;
  762. break;
  763. case CDSP:
  764. if (!g_sysmon_stats.smem_init_cdsp)
  765. sysmon_smem_init_cdsp();
  766. if (!IS_ERR_OR_NULL(g_sysmon_stats.q6_avg_load_cdsp)) {
  767. q6_average_load = sysmon_read_q6_load(CDSP);
  768. memcpy(q6load_avg, &q6_average_load, sizeof(u32));
  769. } else
  770. ret = -ENOKEY;
  771. break;
  772. case SLPI:
  773. if (!g_sysmon_stats.smem_init_slpi)
  774. sysmon_smem_init_slpi();
  775. if (!IS_ERR_OR_NULL(g_sysmon_stats.q6_avg_load_slpi)) {
  776. q6_average_load = sysmon_read_q6_load(SLPI);
  777. memcpy(q6load_avg, &q6_average_load, sizeof(u32));
  778. } else
  779. ret = -ENOKEY;
  780. break;
  781. default:
  782. pr_err("%s:Provided subsystem %d is not supported\n", __func__, dsp_id);
  783. ret = -EINVAL;
  784. break;
  785. }
  786. return ret;
  787. }
  788. EXPORT_SYMBOL(sysmon_stats_query_q6_load);
  789. /*
  790. * API to query requested DSP subsystem sleep stats for
  791. * LPM and LPI.On success, returns sleep
  792. * statistics in the given sleep_stats structure for LPM and
  793. * LPI(on supported subsystems).
  794. */
  795. int sysmon_stats_query_sleep(enum dsp_id_t dsp_id,
  796. struct sleep_stats *sleep_stats_lpm,
  797. struct sleep_stats_island *sleep_stats_lpi)
  798. {
  799. int ret = 0;
  800. if (!sleep_stats_lpm && !sleep_stats_lpi) {
  801. pr_err("%s: Null pointer received\n", __func__);
  802. return -EINVAL;
  803. }
  804. switch (dsp_id) {
  805. case ADSP:
  806. if (!g_sysmon_stats.smem_init_adsp)
  807. sysmon_smem_init_adsp();
  808. /*
  809. * If a subsystem is in sleep when reading the sleep stats adjust
  810. * the accumulated sleep duration to show actual sleep time.
  811. */
  812. if (sleep_stats_lpm) {
  813. if (!IS_ERR_OR_NULL(g_sysmon_stats.sleep_stats_adsp)) {
  814. if (g_sysmon_stats.sleep_stats_adsp->last_entered_at >
  815. g_sysmon_stats.sleep_stats_adsp->last_exited_at)
  816. g_sysmon_stats.sleep_stats_adsp->accumulated
  817. += arch_timer_read_counter() -
  818. g_sysmon_stats.sleep_stats_adsp->last_entered_at;
  819. memcpy(sleep_stats_lpm, g_sysmon_stats.sleep_stats_adsp,
  820. sizeof(struct sleep_stats));
  821. } else
  822. ret = -ENOKEY;
  823. }
  824. if (sleep_stats_lpi) {
  825. if (!IS_ERR_OR_NULL(g_sysmon_stats.sleep_lpi_adsp)) {
  826. if (g_sysmon_stats.sleep_lpi_adsp->last_entered_at >
  827. g_sysmon_stats.sleep_lpi_adsp->last_exited_at)
  828. g_sysmon_stats.sleep_lpi_adsp->accumulated
  829. += arch_timer_read_counter() -
  830. g_sysmon_stats.sleep_lpi_adsp->last_entered_at;
  831. memcpy(sleep_stats_lpi, g_sysmon_stats.sleep_lpi_adsp,
  832. sizeof(struct sleep_stats_island));
  833. } else
  834. ret = -ENOKEY;
  835. }
  836. break;
  837. case CDSP:
  838. if (!g_sysmon_stats.smem_init_cdsp)
  839. sysmon_smem_init_cdsp();
  840. if (sleep_stats_lpm) {
  841. if (!IS_ERR_OR_NULL(g_sysmon_stats.sleep_stats_cdsp)) {
  842. if (g_sysmon_stats.sleep_stats_cdsp->last_entered_at >
  843. g_sysmon_stats.sleep_stats_cdsp->last_exited_at)
  844. g_sysmon_stats.sleep_stats_cdsp->accumulated
  845. += arch_timer_read_counter() -
  846. g_sysmon_stats.sleep_stats_cdsp->last_entered_at;
  847. memcpy(sleep_stats_lpm, g_sysmon_stats.sleep_stats_cdsp,
  848. sizeof(struct sleep_stats));
  849. } else
  850. ret = -ENOKEY;
  851. }
  852. break;
  853. case SLPI:
  854. if (!g_sysmon_stats.smem_init_slpi)
  855. sysmon_smem_init_slpi();
  856. if (sleep_stats_lpm) {
  857. if (!IS_ERR_OR_NULL(g_sysmon_stats.sleep_stats_slpi)) {
  858. if (g_sysmon_stats.sleep_stats_slpi->last_entered_at >
  859. g_sysmon_stats.sleep_stats_slpi->last_exited_at)
  860. g_sysmon_stats.sleep_stats_slpi->accumulated
  861. += arch_timer_read_counter() -
  862. g_sysmon_stats.sleep_stats_slpi->last_entered_at;
  863. memcpy(sleep_stats_lpm, g_sysmon_stats.sleep_stats_slpi,
  864. sizeof(struct sleep_stats));
  865. } else
  866. ret = -ENOKEY;
  867. }
  868. if (sleep_stats_lpi) {
  869. if (!IS_ERR_OR_NULL(g_sysmon_stats.sleep_lpi_slpi)) {
  870. if (g_sysmon_stats.sleep_lpi_slpi->last_entered_at >
  871. g_sysmon_stats.sleep_lpi_slpi->last_exited_at)
  872. g_sysmon_stats.sleep_lpi_slpi->accumulated
  873. += arch_timer_read_counter() -
  874. g_sysmon_stats.sleep_lpi_slpi->last_entered_at;
  875. memcpy(sleep_stats_lpi, g_sysmon_stats.sleep_lpi_slpi,
  876. sizeof(struct sleep_stats_island));
  877. } else
  878. ret = -ENOKEY;
  879. }
  880. break;
  881. default:
  882. pr_err("%s:Provided subsystem %d is not supported\n", __func__, dsp_id);
  883. ret = -EINVAL;
  884. break;
  885. }
  886. return ret;
  887. }
  888. EXPORT_SYMBOL(sysmon_stats_query_sleep);
  889. static int master_adsp_stats_show(struct seq_file *s, void *d)
  890. {
  891. int i = 0, j = 0, ret = 0;
  892. u64 lpi_accumulated = 0;
  893. u64 lpm_accumulated = 0;
  894. u32 q6_load;
  895. u8 ver = 0;
  896. struct sysmon_smem_power_stats_extended *ptr = NULL, sysmon_power_stats = { 0 };
  897. if (!g_sysmon_stats.smem_init_adsp)
  898. sysmon_smem_init_adsp();
  899. if (g_sysmon_stats.sysmon_event_stats_adsp) {
  900. seq_puts(s, "\nsysMon stats:\n\n");
  901. seq_printf(s, "Core clock(KHz): %d\n",
  902. g_sysmon_stats.sysmon_event_stats_adsp->QDSP6_clk);
  903. seq_printf(s, "Ab vote(Bytes): %llu\n",
  904. (((u64)g_sysmon_stats.sysmon_event_stats_adsp->Ab_vote_msb << 32) |
  905. g_sysmon_stats.sysmon_event_stats_adsp->Ab_vote_lsb));
  906. seq_printf(s, "Ib vote(Bytes): %llu\n",
  907. (((u64)g_sysmon_stats.sysmon_event_stats_adsp->Ib_vote_msb << 32) |
  908. g_sysmon_stats.sysmon_event_stats_adsp->Ib_vote_lsb));
  909. seq_printf(s, "Sleep latency(usec): %u\n",
  910. g_sysmon_stats.sysmon_event_stats_adsp->Sleep_latency > 0 ?
  911. g_sysmon_stats.sysmon_event_stats_adsp->Sleep_latency : U32_MAX);
  912. }
  913. if (g_sysmon_stats.dsppm_stats_adsp) {
  914. seq_puts(s, "\nDSPPM stats:\n\n");
  915. seq_printf(s, "Version: %u\n", g_sysmon_stats.dsppm_stats_adsp->version);
  916. seq_printf(s, "Sleep latency(usec): %u\n",
  917. g_sysmon_stats.dsppm_stats_adsp->latency_us ?
  918. g_sysmon_stats.dsppm_stats_adsp->latency_us : U32_MAX);
  919. seq_printf(s, "Timestamp: %llu\n", g_sysmon_stats.dsppm_stats_adsp->timestamp);
  920. for (; i < DSPPMSTATS_NUMPD; i++) {
  921. seq_printf(s, "Pid: %d, Num active clients: %d\n",
  922. g_sysmon_stats.dsppm_stats_adsp->pd[i].pid,
  923. g_sysmon_stats.dsppm_stats_adsp->pd[i].num_active);
  924. }
  925. }
  926. if (g_sysmon_stats.sleep_stats_adsp) {
  927. lpm_accumulated = g_sysmon_stats.sleep_stats_adsp->accumulated;
  928. if (g_sysmon_stats.sleep_stats_adsp->last_entered_at >
  929. g_sysmon_stats.sleep_stats_adsp->last_exited_at)
  930. lpm_accumulated += arch_timer_read_counter() -
  931. g_sysmon_stats.sleep_stats_adsp->last_entered_at;
  932. seq_puts(s, "\nLPM stats:\n\n");
  933. seq_printf(s, "Count = %u\n", g_sysmon_stats.sleep_stats_adsp->count);
  934. seq_printf(s, "Last Entered At = %llu\n",
  935. g_sysmon_stats.sleep_stats_adsp->last_entered_at);
  936. seq_printf(s, "Last Exited At = %llu\n",
  937. g_sysmon_stats.sleep_stats_adsp->last_exited_at);
  938. seq_printf(s, "Accumulated Duration = %llu\n", lpm_accumulated);
  939. }
  940. if (g_sysmon_stats.sleep_lpi_adsp) {
  941. lpi_accumulated = g_sysmon_stats.sleep_lpi_adsp->accumulated;
  942. if (g_sysmon_stats.sleep_lpi_adsp->last_entered_at >
  943. g_sysmon_stats.sleep_lpi_adsp->last_exited_at)
  944. lpi_accumulated += arch_timer_read_counter() -
  945. g_sysmon_stats.sleep_lpi_adsp->last_entered_at;
  946. seq_puts(s, "\nLPI stats:\n\n");
  947. seq_printf(s, "Count = %u\n", g_sysmon_stats.sleep_lpi_adsp->count);
  948. seq_printf(s, "Last Entered At = %llu\n",
  949. g_sysmon_stats.sleep_lpi_adsp->last_entered_at);
  950. seq_printf(s, "Last Exited At = %llu\n",
  951. g_sysmon_stats.sleep_lpi_adsp->last_exited_at);
  952. seq_printf(s, "Accumulated Duration = %llu\n",
  953. lpi_accumulated);
  954. }
  955. if (g_sysmon_stats.sysmon_power_stats_adsp) {
  956. memcpy(&sysmon_power_stats, g_sysmon_stats.sysmon_power_stats_adsp,
  957. sizeof(struct sysmon_smem_power_stats_extended));
  958. ptr = g_sysmon_stats.sysmon_power_stats_adsp;
  959. ver = (ptr->powerstats.version) & 0xFF;
  960. ret = add_delta_time(ver, lpi_accumulated,
  961. lpm_accumulated, &sysmon_power_stats);
  962. if (ret != 0)
  963. seq_puts(s, "\nWarning: Power Stats are might be Invalid\n");
  964. seq_puts(s, "\nPower Stats:\n\n");
  965. for (j = 0; j < SYSMON_POWER_STATS_MAX_CLK_LEVELS; j++) {
  966. if (sysmon_power_stats.powerstats.clk_arr[j]) {
  967. if (ver >= 2) {
  968. seq_printf(s, "%u : Core Clock(KHz) : %u \tActive Time(sec) : %u \tLPI time(sec) : %u\n",
  969. j,
  970. sysmon_power_stats.powerstats.clk_arr[j],
  971. sysmon_power_stats.powerstats.active_time[j],
  972. sysmon_power_stats.powerstats.island_time[j]);
  973. } else {
  974. seq_printf(s, "%u : Core Clock(KHz): %u \tActive Time(sec): %u\n",
  975. j,
  976. sysmon_power_stats.powerstats.clk_arr[j],
  977. sysmon_power_stats.powerstats.active_time[j]);
  978. }
  979. }
  980. }
  981. seq_printf(s, "Power collapse time(sec) = %u\n",
  982. sysmon_power_stats.powerstats.pc_time);
  983. seq_printf(s, "Total LPI time(sec) = %u\n",
  984. sysmon_power_stats.powerstats.lpi_time);
  985. if (ver >= 2)
  986. seq_printf(s, "Current core clock(KHz) = %u\n",
  987. sysmon_power_stats.powerstats.current_clk);
  988. }
  989. if (g_sysmon_stats.q6_avg_load_adsp) {
  990. seq_puts(s, "\nQ6 load:\n\n");
  991. q6_load = sysmon_read_q6_load(ADSP);
  992. seq_printf(s, "Average Q6 load in KCPS = %u\n", q6_load);
  993. }
  994. return 0;
  995. }
  996. DEFINE_SHOW_ATTRIBUTE(master_adsp_stats);
  997. static int master_cdsp_stats_show(struct seq_file *s, void *d)
  998. {
  999. int i = 0, j = 0, ret = 0;
  1000. u32 hmx_util, hvx_util;
  1001. u32 q6_load;
  1002. u64 lpm_accumulated = 0;
  1003. u8 ver = 0;
  1004. struct sysmon_smem_power_stats_extended *ptr = NULL, sysmon_power_stats = { 0 };
  1005. if (!g_sysmon_stats.smem_init_cdsp)
  1006. sysmon_smem_init_cdsp();
  1007. if (g_sysmon_stats.sysmon_event_stats_cdsp) {
  1008. seq_puts(s, "\nsysMon stats:\n\n");
  1009. seq_printf(s, "Core clock(KHz): %d\n",
  1010. g_sysmon_stats.sysmon_event_stats_cdsp->QDSP6_clk);
  1011. seq_printf(s, "Ab vote(Bytes): %llu\n",
  1012. (((u64)g_sysmon_stats.sysmon_event_stats_cdsp->Ab_vote_msb << 32) |
  1013. g_sysmon_stats.sysmon_event_stats_cdsp->Ab_vote_lsb));
  1014. seq_printf(s, "Ib vote(Bytes): %llu\n",
  1015. (((u64)g_sysmon_stats.sysmon_event_stats_cdsp->Ib_vote_msb << 32) |
  1016. g_sysmon_stats.sysmon_event_stats_cdsp->Ib_vote_lsb));
  1017. seq_printf(s, "Sleep latency(usec): %u\n",
  1018. g_sysmon_stats.sysmon_event_stats_cdsp->Sleep_latency > 0 ?
  1019. g_sysmon_stats.sysmon_event_stats_cdsp->Sleep_latency : U32_MAX);
  1020. }
  1021. if (g_sysmon_stats.dsppm_stats_cdsp) {
  1022. seq_puts(s, "\nDSPPM stats:\n\n");
  1023. seq_printf(s, "Version: %u\n",
  1024. g_sysmon_stats.dsppm_stats_cdsp->version);
  1025. seq_printf(s, "Sleep latency(usec): %u\n",
  1026. g_sysmon_stats.dsppm_stats_cdsp->latency_us ?
  1027. g_sysmon_stats.dsppm_stats_cdsp->latency_us : U32_MAX);
  1028. seq_printf(s, "Timestamp: %llu\n",
  1029. g_sysmon_stats.dsppm_stats_cdsp->timestamp);
  1030. for (; i < DSPPMSTATS_NUMPD; i++) {
  1031. seq_printf(s, "Pid: %d, Num active clients: %d\n",
  1032. g_sysmon_stats.dsppm_stats_cdsp->pd[i].pid,
  1033. g_sysmon_stats.dsppm_stats_cdsp->pd[i].num_active);
  1034. }
  1035. }
  1036. if (g_sysmon_stats.sleep_stats_cdsp) {
  1037. lpm_accumulated = g_sysmon_stats.sleep_stats_cdsp->accumulated;
  1038. if (g_sysmon_stats.sleep_stats_cdsp->last_entered_at >
  1039. g_sysmon_stats.sleep_stats_cdsp->last_exited_at)
  1040. lpm_accumulated += arch_timer_read_counter() -
  1041. g_sysmon_stats.sleep_stats_cdsp->last_entered_at;
  1042. seq_puts(s, "\nLPM stats:\n\n");
  1043. seq_printf(s, "Count = %u\n",
  1044. g_sysmon_stats.sleep_stats_cdsp->count);
  1045. seq_printf(s, "Last Entered At = %llu\n",
  1046. g_sysmon_stats.sleep_stats_cdsp->last_entered_at);
  1047. seq_printf(s, "Last Exited At = %llu\n",
  1048. g_sysmon_stats.sleep_stats_cdsp->last_exited_at);
  1049. seq_printf(s, "Accumulated Duration = %llu\n", lpm_accumulated);
  1050. }
  1051. if (g_sysmon_stats.sysmon_power_stats_cdsp) {
  1052. memcpy(&sysmon_power_stats, g_sysmon_stats.sysmon_power_stats_cdsp,
  1053. sizeof(struct sysmon_smem_power_stats_extended));
  1054. ptr = g_sysmon_stats.sysmon_power_stats_cdsp;
  1055. ver = (ptr->powerstats.version) & 0xFF;
  1056. ret = add_delta_time(ver, 0, lpm_accumulated, &sysmon_power_stats);
  1057. if (ret)
  1058. seq_puts(s, "\nWarning: Power Stats might be Invalid\n");
  1059. seq_puts(s, "\nPower Stats:\n\n");
  1060. for (j = 0; j < SYSMON_POWER_STATS_MAX_CLK_LEVELS; j++) {
  1061. if (sysmon_power_stats.powerstats.clk_arr[j])
  1062. seq_printf(s, "%u : Core Clock(KHz) : %u \tActive Time(sec) : %u\n",
  1063. j,
  1064. sysmon_power_stats.powerstats.clk_arr[j],
  1065. sysmon_power_stats.powerstats.active_time[j]);
  1066. }
  1067. seq_printf(s, "Power collapse time(sec) = %u\n",
  1068. sysmon_power_stats.powerstats.pc_time);
  1069. seq_printf(s, "Total LPI time(sec) = %u\n",
  1070. sysmon_power_stats.powerstats.lpi_time);
  1071. if (ver >= 2)
  1072. seq_printf(s, "Current core clock(KHz) = %u\n",
  1073. sysmon_power_stats.powerstats.current_clk);
  1074. if (ret)
  1075. return ret;
  1076. }
  1077. if (g_sysmon_stats.q6_avg_load_cdsp) {
  1078. seq_puts(s, "\nQ6 load:\n\n");
  1079. q6_load = sysmon_read_q6_load(CDSP);
  1080. seq_printf(s, "Average Q6 load in KCPS = %u\n", q6_load);
  1081. }
  1082. ret = sysmon_stats_query_hmx_utlization(&hmx_util);
  1083. if (ret) {
  1084. seq_printf(s, "\nHMX stats not available, error code: %d\n", ret);
  1085. } else {
  1086. seq_puts(s, "\nHMX stats:\n\n");
  1087. seq_printf(s, "HMX utilization in percentage = %u\n", hmx_util);
  1088. }
  1089. ret = sysmon_stats_query_hvx_utlization(&hvx_util);
  1090. if (ret) {
  1091. seq_printf(s, "\nHVX stats not available, error code: %d\n", ret);
  1092. } else {
  1093. seq_puts(s, "\nHVX Stats:\n\n");
  1094. seq_printf(s, "HVX utilization in percentage = %u\n", hvx_util);
  1095. }
  1096. return 0;
  1097. }
  1098. DEFINE_SHOW_ATTRIBUTE(master_cdsp_stats);
  1099. static int __init sysmon_stats_init(void)
  1100. {
  1101. g_sysmon_stats.debugfs_dir = debugfs_create_dir("sysmon_subsystem_stats", NULL);
  1102. if (!g_sysmon_stats.debugfs_dir) {
  1103. pr_err("Failed to create debugfs directory for sysmon_subsystem_stats\n");
  1104. goto debugfs_bail;
  1105. }
  1106. g_sysmon_stats.debugfs_master_adsp_stats =
  1107. debugfs_create_file("master_adsp_stats",
  1108. 0444, g_sysmon_stats.debugfs_dir, NULL, &master_adsp_stats_fops);
  1109. if (!g_sysmon_stats.debugfs_master_adsp_stats)
  1110. pr_err("Failed to create debugfs file for ADSP master stats\n");
  1111. g_sysmon_stats.debugfs_master_cdsp_stats =
  1112. debugfs_create_file("master_cdsp_stats",
  1113. 0444, g_sysmon_stats.debugfs_dir, NULL, &master_cdsp_stats_fops);
  1114. if (!g_sysmon_stats.debugfs_master_cdsp_stats)
  1115. pr_err("Failed to create debugfs file for CDSP master stats\n");
  1116. debugfs_bail:
  1117. return 0;
  1118. }
  1119. static void __exit sysmon_stats_exit(void)
  1120. {
  1121. debugfs_remove_recursive(g_sysmon_stats.debugfs_dir);
  1122. }
  1123. module_init(sysmon_stats_init);
  1124. module_exit(sysmon_stats_exit);
  1125. MODULE_LICENSE("GPL");
  1126. MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Sysmon subsystem Stats driver");