glink_ssr.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2017, Linaro Ltd.
  5. */
  6. #include <linux/completion.h>
  7. #include <linux/module.h>
  8. #include <linux/notifier.h>
  9. #include <linux/rpmsg.h>
  10. #include <linux/remoteproc/qcom_rproc.h>
  11. /**
  12. * struct do_cleanup_msg - The data structure for an SSR do_cleanup message
  13. * version: The G-Link SSR protocol version
  14. * command: The G-Link SSR command - do_cleanup
  15. * seq_num: Sequence number
  16. * name_len: Length of the name of the subsystem being restarted
  17. * name: G-Link edge name of the subsystem being restarted
  18. */
  19. struct do_cleanup_msg {
  20. __le32 version;
  21. __le32 command;
  22. __le32 seq_num;
  23. __le32 name_len;
  24. char name[32];
  25. };
  26. /**
  27. * struct cleanup_done_msg - The data structure for an SSR cleanup_done message
  28. * version: The G-Link SSR protocol version
  29. * response: The G-Link SSR response to a do_cleanup command, cleanup_done
  30. * seq_num: Sequence number
  31. */
  32. struct cleanup_done_msg {
  33. __le32 version;
  34. __le32 response;
  35. __le32 seq_num;
  36. };
  37. /**
  38. * G-Link SSR protocol commands
  39. */
  40. #define GLINK_SSR_DO_CLEANUP 0
  41. #define GLINK_SSR_CLEANUP_DONE 1
  42. struct glink_ssr {
  43. struct device *dev;
  44. struct rpmsg_endpoint *ept;
  45. struct notifier_block nb;
  46. u32 seq_num;
  47. struct completion completion;
  48. };
  49. static int qcom_glink_ssr_callback(struct rpmsg_device *rpdev,
  50. void *data, int len, void *priv, u32 addr)
  51. {
  52. struct cleanup_done_msg *msg = data;
  53. struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
  54. if (len < sizeof(*msg)) {
  55. dev_err(ssr->dev, "message too short\n");
  56. return -EINVAL;
  57. }
  58. if (le32_to_cpu(msg->version) != 0)
  59. return -EINVAL;
  60. if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE)
  61. return 0;
  62. if (le32_to_cpu(msg->seq_num) != ssr->seq_num) {
  63. dev_err(ssr->dev, "invalid sequence number of response\n");
  64. return -EINVAL;
  65. }
  66. complete(&ssr->completion);
  67. return 0;
  68. }
  69. static int qcom_glink_ssr_notify(struct notifier_block *nb, unsigned long event,
  70. void *data)
  71. {
  72. struct glink_ssr *ssr = container_of(nb, struct glink_ssr, nb);
  73. struct do_cleanup_msg msg;
  74. char *ssr_name = data;
  75. int ret;
  76. ssr->seq_num++;
  77. reinit_completion(&ssr->completion);
  78. memset(&msg, 0, sizeof(msg));
  79. msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP);
  80. msg.seq_num = cpu_to_le32(ssr->seq_num);
  81. msg.name_len = cpu_to_le32(strlen(ssr_name));
  82. strlcpy(msg.name, ssr_name, sizeof(msg.name));
  83. ret = rpmsg_send(ssr->ept, &msg, sizeof(msg));
  84. if (ret < 0)
  85. dev_err(ssr->dev, "failed to send cleanup message\n");
  86. ret = wait_for_completion_timeout(&ssr->completion, HZ);
  87. if (!ret)
  88. dev_err(ssr->dev, "timeout waiting for cleanup done message\n");
  89. return NOTIFY_DONE;
  90. }
  91. static int qcom_glink_ssr_probe(struct rpmsg_device *rpdev)
  92. {
  93. struct glink_ssr *ssr;
  94. ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL);
  95. if (!ssr)
  96. return -ENOMEM;
  97. init_completion(&ssr->completion);
  98. ssr->dev = &rpdev->dev;
  99. ssr->ept = rpdev->ept;
  100. ssr->nb.notifier_call = qcom_glink_ssr_notify;
  101. dev_set_drvdata(&rpdev->dev, ssr);
  102. return qcom_register_ssr_notifier(&ssr->nb);
  103. }
  104. static void qcom_glink_ssr_remove(struct rpmsg_device *rpdev)
  105. {
  106. struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
  107. qcom_unregister_ssr_notifier(&ssr->nb);
  108. }
  109. static const struct rpmsg_device_id qcom_glink_ssr_match[] = {
  110. { "glink_ssr" },
  111. {}
  112. };
  113. static struct rpmsg_driver qcom_glink_ssr_driver = {
  114. .probe = qcom_glink_ssr_probe,
  115. .remove = qcom_glink_ssr_remove,
  116. .callback = qcom_glink_ssr_callback,
  117. .id_table = qcom_glink_ssr_match,
  118. .drv = {
  119. .name = "qcom_glink_ssr",
  120. },
  121. };
  122. module_rpmsg_driver(qcom_glink_ssr_driver);
  123. MODULE_ALIAS("rpmsg:glink_ssr");
  124. MODULE_DESCRIPTION("Qualcomm GLINK SSR notifier");
  125. MODULE_LICENSE("GPL v2");