sys_pm_vx.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2021-2024, Qualcomm Innovation Center, Inc. All rights reserved.
  5. *
  6. */
  7. #define pr_fmt(fmt) "%s: " fmt, __func__
  8. #include <linux/debugfs.h>
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/platform_device.h>
  13. #include <linux/types.h>
  14. #include <linux/of.h>
  15. #include <linux/of_address.h>
  16. #include <linux/slab.h>
  17. #include <linux/seq_file.h>
  18. #include <linux/uaccess.h>
  19. #include <linux/soc/qcom/qcom_aoss.h>
  20. #include <soc/qcom/qcom_stats.h>
  21. #define MAX_QMP_MSG_SIZE 96
  22. #define MODE_AOSS 0xaa
  23. #define MODE_CXPC 0xcc
  24. #define MODE_DDR 0xdd
  25. #define MODE_STR(m) (m == MODE_CXPC ? "CXPC" : \
  26. (m == MODE_AOSS ? "AOSS" : \
  27. (m == MODE_DDR ? "DDR" : "")))
  28. #define VX_MODE_MASK_TYPE 0xFF
  29. #define VX_MODE_MASK_LOGSIZE 0xFF
  30. #define VX_MODE_SHIFT_LOGSIZE 8
  31. #define VX_FLAG_MASK_DUR 0xFFFF
  32. #define VX_FLAG_MASK_TS 0xFF
  33. #define VX_FLAG_SHIFT_TS 16
  34. #define VX_FLAG_MASK_FLUSH_THRESH 0xFF
  35. #define VX_FLAG_SHIFT_FLUSH_THRESH 24
  36. #define DEFAULT_DEBUG_TIME (10 * 1000)
  37. #define DEFAULT_TIMER (5000)
  38. #define MAX_DRV_NAMES 27
  39. #define read_word(base, itr) ({ \
  40. u32 v; \
  41. v = le32_to_cpu(readl_relaxed(base + itr)); \
  42. pr_debug("Addr:%p val:%#x\n", base + itr, v); \
  43. itr += sizeof(u32); \
  44. /* Barrier to enssure sequential read */ \
  45. smp_rmb(); \
  46. v; \
  47. })
  48. struct vx_header {
  49. struct {
  50. u16 unused;
  51. u8 logsize;
  52. u8 type;
  53. } mode;
  54. struct {
  55. u8 flush_threshold;
  56. u8 ts_shift;
  57. u16 dur_ms;
  58. } flags;
  59. };
  60. struct vx_data {
  61. u32 ts;
  62. u32 *drv_vx;
  63. };
  64. struct vx_log {
  65. struct vx_header header;
  66. struct vx_data *data;
  67. int loglines;
  68. };
  69. struct vx_platform_data {
  70. void __iomem *base;
  71. struct dentry *vx_dir;
  72. size_t n_cxpc_drv;
  73. size_t n_aoss_drv;
  74. const char **cxpc_drvs;
  75. const char **aoss_drvs;
  76. struct mutex lock;
  77. struct qmp *qmp;
  78. ktime_t suspend_time;
  79. ktime_t resume_time;
  80. bool debug_enable;
  81. u32 detect_time_ms;
  82. u32 timer_ms;
  83. bool monitor_enable;
  84. bool debug_dump_enable;
  85. };
  86. static struct vx_platform_data *g_pd;
  87. enum {
  88. CXPC_DRV_NAME,
  89. AOSS_DRV_NAME,
  90. };
  91. static const char * const drv_names_kalama[][MAX_DRV_NAMES] = {
  92. [CXPC_DRV_NAME] = {"TZ", "HYP", "HLOS", "L3", "SECPROC", "AUDIO", "AOP", "DEBUG",
  93. "GPU", "DISPLAY", "COMPUTE_DSP", "TME_SW", "TME_HW", "MDM SW",
  94. "MDM HW", "WLAN RF", "WLAN BB", "CAM_IFE0", "CAM_IFE1", "CAM_IFE2",
  95. "DDR AUX", "ARC CPRF", ""},
  96. [AOSS_DRV_NAME] = {"APPS", "SP", "AUDIO", "AOP", "DEBUG", "GPU", "DISPLAY", "COMPUTE",
  97. "TME", "MODEM", "WLAN RF", "WLAN BB", "CAM", ""},
  98. };
  99. static const char * const drv_names_pineapple[][MAX_DRV_NAMES] = {
  100. [CXPC_DRV_NAME] = {"TZ", "L3", "HLOS", "HYP", "SECPROC", "AUDIO", "AOP", "DEBUG",
  101. "GPU", "DISPLAY", "COMPUTE_DSP", "TME_HW", "TME_SW", "MDM SW",
  102. "MDM HW", "MDM Q6 CESTA", "WLAN RF", "WLAN BB", "CAM_IFE0 CESTA",
  103. "CAM_IFE1", "CAM_IFE2", "PCI0 CESTA", "PCI1 CESTA",
  104. "DDR AUX", "ARC CPRF", ""},
  105. [AOSS_DRV_NAME] = {"APPS", "SP", "AUDIO", "AOP", "DEBUG", "GPU", "DISPLAY", "COMPUTE",
  106. "TME", "MODEM", "WLAN RF", "WLAN BB", "CAM", "PCIE", ""},
  107. };
  108. static const char * const drv_names_volcano[][MAX_DRV_NAMES] = {
  109. [CXPC_DRV_NAME] = {"TZ", "L3", "HLOS", "HYP", "RESERVED", "AUDIO", "AOP", "DEBUG",
  110. "GPU", "DISPLAY", "COMPUTE_DSP", "TME_HW", "TME_SW", "MDM SW",
  111. "MDM HW", "RESERVED", "WLAN RF", "WLAN BB", "RESERVED",
  112. "RESERVED", "RESERVED", "RESERVED", "RESERVED", "WPSS",
  113. "DDR AUX", "ARC CPRF", ""},
  114. [AOSS_DRV_NAME] = {"APPS", "RESERVED", "AUDIO", "AOP", "DEBUG", "GPU", "DISPLAY", "COMPUTE",
  115. "TME", "MODEM", "WLAN RF", "WLAN BB", "RESERVED", "RESERVED", "WPSS", ""},
  116. };
  117. static const char * const drv_names_cliffs[][MAX_DRV_NAMES] = {
  118. [CXPC_DRV_NAME] = {"TZ", "L3", "HLOS", "HYP", "SECPROC", "AUDIO", "AOP", "DEBUG",
  119. "GPU", "DISPLAY", "COMPUTE_DSP", "TME_HW", "TME_SW", "MDM SW",
  120. "MDM HW", "MDM Q6 CESTA", "WLAN RF", "WLAN BB", "CAM_IFE0 CESTA",
  121. "CAM_IFE1", "CAM_IFE2", "PCI0 CESTA", "PCI1 CESTA", "WPSS",
  122. "DDR AUX", "ARC CPRF", ""},
  123. [AOSS_DRV_NAME] = {"APPS", "SP", "AUDIO", "AOP", "DEBUG", "GPU", "DISPLAY", "COMPUTE",
  124. "TME", "MODEM", "WLAN RF", "WLAN BB", "CAM", "PCIE", "WPSS", ""},
  125. };
  126. static const char * const drv_names_niobe[][MAX_DRV_NAMES] = {
  127. [CXPC_DRV_NAME] = {"TZ", "L3", "HLOS", "HYP", "SECPROC", "AUDIO", "AOP", "DEBUG",
  128. "GPU", "DISPLAY", "COMPUTE_DSP", "TME_HW", "TME_SW", "DISPLAY",
  129. "RESERVED", "RESERVED", "WLAN RF", "WLAN BB", "RESERVED",
  130. "RESERVED", "PCIE0 CESTA", "PCIE1 CESTA", "PCIE2_CESTA", "DDR AUX",
  131. "ARC CPRF", ""},
  132. [AOSS_DRV_NAME] = {"APPS", "SP", "AUDIO", "AOP", "DEBUG", "GPU", "DISPLAY", "COMPUTE",
  133. "DISPLAY_2ND", "MODEM", "WLAN RF", "WLAN BB", "CAM", "PCIE", ""},
  134. };
  135. static const char * const drv_names_anorak[] = {
  136. "TZ", "L3", "HLOS", "HYP", "SECPROC", "AUDIO", "SENSOR", "AOP", "DEBUG",
  137. "GPU", "DISPLAY", "COMPUTE_DSP", "TIME_HW", "TIME_SW", "DISPLAY_1",
  138. "MDM SW", "MDM HW", "WLAN RF", "WLAN BB", "DDR AUX", "ARC CPRF",
  139. ""
  140. };
  141. static ssize_t debug_time_ms_show(struct device *dev,
  142. struct device_attribute *attr, char *buf)
  143. {
  144. struct vx_platform_data *pd = dev_get_drvdata(dev);
  145. return scnprintf(buf, PAGE_SIZE, "%d\n", pd->detect_time_ms);
  146. }
  147. static ssize_t debug_time_ms_store(struct device *dev,
  148. struct device_attribute *attr, const char *buf, size_t count)
  149. {
  150. struct vx_platform_data *pd = dev_get_drvdata(dev);
  151. int val;
  152. if (kstrtos32(buf, 0, &val))
  153. return -EINVAL;
  154. if (val <= 0) {
  155. pr_err("debug time ms should be greater than zero\n");
  156. return -EINVAL;
  157. }
  158. mutex_lock(&pd->lock);
  159. pd->detect_time_ms = val;
  160. mutex_unlock(&pd->lock);
  161. return count;
  162. }
  163. static DEVICE_ATTR_RW(debug_time_ms);
  164. static ssize_t set_timer_ms_show(struct device *dev,
  165. struct device_attribute *attr, char *buf)
  166. {
  167. struct vx_platform_data *pd = dev_get_drvdata(dev);
  168. return scnprintf(buf, PAGE_SIZE, "%d\n", pd->timer_ms);
  169. }
  170. static ssize_t set_timer_ms_store(struct device *dev,
  171. struct device_attribute *attr, const char *buf, size_t count)
  172. {
  173. struct vx_platform_data *pd = dev_get_drvdata(dev);
  174. int val;
  175. if (kstrtos32(buf, 0, &val))
  176. return -EINVAL;
  177. if (val <= 0) {
  178. pr_err("timer ms should be greater than zero\n");
  179. return -EINVAL;
  180. }
  181. mutex_lock(&pd->lock);
  182. pd->timer_ms = val;
  183. mutex_unlock(&pd->lock);
  184. return count;
  185. }
  186. static DEVICE_ATTR_RW(set_timer_ms);
  187. static ssize_t debug_enable_show(struct device *dev,
  188. struct device_attribute *attr, char *buf)
  189. {
  190. struct vx_platform_data *pd = dev_get_drvdata(dev);
  191. return scnprintf(buf, PAGE_SIZE, "%d\n", pd->debug_enable);
  192. }
  193. static ssize_t debug_enable_store(struct device *dev,
  194. struct device_attribute *attr, const char *buf, size_t count)
  195. {
  196. struct vx_platform_data *pd = dev_get_drvdata(dev);
  197. int val;
  198. if (kstrtos32(buf, 0, &val))
  199. return -EINVAL;
  200. if ((val < 0) || (val > 1)) {
  201. pr_err("input error\n");
  202. return -EINVAL;
  203. }
  204. mutex_lock(&pd->lock);
  205. pd->debug_enable = val;
  206. mutex_unlock(&pd->lock);
  207. subsystem_sleep_debug_enable(pd->debug_enable);
  208. return count;
  209. }
  210. static DEVICE_ATTR_RW(debug_enable);
  211. static void trigger_dump(struct vx_platform_data *pd)
  212. {
  213. int ret = 0;
  214. char buf[MAX_QMP_MSG_SIZE] = {};
  215. if (!pd->debug_dump_enable)
  216. return;
  217. mutex_lock(&pd->lock);
  218. scnprintf(buf, sizeof(buf),
  219. "{class: misc_debug, res: do_crash_dump, tmr: %d}", pd->timer_ms);
  220. ret = qmp_send(pd->qmp, buf, sizeof(buf));
  221. if (ret)
  222. pr_err("Error sending qmp message: %d\n", ret);
  223. mutex_unlock(&pd->lock);
  224. }
  225. static void sys_pm_vx_send_msg(struct vx_platform_data *pd, bool enable)
  226. {
  227. int ret = 0;
  228. char buf[MAX_QMP_MSG_SIZE] = {};
  229. mutex_lock(&pd->lock);
  230. if (enable)
  231. scnprintf(buf, sizeof(buf),
  232. "{class: lpm_mon, type: cxpc, dur: 1000, flush: 5, ts_adj: 1}");
  233. else
  234. scnprintf(buf, sizeof(buf),
  235. "{class: lpm_mon, type: cxpc, dur: 1000, flush: 1, log_once: 1}");
  236. ret = qmp_send(pd->qmp, buf, sizeof(buf));
  237. if (ret)
  238. pr_err("Error sending qmp message: %d\n", ret);
  239. mutex_unlock(&pd->lock);
  240. }
  241. static const char **vx_get_drvs_info(u8 type, struct vx_platform_data *pd,
  242. size_t *ndrvs)
  243. {
  244. const char **drvs;
  245. switch (type) {
  246. case MODE_CXPC:
  247. case MODE_DDR:
  248. *ndrvs = pd->n_cxpc_drv;
  249. drvs = pd->cxpc_drvs;
  250. break;
  251. case MODE_AOSS:
  252. *ndrvs = pd->n_aoss_drv;
  253. drvs = pd->aoss_drvs;
  254. break;
  255. default:
  256. return NULL;
  257. }
  258. return drvs;
  259. }
  260. static int read_vx_data(struct vx_platform_data *pd, struct vx_log *log)
  261. {
  262. void __iomem *base = pd->base;
  263. struct vx_header *hdr = &log->header;
  264. struct vx_data *data;
  265. u32 *vx, val, itr = 0;
  266. int i, j, k;
  267. size_t n_drv;
  268. const char **drvs;
  269. val = read_word(base, itr);
  270. if (!val)
  271. return -ENOENT;
  272. hdr->mode.type = val & VX_MODE_MASK_TYPE;
  273. hdr->mode.logsize = (val >> VX_MODE_SHIFT_LOGSIZE) &
  274. VX_MODE_MASK_LOGSIZE;
  275. drvs = vx_get_drvs_info(hdr->mode.type, pd, &n_drv);
  276. if (!drvs || !n_drv)
  277. return -ENODEV;
  278. val = read_word(base, itr);
  279. if (!val)
  280. return -ENOENT;
  281. hdr->flags.dur_ms = val & VX_FLAG_MASK_DUR;
  282. hdr->flags.ts_shift = (val >> VX_FLAG_SHIFT_TS) & VX_FLAG_MASK_TS;
  283. hdr->flags.flush_threshold = (val >> VX_FLAG_SHIFT_FLUSH_THRESH) &
  284. VX_FLAG_MASK_FLUSH_THRESH;
  285. data = kcalloc(hdr->mode.logsize, sizeof(*data), GFP_KERNEL);
  286. if (!data)
  287. return -ENOMEM;
  288. for (i = 0; i < hdr->mode.logsize; i++) {
  289. data[i].ts = read_word(base, itr);
  290. if (!data[i].ts)
  291. break;
  292. data[i].ts <<= hdr->flags.ts_shift;
  293. vx = kcalloc(ALIGN(n_drv, 4), sizeof(*vx), GFP_KERNEL);
  294. if (!vx)
  295. goto no_mem;
  296. for (j = 0; j < n_drv;) {
  297. val = read_word(base, itr);
  298. for (k = 0; k < 4; k++)
  299. vx[j++] = val >> (8 * k) & 0xFF;
  300. }
  301. data[i].drv_vx = vx;
  302. }
  303. log->data = data;
  304. log->loglines = i;
  305. return 0;
  306. no_mem:
  307. for (j = 0; j < i; j++)
  308. kfree(data[j].drv_vx);
  309. kfree(data);
  310. return -ENOMEM;
  311. }
  312. static void vx_check_drv(struct vx_platform_data *pd)
  313. {
  314. struct vx_log log;
  315. int i, j, ret;
  316. ret = read_vx_data(pd, &log);
  317. if (ret) {
  318. pr_err("fail to read vx data\n");
  319. return;
  320. }
  321. for (i = 0; i < pd->n_cxpc_drv; i++) {
  322. for (j = 0; j < log.loglines; j++) {
  323. if (log.data[j].drv_vx[i] == 0)
  324. break;
  325. if (j == log.loglines - 1) {
  326. pr_warn("DRV: %s has blocked power collapse\n", pd->cxpc_drvs[i]);
  327. trigger_dump(pd);
  328. }
  329. }
  330. }
  331. for (i = 0; i < log.loglines; i++)
  332. kfree(log.data[i].drv_vx);
  333. kfree(log.data);
  334. }
  335. static void show_vx_data(struct vx_platform_data *pd, struct vx_log *log,
  336. struct seq_file *seq)
  337. {
  338. int i, j;
  339. struct vx_header *hdr = &log->header;
  340. struct vx_data *data;
  341. u32 prev;
  342. bool from_exit = false;
  343. const char **drvs;
  344. size_t ndrv;
  345. drvs = vx_get_drvs_info(hdr->mode.type, pd, &ndrv);
  346. if (!drvs || !ndrv)
  347. return;
  348. seq_printf(seq, "Mode : %s\n"
  349. "Duration (ms) : %u\n"
  350. "Time Shift : %u\n"
  351. "Flush Threshold: %u\n"
  352. "Max Log Entries: %u\n",
  353. MODE_STR(hdr->mode.type),
  354. hdr->flags.dur_ms,
  355. hdr->flags.ts_shift,
  356. hdr->flags.flush_threshold,
  357. hdr->mode.logsize);
  358. seq_puts(seq, "Timestamp|");
  359. for (i = 0; i < ndrv; i++)
  360. seq_printf(seq, "%*s|", 8, drvs[i]);
  361. seq_puts(seq, "\n");
  362. for (i = 0; i < log->loglines; i++) {
  363. data = &log->data[i];
  364. seq_printf(seq, "%*x|", 9, data->ts);
  365. /* An all-zero line indicates we entered LPM */
  366. for (j = 0, prev = data->drv_vx[0]; j < ndrv; j++)
  367. prev |= data->drv_vx[j];
  368. if (!prev) {
  369. if (!from_exit) {
  370. seq_printf(seq, "%s Enter\n", MODE_STR(hdr->mode.type));
  371. from_exit = true;
  372. } else {
  373. seq_printf(seq, "%s Exit\n", MODE_STR(hdr->mode.type));
  374. from_exit = false;
  375. }
  376. continue;
  377. }
  378. for (j = 0; j < ndrv; j++)
  379. seq_printf(seq, "%*u|", 8, data->drv_vx[j]);
  380. seq_puts(seq, "\n");
  381. }
  382. }
  383. static int vx_show(struct seq_file *seq, void *data)
  384. {
  385. struct vx_platform_data *pd = seq->private;
  386. struct vx_log log;
  387. int ret;
  388. int i;
  389. /*
  390. * Read the data into memory to allow for
  391. * post processing of data and present it
  392. * cleanly.
  393. */
  394. ret = read_vx_data(pd, &log);
  395. if (ret)
  396. return ret;
  397. show_vx_data(pd, &log, seq);
  398. for (i = 0; i < log.loglines; i++)
  399. kfree(log.data[i].drv_vx);
  400. kfree(log.data);
  401. return 0;
  402. }
  403. static int open_vx(struct inode *inode, struct file *file)
  404. {
  405. return single_open(file, vx_show, inode->i_private);
  406. }
  407. static const struct file_operations sys_pm_vx_fops = {
  408. .open = open_vx,
  409. .read = seq_read,
  410. .llseek = seq_lseek,
  411. .release = single_release,
  412. };
  413. static int trigger_dump_enable_get(void *data, u64 *val)
  414. {
  415. struct vx_platform_data *pd = data;
  416. mutex_lock(&pd->lock);
  417. *val = (u64)pd->debug_dump_enable;
  418. mutex_unlock(&pd->lock);
  419. return 0;
  420. }
  421. static int trigger_dump_enable_set(void *data, u64 val)
  422. {
  423. struct vx_platform_data *pd = data;
  424. mutex_lock(&pd->lock);
  425. pd->debug_dump_enable = (bool)val;
  426. mutex_unlock(&pd->lock);
  427. return 0;
  428. }
  429. DEFINE_DEBUGFS_ATTRIBUTE(trigger_dump_enable_fops,
  430. trigger_dump_enable_get,
  431. trigger_dump_enable_set,
  432. "%lld\n");
  433. void trigger_dump_enable(void)
  434. {
  435. mutex_lock(&g_pd->lock);
  436. g_pd->debug_dump_enable = true;
  437. mutex_unlock(&g_pd->lock);
  438. }
  439. EXPORT_SYMBOL(trigger_dump_enable);
  440. void trigger_dump_disable(void)
  441. {
  442. mutex_lock(&g_pd->lock);
  443. g_pd->debug_dump_enable = false;
  444. mutex_unlock(&g_pd->lock);
  445. }
  446. EXPORT_SYMBOL(trigger_dump_disable);
  447. static void vx_create_debug_nodes(struct dentry *root, struct vx_platform_data *pd)
  448. {
  449. debugfs_create_file("sys_pm_violators", 0400, root,
  450. pd, &sys_pm_vx_fops);
  451. debugfs_create_file("trigger_dump", 0600, root,
  452. pd, &trigger_dump_enable_fops);
  453. }
  454. static const struct of_device_id drv_match_table[] = {
  455. { .compatible = "qcom,sys-pm-kalama",
  456. .data = drv_names_kalama },
  457. { .compatible = "qcom,sys-pm-pineapple",
  458. .data = drv_names_pineapple },
  459. { .compatible = "qcom,sys-pm-volcano",
  460. .data = drv_names_volcano },
  461. { .compatible = "qcom,sys-pm-cliffs",
  462. .data = drv_names_cliffs },
  463. { .compatible = "qcom,sys-pm-niobe",
  464. .data = drv_names_niobe },
  465. { .compatible = "qcom,sys-pm-anorak",
  466. .data = drv_names_anorak },
  467. { }
  468. };
  469. static int vx_probe(struct platform_device *pdev)
  470. {
  471. const struct of_device_id *match_id;
  472. struct vx_platform_data *pd;
  473. const char **drvs;
  474. int i, ret;
  475. g_pd = pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
  476. if (!pd)
  477. return -ENOMEM;
  478. pd->base = of_iomap(pdev->dev.of_node, 0);
  479. if (IS_ERR_OR_NULL(pd->base))
  480. return PTR_ERR(pd->base);
  481. match_id = of_match_node(drv_match_table, pdev->dev.of_node);
  482. if (!match_id)
  483. return -ENODEV;
  484. drvs = (const char **)match_id->data;
  485. for (i = 0; ; i++) {
  486. const char *name = (const char *)drvs[i];
  487. if (!name[0])
  488. break;
  489. }
  490. pd->n_cxpc_drv = i;
  491. pd->cxpc_drvs = drvs;
  492. for (i = 0; ; i++) {
  493. const char *name = (const char *)drvs[MAX_DRV_NAMES + i];
  494. if (!name[0])
  495. break;
  496. }
  497. pd->n_aoss_drv = i;
  498. pd->aoss_drvs = &drvs[MAX_DRV_NAMES];
  499. pd->vx_dir = debugfs_create_dir("sys_pm_vx", NULL);
  500. if (!pd->vx_dir)
  501. return -EINVAL;
  502. vx_create_debug_nodes(pd->vx_dir, pd);
  503. ret = device_create_file(&pdev->dev, &dev_attr_debug_time_ms);
  504. if (ret) {
  505. dev_err(&pdev->dev, "failed: create sys pm vx sysfs debug time entry\n");
  506. goto fail_create_debug_time;
  507. }
  508. ret = device_create_file(&pdev->dev, &dev_attr_debug_enable);
  509. if (ret) {
  510. dev_err(&pdev->dev, "failed: create sys pm vx sysfs debug enable entry\n");
  511. goto fail_create_debug_enable;
  512. }
  513. ret = device_create_file(&pdev->dev, &dev_attr_set_timer_ms);
  514. if (ret) {
  515. dev_err(&pdev->dev, "failed: create sys pm vx sysfs set timer_ms entry\n");
  516. goto fail_create_set_timer;
  517. }
  518. pd->qmp = qmp_get(&pdev->dev);
  519. if (IS_ERR(pd->qmp)) {
  520. ret = PTR_ERR(pd->qmp);
  521. goto fail_get_qmp;
  522. }
  523. mutex_init(&pd->lock);
  524. pd->detect_time_ms = DEFAULT_DEBUG_TIME;
  525. pd->timer_ms = DEFAULT_TIMER;
  526. pd->debug_enable = false;
  527. pd->monitor_enable = false;
  528. pd->debug_dump_enable = false;
  529. platform_set_drvdata(pdev, pd);
  530. return 0;
  531. fail_get_qmp:
  532. device_remove_file(&pdev->dev, &dev_attr_set_timer_ms);
  533. fail_create_set_timer:
  534. device_remove_file(&pdev->dev, &dev_attr_debug_enable);
  535. fail_create_debug_enable:
  536. device_remove_file(&pdev->dev, &dev_attr_debug_time_ms);
  537. fail_create_debug_time:
  538. debugfs_remove_recursive(pd->vx_dir);
  539. return ret;
  540. }
  541. static int vx_remove(struct platform_device *pdev)
  542. {
  543. struct vx_platform_data *pd = platform_get_drvdata(pdev);
  544. debugfs_remove_recursive(pd->vx_dir);
  545. device_remove_file(&pdev->dev, &dev_attr_debug_time_ms);
  546. device_remove_file(&pdev->dev, &dev_attr_debug_enable);
  547. device_remove_file(&pdev->dev, &dev_attr_set_timer_ms);
  548. qmp_put(pd->qmp);
  549. subsystem_sleep_debug_enable(false);
  550. return 0;
  551. }
  552. static int vx_suspend(struct device *dev)
  553. {
  554. struct vx_platform_data *pd = dev_get_drvdata(dev);
  555. if (!pd->debug_enable)
  556. return 0;
  557. pd->suspend_time = ktime_get_boottime();
  558. if (pd->monitor_enable)
  559. sys_pm_vx_send_msg(pd, pd->monitor_enable);
  560. return 0;
  561. }
  562. static int vx_resume(struct device *dev)
  563. {
  564. struct vx_platform_data *pd = dev_get_drvdata(dev);
  565. ktime_t time_delta_ms;
  566. bool system_slept;
  567. bool subsystem_slept;
  568. if (!pd->debug_enable)
  569. return 0;
  570. pd->resume_time = ktime_get_boottime();
  571. time_delta_ms = ktime_ms_delta(pd->resume_time, pd->suspend_time);
  572. if (time_delta_ms <= pd->detect_time_ms)
  573. return 0;
  574. system_slept = has_system_slept();
  575. if (system_slept)
  576. goto exit;
  577. subsystem_slept = has_subsystem_slept();
  578. if (!subsystem_slept)
  579. goto exit;
  580. /* if monitor was set last time check DRVs blocking system sleep */
  581. if (pd->monitor_enable)
  582. vx_check_drv(pd);
  583. else
  584. pd->monitor_enable = true;
  585. return 0;
  586. exit:
  587. if (pd->monitor_enable)
  588. sys_pm_vx_send_msg(pd, false);
  589. pd->monitor_enable = false;
  590. return 0;
  591. }
  592. static const struct of_device_id vx_table[] = {
  593. { .compatible = "qcom,sys-pm-violators" },
  594. { }
  595. };
  596. static const struct dev_pm_ops vx_pm_ops = {
  597. .suspend = vx_suspend,
  598. .resume = vx_resume,
  599. };
  600. static struct platform_driver vx_driver = {
  601. .probe = vx_probe,
  602. .remove = vx_remove,
  603. .driver = {
  604. .name = "sys-pm-violators",
  605. .of_match_table = vx_table,
  606. .pm = &vx_pm_ops,
  607. },
  608. };
  609. module_platform_driver(vx_driver);
  610. MODULE_LICENSE("GPL");
  611. MODULE_DESCRIPTION("Qualcomm Technologies, Inc. (QTI) System PM Violators driver");
  612. MODULE_ALIAS("platform:sys_pm_vx");