glink_probe.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */
  3. #include <linux/of.h>
  4. #include <linux/list.h>
  5. #include <linux/slab.h>
  6. #include <linux/module.h>
  7. #include <linux/notifier.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/remoteproc/qcom_rproc.h>
  10. #include <linux/rpmsg/qcom_glink.h>
  11. #include <linux/rpmsg.h>
  12. #include <linux/ipc_logging.h>
  13. #include <trace/events/rproc_qcom.h>
  14. #define GLINK_PROBE_LOG_PAGE_CNT 4
  15. static void *glink_ilc;
  16. #define GLINK_INFO(x, ...) ipc_log_string(glink_ilc, x, ##__VA_ARGS__)
  17. #define GLINK_ERR(dev, x, ...) \
  18. do { \
  19. dev_err(dev, "[%s]: "x, __func__, ##__VA_ARGS__); \
  20. ipc_log_string(glink_ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \
  21. } while (0)
  22. extern const struct dev_pm_ops glink_native_pm_ops;
  23. struct edge_info {
  24. struct list_head list;
  25. struct device *dev;
  26. struct device_node *node;
  27. const char *glink_label;
  28. const char *ssr_label;
  29. void *glink;
  30. int (*register_fn)(struct edge_info *einfo);
  31. void (*unregister_fn)(struct edge_info *einfo);
  32. struct notifier_block nb;
  33. void *notifier_handle;
  34. };
  35. static LIST_HEAD(edge_infos);
  36. static int glink_probe_ssr_cb(struct notifier_block *this,
  37. unsigned long code, void *data)
  38. {
  39. struct edge_info *einfo = container_of(this, struct edge_info, nb);
  40. GLINK_INFO("received %ld for %s\n", code, einfo->ssr_label);
  41. switch (code) {
  42. case QCOM_SSR_AFTER_POWERUP:
  43. trace_rproc_qcom_event(dev_name(einfo->dev),
  44. "QCOM_SSR_AFTER_POWERUP", "glink_probe_ssr-enter");
  45. einfo->register_fn(einfo);
  46. break;
  47. case QCOM_SSR_AFTER_SHUTDOWN:
  48. trace_rproc_qcom_event(dev_name(einfo->dev),
  49. "QCOM_SSR_AFTER_SHUTDOWN", "glink_probe_ssr-enter");
  50. einfo->unregister_fn(einfo);
  51. break;
  52. default:
  53. break;
  54. }
  55. trace_rproc_qcom_event(dev_name(einfo->dev), "glink_probe_ssr", "exit");
  56. return NOTIFY_DONE;
  57. }
  58. static int glink_probe_smem_reg(struct edge_info *einfo)
  59. {
  60. struct device *dev = einfo->dev;
  61. einfo->glink = qcom_glink_smem_register(dev, einfo->node);
  62. if (IS_ERR_OR_NULL(einfo->glink)) {
  63. GLINK_ERR(dev, "register failed for %s\n", einfo->ssr_label);
  64. einfo->glink = NULL;
  65. }
  66. GLINK_INFO("register successful for %s\n", einfo->ssr_label);
  67. return 0;
  68. }
  69. static void glink_probe_smem_unreg(struct edge_info *einfo)
  70. {
  71. if (einfo->glink)
  72. qcom_glink_smem_unregister(einfo->glink);
  73. einfo->glink = NULL;
  74. GLINK_INFO("unregister for %s\n", einfo->ssr_label);
  75. }
  76. static int glink_probe_spss_reg(struct edge_info *einfo)
  77. {
  78. struct device *dev = einfo->dev;
  79. einfo->glink = qcom_glink_spss_register(dev, einfo->node);
  80. if (IS_ERR_OR_NULL(einfo->glink)) {
  81. GLINK_ERR(dev, "register failed for %s\n", einfo->ssr_label);
  82. einfo->glink = NULL;
  83. }
  84. return 0;
  85. }
  86. static void glink_probe_spss_unreg(struct edge_info *einfo)
  87. {
  88. if (einfo->glink)
  89. qcom_glink_spss_unregister(einfo->glink);
  90. einfo->glink = NULL;
  91. }
  92. static void probe_subsystem(struct device *dev, struct device_node *np)
  93. {
  94. struct edge_info *einfo;
  95. const char *transport;
  96. int ret;
  97. void *handle;
  98. einfo = devm_kzalloc(dev, sizeof(*einfo), GFP_KERNEL);
  99. if (!einfo)
  100. return;
  101. ret = of_property_read_string(np, "label", &einfo->ssr_label);
  102. if (ret < 0)
  103. einfo->ssr_label = np->name;
  104. ret = of_property_read_string(np, "qcom,glink-label",
  105. &einfo->glink_label);
  106. if (ret < 0) {
  107. GLINK_ERR(dev, "no qcom,glink-label for %s\n",
  108. einfo->ssr_label);
  109. return;
  110. }
  111. einfo->dev = dev;
  112. einfo->node = np;
  113. ret = of_property_read_string(np, "transport", &transport);
  114. if (ret < 0) {
  115. GLINK_ERR(dev, "%s missing transport\n", einfo->ssr_label);
  116. return;
  117. }
  118. if (!strcmp(transport, "smem")) {
  119. einfo->register_fn = glink_probe_smem_reg;
  120. einfo->unregister_fn = glink_probe_smem_unreg;
  121. } else if (!strcmp(transport, "spss")) {
  122. einfo->register_fn = glink_probe_spss_reg;
  123. einfo->unregister_fn = glink_probe_spss_unreg;
  124. }
  125. einfo->nb.notifier_call = glink_probe_ssr_cb;
  126. handle = qcom_register_ssr_notifier(einfo->ssr_label, &einfo->nb);
  127. if (IS_ERR_OR_NULL(handle)) {
  128. GLINK_ERR(dev, "could not register for SSR notifier for %s\n",
  129. einfo->ssr_label);
  130. return;
  131. }
  132. einfo->notifier_handle = handle;
  133. list_add_tail(&einfo->list, &edge_infos);
  134. GLINK_INFO("probe successful for %s\n", einfo->ssr_label);
  135. }
  136. static int glink_probe(struct platform_device *pdev)
  137. {
  138. struct device_node *pn = pdev->dev.of_node;
  139. struct device_node *cn;
  140. for_each_available_child_of_node(pn, cn) {
  141. probe_subsystem(&pdev->dev, cn);
  142. }
  143. return 0;
  144. }
  145. static int glink_remove(struct platform_device *pdev)
  146. {
  147. struct device_node *pn = pdev->dev.of_node;
  148. struct device_node *cn;
  149. struct edge_info *einfo, *tmp;
  150. for_each_available_child_of_node(pn, cn) {
  151. list_for_each_entry_safe(einfo, tmp, &edge_infos, list) {
  152. qcom_unregister_ssr_notifier(einfo->notifier_handle,
  153. &einfo->nb);
  154. list_del(&einfo->list);
  155. }
  156. }
  157. return 0;
  158. }
  159. static const struct of_device_id glink_match_table[] = {
  160. { .compatible = "qcom,glink" },
  161. {},
  162. };
  163. static struct platform_driver glink_probe_driver = {
  164. .probe = glink_probe,
  165. .remove = glink_remove,
  166. .driver = {
  167. .name = "msm_glink",
  168. .of_match_table = glink_match_table,
  169. .pm = &glink_native_pm_ops,
  170. },
  171. };
  172. static int __init glink_probe_init(void)
  173. {
  174. int ret;
  175. glink_ilc = ipc_log_context_create(GLINK_PROBE_LOG_PAGE_CNT,
  176. "glink_probe", 0);
  177. ret = platform_driver_register(&glink_probe_driver);
  178. if (ret) {
  179. pr_err("%s: glink_probe register failed %d\n",
  180. __func__, ret);
  181. return ret;
  182. }
  183. return 0;
  184. }
  185. arch_initcall(glink_probe_init);
  186. static void __exit glink_probe_exit(void)
  187. {
  188. if (glink_ilc)
  189. ipc_log_context_destroy(glink_ilc);
  190. platform_driver_unregister(&glink_probe_driver);
  191. }
  192. module_exit(glink_probe_exit);
  193. MODULE_DESCRIPTION("Qualcomm Technologies, Inc. GLINK probe helper driver");
  194. MODULE_LICENSE("GPL");