rpm_master_stat.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/debugfs.h>
  7. #include <linux/delay.h>
  8. #include <linux/errno.h>
  9. #include <linux/init.h>
  10. #include <linux/io.h>
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/sched.h>
  15. #include <linux/slab.h>
  16. #include <linux/types.h>
  17. #include <linux/mm.h>
  18. #include <linux/of.h>
  19. #include <linux/uaccess.h>
  20. #define RPM_MASTERS_BUF_LEN 400
  21. #define SNPRINTF(buf, size, format, ...) \
  22. do { \
  23. if (size > 0) { \
  24. int ret; \
  25. ret = scnprintf(buf, size, format, ## __VA_ARGS__); \
  26. buf += ret; \
  27. size -= ret; \
  28. } \
  29. } while (0)
  30. #define GET_MASTER_NAME(a, prvdata) \
  31. ((a >= prvdata->num_masters) ? "Invalid Master Name" : \
  32. prvdata->master_names[a])
  33. #define GET_FIELD(a) ((strnstr(#a, ".", 80) + 1))
  34. #ifdef CONFIG_ARM
  35. #undef readq_relaxed
  36. #define readq_relaxed(a) ({ \
  37. u64 val = readl_relaxed((a) + 4); \
  38. val <<= 32; \
  39. val |= readl_relaxed((a)); \
  40. val; \
  41. })
  42. #endif
  43. struct msm_rpm_master_stats_platform_data {
  44. phys_addr_t phys_addr_base;
  45. u32 phys_size;
  46. char **masters;
  47. /*
  48. * RPM maintains PC stats for each master in MSG RAM,
  49. * it allocates 256 bytes for this use.
  50. * No of masters differs for different targets.
  51. * Based on the number of masters, linux rpm stat
  52. * driver reads (32 * num_masters) bytes to display
  53. * master stats.
  54. */
  55. s32 num_masters;
  56. u32 master_offset;
  57. u32 version;
  58. };
  59. static DEFINE_MUTEX(msm_rpm_master_stats_mutex);
  60. struct msm_rpm_master_stats {
  61. uint32_t active_cores;
  62. uint32_t numshutdowns;
  63. uint64_t shutdown_req;
  64. uint64_t wakeup_ind;
  65. uint64_t bringup_req;
  66. uint64_t bringup_ack;
  67. uint32_t wakeup_reason; /* 0 = rude wakeup, 1 = scheduled wakeup */
  68. uint32_t last_sleep_transition_duration;
  69. uint32_t last_wake_transition_duration;
  70. uint32_t xo_count;
  71. uint64_t xo_last_entered_at;
  72. uint64_t xo_last_exited_at;
  73. uint64_t xo_accumulated_duration;
  74. };
  75. struct msm_rpm_master_stats_private_data {
  76. void __iomem *reg_base;
  77. u32 len;
  78. char **master_names;
  79. u32 num_masters;
  80. char buf[RPM_MASTERS_BUF_LEN];
  81. struct msm_rpm_master_stats_platform_data *platform_data;
  82. };
  83. static int msm_rpm_master_stats_file_close(struct inode *inode,
  84. struct file *file)
  85. {
  86. struct msm_rpm_master_stats_private_data *private = file->private_data;
  87. mutex_lock(&msm_rpm_master_stats_mutex);
  88. if (private->reg_base)
  89. iounmap(private->reg_base);
  90. kfree(file->private_data);
  91. mutex_unlock(&msm_rpm_master_stats_mutex);
  92. return 0;
  93. }
  94. static int msm_rpm_master_copy_stats(
  95. struct msm_rpm_master_stats_private_data *prvdata)
  96. {
  97. struct msm_rpm_master_stats record;
  98. struct msm_rpm_master_stats_platform_data *pdata;
  99. static int master_cnt;
  100. int count, j = 0;
  101. char *buf;
  102. unsigned long active_cores;
  103. /* Iterate possible number of masters */
  104. if (master_cnt > prvdata->num_masters - 1) {
  105. master_cnt = 0;
  106. return 0;
  107. }
  108. pdata = prvdata->platform_data;
  109. count = RPM_MASTERS_BUF_LEN;
  110. buf = prvdata->buf;
  111. if (prvdata->platform_data->version == 2) {
  112. SNPRINTF(buf, count, "%s\n",
  113. GET_MASTER_NAME(master_cnt, prvdata));
  114. record.shutdown_req = readq_relaxed(prvdata->reg_base +
  115. (master_cnt * pdata->master_offset +
  116. offsetof(struct msm_rpm_master_stats, shutdown_req)));
  117. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  118. GET_FIELD(record.shutdown_req),
  119. record.shutdown_req);
  120. record.wakeup_ind = readq_relaxed(prvdata->reg_base +
  121. (master_cnt * pdata->master_offset +
  122. offsetof(struct msm_rpm_master_stats, wakeup_ind)));
  123. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  124. GET_FIELD(record.wakeup_ind),
  125. record.wakeup_ind);
  126. record.bringup_req = readq_relaxed(prvdata->reg_base +
  127. (master_cnt * pdata->master_offset +
  128. offsetof(struct msm_rpm_master_stats, bringup_req)));
  129. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  130. GET_FIELD(record.bringup_req),
  131. record.bringup_req);
  132. record.bringup_ack = readq_relaxed(prvdata->reg_base +
  133. (master_cnt * pdata->master_offset +
  134. offsetof(struct msm_rpm_master_stats, bringup_ack)));
  135. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  136. GET_FIELD(record.bringup_ack),
  137. record.bringup_ack);
  138. record.xo_last_entered_at = readq_relaxed(prvdata->reg_base +
  139. (master_cnt * pdata->master_offset +
  140. offsetof(struct msm_rpm_master_stats,
  141. xo_last_entered_at)));
  142. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  143. GET_FIELD(record.xo_last_entered_at),
  144. record.xo_last_entered_at);
  145. record.xo_last_exited_at = readq_relaxed(prvdata->reg_base +
  146. (master_cnt * pdata->master_offset +
  147. offsetof(struct msm_rpm_master_stats,
  148. xo_last_exited_at)));
  149. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  150. GET_FIELD(record.xo_last_exited_at),
  151. record.xo_last_exited_at);
  152. record.xo_accumulated_duration =
  153. readq_relaxed(prvdata->reg_base +
  154. (master_cnt * pdata->master_offset +
  155. offsetof(struct msm_rpm_master_stats,
  156. xo_accumulated_duration)));
  157. SNPRINTF(buf, count, "\t%s:0x%llX\n",
  158. GET_FIELD(record.xo_accumulated_duration),
  159. record.xo_accumulated_duration);
  160. record.last_sleep_transition_duration =
  161. readl_relaxed(prvdata->reg_base +
  162. (master_cnt * pdata->master_offset +
  163. offsetof(struct msm_rpm_master_stats,
  164. last_sleep_transition_duration)));
  165. SNPRINTF(buf, count, "\t%s:0x%x\n",
  166. GET_FIELD(record.last_sleep_transition_duration),
  167. record.last_sleep_transition_duration);
  168. record.last_wake_transition_duration =
  169. readl_relaxed(prvdata->reg_base +
  170. (master_cnt * pdata->master_offset +
  171. offsetof(struct msm_rpm_master_stats,
  172. last_wake_transition_duration)));
  173. SNPRINTF(buf, count, "\t%s:0x%x\n",
  174. GET_FIELD(record.last_wake_transition_duration),
  175. record.last_wake_transition_duration);
  176. record.xo_count =
  177. readl_relaxed(prvdata->reg_base +
  178. (master_cnt * pdata->master_offset +
  179. offsetof(struct msm_rpm_master_stats,
  180. xo_count)));
  181. SNPRINTF(buf, count, "\t%s:0x%x\n",
  182. GET_FIELD(record.xo_count),
  183. record.xo_count);
  184. record.wakeup_reason = readl_relaxed(prvdata->reg_base +
  185. (master_cnt * pdata->master_offset +
  186. offsetof(struct msm_rpm_master_stats,
  187. wakeup_reason)));
  188. SNPRINTF(buf, count, "\t%s:0x%x\n",
  189. GET_FIELD(record.wakeup_reason),
  190. record.wakeup_reason);
  191. record.numshutdowns = readl_relaxed(prvdata->reg_base +
  192. (master_cnt * pdata->master_offset +
  193. offsetof(struct msm_rpm_master_stats, numshutdowns)));
  194. SNPRINTF(buf, count, "\t%s:0x%x\n",
  195. GET_FIELD(record.numshutdowns),
  196. record.numshutdowns);
  197. record.active_cores = readl_relaxed(prvdata->reg_base +
  198. (master_cnt * pdata->master_offset) +
  199. offsetof(struct msm_rpm_master_stats, active_cores));
  200. SNPRINTF(buf, count, "\t%s:0x%x\n",
  201. GET_FIELD(record.active_cores),
  202. record.active_cores);
  203. } else {
  204. SNPRINTF(buf, count, "%s\n",
  205. GET_MASTER_NAME(master_cnt, prvdata));
  206. record.numshutdowns = readl_relaxed(prvdata->reg_base +
  207. (master_cnt * pdata->master_offset) + 0x0);
  208. SNPRINTF(buf, count, "\t%s:0x%0x\n",
  209. GET_FIELD(record.numshutdowns),
  210. record.numshutdowns);
  211. record.active_cores = readl_relaxed(prvdata->reg_base +
  212. (master_cnt * pdata->master_offset) + 0x4);
  213. SNPRINTF(buf, count, "\t%s:0x%0x\n",
  214. GET_FIELD(record.active_cores),
  215. record.active_cores);
  216. }
  217. active_cores = record.active_cores;
  218. j = find_first_bit(&active_cores, BITS_PER_LONG);
  219. while (j < (BITS_PER_LONG - 1)) {
  220. SNPRINTF(buf, count, "\t\tcore%d\n", j);
  221. j = find_next_bit((const unsigned long *)&active_cores,
  222. BITS_PER_LONG, j + 1);
  223. }
  224. if (j == (BITS_PER_LONG - 1))
  225. SNPRINTF(buf, count, "\t\tcore%d\n", j);
  226. master_cnt++;
  227. return RPM_MASTERS_BUF_LEN - count;
  228. }
  229. static ssize_t msm_rpm_master_stats_file_read(struct file *file,
  230. char __user *bufu, size_t count, loff_t *ppos)
  231. {
  232. struct msm_rpm_master_stats_private_data *prvdata;
  233. struct msm_rpm_master_stats_platform_data *pdata;
  234. ssize_t ret = -EINVAL;
  235. mutex_lock(&msm_rpm_master_stats_mutex);
  236. prvdata = file->private_data;
  237. if (!prvdata)
  238. goto exit;
  239. pdata = prvdata->platform_data;
  240. if (!pdata)
  241. goto exit;
  242. if (!bufu || count == 0)
  243. goto exit;
  244. if (*ppos <= pdata->phys_size) {
  245. prvdata->len = msm_rpm_master_copy_stats(prvdata);
  246. *ppos = 0;
  247. }
  248. ret = simple_read_from_buffer(bufu, count, ppos,
  249. prvdata->buf, prvdata->len);
  250. exit:
  251. mutex_unlock(&msm_rpm_master_stats_mutex);
  252. return ret;
  253. }
  254. static int msm_rpm_master_stats_file_open(struct inode *inode,
  255. struct file *file)
  256. {
  257. struct msm_rpm_master_stats_private_data *prvdata;
  258. struct msm_rpm_master_stats_platform_data *pdata;
  259. int ret = 0;
  260. mutex_lock(&msm_rpm_master_stats_mutex);
  261. pdata = inode->i_private;
  262. file->private_data =
  263. kzalloc(sizeof(struct msm_rpm_master_stats_private_data),
  264. GFP_KERNEL);
  265. if (!file->private_data) {
  266. ret = -ENOMEM;
  267. goto exit;
  268. }
  269. prvdata = file->private_data;
  270. prvdata->reg_base = ioremap(pdata->phys_addr_base,
  271. pdata->phys_size);
  272. if (!prvdata->reg_base) {
  273. kfree(file->private_data);
  274. prvdata = NULL;
  275. pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n",
  276. __func__, &pdata->phys_addr_base,
  277. pdata->phys_size);
  278. ret = -ENOMEM;
  279. goto exit;
  280. }
  281. prvdata->len = 0;
  282. prvdata->num_masters = pdata->num_masters;
  283. prvdata->master_names = pdata->masters;
  284. prvdata->platform_data = pdata;
  285. exit:
  286. mutex_unlock(&msm_rpm_master_stats_mutex);
  287. return ret;
  288. }
  289. static const struct file_operations msm_rpm_master_stats_fops = {
  290. .owner = THIS_MODULE,
  291. .open = msm_rpm_master_stats_file_open,
  292. .read = msm_rpm_master_stats_file_read,
  293. .release = msm_rpm_master_stats_file_close,
  294. .llseek = no_llseek,
  295. };
  296. static struct msm_rpm_master_stats_platform_data
  297. *msm_rpm_master_populate_pdata(struct device *dev)
  298. {
  299. struct msm_rpm_master_stats_platform_data *pdata;
  300. struct device_node *node = dev->of_node;
  301. int rc = 0, i;
  302. pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
  303. if (!pdata)
  304. goto err;
  305. rc = of_property_read_u32(node, "qcom,master-stats-version",
  306. &pdata->version);
  307. if (rc) {
  308. dev_err(dev, "master-stats-version missing rc=%d\n", rc);
  309. goto err;
  310. }
  311. rc = of_property_read_u32(node, "qcom,master-offset",
  312. &pdata->master_offset);
  313. if (rc) {
  314. dev_err(dev, "master-offset missing rc=%d\n", rc);
  315. goto err;
  316. }
  317. pdata->num_masters = of_property_count_strings(node, "qcom,masters");
  318. if (pdata->num_masters < 0) {
  319. dev_err(dev, "Failed to get number of masters =%d\n",
  320. pdata->num_masters);
  321. goto err;
  322. }
  323. pdata->masters = devm_kzalloc(dev, sizeof(char *) * pdata->num_masters,
  324. GFP_KERNEL);
  325. if (!pdata->masters)
  326. goto err;
  327. /*
  328. * Read master names from DT
  329. */
  330. for (i = 0; i < pdata->num_masters; i++) {
  331. const char *master_name;
  332. of_property_read_string_index(node, "qcom,masters",
  333. i, &master_name);
  334. pdata->masters[i] = devm_kstrdup(dev, master_name, GFP_KERNEL);
  335. if (!pdata->masters[i])
  336. goto err;
  337. }
  338. return pdata;
  339. err:
  340. return NULL;
  341. }
  342. static int msm_rpm_master_stats_probe(struct platform_device *pdev)
  343. {
  344. struct dentry *dent;
  345. struct msm_rpm_master_stats_platform_data *pdata;
  346. struct resource *res = NULL;
  347. pdata = msm_rpm_master_populate_pdata(&pdev->dev);
  348. if (!pdata)
  349. return -ENOMEM;
  350. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  351. if (!res) {
  352. dev_err(&pdev->dev,
  353. "%s: Failed to get IO resource from platform device\n",
  354. __func__);
  355. return -ENXIO;
  356. }
  357. pdata->phys_addr_base = res->start;
  358. pdata->phys_size = resource_size(res);
  359. dent = debugfs_create_file("rpm_master_stats", 0444, NULL,
  360. pdata, &msm_rpm_master_stats_fops);
  361. if (!dent) {
  362. dev_err(&pdev->dev, "%s: ERROR debugfs_create_file failed\n",
  363. __func__);
  364. return -ENOMEM;
  365. }
  366. platform_set_drvdata(pdev, dent);
  367. return 0;
  368. }
  369. static int msm_rpm_master_stats_remove(struct platform_device *pdev)
  370. {
  371. struct dentry *dent;
  372. dent = platform_get_drvdata(pdev);
  373. debugfs_remove(dent);
  374. platform_set_drvdata(pdev, NULL);
  375. return 0;
  376. }
  377. static const struct of_device_id rpm_master_table[] = {
  378. {.compatible = "qcom,rpm-master-stats"},
  379. {},
  380. };
  381. static struct platform_driver msm_rpm_master_stats_driver = {
  382. .probe = msm_rpm_master_stats_probe,
  383. .remove = msm_rpm_master_stats_remove,
  384. .driver = {
  385. .name = "msm_rpm_master_stats",
  386. .of_match_table = rpm_master_table,
  387. },
  388. };
  389. static int __init msm_rpm_master_stats_init(void)
  390. {
  391. return platform_driver_register(&msm_rpm_master_stats_driver);
  392. }
  393. static void __exit msm_rpm_master_stats_exit(void)
  394. {
  395. platform_driver_unregister(&msm_rpm_master_stats_driver);
  396. }
  397. module_init(msm_rpm_master_stats_init);
  398. module_exit(msm_rpm_master_stats_exit);
  399. MODULE_LICENSE("GPL");
  400. MODULE_DESCRIPTION("MSM RPM Master Statistics driver");
  401. MODULE_ALIAS("platform:msm_master_stat_log");